22 Commits

Author SHA1 Message Date
Kelvin Lawson
5bc174d316 STM8: Use new Makefile names. 2010-06-03 23:04:11 +01:00
Kelvin Lawson
babfd6b9c5 STM8: Correct IAR Makefile object paths for SREC build. 2010-06-03 23:00:20 +01:00
Kelvin Lawson
5635706d4b TESTS: Remove unused variable. 2010-06-03 22:59:47 +01:00
Kelvin Lawson
7f2b53dd61 STM8: Suppress IAR warnings about volatile ordering on logger messages. 2010-06-03 22:59:01 +01:00
Kelvin Lawson
4b42544c3c STM8: Formatting changes only. 2010-06-03 22:58:44 +01:00
Kelvin Lawson
62c2ae9fec STM8: logger warnings. 2010-06-03 22:29:01 +01:00
Kelvin Lawson
af47062d90 STM8: Add GNU make path to README. 2010-06-03 22:22:49 +01:00
Kelvin Lawson
b39b4eac47 STM8: Add details on Makefile builds to IAR README. 2010-06-03 22:05:39 +01:00
Kelvin Lawson
91793d1398 STM8: Merge IAR and Cosmic Makefiles. 2010-06-03 21:24:45 +01:00
Kelvin Lawson
f050c44d73 STM8: Separate Cosmic and IAR Makefiles. 2010-06-03 21:09:14 +01:00
Kelvin Lawson
98547058bf STM8: Add Makefile for IAR EWSTM8 compiler. 2010-06-03 01:19:22 +01:00
Kelvin Lawson
0a2df500dc STM8: Point out that CPU registers are CPU-saved on interrupts on the STM8. 2010-06-01 22:48:04 +01:00
Kelvin Lawson
d4f68440a2 STM8 port: Seperate IAR and Cosmic compiler README files. 2010-06-01 22:41:21 +01:00
Kelvin Lawson
02c9cd040c STM8: Add README for IAR EWSTM8 compiler. 2010-06-01 22:40:54 +01:00
Kelvin Lawson
973e2fb4aa STM8: Enable linker dead-stripping on Cosmic compiler. 2010-05-27 23:03:19 +01:00
Kelvin Lawson
205c05dc25 STM8: New name for Cosmic assembler file. 2010-05-27 00:55:39 +01:00
Kelvin Lawson
5402faf224 STM8: Cosmic compiler: save virtual register c_lreg. Add details on Cosmic virtual registers to documentation. IAR compiler: Add __task to entry points to reduce unnecessary stack usage. 2010-05-27 00:38:45 +01:00
Kelvin Lawson
c0c953b476 STM8 port: Update IAR assembler comments. The IAR compiler is saving ?b0:?b7 in interrupt handlers as expected. 2010-05-25 00:57:14 +01:00
Kelvin Lawson
619c8c3e4a STM8 port: Rename Cosmic/STVD project to atomthreads-sample-cosmic to differentiate from new IAR project. 2010-05-25 00:25:36 +01:00
Kelvin Lawson
08098370d4 STM8/IAR port: Remove unnecessary .dep file. 2010-05-25 00:16:03 +01:00
Kelvin Lawson
394e04ec4a STM8 port: Add RTOS port for IAR EWSTM8 compiler.
* Split assembler routines into -cosmic.s and -iar.s.
* Split Cosmic and IAR specific code using __CSMC__ and __IAR_SYSTEMS_ICC__.
* Context-switch virtual registers on IAR.
* Add detailed description of IAR context-switch scheme.
* Add sample IAR project.
* Add support for IAR to STM8S peripheral driver modules.
* Fix EWSTM8 compiler warnings.
2010-05-24 22:54:40 +01:00
Kelvin Lawson
538a535fe9 STM8: Remove unused code from STM8S peripheral library. Reduces footprint for the benefit of the Cosmic STM8 compiler which does not perform linker dead-stripping. 2010-05-18 00:07:20 +01:00
29 changed files with 5055 additions and 3849 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Atomthreads Project. All rights reserved.
* Copyright (c) 2010, Atomthreads Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions

View File

@@ -7,10 +7,11 @@ License: BSD Revised
---------------------------------------------------------------------------
STM8 PORT
STM8 PORT - COSMIC COMPILER
This folder contains a port of the Atomthreads real time kernel for the
STM8 processor architecture.
STM8 processor architecture. These instructions cover usage of Atomthreads
with the Cosmic compiler (CXSTM8).
All of the cross-platform kernel code is contained in the top-level
'kernel' folder, while ports to specific CPU architectures are contained in
@@ -20,7 +21,7 @@ as the context-switch routine which saves and restores processor registers
on a thread switch. In this case, the kernel port is split into two files:
* atomport.c: Those functions which can be written in C
* atomport-asm.s: The main register save/restore assembler routines
* atomport-asm-cosmic.s: The main register save/restore assembler routines
Each Atomthreads port requires also a header file which describes various
architecture-specific details such as appropriate types for 8-bit, 16-bit
@@ -43,10 +44,12 @@ provides an easy mechanism for building, downloading and running the test
suite to prove the OS on your target.
The port was carried out and tested on an STM8S105C6 running within an
STM8S-Discovery board, utilising the Cosmic compiler tools. It is possible
to use it with other processors in the STM8 range, as well as other
hardware platforms and compilers, with minimal changes. Platform and
compiler specific code has been kept to an absolute minimum.
STM8S-Discovery board, and supports both the Cosmic and IAR compiler tools.
It is possible to use it with other processors in the STM8 range, as well
as other hardware platforms and compilers, with minimal changes. Platform
and compiler specific code has been kept to an absolute minimum. This
README covers usage of Atomthreads with the Cosmic compiler. Instructions
for users of the IAR compiler are available in README-IAR.
---------------------------------------------------------------------------
@@ -56,8 +59,8 @@ PREREQUISITES
The port works out-of-the-box with the Cosmic compiler tools for building.
Applications are generated in .s19 form and can be programmed with any
supporting programming software, including the free STVP (visual
programmer tool). At this time ST do not provide a command-line programmer
application suitable for use with STM8.
programmer tool). At this time there does not appear to be a command-line
programmer application suitable for use with STM8.
The Cosmic compiler and STVP are currently Windows-only applications. For
users of other operating systems the Cosmic compiler may work in
@@ -73,7 +76,7 @@ The core software prerequisites are therefore:
Optionally, application build, program and debug can be carried out
using ST's visual debug tool, STVD.
Use with alternative compiler tools may require some modification, but you
Use with alternative compiler tools will require some modification, but you
can easily replace STVP by your own favourite programmer if required.
@@ -113,9 +116,9 @@ automated tests.
BUILD VIA STVD PROJECT
For building applications using STVD you can use the sample project file
atomthreads-sample.stw. This builds a sample full application which runs
the "sem1" automated test. Applications can be downloaded directly to the
target hardware (e.g. STM8S-Discovery) and run via the integrated
atomthreads-sample-cosmic.stw. This builds a sample full application which
runs the "sem1" automated test. Applications can be downloaded directly to
the target hardware (e.g. STM8S-Discovery) and run via the integrated
debugger. Press the exclamation button to run, and confirm that the LED
flashes once per second (if running on an STM8S-Discovery) to ensure that
the test has passed.
@@ -152,25 +155,25 @@ should set up your environment variables as follows:
The full build is carried out using simply:
* make
* make -f cosmic.mak
All objects are built into the 'build' folder under ports/stm8. The build
process builds separate target applications for each automated test, and
appropriate .stm8 or .s19 files can be found in the build folder ready for
downloading to and running on the target. Because of the limited resources
on the STM8, and the large amount of automated tests, each test is built
and run as a separate application.
All objects are built into the 'build-cosmic' folder under ports/stm8. The
build process builds separate target applications for each automated test,
and appropriate .stm8 or .s19 files can be found in the build folder ready
for downloading to and running on the target. Because of the limited
resources on the STM8, and the large amount of automated tests, each test
is built and run as a separate application.
All built objects etc can be cleaned using:
* make clean
* make -f cosmic.mak clean
The Atomthreads sources are documented using Doxygen markup. You can build
both the kernel and STM8 port documentation from this folder using:
* make doxygen
* make -f cosmic.mak doxygen
---------------------------------------------------------------------------
@@ -241,11 +244,12 @@ The STM8 device on the Discovery only offers UART2. If you are using a
different device or wish to use an alternative UART then you must change
the stm8s_conf.h file.
If you are using a CPU other than the STM8S105C6 you should modify
PART in the Makefile (or the preprocessor settings for both Debug and
Release projects if using the STVD project) to specify your CPU. You may
also wish to enable any CPU peripherals which you wish to use in the
stm8s_conf.h file.
If you are using a CPU other than the STM8S105C6 you should change the
PART macro from "STM8S105" to your target CPU. This can be changed in the
cosmic.mak Makefile. If you are using the STVD project it should be
changed in the project preprocessor settings for both Debug and Release
builds. You may also wish to enable any CPU peripherals which you wish to
use in the stm8s_conf.h file.
---------------------------------------------------------------------------
@@ -255,10 +259,16 @@ RUNNING THE AUTOMATED TESTS
Atomthreads contains a set of generic kernel tests which can be run on any
port to prove that all core functionality is working on your target.
The full set of tests can be found in the top-level 'tests' folder. Each of
these tests is built as an independent application in the 'build' folder.
Run them individually using the STVP process described above. For example
to run the 'kern1.c' test use STVP to program and run it.
The full set of tests can be found in the top-level 'tests' folder. The
Makefile builds each of these tests as independent applications in the
'build' folder. Run them individually using the STVP process described
above. For example to run the 'kern1.c' test use STVP to program and run
it.
You may also build the tests using the STVD project, but to run each
different test you must manually remove the previous test module (e.g.
kern1.c) and replace it with one of other tests, which can be quite time
consuming compared to building all tests in one command via the Makefile.
To view the test results, watch the LED on the STM8S-Discovery. This will
flash once per second if the test passed, and once every 1/8 second if the
@@ -292,9 +302,9 @@ functions. You can generally simply replace the call to the test modules by
a call to your own application startup code.
Projects developed within STVD can be started using the sample workspace
atomthreads-sample.stw. If you wish to create your own STVD project from
scratch, then you should ensure you change the project settings for both
Debug and Release builds as follows:
atomthreads-sample-cosmic.stw. If you wish to create your own STVD project
from scratch, then you should ensure you change the project settings for
both Debug and Release builds as follows:
* Toolset: "STM8 Cosmic"
* MCU Selection: Appropriate for your platform (STM8S10C56 for Discovery)
@@ -347,9 +357,9 @@ what level of stack the application code in question requires.
At this time the maximum stack consumed by the test threads within the
automated test modules is 95 bytes of stack, and the main test thread has
been seen to consume 161 bytes of stack. At this time the timer2 test is
the largest consumer of test thread stack (95 bytes) and the sem4 test
consumes the largest main thread stack (161 bytes). If your applications
been seen to consume 163 bytes of stack. At this time the timer2 test is
the largest consumer of test thread stack (95 bytes) and the sem3 test
consumes the largest main thread stack (163 bytes). If your applications
have large amounts of local data or call several subroutines then you may
find that you need larger than 128 bytes.
@@ -436,4 +446,73 @@ included in any STM8 products. If it is included in future products then
you will need to put the device in the stack compatible mode described.
---------------------------------------------------------------------------
WRITING NEW INTERRUPT HANDLERS
All interrupt handlers which will call out to the OS kernel and potentially
cause a thread switch must call atomIntEnter() and atomIntExit(). An
example of this can be seen in the timer tick ISR in atomport.c.
With the Cosmic compiler port it is also necessary to add the @svlreg
modifier to any interrupt handlers which call out to the OS kernel.
Alternatively you may use the INTERRUPT macro from atomport-private.h which
always adds the @svlreg modifier. This modifier ensures that the c_lreg
virtual register is saved on the interrupted thread's stack for any
preemptive context switches. It also ensures that longs are available for
use within any OS kernel code called as part of the interrupt handling.
You may also implement fast interrupt handlers in the system which do not
call atomIntEnter()/atomIntExit() and which do not need the @svlreg
modifier, however these ISRs cannot perform OS functions such as posting
semaphores or effecting a thread switch.
---------------------------------------------------------------------------
COSMIC COMPILER VIRTUAL REGISTERS
The STM8 has only very few CPU registers, so the Cosmic compiler augments
them with three "virtual" registers, which are simply locations in fast
memory. These registers are called c_x, c_y and c_lreg.
The Atomthreads context switch for Cosmic/STM8 takes advantage of the fact
that all CPU and virtual registers are automatically saved on the stack by
the compiler when calling out to C functions (and even then only if
necessary).
For cooperative context switches (where a thread calls an OS kernel
function to schedule itself out), any of these registers which should be
preserved across the function call are automatically saved on the stack by
the compiler before the context switch is even called. This means that no
CPU or virtual registers actually have to be saved in the context switch
routine, making cooperative switches potentially very cheap if few
registers must be preserved.
For preemptive switches (where an ISR has interrupted a thread and wishes
to switch to a new thread), the interrupt handler prologue automatically
saves all CPU registers (actually done automatically by the CPU) and all
of the virtual registers. In this case all registers must always be saved
because the ISR has no knowledge of what registers the interrupted thread
was using, so we cannot take advantage of the potential for saving fewer
than the full set of registers that we achieve with cooperative switches.
With the Cosmic compiler, interrupt handlers that call out to C functions
(as would happen on a thread switch) always save the CPU registers (done by
the CPU in fact) and the virtual registers c_x and c_y. For the Atomthreads
port we force interrupt handlers to also save the virtual register c_lreg.
This is to ensure that the interrupted thread's c_lreg value is preserved
across a thread switch, but also ensures that longs can be used within the
OS kernel code called by interrupt handlers (c_lreg is used by the compiler
for handling longs and floats).
An alternative scheme would be to not save c_lreg in all interrupt
handlers and instead save it in the context-switch function. This would
allow interrupt handlers to avoid saving the 4-byte c_lreg on the stack,
but it would mean that any OS kernel code called by interrupt handlers
could not deal with longs, which would be an unfortunate burden on the
core portable OS code just for the benefit of this one architecture and
compiler. It would also mean that c_lreg is always saved unnecessarily
for every cooperative context switch.
---------------------------------------------------------------------------

448
ports/stm8/README-IAR Normal file
View File

