mirror of
https://github.com/kelvinlawson/atomthreads.git
synced 2026-01-11 18:33:16 +01:00
335 lines
15 KiB
Plaintext
335 lines
15 KiB
Plaintext
---------------------------------------------------------------------------
|
|
|
|
Library: Atomthreads
|
|
Author: Kelvin Lawson <info@atomthreads.com>
|
|
Website: http://atomthreads.com
|
|
License: BSD Revised
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
AVR/ATMEGA PORT
|
|
|
|
This folder contains a port of the Atomthreads real time kernel for the
|
|
AVR/ATmega processor architecture.
|
|
|
|
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.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 couple of additional source files are also included here:
|
|
|
|
* tests-main.c: Main application file (used for launching automated tests)
|
|
* uart.c: Simple driver for the ATmega UART
|
|
|
|
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 both an ATmega16 and ATmega32
|
|
running within an STK500 board, utilising the gcc-avr tools. It is possible
|
|
to use it with other processors in the ATmega range, as well as other
|
|
hardware platforms and compilers, with minimal changes. Platform and
|
|
compiler specific code has been kept to an absolute minimum.
|
|
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
PREREQUISITES
|
|
|
|
The port works out-of-the-box with the GCC tools (for building) and UISP
|
|
(for programming). It can be built on any OS for which gcc-avr is
|
|
available, but by way of example you can install all of the required tools
|
|
on Ubuntu/Linux as follows:
|
|
|
|
* sudo apt-get install gcc-avr binutils-avr avr-libc uisp
|
|
|
|
Use with alternative compiler tools may require some modification, but you
|
|
can easily replace UISP by your own favourite programmer if required.
|
|
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
BUILDING THE SOURCE
|
|
|
|
A Makefile is provided for building the kernel, port and automated tests.
|
|
The full build is carried out using simply:
|
|
|
|
* make
|
|
|
|
All objects are built into the 'build' folder under ports/avr. The build
|
|
process builds separate target applications for each automated test, and
|
|
appropriate ELF or HEX files can be found in the build folder ready for
|
|
downloading to and running on the target. Because of the limited resources
|
|
on the ATmega, 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
|
|
|
|
|
|
The Atomthreads sources are documented using Doxygen markup. You can build
|
|
both the kernel and AVR port documentation from this folder using:
|
|
|
|
* make doxygen
|
|
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
PROGRAMMING TO THE TARGET DEVICE
|
|
|
|
Application HEX files which are built into the build folder can be
|
|
downloaded to the target using:
|
|
|
|
* make program app=<appname>
|
|
|
|
For example to download the 'sem1.hex' test application to the target use:
|
|
|
|
* make program app=sem1
|
|
|
|
This uses UISP which will write the application into flash and reset the
|
|
CPU to start running the program automatically.
|
|
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
STK500 SPECIFICS
|
|
|
|
If the STK500 is used, you should connect your serial programming cable to
|
|
the "RS232 CTRL" connector.
|
|
|
|
The test applications make use of a LED to indicate test pass/fail status.
|
|
This is currently configured to use a bit in PORTB, which on the STK500
|
|
maps to a LED on the carrier board. 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
|
|
debug cable to the STK500 "RS232 SPARE" connector. You should also connect
|
|
PD0/1 to "RS232 SPARE RXD/TXD" respectively using a two-wire link. Use of
|
|
a UART is not required if you prefer to use the LED or some other method
|
|
of notifying test pass/fail status.
|
|
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
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. In
|
|
order to accommodate a full testing regime, a large number of test threads
|
|
are spawned which on ATmega platforms requires at least 1KB and possibly
|
|
more RAM. Bear this in mind if you wish to run all of the automated tests
|
|
on your target platform.
|
|
|
|
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:
|
|
|
|
* make program app=testname
|
|
|
|
For example to run the 'kern1.c' test use:
|
|
|
|
* make program app=kern1
|
|
|
|
Before running the program and data size for the application is printed
|
|
out on the terminal. You can use this to verify that your platform has
|
|
enough program and data space to run the application.
|
|
|
|
To view the test results, 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 minutes, so be patient.
|
|
|
|
Note that some tests utilise four test threads, which together with the
|
|
idle thread and main test thread can consume significant RAM resource.
|
|
Those tests which utilise four threads will generally only run on
|
|
platforms with greater than 1KB RAM. They do currently run on a system
|
|
with 1KB RAM but only with stack-checking disabled and this may change
|
|
in future as the RAM usage changes. For platforms with only 1KB internal
|
|
SRAM you should disable stack-checking by disabling STACK_CHECK in the
|
|
Makefile, or ensuring that the ATOM_STACK_CHECKING macro is not defined.
|
|
Platforms with only 512 bytes RAM will be unable to run many of the
|
|
automated tests.
|
|
|
|
The test application also toggles a bit on PORTB to indicate test success
|
|
or failure (once per second if the test was successful and once every
|
|
1/8 second if the test failed). On the STK500 this can be connected to an
|
|
LED for a visual indication of a passed test without the UART. If you do
|
|
not wish to use the UART you may use the LED to indicate passed tests; a
|
|
UART is not a requirement for running the tests.
|
|
|
|
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 and redirects stdout via the UART.
|
|
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
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.
|
|
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
PORTING TO OTHER HARDWARE PLATFORMS
|
|
|
|
If you are using a CPU other than the ATmega16, change the PART definition
|
|
in the Makefile to your own CPU.
|
|
|
|
On CPUs with multiple UARTs, the port uses UART0 to output debug
|
|
information. If you wish to use an alternative UART you may change the
|
|
registers in uart.c. Note that a UART is not vital for Atomthreads
|
|
operation anyway, it is only used by the test applications for indicating
|
|
test pass/fail status. If you do not wish to use a UART you may instead
|
|
flash a LED or use some other indication mechanism.
|
|
|
|
The Atomthreads port uses Timer 1 to drive the system tick. If you wish
|
|
to use some other timer then you may do so by modifying atomport.c.
|
|
|
|
Note that the build scripts make no assumptions about the RAM and program
|
|
space available on your platform, partly because you may have external RAM
|
|
over and above the ATmega device's internal SRAM. You must, therefore,
|
|
ensure that you have sufficient RAM and program space available for the
|
|
applications that you build. This information can be obtained by passing
|
|
the application ELF filename to the avr-size utility.
|
|
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
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 AVR architecture, and by
|
|
its nature will likely have a higher text and data footprint than an RTOS
|
|
targeted at the AVR architecture only.
|
|
|
|
It is very lightweight compared to many of the alternatives, but if you
|
|
have very limited RAM resources then you may prefer to use a more
|
|
AVR-specific RTOS such as those with shared stacks or built entirely from
|
|
assembler. 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 AVR 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 124 bytes of stack, and the main test thread has
|
|
been seen to consume 198 bytes of stack. At this time the queue9 test is
|
|
the largest consumer of test thread stack (124 bytes) and the mutex2 and
|
|
mutex5 tests consume the largest main thread stack (198 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 Makefile
|
|
so that the automated test modules can check for stack overflows, but you
|
|
may wish to undefine this in your application Makefiles 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).
|
|
|
|
The default stack area used by GCC is at the top of RAM (RAMEND), so when
|
|
your application's main() function is called the stack pointer is
|
|
initialised to RAMEND. This initial stack is only required during startup
|
|
for the main() function, and as soon as the OS is started the stack
|
|
pointer switches to the stack areas for the application threads. Once the
|
|
OS is started the initial startup stack is no longer used at all. You may
|
|
continue to use the top of RAM for your startup stack, but in the test
|
|
applications for this port we used another area of RAM. This is an
|
|
optimisation to allow all of the automated tests to run on platforms with
|
|
1KB RAM. The area reused is the idle thread's stack, which is not
|
|
required until the OS is started. Ideally you should provide your own
|
|
area for your applications, but this was an optimisation that allowed all
|
|
of the automated tests to run on ATmega devices with 1KB RAM and did not
|
|
require any AVR-specific changes to the automated test modules. This
|
|
startup stack does not require a large amount of RAM, probably less than
|
|
64 bytes.
|
|
|
|
The application's data starts at the bottom of RAM, and this includes all
|
|
of the thread stacks which are statically allocated arrays. The idle
|
|
thread, main thread, and automated test thread stacks are allocated here.
|
|
|
|
This RAM layout is only the one utilised by the test applications. You
|
|
may choose whatever layout you like.
|
|
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
HANDLING CPUS WITH LARGE PROGRAM SPACES
|
|
|
|
Some devices such as the ATmega2560/2561 support program memory larger than
|
|
128KB. GCC defines __AVR_3_BYTE_PC__ for such devices, which is detected in
|
|
the architecture port wherever special handling is required. GCC does not
|
|
at this time support function pointers greater than 16-bits, however, which
|
|
means that the thread_shell() routine which is the entry point for all
|
|
threads must be located in the bottom 128KB of program space. You may need
|
|
to force this using a linker directive.
|
|
|
|
Note that on the AVR architecture program memory is referenced in multiples
|
|
of 2 bytes, which is how 16-bits can reference 128KB of program memory
|
|
rather than the 64KB which you might expect.
|
|
|
|
|
|
---------------------------------------------------------------------------
|
|
|