@@ -0,0 +1,448 @@
---------------------------------------------------------------------------
Library: Atomthreads
Author: Kelvin Lawson <kelvinl@users.sf.net>
Website: http://atomthreads.com
License: BSD Revised
---------------------------------------------------------------------------
STM8 PORT - IAR COMPILER
This folder contains a port of the Atomthreads real time kernel for the
STM8 processor architecture. These instructions cover usage of Atomthreads
with the IAR Embedded Workbench compiler (EWSTM8).
All of the cross-platform kernel code is contained in the top-level
'kernel' folder, while ports to specific CPU architectures are contained in
the 'ports' folder tree. A port to a CPU architecture can comprise just one
or two modules which provide the architecture-specific functionality, such
as the context-switch routine which saves and restores processor registers
on a thread switch. In this case, the kernel port is split into two files:
* atomport.c: Those functions which can be written in C
* atomport-asm-iar.s: The main register save/restore assembler routines
Each Atomthreads port requires also a header file which describes various
architecture-specific details such as appropriate types for 8-bit, 16-bit
etc variables, the port's system tick frequency, and macros for performing
interrupt lockouts / critical sections:
* atomuser.h: Port-specific header required by the kernel for each port
A few additional source files are also included here:
* tests-main.c: Main application file (used for launching automated tests)
* uart.c: UART wrapper to allow use of stdio/printf()
* stm8s-periphs/*.*: Peripheral drivers as delivered by ST (no changes
to distributed code).
Atomthreads includes a suite of automated tests which prove the key OS
functionality, and can be used with any architecture ports. This port
provides an easy mechanism for building, downloading and running the test
suite to prove the OS on your target.
The port was carried out and tested on an STM8S105C6 running within an
STM8S-Discovery board, and supports both the Cosmic and IAR compiler tools.
It is possible to use it with other processors in the STM8 range, as well
as other hardware platforms and compilers, with minimal changes. Platform
and compiler specific code has been kept to an absolute minimum. This
README covers usage of Atomthreads with the IAR compiler. Instructions for
users of the Cosmic compiler are available in README-COSMIC.
---------------------------------------------------------------------------
PREREQUISITES
The port works out-of-the-box with the IAR compiler tools for building.
Applications are generated in ELF format and can be programmed and debugged
using the IAR Embedded Workbench GUI or the free STVP (visual programmer
tool). At this time there does not appear to be a command-line programmer
application suitable for use with STM8.
IAR Embedded Workbench for STM8 is a Windows-only application. For
users of other operating systems the IAR tools may work in environments
like Wine, but the USB programming tools are less likely to be supported.
Embedded Workbench for STM8 can, however, be run successfully within a VM
such as VirtualBox, including USB download and debug.
The core software prerequisites are therefore:
* IAR Embedded Workbench STM8
Use with alternative compiler tools will require some modification, but you
can easily replace the EWSTM8 IDE by your own favourite programmer if
required (e.g. STVP).
---------------------------------------------------------------------------
BUILDING THE SOURCE
You may build Atomthreads using whichever build environment you desire. For
your convenience we provide both a ready-rolled Makefile-based build system
and an Embedded Workbench (EWSTM8) project. The EWSTM8 project permits easy
building, programming and debugging, but does not easily support building
a wide range of application builds within the same project, which is
useful for building the numerous automated tests. For the automated tests
you may find it easier to use the Makefile which automatically builds all
automated tests.
---------------------------------------------------------------------------
BUILD VIA EWSTM8 PROJECT
For building applications using the EWSTM8 IDE you can use the sample
project file atomthreads-sample-iar.ewp. This builds a sample full
application which runs the "sem1" automated test. Applications can be
downloaded directly to the target hardware (e.g. STM8S-Discovery) and run
via the integrated debugger. You can start the application running, and
confirm that the LED flashes once per second (if running on an
STM8S-Discovery) to ensure that the test has passed.
This is also a good starting point for building your own applications:
simply modify the file tests-main.c which starts the test application.
You can run any of the other automated tests by replacing the file sem1.c
within the project by another of the tests within the atomthreads tests
folder. This is rather painful using a GUI interface due to the large
number of test files, and you may prefer to use the Makefile-based system
instead which builds all automated tests in one command.
---------------------------------------------------------------------------
BUILD VIA MAKEFILE
A Makefile is also provided for building the kernel, port and automated
tests. This is particularly useful for building the automated tests
because many different independent applications need to be built which is
not easily achieved within the EWSTM8 environment.
For a Windows system you can obtain a Make application suitable for use
with the IAR compiler from:
* http://www.cosmic-software.com/comp_utils/GNU_Make.zip
Assuming you install the above into C:\Program Files\GNU_MAKE, you
should set up your environment variables as follows:
* set PATH=%PATH%;C:\Program Files\GNU_MAKE;C:\Program Files\IAR Systems\Embedded Workbench 6.0\stm8\bin
* set MAKE_MODE=DOS
The full build is carried out using simply:
* make -f iar.mak
All objects are built into the 'build-iar' folder under ports/stm8. The
build process builds separate target applications for each automated test,
and appropriate .elf or .s19 files can be found in the build folder ready
for downloading to and running on the target. Because of the limited
resources on the STM8, and the large amount of automated tests, each test
is built and run as a separate application.
All built objects etc can be cleaned using:
* make -f iar.mak clean
The Atomthreads sources are documented using Doxygen markup. You can build
both the kernel and STM8 port documentation from this folder using:
* make -f iar.mak doxygen
---------------------------------------------------------------------------
PROGRAMMING MAKEFILE-BUILT APPLICATIONS TO THE TARGET DEVICE
When developing within EWSTM8, programs can be downloaded directly to the
target. If, however, you are building applications separately using a
Makefile or similar, then you are not able to program the application
using EWSTM8. None of the tools delivered by ST appear to be designed to
cater for those who build applications externally, but it is possible using
STVP.
The following development workflow can be used (note that these settings
apply to the STM8S-Discovery):
* Build app using Makefile.
* Open STVP and configure to use Swim ST-Link for CPU STM8105C6.
* Open application .s19 file and program using "Program All Tabs".
Unfortunately STVP does not have a command to reset and start the CPU
running, but it can be forced into doing so by reconfiguring the
programmer:
* Select "Configure ST Visual Programmer" from the Configure menu.
Your application should now be programmed and running.
If you wish to program and run another application then you can open and
program it in STVP, then use the Configure menu again to reset the
device and start it running.
Other programming tools may exist but are not apparent in the toolset
delivered for use the STM8S Discovery platform.
---------------------------------------------------------------------------
STM8S-DISCOVERY SPECIFICS
There are very minimal board-specific aspects to the STM8 port so it is
trivial to run Atomthreads on other STM8 platforms.
The test applications make use of a LED to indicate test pass/fail status.
This is currently configured to use a bit in GPIOD, which on the Discovery
board maps to the board's only LED. You may change the port and register
bit in tests-main.c to utilise a different pin on other hardware platforms.
You may also completely omit the LED flashing in the test application if
you prefer to use the UART for monitoring test status.
The test applications also make use of the UART to print out pass/fail
indications and other information. For this you should connect a serial
cable to the Discovery board via the external pin connectors. Use of
a UART is not required if you prefer to use the LED or some other method
of notifying test pass/fail status.
To connect a serial cable to the Discovery you will need to connect to
the following pins on the external connectors:
Vcc: CN2 pin 8
GND: CN2 pin 7
UART TX: CN4 pin 10 (connect to RX at the PC end)
UART RX: CN4 pin 9 (connect to TX at the PC end)
Note that the board uses TTL levels so you may need to use a level
converter. External level converters may need to be powered using
a Vdd of 5v, which can be achieved by positioning JP1 on the Discovery.
The STM8 device on the Discovery only offers UART2. If you are using a
different device or wish to use an alternative UART then you must change
the stm8s_conf.h file.
If you are using a CPU other than the STM8S105C6 you should change the
PART macro from "STM8S105" to your target CPU. This can be changed in the
iar.mak Makefile. If you are using the EWSTM8 project it should be
changed in the project C/C++ Compiler Preprocessor settings for both Debug
and Release builds, and you must also change the target device in the
project's "General Options". You may also wish to enable any CPU
peripherals which you wish to use in the stm8s_conf.h file.
---------------------------------------------------------------------------
RUNNING THE AUTOMATED TESTS
Atomthreads contains a set of generic kernel tests which can be run on any
port to prove that all core functionality is working on your target.
The full set of tests can be found in the top-level 'tests' folder. The
Makefile builds each of these tests as independent applications in the
'build' folder. Run them individually using the STVP process described
above. For example to run the 'kern1.c' test use STVP to program and run
it.
You may also build the tests using the EWSTM8 project, but to run each
different test you must manually remove the previous test module (e.g.
kern1.c) and replace it with one of other tests, which can be quite time
consuming compared to building all tests in one command via the Makefile.
To view the test results, watch the LED on the STM8S-Discovery. This will
flash once per second if the test passed, and once every 1/8 second if the
test failed.
If you wish to use the UART, connect a serial debug cable to your target
platform (defaults to 9600bps 8N1). On starting, the test applications
print out "Go" on the UART. Once the test is complete they will print
out "Pass" or "Fail", along with other information if the test failed.
Most of the tests complete within a few seconds, but some (particularly
the stress tests) can take several seconds, so be patient.
The full suite of tests endeavours to exercise as much of the kernel code
as possible, and can be used for quick confirmation of core OS
functionality if you ever need to make a change to the kernel or port.
The test application main() is contained in tests-main.c. This initialises
the OS, creates a main thread, and calls out to the test modules. It also
initialises the UART driver for use by stdout.
---------------------------------------------------------------------------
WRITING APPLICATIONS
The easiest way to start a new application which utilises the Atomthreads
scheduler is to base your main application startup on tests-main.c. This
initialises the OS, sets up a UART and calls out to the test module entry
functions. You can generally simply replace the call to the test modules by
a call to your own application startup code.
Projects developed within EWSTM8 can be started using the sample project
atomthreads-sample-iar.ewp. If you wish to create your own EWSTM8 project
from scratch, then you should ensure you change the project settings for
both Debug and Release builds as follows:
* General Options -> Target -> Device: CPU part (e.g. "STM8S105C6")
* C/C++ Compiler -> Diagnostics: Suppress "Pa050"
* C/C++ Compiler -> Preprocessor -> Defined Symbols:
CPU part (e.g. "STM8S105")
Thread stack-checking if required ("ATOM_STACK_CHECKING")
For example "STM8S105, ATOM_STACK_CHECKING"
* Assembler -> Diagnostics: Suppress "Pa050"
* Repeat above for Debug and Release projects (you may want to
disable ATOM_STACK_CHECKING for Release builds).
Other options you may wish to change:
* Tools -> Options -> Editor -> EOL Characters: "Preserve". This preserves
the line endings, bearing in mind that the Atomthreads kernels works
with many host operating system toolchains.
* Options -> Debugger -> "ST Link" (e.g. for STM8S Discovery)
Add the .C and .S modules from the following folders:
* kernel
* ports/stm8
* ports/stm8s-periphs
Set include paths as appropriate.
---------------------------------------------------------------------------
RAM FOOTPRINT & STACK USAGE
The Atomthreads kernel is written in well-structured pure C which is highly
portable and not targeted at any particular compiler or CPU architecture.
For this reason it is not highly optimised for the STM8 architecture, and
by its nature will likely have a higher text and data footprint than an
RTOS targeted at the STM8 architecture only. The emphasis here is on
C-based portable, readable and maintainable code which can run on any CPU
architecture, from the 8-bitters up.
A good rule of thumb when using Atomthreads on the STM8 architecture is
that a minimum of 1KB RAM is required in order to support an application
with 4 or 5 threads and the idle thread. If a minimum of approximately
128 bytes per thread stack is acceptable then you will benefit from the
easy-to-read, portable implementation of an RTOS herein.
The major consumer of RAM when using Atomthreads is your thread stacks.
Functionality that is shared between several kernel modules is farmed out
to separate functions, resulting in readable and maintainable code but
with some associated stack cost of calling out to subroutines. Further,
each thread stack is used for saving its own registers on a context
switch, and there is no separate interrupt stack which means that each
thread stack has to be able to cope with the maximum stack usage of the
kernel (and application) interrupt handlers.
Clearly the stack requirement for each thread depends on what your
application code does, and what memory model is used etc, but generally
you should find that 128 bytes is enough to allow for the thread to be
switched out (and thus save its registers) while deep within a kernel
or application call stack, and similarly enough to provide stack for
interrupt handlers interrupting while the thread is deep within a kernel
or application call stack. You will need to increase this depending on
what level of stack the application code in question requires.
At this time the maximum stack consumed by the test threads within the
automated test modules is 85 bytes of stack, and the main test thread has
been seen to consume 193 bytes of stack. At this time the queue9 test is
the largest consumer of test thread stack (85 bytes) and the sem8 test
consumes the largest main thread stack (193 bytes). If your applications
have large amounts of local data or call several subroutines then you may
find that you need larger than 128 bytes.
You may monitor the stack usage of your application threads during runtime
by defining the macro ATOM_STACK_CHECKING and calling
atomThreadStackCheck(). This macro is defined by default in the EWSTM8
Debug project so that the automated test modules can check for stack
overflows, but you may wish to undefine this in your application
when you are happy that the stack usage is acceptable. Enabling
ATOM_STACK_CHECKING will increase the size of your threads' TCBs
slightly, and will incur a minor CPU cycles overhead whenever threads are
created due to prefilling the thread stack with a known value.
With careful consideration and few threads it would be possible to use
a platform with 512 bytes RAM, but not all of the automated test suite
would run on such a platform (some of the test modules use 6 threads: a
main thread together with 4 test threads and the idle thread).
---------------------------------------------------------------------------
INTERRUPT HANDLING
Interrupt handlers use the stack of the thread which was running when the
interrupt occurred. If no thread rescheduling occurs during the ISR then
on exit from the ISR any data stacked by the ISR on the thread's stack is
popped off the stack and execution of the thread resumes. If a reschedule
during the ISR causes a context switch to a new thread, then the ISR's
data will remain on the thread's stack until the thread is scheduled back
in.
Interrupt priorities (via the ITC_SPRx registers) are left in their
default power-on state, which disables interrupt nesting. Kernel changes
may be required to support interrupt nesting.
Note that the STM8 programming manual currently describes the following
feature:
"Fast interrupt handling through alternate register files (up to 4
contexts) with standard stack compatible mode (for real time OS
kernels)"
This feature was implemented by ST in the core but has to date never been
included in any STM8 products. If it is included in future products then
you will need to put the device in the stack compatible mode described.
---------------------------------------------------------------------------
WRITING NEW INTERRUPT HANDLERS
All interrupt handlers which will call out to the OS kernel and potentially
cause a thread switch must call atomIntEnter() and atomIntExit(). An
example of this can be seen in the timer tick ISR in atomport.c.
You may also implement fast interrupt handlers in the system which do not
call atomIntEnter()/atomIntExit(), however these ISRs cannot perform OS
functions such as posting semaphores or effecting a thread switch.
---------------------------------------------------------------------------
IAR COMPILER VIRTUAL REGISTERS
The STM8 has only very few CPU registers, so the IAR compiler augments
them with sixteen "virtual" registers, which are simply locations in fast
memory. These registers are called ?b0 to ?b15.
The Atomthreads context switch for IAR/STM8 takes advantage of the fact
that all CPU and most virtual registers are automatically saved on the
stack by the compiler when calling out to C functions (and even then only
if necessary). Only the virtual registers ?b8 to ?b15 are expected to be
preserved by called functions, so these are the only registers that
callers to the context switch routine will not automatically save if
necessary.
For cooperative context switches (where a thread calls an OS kernel
function to schedule itself out), most registers will therefore already
be saved on a thread's stack if necessary. Only ?b8 to ?b15 actually have
to be saved in the context switch routine, making cooperative switches
potentially very cheap if few registers must be preserved.
For preemptive switches (where an ISR has interrupted a thread and wishes
to switch to a new thread), the interrupt handler prologue automatically
saves all CPU registers (actually done automatically by the CPU) and the
virtual registers ?b0 to ?b7. Still only the registers ?b8 to ?b15 have to
be saved by the context-switch routine, but in this case ?b0 to ?b7 and the
CPU registers are always saved on the thread's stack by the ISR prologue.
This is because the ISR has no knowledge of what registers the interrupted
thread was using, so we cannot take advantage of the potential for saving
fewer than the full set of registers that we achieve with cooperative
switches.
---------------------------------------------------------------------------

View File

@@ -1,5 +1,5 @@
;
; Copyright (c) 2005, Atomthreads Project. All rights reserved.
; Copyright (c) 2010, Atomthreads Project. All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; Modification, are permitted provided that the following conditions
@@ -28,28 +28,31 @@
;
; Cosmic assembler routines
; Export functions to other modules
xdef _archContextSwitch, _archFirstThreadRestore
; \b archContextSwitch
;
;
; Architecture-specific context switch routine.
;
;
; Note that interrupts are always locked out when this routine is
; called. For cooperative switches, the scheduler will have entered
; a critical region. For preemptions (called from an ISR), the
; ISR will have disabled interrupts on entry.
;
;
; @param[in] old_tcb_ptr Pointer to the thread being scheduled out
; @param[in] new_tcb_ptr Pointer to the thread being scheduled in
;
;
; @return None
;
;
; void archContextSwitch (ATOM_TCB *old_tcb_ptr, ATOM_TCB *new_tcb_ptr)
_archContextSwitch:
; Parameter locations:
; Parameter locations (Cosmic calling convention):
; old_tcb_ptr = X register (word-width)
; new_tcb_ptr = stack (word-width)
@@ -60,7 +63,11 @@ _archContextSwitch:
; PC: Program counter
; CC: Code condition register
;
;
; Cosmic compiler virtual registers:
;
; c_x, c_y: Scratch memory areas saved by ISRs
; c_lreg: Scratch memory area only saved by ISRs with @svlreg
;
; If this is a cooperative context switch (a thread has called us
; to schedule itself out), the Cosmic compiler will have saved any
; of the registers which it does not want us to clobber. There are
@@ -74,15 +81,19 @@ _archContextSwitch:
; similarly saved all registers which it needs us not to clobber
; which in the case of this compiler is all registers. Again, we
; do not need to save any registers because no registers are
; expected to be unclobbered by a subroutine.
; expected to be unclobbered by a subroutine. Note that it is
; necessary to add the @svlreg modifier to ISRs which call out to
; the OS in order to force a save of c_lreg. The rest of the CPU
; registers and the c_x and c_y virtual registers are, however,
; always saved by ISRs which call out to C subroutines.
;
; This is an unusual context switch routine, because it does not
; need to actually save any registers. Instead, the act of
; calling this function causes all registers which must not be
; clobbered to be saved on the stack anyway in the case of
; clobbered to be saved on the stack anyway in the case of
; cooperative context switches. For preemptive switches, the
; interrupt service routine which calls out to here causes all
; registers to be saved in a similar fashion.
; interrupt service routine which calls out to here also causes
; all registers to be saved in a similar fashion.
; We do have to do some work in here though: we need to store
; the current stack pointer to the current thread's TCB, and
@@ -106,7 +117,7 @@ _archContextSwitch:
; Our stack frame now contains all registers (if this is a preemptive
; switch due to an interrupt handler) or those registers which the
; calling function did not wish to be clobbered (if this is a
; cooperative context switch). It also contains the return address
; cooperative context switch). It also contains the return address
; which will be either a function called via an ISR (for preemptive
; switches) or a function called from thread context (for cooperative
; switches). Finally, the stack also contains the aforementioned
@@ -115,7 +126,7 @@ _archContextSwitch:
; In addition, the thread's stack pointer (after context-save) is
; stored in the thread's TCB.
; We are now ready to restore the new thread's context. In most
; We are now ready to restore the new thread's context. In most
; architecture ports we would typically switch our stack pointer
; to the new thread's stack pointer, and pop all of its context
; off the stack, before returning to the caller (the original
@@ -132,11 +143,11 @@ _archContextSwitch:
; Pull the new_tcb_ptr parameter from the stack into X register
ldw X,($3,SP)
; Pull the first entry out of new_tcb_ptr (the new thread's
; Pull the first entry out of new_tcb_ptr (the new thread's
; stack pointer) into X register.
ldw X,(X)
; Switch our current stack pointer to that of the new thread.
ldw SP,X
@@ -158,7 +169,7 @@ _archContextSwitch:
; because this is a subroutine regardless of whether we were called
; during an ISR or by a thread cooperatively switching out. The
; difference between RET and IRET on the STM8 architecture is that
; RET only pops the return address off the stack, while IRET also
; RET only pops the return address off the stack, while IRET also
; pops from the stack all of the CPU registers saved when the ISR
; started, including restoring the interrupt-enable bits from the CC
; register.
@@ -240,8 +251,8 @@ _archContextSwitch:
; different thread's stack. Because the stack pointer is
; switched, it does not matter that on entry via ISRs more
; registers are saved on the original thread's stack than entries
; via non-ISRs. Those extra registers will be restored properly
; by an IRET when the thread is eventually scheduled back in
; via non-ISRs. Those extra registers will be restored properly
; by an IRET when the thread is eventually scheduled back in
; (which could be a long way off). This assumes that the CPU does
; not have hidden behaviour that occurs on interrupts, and we can
; in fact trick it into leaving via another thread's call stack,
@@ -266,7 +277,7 @@ _archContextSwitch:
; data for being restored by either this function or the normal
; function used for scheduling threads in, archContextSwitch(). Only
; the first thread run by the system is launched via this function,
; after which all other new threads will first be run by
; after which all other new threads will first be run by
; archContextSwitch().
;
; Typically ports will implement something similar here to the
@@ -274,21 +285,21 @@ _archContextSwitch:
; switch does not restore many registers, and instead relies on the
; fact that returning from any function which called
; archContextSwitch() will restore any of the necessary registers.
; For new threads which have never been run there is no calling
; For new threads which have never been run there is no calling
; function which will restore context on return, therefore we
; do not restore many register values here. It is not necessary
; for the new threads to have initialised values for the scratch
; registers A, X and Y or the code condition register CC which
; registers A, X and Y or the code condition register CC which
; leaves SP and PC. SP is restored because this is always needed to
; switch to a new thread's stack context. It is not necessary to
; restore PC, because the thread's entry point is in the stack
; context (when this function returns using RET the PC is
; switch to a new thread's stack context. It is not necessary to
; restore PC, because the thread's entry point is in the stack
; context (when this function returns using RET the PC is
; automatically changed to the thread's entry point because the
; entry point is stored in the preinitialised stack).
; entry point is stored in the preinitialised stack).
;
; When new threads are started interrupts must be enabled, so there
; is some scope for enabling interrupts in the CC here. It must be
; done for all new threads, however, not just the first thread, so
; done for all new threads, however, not just the first thread, so
; we use a different system. We instead use a thread shell routine
; which all functions run when they are first started, and
; interrupts are enabled in there. This allows us to avoid having
@@ -324,7 +335,7 @@ _archFirstThreadRestore:
; As described above, first thread restores in this port do not
; expect any initial register context to be pre-initialised in
; the thread's stack area. The thread's initial stack need only
; contain the thread's initial entry point, and we do not even
; contain the thread's initial entry point, and we do not even
; "restore" that within this function. We leave the thread's entry
; point in the stack, and RET at the end of the function pops it
; off and "returns" to the entry point as if we were called from
@@ -339,7 +350,7 @@ _archFirstThreadRestore:
; pointer it conveniently located at the top of the TCB so no
; indexing is required to pull it out.
ldw X,(X)
; Switch our current stack pointer to that of the new thread.
ldw SP,X
@@ -350,4 +361,4 @@ _archFirstThreadRestore:
ret
end
end

View File

@@ -0,0 +1,396 @@
;
; Copyright (c) 2010, Atomthreads Project. All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; Modification, are permitted provided that the following conditions
; are met:
;
; 1. Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
; 2. Redistributions in binary form must reproduce the above copyright
; notice, this list of conditions and the following disclaimer in the
; documentation and/or other materials provided with the distribution.
; 3. No personal names or organizations' names associated with the
; Atomthreads project may be used to endorse or promote products
; derived from this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
; TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
; POSSIBILITY OF SUCH DAMAGE.
;
; IAR assembler routines
NAME ATOMPORTASM
SECTION .text:code
; Get definitions for virtual registers used by the compiler
#include "vregs.inc"
; \b archContextSwitch
;
; Architecture-specific context switch routine.
;
; Note that interrupts are always locked out when this routine is
; called. For cooperative switches, the scheduler will have entered
; a critical region. For preemptions (called from an ISR), the
; ISR will have disabled interrupts on entry.
;
; @param[in] old_tcb_ptr Pointer to the thread being scheduled out
; @param[in] new_tcb_ptr Pointer to the thread being scheduled in
;
; @return None
;
; void archContextSwitch (ATOM_TCB *old_tcb_ptr, ATOM_TCB *new_tcb_ptr)
PUBLIC archContextSwitch
archContextSwitch:
; Parameter locations (IAR calling convention):
; old_tcb_ptr = X register (word-width)
; new_tcb_ptr = Y register (word-width)
; STM8 CPU Registers:
;
; A, X, Y: Standard working registers
; SP: Stack pointer
; PC: Program counter
; CC: Code condition register
;
; IAR compiler virtual registers
;
; ?b0 - ?b7: Scratch registers
; ?b8 - ?b15: Preserved registers
;
; The basic scheme is that some registers will already be saved
; onto the stack if the caller wishes them not to be clobbered.
; We only need to context-switch additional registers which the
; caller does not expect to be modified in a subroutine.
;
; If this is a cooperative context switch (a thread has called us
; to schedule itself out), the IAR compiler will have saved any
; of the registers which it does not want us to clobber. For IAR
; only virtual registers ?b8 to ?b15 are expected to retain their
; value across a function call, hence for cooperative context
; switches with this compiler we only need to save ?b8 to ?b15.
;
; If we were called from an interrupt routine (because a thread
; is being preemptively scheduled out), the situation is exactly
; the same. Any ISR which calls out to a subroutine will have
; similarly saved all registers which it needs us not to clobber,
; leaving only ?b8 to ?b15 which must be saved.
;
; The Cosmic compiler version of this context switch routine
; does not require any registers to be saved/restored, whereas
; this IAR equivalent reqires that 8 of the virtual registers
; are.
; We also have to do a little more work in here: we need to store
; the current stack pointer to the current thread's TCB, and
; switch in the new thread by taking the stack pointer from
; the new thread's TCB and making that our new stack pointer.
; (IAR) Compiler will have already saved any scratch registers
; (A, X, Y, CC, and ?b0 to ?b7) which it needs before calling here
; for cooperative switches. So these will already be on the stack
; and do not need to be context-switched. The same goes for
; __interrupt functions (i.e. preemptive switches): with the IAR
; compiler A, X, Y and CC will already be saved by interrupt handlers
; (those are actually automatically done by the CPU), and (because
; we call out from interrupt handlers to C kernel code (e.g.
; atomIntExit()) before calling here for a context-switch, the
; compiler will also have saved ?b0 to ?b7. This is because those
; called C functions cannot know they were called from an interrupt
; and will assume that they have ?b0 to ?b7 available as scratch
; registers. Either way (cooperative or interrupt/preemptive) we
; know that the only registers which must be preserved that are not
; already on the stack-frame are ?b8 to ?b15.
PUSH ?b8
PUSH ?b9
PUSH ?b10
PUSH ?b11
PUSH ?b12
PUSH ?b13
PUSH ?b14
PUSH ?b15
; The parameter pointing to the the old TCB (a word-width
; pointer) is still untouched in the X register.
; (IAR) Take a copy of the new_tcb_ptr parameter from Y-reg in
; a temporary (?b0) register. We need to use Y briefly for SP
; access.
ldw ?b0, Y
; Store current stack pointer as first entry in old_tcb_ptr
ldw Y, SP ; Move current stack pointer into Y register
ldw (X), Y ; Store current stack pointer at first offset in TCB
; At this point, all of the current thread's context has been saved
; so we no longer care about keeping the contents of any registers
; except ?b0 which contains our passed new_tcb_ptr parameter (a
; pointer to the TCB of the thread which we wish to switch in).
;
; Our stack frame now contains all registers which need to be
; preserved or context-switched. It also contains the return address
; which will be either a function called via an ISR (for preemptive
; switches) or a function called from thread context (for cooperative
; switches).
;
; In addition, the thread's stack pointer (after context-save) is
; stored in the thread's TCB.
; We are now ready to restore the new thread's context. We switch
; our stack pointer to the new thread's stack pointer, and pop its
; context off the stack, before returning to the caller (the
; original caller when the new thread was last scheduled out).
; Get the new thread's stack pointer off the TCB (new_tcb_ptr).
; We kept a copy of new_tcb_ptr earlier in ?b0, copy it into X.
ldw X,?b0
; Pull the first entry out of new_tcb_ptr (the new thread's
; stack pointer) into X register.
ldw X,(X)
; Switch our current stack pointer to that of the new thread.
ldw SP,X
; (IAR) We only save/restore ?b8 to ?b15
POP ?b15
POP ?b14
POP ?b13
POP ?b12
POP ?b11
POP ?b10
POP ?b9
POP ?b8
; The return address on the stack will now be the new thread's return
; address - i.e. although we just entered this function from a
; function called by the old thread, now that we have restored the new
; thread's stack, we actually return from this function to wherever
; the new thread was when it was previously scheduled out. This could
; be either a regular C routine if the new thread previously scheduled
; itself out cooperatively, or it could be an ISR if this new thread was
; previously preempted (on exiting the ISR, execution will return to
; wherever the new thread was originally interrupted).
; Return to the caller. Note that we always use a regular RET here
; because this is a subroutine regardless of whether we were called
; during an ISR or by a thread cooperatively switching out. The
; difference between RET and IRET on the STM8 architecture is that
; RET only pops the return address off the stack, while IRET also
; pops from the stack all of the CPU registers saved when the ISR
; started, including restoring the interrupt-enable bits from the CC
; register.
;
; It is important that whenever we call this function (whether from
; an ISR for preemptive switches or from thread context for
; cooperative switches) interrupts are always disabled. This means
; that whichever method by which we leave this routine we always
; have to reenable interrupts, so we can use the same context-switch
; routine for preemptive and cooperative switches.
;
; The possible call/return paths are as follows:
;
; Scenario 1 (cooperative -> cooperative):
; Thread A: cooperatively switches out
; * Thread A relinquishes control / cooperatively switches out
; * Interrupts already disabled by kernel for cooperative reschedules
; * Partial register context saved by calling function
; * Call here at thread context
; * Switch to Thread B
; Thread B (was previously cooperatively switched out):
; * Stack context for Thread B contains its return address
; * Return to function which was called at thread context
; * Interrupts are reenabled by CRITICAL_END() call in kernel
; * Return to Thread B application code
;
; Scenario 2 (preemptive -> preemptive):
; Thread A: preemptively switches out
; * ISR occurs
; * Interrupts disabled by CPU at ISR entry (assume no nesting allowed)
; * Full register context saved by CPU at ISR entry
; * Call here at ISR context
; * Switch to Thread B
; Thread B (was previously preemptively switched out):
; * Stack context for Thread B contains its return address
; and all context saved by the CPU on ISR entry
; * Return to function which was called at ISR context
; * Eventually returns to calling ISR which calls IRET
; * IRET performs full register context restore
; * IRET reenables interrupts
; * Return to Thread B application code
;
; Scenario 3 (cooperative -> preemptive):
; Thread A: cooperatively switches out
; * Thread A relinquishes control / cooperatively switches out
; * Interrupts already disabled by kernel for cooperative reschedules
; * Partial register context saved by calling function
; * Call here at thread context
; * Switch to Thread B
; Thread B (was previously preemptively switched out):
; * Stack context for Thread B contains its return address
; and all context saved by the CPU on ISR entry
; * Return to function which was called at ISR context
; * Eventually returns to calling ISR which calls IRET
; * IRET performs full register context restore
; * IRET reenables interrupts
; * Return to Thread B application code
;
; Scenario 4 (preemptive -> cooperative):
; Thread A: preemptively switches out
; * ISR occurs
; * Interrupts disabled by CPU at ISR entry (assume no nesting allowed)
; * Full register context saved by CPU at ISR entry
; * Call here at ISR context
; * Switch to Thread B
; Thread B (was previously cooperatively switched out):
; * Stack context for Thread B contains its return address
; * Return to function which was called at thread context
; * Interrupts are reenabled by CRITICAL_END() call in kernel
; * Return to Thread B application code
;
; The above shows that it does not matter whether we are rescheduling
; from/to thread context or ISR context. It is perfectly valid to
; enter here at ISR context but leave via a thread which previously
; cooperatively switched out because:
; 1. Although the CPU handles ISRs differently by automatically
; stacking all 6 CPU registers, and restoring them on an IRET,
; we handle this because we switch the stack pointer to a
; different thread's stack. Because the stack pointer is
; switched, it does not matter that on entry via ISRs more
; registers are saved on the original thread's stack than entries
; via non-ISRs. Those extra registers will be restored properly
; by an IRET when the thread is eventually scheduled back in
; (which could be a long way off). This assumes that the CPU does
; not have hidden behaviour that occurs on interrupts, and we can
; in fact trick it into leaving via another thread's call stack,
; and performing the IRET much later.
; 2. Although the CPU handles ISRs differently by setting the CC
; register interrupt-enable bits on entry/exit, we handle this
; anyway by always assuming interrupts are disabled on entry
; and exit regardless of the call path.
; Return from subroutine
ret
; \b archFirstThreadRestore
;
; Architecture-specific function to restore and start the first thread.
; This is called by atomOSStart() when the OS is starting. Its job is to
; restore the context for the first thread and start running at its
; entry point.
;
; All new threads have a stack context pre-initialised with suitable
; data for being restored by either this function or the normal
; function used for scheduling threads in, archContextSwitch(). Only
; the first thread run by the system is launched via this function,
; after which all other new threads will first be run by
; archContextSwitch().
;
; Typically ports will implement something similar here to the
; latter half of archContextSwitch(). In this port the context
; switch does not restore many registers, and instead relies on the
; fact that returning from any function which called
; archContextSwitch() will restore any of the necessary registers.
; For new threads which have never been run there is no calling
; function which will restore context on return, therefore we
; do not restore many register values here. It is not necessary
; for the new threads to have initialised values for the scratch
; registers A, X and Y or the code condition register CC which
; leaves SP and PC. SP is restored because this is always needed to
; switch to a new thread's stack context. It is not necessary to
; restore PC, because the thread's entry point is in the stack
; context (when this function returns using RET the PC is
; automatically changed to the thread's entry point because the
; entry point is stored in the preinitialised stack).
;
; When new threads are started interrupts must be enabled, so there
; is some scope for enabling interrupts in the CC here. It must be
; done for all new threads, however, not just the first thread, so
; we use a different system. We instead use a thread shell routine
; which all functions run when they are first started, and
; interrupts are enabled in there. This allows us to avoid having
; to enable interrupts both in here and in the normal context
; switch routine (archContextSwitch()). For the normal context
; switch routine we would otherwise need to pass in notification of
; and implement special handling for the first time a thread is
; restored.
;
; In summary, first threads do not require a set of CPU registers
; to be initialised to known values, so we only set SP to the new
; thread's stack pointer. PC is restored for free because the RET
; call at the end of this function pops the return address off the
; stack.
;
; Note that you can create more than one thread before starting
; the OS - only one thread is restored using this function, so
; all other threads are actually restored by archContextSwitch().
; This is another reminder that the initial context set up by
; archThreadContextInit() must look the same whether restored by
; archFirstThreadRestore() or archContextSwitch().
;
; @param[in] new_tcb_ptr Pointer to the thread being scheduled in
;
; @return None
;
; void archFirstThreadRestore (ATOM_TCB *new_tcb_ptr)
PUBLIC archFirstThreadRestore
archFirstThreadRestore:
; Parameter locations:
; new_tcb_ptr = X register (word-width)
; As described above, first thread restores in this port do not
; expect any initial register context to be pre-initialised in
; the thread's stack area. The thread's initial stack need only
; contain the thread's initial entry point, and we do not even
; "restore" that within this function. We leave the thread's entry
; point in the stack, and RET at the end of the function pops it
; off and "returns" to the entry point as if we were called from
; there.
;
; The one thing we do need to set in here, though, is the thread's
; stack pointer. This is available from the passed thread TCB
; structure.
; Get the new thread's stack pointer off the TCB (new_tcb_ptr).
; new_tcb_ptr is stored in the parameter register X. The stack
; pointer it conveniently located at the top of the TCB so no
; indexing is required to pull it out.
ldw X,(X)
; Switch our current stack pointer to that of the new thread.
ldw SP,X
; (IAR) We only context switch ?b8 to ?b15
POP ?b15
POP ?b14
POP ?b13
POP ?b12
POP ?b11
POP ?b10
POP ?b9
POP ?b8
; The "return address" left on the stack now will be the new
; thread's entry point. RET will take us there as if we had
; actually been there before calling this subroutine, whereas
; the return address was actually set up by archThreadContextInit().
ret
end

View File

@@ -31,9 +31,40 @@
#define __ATOM_PORT_PRIVATE_H
/**
* Compiler-specific modifier to prevent some functions from saving
* and restoring registers on entry and exit, if the function is
* known to never complete (e.g. thread entry points).
* Reduces stack usage on supporting compilers.
*/
#ifdef __IAR_SYSTEMS_ICC__
#define NO_REG_SAVE __task
#else
#define NO_REG_SAVE
#endif
/**
* Compiler-specific modifiers for interrupt handler functions.
*
* COSMIC: Uses @interrupt modifier for interrupt handlers. We
* also force all interrupts to save c_lreg, a separate memory
* area which Cosmic uses for longs and floats. This memory
* area must be saved by interrupt handlers for context
* switch purposes, and to avoid making it impossible to use
* longs in any OS kernel code accessed by interrupt handlers.
*
* IAR: Uses __interrupt modifier for interrupt handlers.
*/
#ifdef __CSMC__
#define INTERRUPT @far @interrupt @svlreg
#else
#define INTERRUPT __interrupt
#endif
/* Function prototypes */
void archInitSystemTickTimer (void);
@far @interrupt void TIM1_SystemTickISR (void);
INTERRUPT void TIM1_SystemTickISR (void);
#endif /* __ATOM_PORT_PRIVATE_H */

View File

@@ -49,7 +49,15 @@
#define TEST_THREAD_STACK_SIZE 128
/* Uncomment to enable logging of stack usage to UART */
/* #define TESTS_LOG_STACK_USAGE */
#define TESTS_LOG_STACK_USAGE
/**
* IAR EWSTM8: Ignore warnings on volatile ordering thrown up
* by ATOMLOG() statements in the test modules.
*/
#ifdef __IAR_SYSTEMS_ICC__
#pragma diag_suppress=Pa082
#endif
#endif /* __ATOM_PORT_TESTS_H */

View File

@@ -34,7 +34,7 @@
/** Forward declarations */
static void thread_shell (void);
static NO_REG_SAVE void thread_shell (void);
/**
@@ -66,9 +66,16 @@ static void thread_shell (void);
* first time because you can preinitialise the stack context with
* a suitable register value that will enable interrupts.
*
* If the compiler supports it, stack space can be saved by preventing
* the function from saving registers on entry. This is because we
* are called directly by the context-switch assembler, and know that
* threads cannot return from here. The NO_REG_SAVE macro is used to
* denote such functions in a compiler-agnostic way, though not all
* compilers support it.
*
* @return None
*/
static void thread_shell (void)
static NO_REG_SAVE void thread_shell (void)
{
ATOM_TCB *curr_tcb;
@@ -79,7 +86,11 @@ static void thread_shell (void)
* Enable interrupts - these will not be enabled when a thread
* is first restored.
*/
#if defined(__CSMC__)
_asm("rim");
#elif defined(__IAR_SYSTEMS_ICC__)
rim();
#endif
/* Call the thread entry point */
if (curr_tcb && curr_tcb->entry_point)
@@ -101,19 +112,30 @@ static void thread_shell (void)
* and running the thread via archFirstThreadRestore() or
* archContextSwitch().
*
* On this port we take advantage of the fact that when the context
* switch routine is called the compiler will automatically stack
* all registers which should not be clobbered. This means that the
* context switch need only save and restore the stack pointer,
* which is stored in the thread's TCB. Because of this, it is not
* necessary to prefill a new thread's stack with any register
* values here. The only entry we need to make in the stack is the
* thread's entry point - this is not exactly restored when the
* (COSMIC) On this port we take advantage of the fact that when
* the context switch routine is called the compiler will
* automatically stack all registers which should not be clobbered.
* This means that the context switch need only save and restore the
* stack pointer, which is stored in the thread's TCB. Because of
* this, it is not necessary to prefill a new thread's stack with any
* register values here. The only entry we need to make in the stack
* is the thread's entry point - this is not exactly restored when
* the thread is context switched in, but rather is popped off the
* stack by the context switch routine's RET call. That is used to
* direct the program counter to our thread's entry point - we are
* faking a return to a caller which never actually existed.
*
* (IAR) The IAR compiler works around the lack of CPU registers on
* STM8 by allocating some space in low SRAM which is used for
* "virtual" registers. The compiler uses these like normal CPU
* registers, and hence their values must be preserved when
* context-switching between threads. Some of these (?b8 to ?b15)
* are expected to be preserved by called functions, and hence we
* actually need to save/restore those registers (unlike the rest
* of the virtual registers and the standard CPU registers). We
* therefore must prefill the stack with values for ?b8 to ?b15
* here.
*
* We could pre-initialise the stack so that the RET call goes
* directly to the thread entry point, with the thread entry
* parameter filled in. On this architecture, however, we use an
@@ -172,11 +194,28 @@ void archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_poi
*/
/**
* In this port we do not initialise any registers via the initial
* stack context at all. All thread context has now been
* initialised. All that is left is to save the current stack
* pointer to the thread's TCB so that it knows where to start
* looking when the thread is started.
* (IAR) Set up initial values for ?b8 to ?b15.
*/
#if defined(__IAR_SYSTEMS_ICC__)
*stack_ptr-- = 0; // ?b8
*stack_ptr-- = 0; // ?b9
*stack_ptr-- = 0; // ?b10
*stack_ptr-- = 0; // ?b11
*stack_ptr-- = 0; // ?b12
*stack_ptr-- = 0; // ?b13
*stack_ptr-- = 0; // ?b14
*stack_ptr-- = 0; // ?b15
#endif
/**
* (COSMIC) We do not initialise any registers via the initial
* stack context at all.
*/
/**
* All thread context has now been initialised. All that is left
* is to save the current stack pointer to the thread's TCB so
* that it knows where to start looking when the thread is started.
*/
tcb_ptr->sp_save_ptr = stack_ptr;
@@ -192,16 +231,16 @@ void archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_poi
*/
void archInitSystemTickTimer ( void )
{
/* Reset TIM1 */
/* Reset TIM1 */
TIM1_DeInit();
/* Configure a 10ms tick */
/* Configure a 10ms tick */
TIM1_TimeBaseInit(10000, TIM1_COUNTERMODE_UP, 1, 0);
/* Generate an interrupt on timer count overflow */
/* Generate an interrupt on timer count overflow */
TIM1_ITConfig(TIM1_IT_UPDATE, ENABLE);
/* Enable TIM1 */
/* Enable TIM1 */
TIM1_Cmd(ENABLE);
}
@@ -243,7 +282,10 @@ void archInitSystemTickTimer ( void )
*
* @return None
*/
void TIM1_SystemTickISR (void)
#if defined(__IAR_SYSTEMS_ICC__)
#pragma vector = 13
#endif
INTERRUPT void TIM1_SystemTickISR (void)
{
/* Call the interrupt entry routine */
atomIntEnter();
@@ -252,7 +294,7 @@ void TIM1_SystemTickISR (void)
atomTimerTick();
/* Ack the interrupt (Clear TIM1:SR1 register bit 0) */
TIM1->SR1 = (uint8_t)(~(uint8_t)TIM1_IT_UPDATE);
TIM1->SR1 = (uint8_t)(~(uint8_t)TIM1_IT_UPDATE);
/* Call the interrupt exit routine */
atomIntExit(TRUE);

View File

@@ -33,6 +33,10 @@
#include "stm8s_type.h"
#if defined(__IAR_SYSTEMS_ICC__)
#include "intrinsics.h"
#endif
/* Required number of system ticks per second (normally 100 for 10ms tick) */
#define SYSTEM_TICKS_PER_SEC 100
@@ -51,10 +55,19 @@
/* Critical region protection */
/* COSMIC: Use inline assembler */
#if defined(__CSMC__)
#define CRITICAL_STORE uint8_t ccr
#define CRITICAL_START() _asm ("push CC\npop a\nld (X),A\nsim", &ccr)
#define CRITICAL_END() _asm ("ld A,(X)\npush A\npop CC", &ccr)
/* IAR: Use intrinsics */
#elif defined(__IAR_SYSTEMS_ICC__)
#define CRITICAL_STORE __istate_t _istate
#define CRITICAL_START() _istate = __get_interrupt_state(); __disable_interrupt()
#define CRITICAL_END() __set_interrupt_state(_istate)
#endif
/* Uncomment to enable stack-checking */
/* #define ATOM_STACK_CHECKING */

View File

@@ -83,10 +83,10 @@ String.100.0=STM8S105C6
[Root.Config.0.Settings.3]
String.2.0=Compiling $(InputFile)...
String.3.0=cxstm8 +modsl0 -customDebCompat -customOpt-no -customC-pp -customLst -l -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.3.0=cxstm8 +modsl0 -customDebCompat -customOpt -no +split -customC-pp -customLst -l -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.4.0=$(IntermPath)$(InputName).$(ObjectExt)
String.5.0=$(IntermPath)$(InputName).ls
String.6.0=2010,3,6,17,19,51
String.6.0=2010,5,27,22,48,49
[Root.Config.0.Settings.4]
String.2.0=Assembling $(InputFile)...
@@ -166,10 +166,10 @@ String.100.0=STM8S105C6
[Root.Config.1.Settings.3]
String.2.0=Compiling $(InputFile)...
String.3.0=cxstm8 +modsl0 -customC-pp -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.3.0=cxstm8 +modsl0 -customOpt +split -customC-pp -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.4.0=$(IntermPath)$(InputName).$(ObjectExt)
String.5.0=$(IntermPath)$(InputName).ls
String.6.0=2010,3,6,17,19,51
String.6.0=2010,5,27,22,48,49
[Root.Config.1.Settings.4]
String.2.0=Assembling $(InputFile)...
@@ -189,7 +189,7 @@ String.3.0=clnk $(ToolsetLibOpts) -o $(OutputPath)$(TargetSName).sm8 -fakeIntege
String.3.1=cvdwarf $(OutputPath)$(TargetSName).sm8
String.4.0=$(OutputPath)$(TargetFName)
String.5.0=$(OutputPath)$(ProjectSFile).elf
String.6.0=2010,3,9,0,24,9
String.6.0=2010,5,27,22,49,45
String.100.0=
String.101.0=crtsi.st7
String.102.0=+seg .const -b 0x8080 -m 0x7f80 -n .const -it
@@ -206,7 +206,7 @@ String.103.1=Eeprom[0x4000-0x43ff]=.eeprom
String.103.2=Zero Page[0x2-0xff]=.bsct,.ubsct,.bit,.share
String.103.3=Ram[0x100-0x7bf]=.data,.bss
String.104.0=0x7ff
String.105.0=libis0.sm8;libm0.sm8
String.105.0=libisl0.sm8;libm0.sm8
Int.0=0
Int.1=0
@@ -247,10 +247,10 @@ Int.1=0
[Root.Kernel.Config.0.Settings.1]
String.2.0=Compiling $(InputFile)...
String.3.0=cxstm8 +modsl0 -customDebCompat -customOpt-no -customC-pp -customLst -l -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.3.0=cxstm8 +modsl0 -customDebCompat -customOpt -no +split -customC-pp -customLst -l -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.4.0=$(IntermPath)$(InputName).$(ObjectExt)
String.5.0=$(IntermPath)$(InputName).ls
String.6.0=2010,3,6,17,19,51
String.6.0=2010,5,27,22,48,49
[Root.Kernel.Config.0.Settings.2]
String.2.0=Assembling $(InputFile)...
@@ -271,10 +271,10 @@ Int.1=0
[Root.Kernel.Config.1.Settings.1]
String.2.0=Compiling $(InputFile)...
String.3.0=cxstm8 +modsl0 -customC-pp -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.3.0=cxstm8 +modsl0 -customOpt +split -customC-pp -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.4.0=$(IntermPath)$(InputName).$(ObjectExt)
String.5.0=$(IntermPath)$(InputName).ls
String.6.0=2010,3,6,17,19,51
String.6.0=2010,5,27,22,48,49
[Root.Kernel.Config.1.Settings.2]
String.2.0=Assembling $(InputFile)...
@@ -364,10 +364,10 @@ Int.1=0
[Root.Peripherals.Config.0.Settings.1]
String.2.0=Compiling $(InputFile)...
String.3.0=cxstm8 +modsl0 -customDebCompat -customOpt-no -customC-pp -customLst -l -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.3.0=cxstm8 +modsl0 -customDebCompat -customOpt -no +split -customC-pp -customLst -l -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.4.0=$(IntermPath)$(InputName).$(ObjectExt)
String.5.0=$(IntermPath)$(InputName).ls
String.6.0=2010,3,6,17,19,51
String.6.0=2010,5,27,22,48,49
[Root.Peripherals.Config.0.Settings.2]
String.2.0=Assembling $(InputFile)...
@@ -391,10 +391,10 @@ Int.1=0
[Root.Peripherals.Config.1.Settings.1]
String.2.0=Compiling $(InputFile)...
String.3.0=cxstm8 +modsl0 -customC-pp -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.3.0=cxstm8 +modsl0 -customOpt +split -customC-pp -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.4.0=$(IntermPath)$(InputName).$(ObjectExt)
String.5.0=$(IntermPath)$(InputName).ls
String.6.0=2010,3,6,17,19,51
String.6.0=2010,5,27,22,48,49
[Root.Peripherals.Config.1.Settings.2]
String.2.0=Assembling $(InputFile)...
@@ -491,10 +491,10 @@ Int.1=0
[Root.Port.Config.0.Settings.1]
String.2.0=Compiling $(InputFile)...
String.3.0=cxstm8 +modsl0 -customDebCompat -customOpt-no -customC-pp -customLst -l -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.3.0=cxstm8 +modsl0 -customDebCompat -customOpt -no +split -customC-pp -customLst -l -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.4.0=$(IntermPath)$(InputName).$(ObjectExt)
String.5.0=$(IntermPath)$(InputName).ls
String.6.0=2010,3,6,17,19,51
String.6.0=2010,5,27,22,48,49
[Root.Port.Config.0.Settings.2]
String.2.0=Assembling $(InputFile)...
@@ -518,10 +518,10 @@ Int.1=0
[Root.Port.Config.1.Settings.1]
String.2.0=Compiling $(InputFile)...
String.3.0=cxstm8 +modsl0 -customC-pp -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.3.0=cxstm8 +modsl0 -customOpt +split -customC-pp -dSTM8S105 -dATOM_STACK_CHECKING -istm8s-periphs -i../../kernel -i../../tests $(ToolsetIncOpts) -cl$(IntermPath) -co$(IntermPath) $(InputFile)
String.4.0=$(IntermPath)$(InputName).$(ObjectExt)
String.5.0=$(IntermPath)$(InputName).ls
String.6.0=2010,3,6,17,19,51
String.6.0=2010,5,27,22,48,49
[Root.Port.Config.1.Settings.2]
String.2.0=Assembling $(InputFile)...
@@ -580,11 +580,11 @@ Next=Root.Port.atomport.c
[Root.Port.atomport.c]
ElemType=File
PathName=atomport.c
Next=Root.Port.atomport-asm.s
Next=Root.Port.atomport-asm-cosmic.s
[Root.Port.atomport-asm.s]
[Root.Port.atomport-asm-cosmic.s]
ElemType=File
PathName=atomport-asm.s
PathName=atomport-asm-cosmic.s
Next=Root.Port.stm8_interrupt_vector.c
[Root.Port.stm8_interrupt_vector.c]

View File

@@ -4,9 +4,9 @@
Keyword=ST7Workspace-V0.7
[Project0]
Filename=atomthreads-sample.stp
Filename=atomthreads-sample-cosmic.stp
Dependencies=
[Options]
ActiveProject=atomthreads
ActiveConfig=Debug
ActiveConfig=Release
AddSortedElements=0

View File

@@ -0,0 +1,369 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<project>
<fileVersion>2</fileVersion>
<configuration>
<name>Debug</name>
<toolchain>
<name>STM8</name>
</toolchain>
<debug>1</debug>
<settings>
<name>C-SPY</name>
<archiveVersion>1</archiveVersion>
<data>
<version>0</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
<name>CSpyMandatory</name>
<state>1</state>
</option>
<option>
<name>CSpyInput</name>
<state>1</state>
</option>
<option>
<name>CSpyRunToEnable</name>
<state>1</state>
</option>
<option>
<name>CSpyRunToName</name>
<state>main</state>
</option>
<option>
<name>CSpyMacOverride</name>
<state>0</state>
</option>
<option>
<name>CSpyMacFile</name>
<state></state>
</option>
<option>
<name>DynDriver</name>
<state>STLINK_STM8</state>
</option>
<option>
<name>CSpyDDFOverride</name>
<state>0</state>
</option>
<option>
<name>CSpyDDFFile</name>
<state>$TOOLKIT_DIR$\config\ddf\iostm8s105c6.ddf</state>
</option>
<option>
<name>CSpyEnableExtraOptions</name>
<state>0</state>
</option>
<option>
<name>CSpyExtraOptions</name>
<state></state>
</option>
<option>
<name>CSpyImagesSuppressCheck1</name>
<state>0</state>
</option>
<option>
<name>CSpyImagesPath1</name>
<state></state>
</option>
<option>
<name>CSpyImagesSuppressCheck2</name>
<state>0</state>
</option>
<option>
<name>CSpyImagesPath2</name>
<state></state>
</option>
<option>
<name>CSpyImagesSuppressCheck3</name>
<state>0</state>
</option>
<option>
<name>CSpyImagesPath3</name>
<state></state>
</option>
</data>
</settings>
<settings>
<name>SIMULATOR_STM8</name>
<archiveVersion>1</archiveVersion>
<data>
<version>0</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
<name>SimMandatory</name>
<state>1</state>
</option>
</data>
</settings>
<settings>
<name>STICE_STM8</name>
<archiveVersion>1</archiveVersion>
<data>
<version>0</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
<name>STiceMandatory</name>
<state>0</state>
</option>
<option>
<name>STiceSuppressLoad</name>
<state>0</state>
</option>
<option>
<name>STiceVerifyLoad</name>
<state>0</state>
</option>
<option>
<name>STiceLogFileOver</name>
<state>0</state>
</option>
<option>
<name>STiceLogFile</name>
<state>$PROJ_DIR$\cspycomm.log</state>
</option>
<option>
<name>STiceUseSwim</name>
<state>0</state>
</option>
</data>
</settings>
<settings>
<name>STLINK_STM8</name>
<archiveVersion>1</archiveVersion>
<data>
<version>0</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
<name>STlinkMandatory</name>
<state>0</state>
</option>
<option>
<name>STlinkSuppressLoad</name>
<state>0</state>
</option>
<option>
<name>STlinkVerifyLoad</name>
<state>0</state>
</option>
<option>
<name>STlinkLogFileOver</name>
<state>0</state>
</option>
<option>
<name>STlinkLogFile</name>
<state>$PROJ_DIR$\cspycomm.log</state>
</option>
</data>
</settings>
<debuggerPlugins>
<plugin>
<file>$EW_DIR$\common\plugins\CodeCoverage\CodeCoverage.ENU.ewplugin</file>
<loadFlag>1</loadFlag>
</plugin>
<plugin>
<file>$EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin</file>
<loadFlag>0</loadFlag>
</plugin>
<plugin>
<file>$EW_DIR$\common\plugins\Profiling\Profiling.ENU.ewplugin</file>
<loadFlag>1</loadFlag>
</plugin>
<plugin>
<file>$EW_DIR$\common\plugins\Stack\Stack.ENU.ewplugin</file>
<loadFlag>1</loadFlag>
</plugin>
<plugin>
<file>$EW_DIR$\common\plugins\SymList\SymList.ENU.ewplugin</file>
<loadFlag>1</loadFlag>
</plugin>
</debuggerPlugins>
</configuration>
<configuration>
<name>Release</name>
<toolchain>
<name>STM8</name>
</toolchain>
<debug>0</debug>
<settings>
<name>C-SPY</name>
<archiveVersion>1</archiveVersion>
<data>
<version>0</version>
<wantNonLocal>1</wantNonLocal>
<debug>0</debug>
<option>
<name>CSpyMandatory</name>
<state>1</state>
</option>
<option>
<name>CSpyInput</name>
<state>1</state>
</option>
<option>
<name>CSpyRunToEnable</name>
<state>1</state>
</option>
<option>
<name>CSpyRunToName</name>
<state>main</state>
</option>
<option>
<name>CSpyMacOverride</name>
<state>0</state>
</option>
<option>
<name>CSpyMacFile</name>
<state></state>
</option>
<option>
<name>DynDriver</name>
<state>STLINK_STM8</state>
</option>
<option>
<name>CSpyDDFOverride</name>
<state>0</state>
</option>
<option>
<name>CSpyDDFFile</name>
<state>$TOOLKIT_DIR$\config\ddf\iostm8s105c6.ddf</state>
</option>
<option>
<name>CSpyEnableExtraOptions</name>
<state>0</state>
</option>
<option>
<name>CSpyExtraOptions</name>
<state></state>
</option>
<option>
<name>CSpyImagesSuppressCheck1</name>
<state>0</state>
</option>
<option>
<name>CSpyImagesPath1</name>
<state></state>
</option>
<option>
<name>CSpyImagesSuppressCheck2</name>
<state>0</state>
</option>
<option>
<name>CSpyImagesPath2</name>
<state></state>
</option>
<option>
<name>CSpyImagesSuppressCheck3</name>
<state>0</state>
</option>
<option>
<name>CSpyImagesPath3</name>
<state></state>
</option>
</data>
</settings>
<settings>
<name>SIMULATOR_STM8</name>
<archiveVersion>1</archiveVersion>
<data>
<version>0</version>
<wantNonLocal>1</wantNonLocal>
<debug>0</debug>
<option>
<name>SimMandatory</name>
<state>1</state>
</option>
</data>
</settings>
<settings>
<name>STICE_STM8</name>
<archiveVersion>1</archiveVersion>
<data>
<version>0</version>
<wantNonLocal>1</wantNonLocal>
<debug>0</debug>
<option>
<name>STiceMandatory</name>
<state>0</state>
</option>
<option>
<name>STiceSuppressLoad</name>
<state>0</state>
</option>
<option>
<name>STiceVerifyLoad</name>
<state>0</state>
</option>
<option>
<name>STiceLogFileOver</name>
<state>0</state>
</option>
<option>
<name>STiceLogFile</name>
<state>$PROJ_DIR$\cspycomm.log</state>
</option>
<option>
<name>STiceUseSwim</name>
<state>0</state>
</option>
</data>
</settings>
<settings>
<name>STLINK_STM8</name>
<archiveVersion>1</archiveVersion>
<data>
<version>0</version>
<wantNonLocal>1</wantNonLocal>
<debug>0</debug>
<option>
<name>STlinkMandatory</name>
<state>0</state>
</option>
<option>
<name>STlinkSuppressLoad</name>
<state>0</state>
</option>
<option>
<name>STlinkVerifyLoad</name>
<state>0</state>
</option>
<option>
<name>STlinkLogFileOver</name>
<state>0</state>
</option>
<option>
<name>STlinkLogFile</name>
<state>$PROJ_DIR$\cspycomm.log</state>
</option>
</data>
</settings>
<debuggerPlugins>
<plugin>
<file>$EW_DIR$\common\plugins\CodeCoverage\CodeCoverage.ENU.ewplugin</file>
<loadFlag>1</loadFlag>
</plugin>
<plugin>
<file>$EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin</file>
<loadFlag>0</loadFlag>
</plugin>
<plugin>
<file>$EW_DIR$\common\plugins\Profiling\Profiling.ENU.ewplugin</file>
<loadFlag>1</loadFlag>
</plugin>
<plugin>
<file>$EW_DIR$\common\plugins\Stack\Stack.ENU.ewplugin</file>
<loadFlag>1</loadFlag>
</plugin>
<plugin>
<file>$EW_DIR$\common\plugins\SymList\SymList.ENU.ewplugin</file>
<loadFlag>1</loadFlag>
</plugin>
</debuggerPlugins>
</configuration>
</project>

File diff suppressed because it is too large Load Diff

View File

@@ -38,7 +38,7 @@ build\stm8s_uart2.o
build\tests-main.o
build\atomport.o
build\uart.o
build\atomport-asm.o
build\atomport-asm-cosmic.o
# Caller passes in test application object name as param1
@1
#<END OBJECT_FILES>

View File

@@ -2,8 +2,13 @@
# Settings #
############
# Set up build environment (using GNU Make)
# set PATH=%PATH%;C:\Program Files\GNU_MAKE;C:\Program Files\COSMIC\CXSTM8_16K
# set MAKE_MODE=DOS
# Build all test applications:
# make
# make -f cosmic.mak
# Location of build tools and atomthreads sources
KERNEL_DIR=../../kernel
@@ -14,17 +19,19 @@ CC=cxstm8
ASM=castm8
LINK=clnk
CHEX=chex
# CPU part number
PART=STM8S105
# Enable stack-checking
STACK_CHECK=true
# Directory for built objects
BUILD_DIR=build
BUILD_DIR=build-cosmic
# Port/application object files
APP_OBJECTS = atomport.o tests-main.o stm8_interrupt_vector.o uart.o
APP_ASM_OBJECTS = atomport-asm.o
APP_ASM_OBJECTS = atomport-asm-cosmic.o
# STM8S Peripheral driver object files
PERIPH_OBJECTS = stm8s_gpio.o stm8s_tim1.o stm8s_clk.o stm8s_uart2.o
@@ -49,8 +56,8 @@ vpath %.elf .\$(BUILD_DIR)
vpath %.hex .\$(BUILD_DIR)
# Compiler/Assembler flags
CFLAGS=+modsl0 -pp -d$(PART)
DBG_CFLAGS=+modsl0 +debug -pxp -no -pp -l -d$(PART)
CFLAGS=+modsl0 +split -pp -d$(PART)
DBG_CFLAGS=+modsl0 +split +debug -pxp -no -pp -l -d$(PART)
ASMFLAGS=
DBG_ASMFLAGS=-xx -u
@@ -66,7 +73,7 @@ endif
#################
# All tests
all: $(BUILD_DIR) $(TEST_S19S) Makefile
all: $(BUILD_DIR) $(TEST_S19S) cosmic.mak
# Make build/output directory
$(BUILD_DIR):
@@ -79,7 +86,7 @@ $(TEST_S19S): %.s19: %.stm8
# Test ELF files (one application build for each test)
$(TEST_STM8S): %.stm8: %.o $(KERNEL_OBJECTS) $(PERIPH_OBJECTS) $(APP_OBJECTS) $(APP_ASM_OBJECTS)
$(LINK) -l$(LIBS_DIR) -o $(BUILD_DIR)/$@ atomthreads.lkf $(BUILD_DIR)/$(notdir $<)
$(LINK) -l$(LIBS_DIR) -o $(BUILD_DIR)/$@ -m $(BUILD_DIR)/$(basename $@).map atomthreads.lkf $(BUILD_DIR)/$(notdir $<)
# Kernel objects builder
$(KERNEL_OBJECTS): %.o: $(KERNEL_DIR)/%.c
@@ -106,7 +113,7 @@ clean:
rm -f *.o *.elf *.map *.hex *.bin *.lst *.stm8 *.s19
rm -rf doxygen-kernel
rm -rf doxygen-stm8
rm -rf build
rm -rf build-cosmic
doxygen:
doxygen $(KERNEL_DIR)/Doxyfile

137
ports/stm8/iar.mak Normal file
View File

@@ -0,0 +1,137 @@
############
# Settings #
############
# Set up build environment (using GNU Make)
# set PATH=%PATH%;C:\Program Files\GNU_MAKE;C:\Program Files\IAR Systems\Embedded Workbench 6.0\stm8\bin
# set MAKE_MODE=DOS
# Build all test applications:
# make -f iar.mak
# Location of build tools and atomthreads sources
EWSTM8_DIR=C:\Program Files\IAR Systems\Embedded Workbench 6.0\stm8
KERNEL_DIR=../../kernel
TESTS_DIR=../../tests
PERIPHS_DIR=stm8s-periphs
CC=iccstm8
ASM=iasmstm8
LINK=ilinkstm8
HEX=ielftool
# CPU part number
PART=STM8S105
# Enable stack-checking
STACK_CHECK=true
# Directory for built objects
BUILD_DIR=build-iar
# Port/application object files
APP_OBJECTS = atomport.o tests-main.o uart.o
APP_ASM_OBJECTS = atomport-asm-iar.o
# STM8S Peripheral driver object files
PERIPH_OBJECTS = stm8s_gpio.o stm8s_tim1.o stm8s_clk.o stm8s_uart2.o
# Kernel object files
KERNEL_OBJECTS = atomkernel.o atomsem.o atommutex.o atomtimer.o atomqueue.o
# Collection of built objects (excluding test applications)
ALL_OBJECTS = $(APP_OBJECTS) $(APP_ASM_OBJECTS) $(PERIPH_OBJECTS) $(KERNEL_OBJECTS)
BUILT_OBJECTS = $(patsubst %,$(BUILD_DIR)/%,$(ALL_OBJECTS))
# Test object files (dealt with separately as only one per application build)
TEST_OBJECTS = $(notdir $(patsubst %.c,%.o,$(wildcard $(TESTS_DIR)/*.c)))
# Target application filenames (.elf) for each test object
TEST_ELFS = $(patsubst %.o,%.elf,$(TEST_OBJECTS))
TEST_S19S = $(patsubst %.o,%.s19,$(TEST_OBJECTS))
# Search build/output directory for dependencies
vpath %.o .\$(BUILD_DIR)
vpath %.elf .\$(BUILD_DIR)
vpath %.hex .\$(BUILD_DIR)
# Compiler/Assembler flags
CFLAGS=-e -Oh --code_model small --data_model medium \
--dlib_config "$(EWSTM8_DIR)\lib\dlstm8smn.h" -D NDEBUG -D $(PART) \
--diag_suppress Pa050
DBG_CFLAGS=-e -Ol --no_cse --no_unroll --no_inline --no_code_motion --no_tbaa \
--no_cross_call --debug --code_model small --data_model medium \
--dlib_config "$(EWSTM8_DIR)\lib\dlstm8smn.h" -D $(PART) \
--diag_suppress Pa050
ASMFLAGS=-M'<>' -ld $(BUILD_DIR)\list --diag_suppress Pa050 --code_model small \
--data_model medium
DBG_ASMFLAGS=-M'<>' -r -ld $(BUILD_DIR)\list --diag_suppress Pa050 --code_model small \
--data_model medium
LINKFLAGS=--redirect _Printf=_PrintfSmall --redirect _Scanf=_ScanfSmall \
--config "$(EWSTM8_DIR)\config\lnkstm8s105c6.icf" --config_def \
_CSTACK_SIZE=0x100 --config_def _HEAP_SIZE=0x100 \
--entry __iar_program_start
DBG_LINKFLAGS=--redirect _Printf=_PrintfSmall --redirect _Scanf=_ScanfSmall \
--config "$(EWSTM8_DIR)\config\lnkstm8s105c6.icf" --config_def \
_CSTACK_SIZE=0x100 --config_def _HEAP_SIZE=0x100 \
--entry __iar_program_start
# Enable stack-checking (disable if not required)
ifeq ($(STACK_CHECK),true)
CFLAGS += -D ATOM_STACK_CHECKING
DBG_CFLAGS += -D ATOM_STACK_CHECKING
endif
#################
# Build targets #
#################
# All tests
all: $(BUILD_DIR) $(TEST_S19S) iar.mak
# Make build/output directory
$(BUILD_DIR):
mkdir $(BUILD_DIR)
# Test HEX files (one application build for each test)
$(TEST_S19S): %.s19: %.elf
@echo Building $@
$(HEX) $(BUILD_DIR)/$(notdir $<) $(BUILD_DIR)/$@ --srec
# Test ELF files (one application build for each test)
$(TEST_ELFS): %.elf: %.o $(KERNEL_OBJECTS) $(PERIPH_OBJECTS) $(APP_OBJECTS) $(APP_ASM_OBJECTS)
$(LINK) $(BUILD_DIR)/$(notdir $<) $(BUILT_OBJECTS) $(LINKFLAGS) -o $(BUILD_DIR)/$@
# Kernel objects builder
$(KERNEL_OBJECTS): %.o: $(KERNEL_DIR)/%.c
$(CC) $< $(CFLAGS) -I . -I $(PERIPHS_DIR) -o $(BUILD_DIR)
# Test objects builder
$(TEST_OBJECTS): %.o: $(TESTS_DIR)/%.c
$(CC) $< $(CFLAGS) -I . -I $(KERNEL_DIR) -I $(PERIPHS_DIR) -o $(BUILD_DIR)
# Kernel objects builder
$(PERIPH_OBJECTS): %.o: $(PERIPHS_DIR)/%.c
$(CC) $< $(CFLAGS) -I . -I $(PERIPHS_DIR) -o $(BUILD_DIR)
# Application C objects builder
$(APP_OBJECTS): %.o: ./%.c
$(CC) $< $(CFLAGS) -I $(KERNEL_DIR) -I $(TESTS_DIR) -I $(PERIPHS_DIR) -o $(BUILD_DIR)
# Application asm objects builder
$(APP_ASM_OBJECTS): %.o: ./%.s
$(ASM) $< $(ASMFLAGS) -I $(KERNEL_DIR) -o $(BUILD_DIR)/$(notdir $@)
# Clean
clean:
rm -f *.o *.elf *.map *.hex *.bin *.lst *.stm8 *.s19 *.out
rm -rf doxygen-kernel
rm -rf doxygen-stm8
rm -rf build-iar
doxygen:
doxygen $(KERNEL_DIR)/Doxyfile
doxygen ./Doxyfile

View File

@@ -3,6 +3,9 @@
*/
/* COSMIC: Requires interrupt vector table */
#if defined(__CSMC__)
/* Import Atomthreads system tick ISR prototype */
#include "atomport-private.h"
@@ -58,3 +61,5 @@ struct interrupt_vector const _vectab[] = {
{0x82, NonHandledInterrupt}, /* irq28 */
{0x82, NonHandledInterrupt}, /* irq29 */
};
#endif /* __CSMC__ */

View File

@@ -29,10 +29,16 @@
/* Check the used compiler */
#if defined(__CSMC__)
#undef _RAISONANCE_
#undef _IAR_SYSTEMS_
#define _COSMIC_
#elif defined(__RCST7__)
#undef _COSMIC_
#undef _IAR_SYSTEMS_
#define _RAISONANCE_
#elif defined(__IAR_SYSTEMS_ICC__)
#undef _COSMIC_
#undef _RAISONANCE_
#define _IAR_SYSTEMS_
#else
#error "Unsupported Compiler!" /* Compiler defines not found */
#endif
@@ -42,7 +48,8 @@
Tip: To avoid modifying this file each time you need to switch between these
devices, you can define the device in your toolchain compiler preprocessor. */
#if !defined (STM8S208) && !defined (STM8S207) && !defined (STM8S105) && !defined (STM8S103) && !defined (STM8S903)
#define STM8S208
# error "STM8S device not specified"
/* #define STM8S208 */
/* #define STM8S207 */
/* #define STM8S105 */
/* #define STM8S103 */
@@ -67,12 +74,21 @@
#define NEAR @near
#define TINY @tiny
#define __CONST const
#else /* __RCST7__ */
#endif
#ifdef _RAISONANCE_
#define FAR far
#define NEAR data
#define TINY page0
#define __CONST code
#endif /* __CSMC__ */
#endif
#ifdef _IAR_SYSTEMS_
#define FAR __far
#define NEAR __near
#define TINY __tiny
#define __CONST const
#endif
#ifdef PointerAttr_Far
#define PointerAttr FAR
@@ -2495,7 +2511,9 @@ CFG_TypeDef;
#define trap() _trap_() /* Trap (soft IT) */
#define wfi() _wfi_() /* Wait For Interrupt */
#define halt() _halt_() /* Halt */
#else /* COSMIC */
#endif
#ifdef _COSMIC_
#define enableInterrupts() {_asm("rim\n");} /* enable interrupts */
#define disableInterrupts() {_asm("sim\n");} /* disable interrupts */
#define rim() {_asm("rim\n");} /* enable interrupts */
@@ -2506,6 +2524,18 @@ CFG_TypeDef;
#define halt() {_asm("halt\n");} /* Halt */
#endif
#ifdef _IAR_SYSTEMS_
#include <intrinsics.h>
#define enableInterrupts() __enable_interrupt() /* enable interrupts */
#define disableInterrupts() __disable_interrupt() /* disable interrupts */
#define rim() __enable_interrupt() /* enable interrupts */
#define sim() __disable_interrupt() /* disable interrupts */
#define nop() __no_operation() /* No Operation */
#define trap() __trap_() /* Trap (soft IT) */
#define wfi() __wait_for_interrupt() /* Wait For Interrupt */
#define halt() __halt_() /* Halt */
#endif
/*============================== Handling bits ====================================*/
/*-----------------------------------------------------------------------------
Method : I

View File

@@ -49,549 +49,6 @@ uc8 CLKPrescTable[8] = {1, 2, 4, 8, 10, 16, 20, 40}; /*!< Holds the different CL
* @{
*/
/**
* @brief Deinitializes the CLK peripheral registers to their default reset
* values.
* @par Parameters:
* None
* @retval None
* @par Warning:
* Resetting the CCOR register: \n
* When the CCOEN bit is set, the reset of the CCOR register require
* two consecutive write instructions in order to reset first the CCOEN bit
* and the second one is to reset the CCOSEL bits.
*/
void CLK_DeInit(void)
{
CLK->ICKR = CLK_ICKR_RESET_VALUE;
CLK->ECKR = CLK_ECKR_RESET_VALUE;
CLK->SWR = CLK_SWR_RESET_VALUE;
CLK->SWCR = CLK_SWCR_RESET_VALUE;
CLK->CKDIVR = CLK_CKDIVR_RESET_VALUE;
CLK->PCKENR1 = CLK_PCKENR1_RESET_VALUE;
CLK->PCKENR2 = CLK_PCKENR2_RESET_VALUE;
CLK->CSSR = CLK_CSSR_RESET_VALUE;
CLK->CCOR = CLK_CCOR_RESET_VALUE;
while (CLK->CCOR & CLK_CCOR_CCOEN)
{}
CLK->CCOR = CLK_CCOR_RESET_VALUE;
CLK->CANCCR = CLK_CANCCR_RESET_VALUE;
CLK->HSITRIMR = CLK_HSITRIMR_RESET_VALUE;
CLK->SWIMCCR = CLK_SWIMCCR_RESET_VALUE;
}
/**
* @brief Configures the High Speed Internal oscillator (HSI).
* @par Full description:
* If CLK_FastHaltWakeup is enabled, HSI oscillator is automatically
* switched-on (HSIEN=1) and selected as next clock master
* (CKM=SWI=HSI) when resuming from HALT/ActiveHalt modes.\n
* @param[in] NewState this parameter is the Wake-up Mode state.
* @retval None
*/
void CLK_FastHaltWakeUpCmd(FunctionalState NewState)
{
/* check the parameters */
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE)
{
/* Set FHWU bit (HSI oscillator is automatically switched-on) */
CLK->ICKR |= CLK_ICKR_FHWU;
}
else /* FastHaltWakeup = DISABLE */
{
/* Reset FHWU bit */
CLK->ICKR &= (u8)(~CLK_ICKR_FHWU);
}
}
/**
* @brief Enable or Disable the External High Speed oscillator (HSE).
* @param[in] NewState new state of HSEEN, value accepted ENABLE, DISABLE.
* @retval None
*/
void CLK_HSECmd(FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE)
{
/* Set HSEEN bit */
CLK->ECKR |= CLK_ECKR_HSEEN;
}
else
{
/* Reset HSEEN bit */
CLK->ECKR &= (u8)(~CLK_ECKR_HSEEN);
}
}
/**
* @brief Enables or disables the Internal High Speed oscillator (HSI).
* @param[in] NewState new state of HSIEN, value accepted ENABLE, DISABLE.
* @retval None
*/
void CLK_HSICmd(FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE)
{
/* Set HSIEN bit */
CLK->ICKR |= CLK_ICKR_HSIEN;
}
else
{
/* Reset HSIEN bit */
CLK->ICKR &= (u8)(~CLK_ICKR_HSIEN);
}
}
/**
* @brief Enables or disables the Internal Low Speed oscillator (LSI).
* @param[in] NewState new state of LSIEN, value accepted ENABLE, DISABLE.
* @retval None
*/
void CLK_LSICmd(FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE)
{
/* Set LSIEN bit */
CLK->ICKR |= CLK_ICKR_LSIEN;
}
else
{
/* Reset LSIEN bit */
CLK->ICKR &= (u8)(~CLK_ICKR_LSIEN);
}
}
/**
* @brief Enables or disablle the Configurable Clock Output (CCO).
* @param[in] NewState : New state of CCEN bit (CCO register).
* This parameter can be any of the @ref FunctionalState enumeration.
* @retval None
*/
void CLK_CCOCmd(FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE)
{
/* Set CCOEN bit */
CLK->CCOR |= CLK_CCOR_CCOEN;
}
else
{
/* Reset CCOEN bit */
CLK->CCOR &= (u8)(~CLK_CCOR_CCOEN);
}
}
/**
* @brief Starts or Stops manually the clock switch execution.
* @par Full description:
* NewState parameter set the SWEN.
* @param[in] NewState new state of SWEN, value accepted ENABLE, DISABLE.
* @retval None
*/
void CLK_ClockSwitchCmd(FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE )
{
/* Enable the Clock Switch */
CLK->SWCR |= CLK_SWCR_SWEN;
}
else
{
/* Disable the Clock Switch */
CLK->SWCR &= (u8)(~CLK_SWCR_SWEN);
}
}
/**
* @brief Configures the slow active halt wake up
* @param[in] NewState: specifies the Slow Active Halt wake up state.
* can be set of the following values:
* - DISABLE: Slow Active Halt mode disabled;
* - ENABLE: Slow Active Halt mode enabled.
* @retval None
*/
void CLK_SlowActiveHaltWakeUpCmd(FunctionalState NewState)
{
/* check the parameters */
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE)
{
/* Set S_ACTHALT bit */
CLK->ICKR |= CLK_ICKR_SWUAH;
}
else
{
/* Reset S_ACTHALT bit */
CLK->ICKR &= (u8)(~CLK_ICKR_SWUAH);
}
}
/**
* @brief Enables or disables the specified peripheral CLK.
* @param[in] CLK_Peripheral : This parameter specifies the peripheral clock to gate.
* This parameter can be any of the @ref CLK_Peripheral_TypeDef enumeration.
* @param[in] NewState : New state of specified peripheral clock.
* This parameter can be any of the @ref FunctionalState enumeration.
* @retval None
*/
void CLK_PeripheralClockConfig(CLK_Peripheral_TypeDef CLK_Peripheral, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
assert_param(IS_CLK_PERIPHERAL_OK(CLK_Peripheral));
if (((u8)CLK_Peripheral & (u8)0x10) == 0x00)
{
if (NewState != DISABLE)
{
/* Enable the peripheral Clock */
CLK->PCKENR1 |= (u8)((u8)1 << ((u8)CLK_Peripheral & (u8)0x0F));
}
else
{
/* Disable the peripheral Clock */
CLK->PCKENR1 &= (u8)(~(u8)(((u8)1 << ((u8)CLK_Peripheral & (u8)0x0F))));
}
}
else
{
if (NewState != DISABLE)
{
/* Enable the peripheral Clock */
CLK->PCKENR2 |= (u8)((u8)1 << ((u8)CLK_Peripheral & (u8)0x0F));
}
else
{
/* Disable the peripheral Clock */
CLK->PCKENR2 &= (u8)(~(u8)(((u8)1 << ((u8)CLK_Peripheral & (u8)0x0F))));
}
}
}
/**
* @brief configures the Switch from one clock to another
* @param[in] CLK_SwitchMode select the clock switch mode.
* It can be set of the values of @ref CLK_SwitchMode_TypeDef
* @param[in] CLK_NewClock choice of the future clock.
* It can be set of the values of @ref CLK_Source_TypeDef
* @param[in] NewState Enable or Disable the Clock Switch interrupt.
* @param[in] CLK_CurrentClockState current clock to switch OFF or to keep ON.
* It can be set of the values of @ref CLK_CurrentClockState_TypeDef
* @retval ErrorStatus this shows the clock switch status (ERROR/SUCCESS).
*/
ErrorStatus CLK_ClockSwitchConfig(CLK_SwitchMode_TypeDef CLK_SwitchMode, CLK_Source_TypeDef CLK_NewClock, FunctionalState ITState, CLK_CurrentClockState_TypeDef CLK_CurrentClockState)
{
CLK_Source_TypeDef clock_master;
u16 DownCounter = CLK_TIMEOUT;
ErrorStatus Swif = ERROR;
/* Check the parameters */
assert_param(IS_CLK_SOURCE_OK(CLK_NewClock));
assert_param(IS_CLK_SWITCHMODE_OK(CLK_SwitchMode));
assert_param(IS_FUNCTIONALSTATE_OK(ITState));
assert_param(IS_CLK_CURRENTCLOCKSTATE_OK(CLK_CurrentClockState));
/* Current clock master saving */
clock_master = (CLK_Source_TypeDef)CLK->CMSR;
/* Automatic switch mode management */
if (CLK_SwitchMode == CLK_SWITCHMODE_AUTO)
{
/* Enables Clock switch */
CLK->SWCR |= CLK_SWCR_SWEN;
/* Enables or Disables Switch interrupt */
if (ITState != DISABLE)
{
CLK->SWCR |= CLK_SWCR_SWIEN;
}
else
{
CLK->SWCR &= (u8)(~CLK_SWCR_SWIEN);
}
/* Selection of the target clock source */
CLK->SWR = (u8)CLK_NewClock;
while (((CLK->SWCR & CLK_SWCR_SWBSY) && (DownCounter != 0)))
{
DownCounter--;
}
if (DownCounter != 0)
{
Swif = SUCCESS;
}
else
{
Swif = ERROR;
}
}
else /* CLK_SwitchMode == CLK_SWITCHMODE_MANUAL */
{
/* Enables or Disables Switch interrupt if required */
if (ITState != DISABLE)
{
CLK->SWCR |= CLK_SWCR_SWIEN;
}
else
{
CLK->SWCR &= (u8)(~CLK_SWCR_SWIEN);
}
/* Selection of the target clock source */
CLK->SWR = (u8)CLK_NewClock;
/* In manual mode, there is no risk to be stucked in a loop, value returned
is then always SUCCESS */
Swif = SUCCESS;
}
/* Switch OFF current clock if required */
if ((CLK_CurrentClockState == CLK_CURRENTCLOCKSTATE_DISABLE) && ( clock_master == CLK_SOURCE_HSI))
{
CLK->ICKR &= (u8)(~CLK_ICKR_HSIEN);
}
else if ((CLK_CurrentClockState == CLK_CURRENTCLOCKSTATE_DISABLE) && ( clock_master == CLK_SOURCE_LSI))
{
CLK->ICKR &= (u8)(~CLK_ICKR_LSIEN);
}
else if ((CLK_CurrentClockState == CLK_CURRENTCLOCKSTATE_DISABLE) && ( clock_master == CLK_SOURCE_HSE))
{
CLK->ECKR &= (u8)(~CLK_ECKR_HSEEN);
}
return(Swif);
}
/**
* @brief Configures the HSI clock dividers.
* @param[in] HSIPrescaler : Specifies the HSI clock divider to apply.
* This parameter can be any of the @ref CLK_Prescaler_TypeDef enumeration.
* @retval None
*/
void CLK_HSIPrescalerConfig(CLK_Prescaler_TypeDef HSIPrescaler)
{
/* check the parameters */
assert_param(IS_CLK_HSIPRESCALER_OK(HSIPrescaler));
/* Clear High speed internal clock prescaler */
CLK->CKDIVR &= (u8)(~CLK_CKDIVR_HSIDIV);
/* Set High speed internal clock prescaler */
CLK->CKDIVR |= (u8)HSIPrescaler;
}
/**
* @brief Output the selected clock on a dedicated I/O pin.
* @param[in] CLK_CCO : Specifies the clock source.
* This parameter can be any of the @ref CLK_Output_TypeDef enumeration.
* @retval None
* @par Required preconditions:
* The dedicated I/O pin must be set at 1 in the corresponding Px_CR1 register \n
* to be set as input with pull-up or push-pull output.
*/
void CLK_CCOConfig(CLK_Output_TypeDef CLK_CCO)
{
/* check the parameters */
assert_param(IS_CLK_OUTPUT_OK(CLK_CCO));
/* Clears of the CCO type bits part */
CLK->CCOR &= (u8)(~CLK_CCOR_CCOSEL);
/* Selects the source provided on cco_ck output */
CLK->CCOR |= (u8)CLK_CCO;
/* Enable the clock output */
CLK->CCOR |= CLK_CCOR_CCOEN;
}
/**
* @brief Enables or disables the specified CLK interrupts.
* @param[in] CLK_IT This parameter specifies the interrupt sources.
* It can be one of the values of @ref CLK_IT_TypeDef.
* @param[in] NewState New state of the Interrupt.
* Value accepted ENABLE, DISABLE.
* @retval None
*/
void CLK_ITConfig(CLK_IT_TypeDef CLK_IT, FunctionalState NewState)
{
/* check the parameters */
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
assert_param(IS_CLK_IT_OK(CLK_IT));
if (NewState != DISABLE)
{
switch (CLK_IT)
{
case CLK_IT_SWIF: /* Enable the clock switch interrupt */
CLK->SWCR |= CLK_SWCR_SWIEN;
break;
case CLK_IT_CSSD: /* Enable the clock security system detection interrupt */
CLK->CSSR |= CLK_CSSR_CSSDIE;
break;
default:
break;
}
}
else /*(NewState == DISABLE)*/
{
switch (CLK_IT)
{
case CLK_IT_SWIF: /* Disable the clock switch interrupt */
CLK->SWCR &= (u8)(~CLK_SWCR_SWIEN);
break;
case CLK_IT_CSSD: /* Disable the clock security system detection interrupt */
CLK->CSSR &= (u8)(~CLK_CSSR_CSSDIE);
break;
default:
break;
}
}
}
/**
* @brief Configures the HSI and CPU clock dividers.
* @param[in] ClockPrescaler Specifies the HSI or CPU clock divider to apply.
* @retval None
*/
void CLK_SYSCLKConfig(CLK_Prescaler_TypeDef ClockPrescaler)
{
/* check the parameters */
assert_param(IS_CLK_PRESCALER_OK(ClockPrescaler));
if (((u8)ClockPrescaler & (u8)0x80) == 0x00) /* Bit7 = 0 means HSI divider */
{
CLK->CKDIVR &= (u8)(~CLK_CKDIVR_HSIDIV);
CLK->CKDIVR |= (u8)((u8)ClockPrescaler & (u8)CLK_CKDIVR_HSIDIV);
}
else /* Bit7 = 1 means CPU divider */
{
CLK->CKDIVR &= (u8)(~CLK_CKDIVR_CPUDIV);
CLK->CKDIVR |= (u8)((u8)ClockPrescaler & (u8)CLK_CKDIVR_CPUDIV);
}
}
/**
* @brief Configures the SWIM clock frequency on the fly.
* @param[in] CLK_SWIMDivider Specifies the SWIM clock divider to apply.
* can be one of the value of @ref CLK_SWIMDivider_TypeDef
* @retval None
*/
void CLK_SWIMConfig(CLK_SWIMDivider_TypeDef CLK_SWIMDivider)
{
/* check the parameters */
assert_param(IS_CLK_SWIMDIVIDER_OK(CLK_SWIMDivider));
if (CLK_SWIMDivider != CLK_SWIMDIVIDER_2)
{
/* SWIM clock is not divided by 2 */
CLK->SWIMCCR |= CLK_SWIMCCR_SWIMDIV;
}
else /* CLK_SWIMDivider == CLK_SWIMDIVIDER_2 */
{
/* SWIM clock is divided by 2 */
CLK->SWIMCCR &= (u8)(~CLK_SWIMCCR_SWIMDIV);
}
}
/**
* @brief Configure the divider for the external CAN clock.
* @param[in] CLK_CANDivider Specifies the CAN clock divider to apply.
* can be one of the value of @ref CLK_CANDivider_TypeDef
* @retval None
*/
void CLK_CANConfig(CLK_CANDivider_TypeDef CLK_CANDivider)
{
/* check the parameters */
assert_param(IS_CLK_CANDIVIDER_OK(CLK_CANDivider));
/* Clear the CANDIV bits */
CLK->CANCCR &= (u8)(~CLK_CANCCR_CANDIV);
/* Select divider */
CLK->CANCCR |= (u8)CLK_CANDivider;
}
/**
* @brief Enables the Clock Security System.
* @par Full description:
* once CSS is enabled it cannot be disabled until the next reset.
* @par Parameters:
* None
* @retval None
*/
void CLK_ClockSecuritySystemEnable(void)
{
/* Set CSSEN bit */
CLK->CSSR |= CLK_CSSR_CSSEN;
}
/**
* @brief Returns the clock source used as system clock.
* @par Parameters:
* None
* @retval Clock source used.
* can be one of the values of @ref CLK_Source_TypeDef
*/
CLK_Source_TypeDef CLK_GetSYSCLKSource(void)
{
return((CLK_Source_TypeDef)CLK->CMSR);
}
/**
* @brief This function returns the frequencies of different on chip clocks.
@@ -628,164 +85,8 @@ u32 CLK_GetClockFreq(void)
return((u32)clockfrequency);
}
/**
* @brief Adjusts the Internal High Speed oscillator (HSI) calibration value.
* @par Full description:
* @param[in] CLK_HSICalibrationValue calibration trimming value.
* can be one of the values of @ref CLK_HSITrimValue_TypeDef
* @retval None
*/
void CLK_AdjustHSICalibrationValue(CLK_HSITrimValue_TypeDef CLK_HSICalibrationValue)
{
/* check the parameters */
assert_param(IS_CLK_HSITRIMVALUE_OK(CLK_HSICalibrationValue));
/* Store the new value */
CLK->HSITRIMR = (u8)((CLK->HSITRIMR & (u8)(~CLK_HSITRIMR_HSITRIM))|((u8)CLK_HSICalibrationValue));
}
/**
* @brief Reset the SWBSY flag (SWICR Reister)
* @par Full description:
* This function reset SWBSY flag in order to reset clock switch operations (target
* oscillator is broken, stabilization is longing too much, etc.). If at the same time \n
* software attempts to set SWEN and clear SWBSY, SWBSY action takes precedence.
* @par Parameters:
* None
* @retval None
*/
void CLK_SYSCLKEmergencyClear(void)
{
CLK->SWCR &= (u8)(~CLK_SWCR_SWBSY);
}
/**
* @brief Checks whether the specified CLK flag is set or not.
* @par Full description:
* @param[in] CLK_FLAG Flag to check.
* can be one of the values of @ref CLK_Flag_TypeDef
* @retval FlagStatus, status of the checked flag
*/
FlagStatus CLK_GetFlagStatus(CLK_Flag_TypeDef CLK_FLAG)
{
u16 statusreg = 0;
u8 tmpreg = 0;
FlagStatus bitstatus = RESET;
/* check the parameters */
assert_param(IS_CLK_FLAG_OK(CLK_FLAG));
/* Get the CLK register index */
statusreg = (u16)((u16)CLK_FLAG & (u16)0xFF00);
if (statusreg == 0x0100) /* The flag to check is in ICKRregister */
{
tmpreg = CLK->ICKR;
}
else if (statusreg == 0x0200) /* The flag to check is in ECKRregister */
{
tmpreg = CLK->ECKR;
}
else if (statusreg == 0x0300) /* The flag to check is in SWIC register */
{
tmpreg = CLK->SWCR;
}
else if (statusreg == 0x0400) /* The flag to check is in CSS register */
{
tmpreg = CLK->CSSR;
}
else /* The flag to check is in CCO register */
{
tmpreg = CLK->CCOR;
}
if ((tmpreg & (u8)CLK_FLAG) != (u8)RESET)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
/* Return the flag status */
return((FlagStatus)bitstatus);
}
/**
* @brief Checks whether the specified CLK interrupt has is enabled or not.
* @param[in] CLK_IT specifies the CLK interrupt.
* can be one of the values of @ref CLK_IT_TypeDef
* @retval ITStatus, new state of CLK_IT (SET or RESET).
*/
ITStatus CLK_GetITStatus(CLK_IT_TypeDef CLK_IT)
{
ITStatus bitstatus = RESET;
/* check the parameters */
assert_param(IS_CLK_IT_OK(CLK_IT));
if (CLK_IT == CLK_IT_SWIF)
{
/* Check the status of the clock switch interrupt */
if ((CLK->SWCR & (u8)CLK_IT) == (u8)0x0C)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
}
else /* CLK_IT == CLK_IT_CSSDIE */
{
/* Check the status of the security system detection interrupt */
if ((CLK->CSSR & (u8)CLK_IT) == (u8)0x0C)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
}
/* Return the CLK_IT status */
return bitstatus;
}
/**
* @brief Clears the CLKs interrupt pending bits.
* @param[in] CLK_IT specifies the interrupt pending bits.
* can be one of the values of @ref CLK_IT_TypeDef
* @retval None
*/
void CLK_ClearITPendingBit(CLK_IT_TypeDef CLK_IT)
{
/* check the parameters */
assert_param(IS_CLK_IT_OK(CLK_IT));
if (CLK_IT == (u8)CLK_IT_CSSD)
{
/* Clear the status of the security system detection interrupt */
CLK->CSSR &= (u8)(~CLK_CSSR_CSSD);
}
else /* CLK_PendingBit == (u8)CLK_IT_SWIF */
{
/* Clear the status of the clock switch interrupt */
CLK->SWCR &= (u8)(~CLK_SWCR_SWIF);
}
}
/**
* @}
*/

View File

@@ -117,47 +117,6 @@ void GPIO_Init(GPIO_TypeDef* GPIOx,
}
/**
* @brief Writes data to the specified GPIO data port.
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
* @param[in] PortVal : Specifies the value to be written to the port output.
* data register.
* @retval None
* @par Required preconditions:
* The port must be configured in output mode.
*/
void GPIO_Write(GPIO_TypeDef* GPIOx, u8 PortVal)
{
GPIOx->ODR = PortVal;
}
/**
* @brief Writes high level to the specified GPIO pins.
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
* @param[in] PortPins : Specifies the pins to be turned high to the port output.
* data register.
* @retval None
* @par Required preconditions:
* The port must be configured in output mode.
*/
void GPIO_WriteHigh(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins)
{
GPIOx->ODR |= (u8)PortPins;
}
/**
* @brief Writes low level to the specified GPIO pins.
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
* @param[in] PortPins : Specifies the pins to be turned low to the port output.
* data register.
* @retval None
* @par Required preconditions:
* The port must be configured in output mode.
*/
void GPIO_WriteLow(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins)
{
GPIOx->ODR &= (u8)(~PortPins);
}
/**
* @brief Writes reverse level to the specified GPIO pins.
@@ -173,67 +132,6 @@ void GPIO_WriteReverse(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins)
GPIOx->ODR ^= (u8)PortPins;
}
/**
* @brief Reads the specified GPIO output data port.
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
* @retval u8 : GPIO output data port value.
* @par Required preconditions:
* The port must be configured in input mode.
*/
u8 GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)
{
return ((u8)GPIOx->ODR);
}
/**
* @brief Reads the specified GPIO input data port.
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
* @retval u8 : GPIO input data port value.
* @par Required preconditions:
* The port must be configured in input mode.
*/
u8 GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
{
return ((u8)GPIOx->IDR);
}
/**
* @brief Reads the specified GPIO input data pin.
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
* @param[in] GPIO_Pin : This parameter contains the pin number, it can be one member
* of the @ref GPIO_Pin_TypeDef enumeration.
* @retval BitStatus : GPIO input pin status.
* This parameter can be any of the @ref BitStatus enumeration.
* @par Required preconditions:
* The port must be configured in input mode.
*/
BitStatus GPIO_ReadInputPin(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin)
{
return ((BitStatus)(GPIOx->IDR & (vu8)GPIO_Pin));
}
/**
* @brief Configures the external pull-up on GPIOx pins.
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
* @param[in] GPIO_Pin : This parameter contains the pin number, it can be one or many members
* of the @ref GPIO_Pin_TypeDef enumeration.
* @param[in] NewState : The new state of the pull up pin.
* This parameter can be any of the @ref FunctionalState enumeration.
* @retval None
*/
void GPIO_ExternalPullUpConfig(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_GPIO_PIN_OK(GPIO_Pin));
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE) /* External Pull-Up Set*/
{
GPIOx->CR1 |= (u8)GPIO_Pin;
} else /* External Pull-Up Reset*/
{
GPIOx->CR1 &= (u8)(~(GPIO_Pin));
}
}
/**
* @}

View File

@@ -47,18 +47,18 @@
*/
typedef enum
{
GPIO_MODE_IN_FL_NO_IT = (u8)0b00000000, /*!< Input floating, no external interrupt */
GPIO_MODE_IN_PU_NO_IT = (u8)0b01000000, /*!< Input pull-up, no external interrupt */
GPIO_MODE_IN_FL_IT = (u8)0b00100000, /*!< Input floating, external interrupt */
GPIO_MODE_IN_PU_IT = (u8)0b01100000, /*!< Input pull-up, external interrupt */
GPIO_MODE_OUT_OD_LOW_FAST = (u8)0b10100000, /*!< Output open-drain, low level, 10MHz */
GPIO_MODE_OUT_PP_LOW_FAST = (u8)0b11100000, /*!< Output push-pull, low level, 10MHz */
GPIO_MODE_OUT_OD_LOW_SLOW = (u8)0b10000000, /*!< Output open-drain, low level, 2MHz */
GPIO_MODE_OUT_PP_LOW_SLOW = (u8)0b11000000, /*!< Output push-pull, low level, 2MHz */
GPIO_MODE_OUT_OD_HIZ_FAST = (u8)0b10110000, /*!< Output open-drain, high-impedance level,10MHz */
GPIO_MODE_OUT_PP_HIGH_FAST = (u8)0b11110000, /*!< Output push-pull, high level, 10MHz */
GPIO_MODE_OUT_OD_HIZ_SLOW = (u8)0b10010000, /*!< Output open-drain, high-impedance level, 2MHz */
GPIO_MODE_OUT_PP_HIGH_SLOW = (u8)0b11010000 /*!< Output push-pull, high level, 2MHz */
GPIO_MODE_IN_FL_NO_IT = (u8)0x00, // 0b00000000, /*!< Input floating, no external interrupt */
GPIO_MODE_IN_PU_NO_IT = (u8)0x40, // 0b01000000, /*!< Input pull-up, no external interrupt */
GPIO_MODE_IN_FL_IT = (u8)0x20, // 0b00100000, /*!< Input floating, external interrupt */
GPIO_MODE_IN_PU_IT = (u8)0x60, // 0b01100000, /*!< Input pull-up, external interrupt */
GPIO_MODE_OUT_OD_LOW_FAST = (u8)0xA0, // 0b10100000, /*!< Output open-drain, low level, 10MHz */
GPIO_MODE_OUT_PP_LOW_FAST = (u8)0xE0, // 0b11100000, /*!< Output push-pull, low level, 10MHz */
GPIO_MODE_OUT_OD_LOW_SLOW = (u8)0x80, // 0b10000000, /*!< Output open-drain, low level, 2MHz */
GPIO_MODE_OUT_PP_LOW_SLOW = (u8)0xC0, // 0b11000000, /*!< Output push-pull, low level, 2MHz */
GPIO_MODE_OUT_OD_HIZ_FAST = (u8)0xB0, // 0b10110000, /*!< Output open-drain, high-impedance level,10MHz */
GPIO_MODE_OUT_PP_HIGH_FAST = (u8)0xF0, // 0b11110000, /*!< Output push-pull, high level, 10MHz */
GPIO_MODE_OUT_OD_HIZ_SLOW = (u8)0x90, // 0b10010000, /*!< Output open-drain, high-impedance level, 2MHz */
GPIO_MODE_OUT_PP_HIGH_SLOW = (u8)0xD0 // 0b11010000 /*!< Output push-pull, high level, 2MHz */
}GPIO_Mode_TypeDef;
/**

View File

@@ -45,9 +45,16 @@ u8 ITC_GetCPUCC(void)
_asm("push cc");
_asm("pop a");
return; /* Ignore compiler warning, the returned value is in A register */
#else /* _RAISONANCE_ */
#endif
#ifdef _RAISONANCE_
return _getCC_();
#endif /* _COSMIC_*/
#endif
#ifdef _IAR_SYSTEMS_
__asm("push cc");
__asm("pop a");
#endif
}

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,14 @@
/* Private functions ---------------------------------------------------------*/
/* Public functions ----------------------------------------------------------*/
/**
* IAR EWSTM8: Ignore unused variable warning on dummy variable.
*/
#ifdef __IAR_SYSTEMS_ICC__
#pragma diag_suppress=Pe550
#endif
/** @}
* @addtogroup UART2_Public_Functions
* @{
@@ -149,335 +157,6 @@ void UART2_Init(u32 BaudRate, UART2_WordLength_TypeDef WordLength, UART2_StopBit
UART2->CR3 |= (u8)((u8)SyncMode & UART2_CR3_CKEN);
}
}
/**
* @brief Enable the UART2 peripheral.
* @par Full description:
* Enable the UART2 peripheral.
* @param[in] NewState new state of the UART2 Communication.
* This parameter can be:
* - ENABLE
* - DISABLE
* @retval None
*/
void UART2_Cmd(FunctionalState NewState)
{
if (NewState != DISABLE)
{
UART2->CR1 &= (u8)(~UART2_CR1_UARTD); /**< UART2 Enable */
}
else
{
UART2->CR1 |= UART2_CR1_UARTD; /**< UART2 Disable (for low power consumption) */
}
}
/**
* @brief Enables or disables the specified UART2 interrupts.
* @par Full description:
* Enables or disables the specified UART2 interrupts.
* @param[in] UART2_IT specifies the UART2 interrupt sources to be enabled or disabled.
* This parameter can be one of the following values:
* - UART2_IT_LBDF: LIN Break detection interrupt
* - UART2_IT_LHDF: LIN Break detection interrupt
* - UART2_IT_TXE: Tansmit Data Register empty interrupt
* - UART2_IT_TC: Transmission complete interrupt
* - UART2_IT_RXNE_OR: Receive Data register not empty/Over run error interrupt
* - UART2_IT_IDLE: Idle line detection interrupt
* - UART2_IT_PE: Parity Error interrupt
* @param[in] NewState new state of the specified UART2 interrupts.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void UART2_ITConfig(UART2_IT_TypeDef UART2_IT, FunctionalState NewState)
{
u8 uartreg, itpos = 0x00;
assert_param(IS_UART2_CONFIG_IT_OK(UART2_IT));
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
/* Get the UART2 register index */
uartreg = (u8)(UART2_IT >> 0x08);
/* Get the UART2 IT index */
itpos = (u8)((u8)1 << (u8)((u8)UART2_IT & (u8)0x0F));
if (NewState != DISABLE)
{
/**< Enable the Interrupt bits according to UART2_IT mask */
if (uartreg == 0x01)
{
UART2->CR1 |= itpos;
}
else if (uartreg == 0x02)
{
UART2->CR2 |= itpos;
}
else if (uartreg == 0x03)
{
UART2->CR4 |= itpos;
}
else
{
UART2->CR6 |= itpos;
}
}
else
{
/**< Disable the interrupt bits according to UART2_IT mask */
if (uartreg == 0x01)
{
UART2->CR1 &= (u8)(~itpos);
}
else if (uartreg == 0x02)
{
UART2->CR2 &= (u8)(~itpos);
}
else if (uartreg == 0x03)
{
UART2->CR4 &= (u8)(~itpos);
}
else
{
UART2->CR6 &= (u8)(~itpos);
}
}
}
/**
* @brief Configures the UART2s IrDA interface.
* @par Full description:
* Configures the UART2s IrDA interface.
* @par This function is valid only for UART2.
* @param[in] UART2_IrDAMode specifies the IrDA mode.
* This parameter can be any of the @ref UART2_IrDAMode_TypeDef values.
* @retval None
*/
void UART2_IrDAConfig(UART2_IrDAMode_TypeDef UART2_IrDAMode)
{
assert_param(IS_UART2_IRDAMODE_OK(UART2_IrDAMode));
if (UART2_IrDAMode != UART2_IRDAMODE_NORMAL)
{
UART2->CR5 |= UART2_CR5_IRLP;
}
else
{
UART2->CR5 &= ((u8)~UART2_CR5_IRLP);
}
}
/**
* @brief Enables or disables the UART2s IrDA interface.
* @par Full description:
* Enables or disables the UART2s IrDA interface.
* @par This function is related to IrDA mode.
* @param[in] NewState new state of the IrDA mode.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void UART2_IrDACmd(FunctionalState NewState)
{
/* Check parameters */
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE)
{
/* Enable the IrDA mode by setting the IREN bit in the CR3 register */
UART2->CR5 |= UART2_CR5_IREN;
}
else
{
/* Disable the IrDA mode by clearing the IREN bit in the CR3 register */
UART2->CR5 &= ((u8)~UART2_CR5_IREN);
}
}
/**
* @brief Sets the UART2 LIN Break detection length.
* @par Full description:
* Sets the UART2 LIN Break detection length.
* @param[in] UART2_LINBreakDetectionLength specifies the LIN break detection length.
* This parameter can be any of the @ref UART2_LINBreakDetectionLength_TypeDef values.
* @retval None
*/
void UART2_LINBreakDetectionConfig(UART2_LINBreakDetectionLength_TypeDef UART2_LINBreakDetectionLength)
{
assert_param(IS_UART2_LINBREAKDETECTIONLENGTH_OK(UART2_LINBreakDetectionLength));
if (UART2_LINBreakDetectionLength != UART2_LINBREAKDETECTIONLENGTH_10BITS)
{
UART2->CR4 |= UART2_CR4_LBDL;
}
else
{
UART2->CR4 &= ((u8)~UART2_CR4_LBDL);
}
}
/**
* @brief Configue the UART2 peripheral.
* @par Full description:
* Configue the UART2 peripheral.
* @param[in] UART2_Mode specifies the LIN mode.
* This parameter can be any of the @ref UART2_LinMode_TypeDef values.
* @param[in] UART2_Autosync specifies the LIN automatic resynchronization mode.
* This parameter can be any of the @ref UART2_LinAutosync_TypeDef values.
* @param[in] UART2_DivUp specifies the LIN divider update method.
* This parameter can be any of the @ref UART2_LinDivUp_TypeDef values.
* @retval None
*/
void UART2_LINConfig(UART2_LinMode_TypeDef UART2_Mode, UART2_LinAutosync_TypeDef UART2_Autosync, UART2_LinDivUp_TypeDef UART2_DivUp)
{
assert_param(IS_UART2_SLAVE_OK(UART2_Mode));
assert_param(IS_UART2_AUTOSYNC_OK(UART2_Autosync));
assert_param(IS_UART2_DIVUP_OK(UART2_DivUp));
if (UART2_Mode != UART2_LIN_MODE_MASTER)
{
UART2->CR6 |= UART2_CR6_LSLV;
}
else
{
UART2->CR6 &= ((u8)~UART2_CR6_LSLV);
}
if (UART2_Autosync != UART2_LIN_AUTOSYNC_DISABLE)
{
UART2->CR6 |= UART2_CR6_LASE ;
}
else
{
UART2->CR6 &= ((u8)~ UART2_CR6_LASE );
}
if (UART2_DivUp != UART2_LIN_DIVUP_LBRR1)
{
UART2->CR6 |= UART2_CR6_LDUM;
}
else
{
UART2->CR6 &= ((u8)~ UART2_CR6_LDUM);
}
}
/**
* @brief Enables or disables the UART2 LIN mode.
* @par Full description:
* Enables or disables the UART2s LIN mode.
* @param[in] NewState is new state of the UART2 LIN mode.
* This parameter can be:
* - ENABLE
* - DISABLE
* @retval None
*/
void UART2_LINCmd(FunctionalState NewState)
{
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE)
{
/* Enable the LIN mode by setting the LINE bit in the CR2 register */
UART2->CR3 |= UART2_CR3_LINEN;
}
else
{
/* Disable the LIN mode by clearing the LINE bit in the CR2 register */
UART2->CR3 &= ((u8)~UART2_CR3_LINEN);
}
}
/**
* @brief Enables or disables the UART2 Smart Card mode.
* @par Full description:
* Enables or disables the UART2 Smart Card mode.
* @par This function is related to SmartCard mode.
* @param[in] NewState: new state of the Smart Card mode.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void UART2_SmartCardCmd(FunctionalState NewState)
{
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE)
{
/* Enable the SC mode by setting the SCEN bit in the CR5 register */
UART2->CR5 |= UART2_CR5_SCEN;
}
else
{
/* Disable the SC mode by clearing the SCEN bit in the CR5 register */
UART2->CR5 &= ((u8)(~UART2_CR5_SCEN));
}
}
/**
* @brief Enables or disables NACK transmission.
* @par Full description:
* Enables or disables NACK transmission.
* @par This function is valid only for UART2 because is related to SmartCard mode.
* @param[in] NewState: new state of the Smart Card mode.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void UART2_SmartCardNACKCmd(FunctionalState NewState)
{
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE)
{
/* Enable the NACK transmission by setting the NACK bit in the CR5 register */
UART2->CR5 |= UART2_CR5_NACK;
}
else
{
/* Disable the NACK transmission by clearing the NACK bit in the CR5 register */
UART2->CR5 &= ((u8)~(UART2_CR5_NACK));
}
}
/**
* @brief Selects the UART2 WakeUp method.
* @par Full description:
* Selects the UART2 WakeUp method.
* @param[in] UART2_WakeUp: specifies the UART2 wakeup method.
* This parameter can be any of the @ref UART2_WakeUp_TypeDef values.
* @retval None
*/
void UART2_WakeUpConfig(UART2_WakeUp_TypeDef UART2_WakeUp)
{
assert_param(IS_UART2_WAKEUP_OK(UART2_WakeUp));
UART2->CR1 &= ((u8)~UART2_CR1_WAKE);
UART2->CR1 |= (u8)UART2_WakeUp;
}
/**
* @brief Determines if the UART2 is in mute mode or not.
* @par Full description:
* Determines if the UART2 is in mute mode or not.
* @param[in] NewState: new state of the UART2 mode.
* This parameter can be:
* - ENABLE
* - DISABLE
* @retval None
*/
void UART2_ReceiverWakeUpCmd(FunctionalState NewState)
{
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE)
{
/* Enable the mute mode UART2 by setting the RWU bit in the CR2 register */
UART2->CR2 |= UART2_CR2_RWU;
}
else
{
/* Disable the mute mode UART2 by clearing the RWU bit in the CR1 register */
UART2->CR2 &= ((u8)~UART2_CR2_RWU);
}
}
/**
@@ -493,20 +172,6 @@ u8 UART2_ReceiveData8(void)
return ((u8)UART2->DR);
}
/**
* @brief Returns the most recent received data by the UART2 peripheral.
* @par Full description:
* Returns the most recent received data by the UART2 peripheral.
* @retval u16 Received Data
* @par Required preconditions:
* UART2_Cmd(ENABLE);
*/
u16 UART2_ReceiveData9(void)
{
return (u16)((((u16)UART2->DR) | ((u16)(((u16)((u16)UART2->CR1 & (u16)UART2_CR1_R8)) << 1))) & ((u16)0x01FF));
}
/**
* @brief Transmits 8 bit data through the UART2 peripheral.
@@ -523,95 +188,6 @@ void UART2_SendData8(u8 Data)
UART2->DR = Data;
}
/**
* @brief Transmits 9 bit data through the UART2 peripheral.
* @par Full description:
* Transmits 9 bit data through the UART2 peripheral.
* @param[in] Data: the data to transmit.
* @retval None
* @par Required preconditions:
* UART2_Cmd(ENABLE);
*/
void UART2_SendData9(u16 Data)
{
UART2->CR1 &= ((u8)~UART2_CR1_T8); /* Clear the transmit data bit 8 */
UART2->CR1 |= (u8)(((u8)(Data >> 2)) & UART2_CR1_T8); /* Write the transmit data bit [8] */
UART2->DR = (u8)(Data); /* Write the transmit data bit [0:7] */
}
/**
* @brief Transmits break characters.
* @par Full description:
* Transmits break characters on the UART2 peripheral.
* @retval None
*/
void UART2_SendBreak(void)
{
UART2->CR2 |= UART2_CR2_SBK;
}
/**
* @brief Sets the address of the UART2 node.
* @par Full description:
* Sets the address of the UART2 node.
* @param[in] UART2_Address: Indicates the address of the UART2 node.
* @retval None
*/
void UART2_SetAddress(u8 UART2_Address)
{
/*assert_param for x UART2_Address*/
assert_param(IS_UART2_ADDRESS_OK(UART2_Address));
/* Clear the UART2 address */
UART2->CR4 &= ((u8)~UART2_CR4_ADD);
/* Set the UART2 address node */
UART2->CR4 |= UART2_Address;
}
/**
* @brief Sets the specified UART2 guard time.
* @par Full description:
* Sets the address of the UART2 node.
* @par This function is related to SmartCard mode.
* @param[in] UART2_GuardTime: specifies the guard time.
* @retval None
* @par Required preconditions:
* SmartCard Mode Enabled
*/
void UART2_SetGuardTime(u8 UART2_GuardTime)
{
/* Set the UART2 guard time */
UART2->GTR = UART2_GuardTime;
}
/**
* @brief Sets the system clock prescaler.
* @par Full description:
* Sets the system clock prescaler.
* @par This function is related to SmartCard and IrDa mode.
* @param[in] UART2_Prescaler: specifies the prescaler clock.
* This parameter can be one of the following values:
* @par IrDA Low Power Mode
* The clock source is diveded by the value given in the register (8 bits)
* - 0000 0000 Reserved
* - 0000 0001 divides the clock source by 1
* - 0000 0010 divides the clock source by 2
* - ...........................................................
* @par Smart Card Mode
* The clock source is diveded by the value given in the register (5 significant bits) multipied by 2
* - 0 0000 Reserved
* - 0 0001 divides the clock source by 2
* - 0 0010 divides the clock source by 4
* - 0 0011 divides the clock source by 6
* - ...........................................................
* @retval None
* @par Required preconditions:
* IrDA Low Power mode or smartcard mode enabled
*/
void UART2_SetPrescaler(u8 UART2_Prescaler)
{
/* Load the UART2 prescaler value*/
UART2->PSCR = UART2_Prescaler;
}
/**
* @brief Checks whether the specified UART2 flag is set or not.
@@ -686,210 +262,8 @@ FlagStatus UART2_GetFlagStatus(UART2_Flag_TypeDef UART2_FLAG)
/* Return the UART2_FLAG status*/
return status;
}
/**
* @brief Clears the UART2 flags.
* @par Full description:
* Clears the UART2 flags.
* @param[in] UART2_FLAG specifies the flag to clear
* This parameter can be any combination of the following values:
* - UART2_FLAG_LBDF: LIN Break detection flag.
* - UART2_FLAG_LHDF: LIN Header detection flag.
* - UART2_FLAG_LSF: LIN synchrone field flag.
* - UART2_FLAG_RXNE: Receive data register not empty flag.
* @par Notes:
* - PE (Parity error), FE (Framing error), NE (Noise error), OR (OverRun error)
* and IDLE (Idle line detected) flags are cleared by software sequence: a read
* operation to UART2_SR register (UART2_GetFlagStatus())followed by a read operation
* to UART2_DR register(UART2_ReceiveData8() or UART2_ReceiveData9()).
* - RXNE flag can be also cleared by a read to the UART2_DR register
* (UART2_ReceiveData8()or UART2_ReceiveData9()).
* - TC flag can be also cleared by software sequence: a read operation to UART2_SR
* register (UART2_GetFlagStatus()) followed by a write operation to UART2_DR register
* (UART2_SendData8() or UART2_SendData9()).
* - TXE flag is cleared only by a write to the UART2_DR register (UART2_SendData8() or
* UART2_SendData9()).
* - SBK flag is cleared during the stop bit of break.
* @retval None
*/
void UART2_ClearFlag(UART2_Flag_TypeDef UART2_FLAG)
{
assert_param(IS_UART2_CLEAR_FLAG_OK(UART2_FLAG));
/*< Clear the Receive Register Not Empty flag */
if (UART2_FLAG == UART2_FLAG_RXNE)
{
UART2->SR = (u8)~(UART2_SR_RXNE);
}
/*< Clear the LIN Break Detection flag */
else if (UART2_FLAG == UART2_FLAG_LBDF)
{
UART2->CR4 &= (u8)(~UART2_CR4_LBDF);
}
/*< Clear the LIN Header Detection Flag */
else if (UART2_FLAG == UART2_FLAG_LHDF)
{
UART2->CR6 &= (u8)(~UART2_CR6_LHDF);
}
/*< Clear the LIN Synch Field flag */
else
{
UART2->CR6 &= (u8)(~UART2_CR6_LSF);
}
}
/**
* @brief Checks whether the specified UART2 interrupt has occurred or not.
* @par Full description:
* Checks whether the specified UART2 interrupt has occurred or not.
* @param[in] UART2_IT: Specifies the UART2 interrupt pending bit to check.
* This parameter can be one of the following values:
* - UART2_IT_LBDF: LIN Break detection interrupt
* - UART2_IT_TXE: Tansmit Data Register empty interrupt
* - UART2_IT_TC: Transmission complete interrupt
* - UART2_IT_RXNE: Receive Data register not empty interrupt
* - UART2_IT_IDLE: Idle line detection interrupt
* - UART2_IT_OR: OverRun Error interrupt
* - UART2_IT_PE: Parity Error interrupt
* @retval
* ITStatus The new state of UART2_IT (SET or RESET).
*/
ITStatus UART2_GetITStatus(UART2_IT_TypeDef UART2_IT)
{
ITStatus pendingbitstatus = RESET;
u8 itpos = 0;
u8 itmask1 = 0;
u8 itmask2 = 0;
u8 enablestatus = 0;
/* Check parameters */
assert_param(IS_UART2_GET_IT_OK(UART2_IT));
/* Get the UART2 IT index*/
itpos = (u8)((u8)1 << (u8)((u8)UART2_IT & (u8)0x0F));
/* Get the UART2 IT index*/
itmask1 = (u8)((u8)UART2_IT >> (u8)4);
/* Set the IT mask*/
itmask2 = (u8)((u8)1 << itmask1);
/* Check the status of the specified UART2 pending bit*/
if (UART2_IT == UART2_IT_PE)
{
/* Get the UART2_ITPENDINGBIT enable bit status*/
enablestatus = (u8)((u8)UART2->CR1 & itmask2);
/* Check the status of the specified UART2 interrupt*/
if (((UART2->SR & itpos) != (u8)0x00) && enablestatus)
{
/* Interrupt occurred*/
pendingbitstatus = SET;
}
else
{
/* Interrupt not occurred*/
pendingbitstatus = RESET;
}
}
else if (UART2_IT == UART2_IT_LBDF)
{
/* Get the UART2_IT enable bit status*/
enablestatus = (u8)((u8)UART2->CR4 & itmask2);
/* Check the status of the specified UART2 interrupt*/
if (((UART2->CR4 & itpos) != (u8)0x00) && enablestatus)
{
/* Interrupt occurred*/
pendingbitstatus = SET;
}
else
{
/* Interrupt not occurred*/
pendingbitstatus = RESET;
}
}
else if (UART2_IT == UART2_IT_LHDF)
{
/* Get the UART2_IT enable bit status*/
enablestatus = (u8)((u8)UART2->CR6 & itmask2);
/* Check the status of the specified UART2 interrupt*/
if (((UART2->CR6 & itpos) != (u8)0x00) && enablestatus)
{
/* Interrupt occurred*/
pendingbitstatus = SET;
}
else
{
/* Interrupt not occurred*/
pendingbitstatus = RESET;
}
}
else
{
/* Get the UART2_IT enable bit status*/
enablestatus = (u8)((u8)UART2->CR2 & itmask2);
/* Check the status of the specified UART2 interrupt*/
if (((UART2->SR & itpos) != (u8)0x00) && enablestatus)
{
/* Interrupt occurred*/
pendingbitstatus = SET;
}
else
{
/* Interrupt not occurred*/
pendingbitstatus = RESET;
}
}
/* Return the UART2_IT status*/
return pendingbitstatus;
}
/**
* @brief Clears the UART2 pending flags.
* @par Full description:
* Clears the UART2 pending bit.
* @param[in] UART2_IT specifies the pending bit to clear
* This parameter can be one of the following values:
* - UART2_IT_LBDF: LIN Break detection interrupt
* - UART2_IT_LHDF: LIN Header detection interrupt
* - UART2_IT_RXNE: Receive Data register not empty interrupt.
*
* @par Notes:
* - PE (Parity error), FE (Framing error), NE (Noise error), OR (OverRun error) and
* IDLE (Idle line detected) pending bits are cleared by software sequence: a read
* operation to UART2_SR register (UART2_GetITStatus()) followed by a read operation
* to UART2_DR register (UART2_ReceiveData8() or UART2_ReceiveData9() ).
* - RXNE pending bit can be also cleared by a read to the UART2_DR register
* (UART2_ReceiveData8() or UART2_ReceiveData9() ).
* - TC (Transmit complet) pending bit can be cleared by software sequence: a read
* operation to UART2_SR register (UART2_GetITStatus()) followed by a write operation
* to UART2_DR register (UART2_SendData8()or UART2_SendData9()).
* - TXE pending bit is cleared only by a write to the UART2_DR register
* (UART2_SendData8() or UART2_SendData9()).
* @retval None
*/
void UART2_ClearITPendingBit(UART2_IT_TypeDef UART2_IT)
{
assert_param(IS_UART2_CLEAR_IT_OK(UART2_IT));
/*< Clear the Receive Register Not Empty pending bit */
if (UART2_IT == UART2_IT_RXNE)
{
UART2->SR = (u8)~(UART2_SR_RXNE);
}
/*< Clear the LIN Break Detection pending bit */
else if (UART2_IT == UART2_IT_LBDF)
{
UART2->CR4 &= (u8)~(UART2_CR4_LBDF);
}
/*< Clear the LIN Header Detection pending bit */
else
{
UART2->CR6 &= (u8)(~UART2_CR6_LHDF);
}
}
/**
* @}
*/

View File

@@ -32,6 +32,7 @@
#include "atom.h"
#include "atomport-private.h"
#include "atomport-tests.h"
#include "atomtests.h"
#include "atomtimer.h"
#include "uart.h"
@@ -104,10 +105,10 @@ extern int _stack;
static ATOM_TCB main_tcb;
/* Main thread's stack area (large so place outside of the small page0 area on STM8) */
@near static uint8_t main_thread_stack[MAIN_STACK_SIZE_BYTES];
NEAR static uint8_t main_thread_stack[MAIN_STACK_SIZE_BYTES];
/* Idle thread's stack area (large so place outside of the small page0 area on STM8) */
@near static uint8_t idle_thread_stack[IDLE_STACK_SIZE_BYTES];
NEAR static uint8_t idle_thread_stack[IDLE_STACK_SIZE_BYTES];
/* Forward declarations */
@@ -121,8 +122,15 @@ static void main_thread_func (uint32_t data);
*
* Sets up the STM8 hardware resources (system tick timer interrupt) necessary
* for the OS to be started. Creates an application thread and starts the OS.
*
* If the compiler supports it, stack space can be saved by preventing
* the function from saving registers on entry. This is because we
* are called directly by the C startup assembler, and know that we will
* never return from here. The NO_REG_SAVE macro is used to denote such
* functions in a compiler-agnostic way, though not all compilers support it.
*
*/
void main ( void )
NO_REG_SAVE void main ( void )
{
int8_t status;
@@ -162,11 +170,11 @@ void main ( void )
}
}
while (1)
;
/* There was an error starting the OS if we reach here */
return;
while (1)
{
}
}

View File

@@ -1,78 +1,138 @@
#include <stdio.h>
#include "stm8s.h"
#include "atom.h"
#include "atommutex.h"
#include "uart.h"
/*
* Semaphore for single-threaded access to UART device
*/
static ATOM_MUTEX uart_mutex;
/*
* Initialize the UART to requested baudrate, tx/rx, 8N1.
*/
int uart_init(uint32_t baudrate)
{
int status;
/**
* Set up UART2 for putting out debug messages.
* This the UART used on STM8S Discovery, change if required.
*/
UART2_DeInit();
UART2_Init (baudrate, UART2_WORDLENGTH_8D, UART2_STOPBITS_1, UART2_PARITY_NO,
UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);
/* Create a mutex for single-threaded putchar() access */
if (atomMutexCreate (&uart_mutex) != ATOM_OK)
{
status = -1;
}
else
{
status = 0;
}
/* Finished */
return (status);
}
/**
* \b putchar
*
* Retarget putchar() to use UART2
*
* @param[in] c Character to send
*
* @return Character sent
*/
char putchar (char c)
{
/* Block on private access to the UART */
if (atomMutexGet(&uart_mutex, 0) == ATOM_OK)
{
/* Convert \n to \r\n */
if (c == '\n')
putchar('\r');
/* Write a character to the UART2 */
UART2_SendData8(c);
/* Loop until the end of transmission */
while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)
;
#include <stdio.h>
#include <stddef.h>
#include "stm8s.h"
#include "atom.h"
#include "atommutex.h"
#include "uart.h"
/*
* Semaphore for single-threaded access to UART device
*/
static ATOM_MUTEX uart_mutex;
/*
* Initialize the UART to requested baudrate, tx/rx, 8N1.
*/
int uart_init(uint32_t baudrate)
{
int status;
/**
* Set up UART2 for putting out debug messages.
* This the UART used on STM8S Discovery, change if required.
*/
UART2_DeInit();
UART2_Init (baudrate, UART2_WORDLENGTH_8D, UART2_STOPBITS_1, UART2_PARITY_NO,
UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);
/* Create a mutex for single-threaded putchar() access */
if (atomMutexCreate (&uart_mutex) != ATOM_OK)
{
status = -1;
}
else
{
status = 0;
}
/* Finished */
return (status);
}
/**
* \b uart_putchar
*
* Write a char out via UART2
*
* @param[in] c Character to send
*
* @return Character sent
*/
char uart_putchar (char c)
{
/* Block on private access to the UART */
if (atomMutexGet(&uart_mutex, 0) == ATOM_OK)
{
/* Convert \n to \r\n */
if (c == '\n')
putchar('\r');
/* Write a character to the UART2 */
UART2_SendData8(c);
/* Loop until the end of transmission */
while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)
;
/* Return mutex access */
atomMutexPut(&uart_mutex);
}
return (c);
}
}
return (c);
}
/* COSMIC: Requires putchar() routine to override stdio */
#if defined(__CSMC__)
/**
* \b putchar
*
* Retarget putchar() to use UART2
*
* @param[in] c Character to send
*
* @return Character sent
*/
char putchar (char c)
{
return (uart_putchar(c));
}
#endif /* __CSMC__ */
/* IAR: Requires __write() routine to override stdio */
#if defined(__IAR_SYSTEMS_ICC__)
/**
* \b __write
*
* Override for IAR stream output
*
* @param[in] handle Stdio handle. -1 to flush.
* @param[in] buf Pointer to buffer to be written
* @param[in] bufSize Number of characters to be written
*
* @return Number of characters sent
*/
size_t __write(int handle, const unsigned char *buf, size_t bufSize)
{
size_t chars_written = 0;
/* Ignore flushes */
if (handle == -1)
{
chars_written = (size_t)0;
}
/* Only allow stdout/stderr output */
else if ((handle != 1) && (handle != 2))
{
chars_written = (size_t)-1;
}
/* Parameters OK, call the low-level character output routine */
else
{
while (chars_written < bufSize)
{
uart_putchar (buf[chars_written]);
chars_written++;
}
}
return (chars_written);
}
#endif /* __IAR_SYSTEMS_ICC__ */

View File

@@ -63,16 +63,16 @@ uint32_t test_start (void)
uint8_t eight = 8;
uint8_t nine = 9;
uint8_t ten = 10;
uint8_t eleven = 11;
uint8_t twelve = 12;
uint8_t thirteen = 13;
uint8_t fourteen = 14;
uint8_t fifteen = 15;
uint8_t sixteen = 16;
uint8_t seventeen = 17;
uint8_t eighteen = 18;
uint8_t nineteen = 19;
uint8_t twenty = 20;
uint16_t eleven = 11;
uint16_t twelve = 12;
uint16_t thirteen = 13;
uint16_t fourteen = 14;
uint16_t fifteen = 15;
uint32_t sixteen = 16;
uint32_t seventeen = 17;
uint32_t eighteen = 18;
uint32_t nineteen = 19;
uint32_t twenty = 20;
/* Default to zero failures */
failures = 0;
@@ -83,106 +83,106 @@ uint32_t test_start (void)
/* Check all variables contain expected values */
if (one != 1)
{
ATOMLOG (_STR("1(%d)\n"), one);
ATOMLOG (_STR("1(%d)\n"), (int)one);
failures++;
}
if (two != 2)
{
ATOMLOG (_STR("2(%d)\n"), two);
ATOMLOG (_STR("2(%d)\n"), (int)two);
failures++;
}
if (three != 3)
{
ATOMLOG (_STR("3(%d)\n"), three);
ATOMLOG (_STR("3(%d)\n"), (int)three);
failures++;
}
if (four != 4)
{
ATOMLOG (_STR("4(%d)\n"), four);
ATOMLOG (_STR("4(%d)\n"), (int)four);
failures++;
}
if (five != 5)
{
ATOMLOG (_STR("5(%d)\n"), five);
ATOMLOG (_STR("5(%d)\n"), (int)five);
failures++;
}
if (six != 6)
{
ATOMLOG (_STR("6(%d)\n"), six);
ATOMLOG (_STR("6(%d)\n"), (int)six);
failures++;
}
if (seven != 7)
{
ATOMLOG (_STR("7(%d)\n"), seven);
ATOMLOG (_STR("7(%d)\n"), (int)seven);
failures++;
}
if (eight != 8)
{
ATOMLOG (_STR("8(%d)\n"), eight);
ATOMLOG (_STR("8(%d)\n"), (int)eight);
failures++;
}
if (nine != 9)
{
ATOMLOG (_STR("9(%d)\n"), nine);
ATOMLOG (_STR("9(%d)\n"), (int)nine);
failures++;
}
if (ten != 10)
{
ATOMLOG (_STR("10(%d)\n"), ten);
ATOMLOG (_STR("10(%d)\n"), (int)ten);
failures++;
}
if (eleven != 11)
{
ATOMLOG (_STR("11(%d)\n"), eleven);
ATOMLOG (_STR("11(%d)\n"), (int)eleven);
failures++;
}
if (twelve != 12)
{
ATOMLOG (_STR("12(%d)\n"), twelve);
ATOMLOG (_STR("12(%d)\n"), (int)twelve);
failures++;
}
if (thirteen != 13)
{
ATOMLOG (_STR("13(%d)\n"), thirteen);
ATOMLOG (_STR("13(%d)\n"), (int)thirteen);
failures++;
}
if (fourteen != 14)
{
ATOMLOG (_STR("14(%d)\n"), fourteen);
ATOMLOG (_STR("14(%d)\n"), (int)fourteen);
failures++;
}
if (fifteen != 15)
{
ATOMLOG (_STR("15(%d)\n"), fifteen);
ATOMLOG (_STR("15(%d)\n"), (int)fifteen);
failures++;
}
if (sixteen != 16)
{
ATOMLOG (_STR("16(%d)\n"), sixteen);
ATOMLOG (_STR("16(%d)\n"), (int)sixteen);
failures++;
}
if (seventeen != 17)
{
ATOMLOG (_STR("17(%d)\n"), seventeen);
ATOMLOG (_STR("17(%d)\n"), (int)seventeen);
failures++;
}
if (eighteen != 18)
{
ATOMLOG (_STR("18(%d)\n"), eighteen);
ATOMLOG (_STR("18(%d)\n"), (int)eighteen);
failures++;
}
if (nineteen != 19)
{
ATOMLOG (_STR("19(%d)\n"), nineteen);
ATOMLOG (_STR("19(%d)\n"), (int)nineteen);
failures++;
}
if (twenty != 20)
{
ATOMLOG (_STR("20(%d)\n"), twenty);
ATOMLOG (_STR("20(%d)\n"), (int)twenty);
failures++;
}
/* Quit */
return failures;
}
}

View File

@@ -139,7 +139,7 @@ uint32_t test_start (void)
/* Check that time has advanced by exactly 1 tick */
if ((end_time - start_time) != 1)
{
ATOMLOG (_STR("Tick1:%d\n"), (end_time-start_time));
ATOMLOG (_STR("Tick1:%d\n"), (int)(end_time-start_time));
failures++;
}
}
@@ -175,7 +175,7 @@ uint32_t test_start (void)
/* Check that time has advanced by exactly 2 ticks */
if ((end_time - start_time) != 2)
{
ATOMLOG (_STR("Tick2:%d\n"), (end_time-start_time));
ATOMLOG (_STR("Tick2:%d\n"), (int)(end_time-start_time));
failures++;
}
}
@@ -211,7 +211,7 @@ uint32_t test_start (void)
/* Check that time has advanced by exactly 500 ticks */
if ((end_time - start_time) != 500)
{
ATOMLOG (_STR("Tick500:%d\n"), (end_time-start_time));
ATOMLOG (_STR("Tick500:%d\n"), (int)(end_time-start_time));
failures++;
}
}

View File

@@ -39,7 +39,6 @@ static ATOM_TIMER timer_cb[4];
/* Global test data */
static volatile uint32_t cb_order[4];
static int cb_cnt = 0;
static uint32_t cb_time[4];
/* Forward declarations */
@@ -136,7 +135,7 @@ uint32_t test_start (void)
{
if (cb_order[i] != i)
{
ATOMLOG (_STR("T%d=%d\n"), i, cb_order[i]);
ATOMLOG (_STR("T%d=%d\n"), i, (int)cb_order[i]);
failures++;
}
}
@@ -165,9 +164,6 @@ static void testCallback (POINTER cb_data)
/* Store our callback order in cb_order[] */
cb_order[cb_cnt] = expected_order;
/* Store the current time for debug purposes */
cb_time[cb_cnt] = atomTimeGet();
/* Interrupts are locked out so we can modify cb_cnt without protection */
cb_cnt++;
}