150 Commits

Author SHA1 Message Date
Kelvin Lawson
1a2f9bae75 Merge pull request #33 from jacquesg/somefixes
C++ and AVR fixes
2017-08-27 11:12:56 +01:00
Jacques Germishuys
6eb64f4414 move AVR port's timers to a different translation unit
this gives greater flexibility in terms of timer choices
2017-08-21 08:53:33 +02:00
Jacques Germishuys
3f68de64b6 guard uart functions with extern "C" 2017-08-20 19:07:56 +02:00
Jacques Germishuys
f9d5f0a10c use F_CPU for the AVR CPU frequency (if available) 2017-08-20 19:07:50 +02:00
Kelvin Lawson
97679e316a Merge pull request #24 from spth/master
Make STM8 port compile with SDCC
2017-08-06 22:24:31 +01:00
Jacques Germishuys
7dfe7bd496 guard avrInitSystemTickTimer with extern "C" 2017-08-04 21:01:10 +02:00
Kelvin Lawson
265d050e2c dm36x-io.h: Correct McBSP register names. 2017-05-23 21:22:11 +01:00
Kelvin Lawson
402fe20926 dm36x-io.h: Add McBSP to Power/Sleep Controller. 2017-04-05 00:35:02 +01:00
Kelvin Lawson
d1dbe313ec dm36x-io.h: MCBPSP should be MCBsP. 2017-04-04 19:26:54 +01:00
Kelvin Lawson
c9dd755f1e dm36x-io.h: Add McBSP registers. 2017-04-03 23:12:28 +01:00
Kelvin Lawson
c6070ee4d7 atomkernel: Initialise new terminated flag in atomThreadCreate(). 2017-01-13 17:57:23 +00:00
Kelvin Lawson
864666d0fa dm36x-io.h: Add DM36x GPIO interrupt handline registers. 2017-01-13 17:08:20 +00:00
Kelvin Lawson
d617014298 dm36x: Add GPIO interrupts. 2017-01-13 06:27:14 +00:00
Kelvin Lawson
097fdb9006 Disable cortex-m CI. 2016-07-14 13:20:11 +01:00
Kelvin Lawson
eda014d8e3 Add cortex-m to CI. 2016-07-14 12:55:04 +01:00
Kelvin Lawson
1adb1e3148 commit-tests-avr: Remove unnecessary cd.
commit-tests-cortex-m: Created.
2016-07-14 12:44:11 +01:00
Kelvin Lawson
a4fefefec2 Rename commit-tests-qemu-arm. 2016-07-14 12:41:38 +01:00
Kelvin Lawson
8d7d07c202 Separate scripts for AVR and QEMU-ARM commit hooks. 2016-07-13 10:43:13 +01:00
Kelvin Lawson
eaf8ea3740 Formatting. 2016-07-13 09:02:28 +01:00
Kelvin Lawson
67a8d8eac2 Use markdown formatting for README. 2016-07-13 09:00:35 +01:00
Kelvin Lawson
3303dc739f Switch to Markdown README. 2016-07-13 08:58:17 +01:00
Kelvin Lawson
f169ebe477 Add travis-ci.org build state image 2016-07-13 08:57:08 +01:00
Kelvin Lawson
35a1bac968 Trial Travis-ci config. 2016-07-13 08:48:36 +01:00
Philipp Klaus Krause
099a3d0a92 Refactor STM8 documentation 2016-06-23 10:34:22 +02:00
Philipp Klaus Krause
ee591c7a51 Refactor STM8 documentation 2016-06-23 10:31:01 +02:00
Philipp Klaus Krause
969e7fa165 Use stdint.h by default 2016-06-23 10:11:52 +02:00
Philipp Klaus Krause
e21c3defc6 Adjust test thread stack size, make all tests pass 2016-06-23 09:56:41 +02:00
Philipp Klaus Krause
7894d81367 Increase main thread stack size due to expensive printf() 2016-06-21 16:49:37 +02:00
Philipp Klaus Krause
2944d95d86 Fix kernel/atom.h extra semicolon 2016-06-18 22:19:58 +02:00
Philipp Klaus Krause
529a386a7a Add debug flags to debug build 2016-06-16 21:53:22 +02:00
Philipp Klaus Krause
ba550c8df7 Make atomthreads run with SDCC 2016-06-16 21:21:06 +02:00
Philipp Klaus Krause
9251272859 Make atomthreads link with SDCC 2016-06-16 21:01:38 +02:00
Philipp Klaus Krause
7e03729526 Make atomthreads assemble with SDCC 2016-06-16 20:59:11 +02:00
Philipp Klaus Krause
a013142b7e Make atomthreads compile with SDCC 2016-06-16 20:37:19 +02:00
Kelvin Lawson
f29a33fd62 timer8.c: Add automated test to check for the behaviour fixed in future. 2016-05-25 20:03:43 +01:00
Kelvin Lawson
01f23be93d Merge branch 'simonccn-master' 2016-05-25 19:44:36 +01:00
Kelvin Lawson
d9b1891eb3 Merge branch 'master' of https://github.com/simonccn/atomthreads into simonccn-master 2016-05-25 19:23:06 +01:00
Kelvin Lawson
100de97d92 Merge pull request #19 from tidklaas/master
Fix potential TCB loss
2016-05-24 23:22:56 +01:00
Tido Klaassen
a710eaed0a Fix potential TCB loss
Always clear "suspended" flag in atomThreadSwitch(), even if new
and old TCB are identical. Otherwise TCB could get lost during
next task scheduling.
2016-05-24 17:57:49 +02:00
Kelvin Lawson
b0afc266d1 atomkernel: Support thread entry points running to completion. Ports which use a thread_shell() can allow the entry point to finish and return back to the thread_shell(), which sets the terminated flag and calls the scheduler to force another thread to be scheduled in. Currently implemented in the ARM and AVR ports. 2016-05-23 20:50:51 +01:00
chencn
9afe5d329c Fixed:Can't register the same timer again at timeout handle function 2016-03-23 10:20:32 +08:00
Kelvin Lawson
e99d05582f ARM reent stdout: Set unbuffered. 2016-03-20 22:44:25 +00:00
Kelvin Lawson
2f858283f1 ARM port reentrancy: Close per-thread stdout when runs to completion. 2016-03-20 22:00:48 +00:00
Kelvin Lawson
2c0965c4a9 ARM port: Support newlib thread reentrancy with thread-specific struct _reent. Tested on qemu_integratorcp. 2016-01-03 00:10:39 +00:00
Kelvin Lawson
da01dde1f9 Makefile: typo leftover from avr port. 2016-01-02 23:12:30 +00:00
Kelvin Lawson
3dbce9b055 ports/arm/atomport-asm.s: Comment change only. 2015-12-03 22:01:38 +00:00
Kelvin Lawson
f47b0b5b3d Formatting change only. 2015-12-02 00:28:53 +00:00
Kelvin Lawson
7f53aa96f2 Merge pull request #14 from tidklaas/master
Making Cortex-M Port Thread Safe
2015-12-02 00:11:45 +00:00
Kelvin Lawson
9ae404ef47 dm36x exception handler matches archIRQHandler() 2015-11-03 23:58:59 +00:00
Kelvin Lawson
e1879ab56b qemu_integratorcp uart.c: Uninit status. 2015-10-20 13:40:09 +01:00
Kelvin Lawson
9e26d7795a dm36x timer/uart: Uninitialised return values. 2015-10-20 13:38:33 +01:00
tidklaas
2ce352714d Add warning about using Debian workaround 2015-10-15 07:14:18 +02:00
Tido Klaassen
a3dd73f023 Fixed handling of uninitialised libopencm3 submodule 2015-10-14 19:12:28 +02:00
Tido Klaassen
9e29fe0abd Debian newlib nano workaround
- made use of newlib's nano version configurable by make variable USE_NANO
- added paragraphs to README.md explaining how and when to use USE_NANO
  and FIX_DEBIAN
2015-10-14 18:48:08 +02:00
Tido Klaassen
0d3c29e6f2 Clean up Makefile, work around Debian bugs (mostly untested)
- cleaned up generation of LDLIBS. Trust nano.specs to choose the right
  libraries.
- workaround for Debian's broken newlib package. Add /usr/include/newlib/nano
  to include search path and -fshort-wchar to CFLAGS when variable FIX_DEBIAN
  is defined.
2015-10-13 09:52:02 +02:00
Tido Klaassen
5e0d384dd8 Added libopencm3 as submodule for Cortex-M port
- removed instructions on adding submodule from README.md and Makefile
- submodule libopencm3 at commit 27b826bc4a09345f63d3b8b5fcd3cb9f145cd1a5
2015-10-13 07:17:02 +02:00
Tido Klaassen
792213d66b More work on making port use newlib's reentry mechanisms
- archContextSwitch stores address of new thread's struct reent in
  ctx_switch_info
- pend_sv_handler uses address in  ctx_switch_info.reent instead of fixed
  offset into atom_tcb
- added header with defines for offsets into struct ctx_switch_info used
  in assembler code. Also added compile time verification for this offsets
2015-09-30 08:51:28 +02:00
Tido Klaassen
0be9a35aeb Some work on using newlib's reentry capabilities. 2015-09-08 15:22:24 +02:00
Kelvin Lawson
c23613360e Merge branch 'tidklaas-master' 2015-08-08 01:37:40 +01:00
Kelvin Lawson
a24ff4c713 atomkernel.c: Comment change to reflect new behaviour needed for Cortex-M. 2015-08-08 01:37:00 +01:00
Tido Klaassen
05329c53e3 Bugfix: Enforce initial stack alignment 2015-07-19 18:54:29 +02:00
Tido Klaassen
f6ee11c088 Added funtionality to run an automated test of all testsuite applications
directly from the build system on the qemu "board".
2015-07-15 18:24:27 +02:00
Tido Klaassen
00a339e3fe Final clean-up (hopefully)
Improved dependency tracking in build system
Added ability to build single target application
Added abililty to build non-testsuite applications
Added 'helloworld' example application
2015-07-14 18:56:15 +02:00
Tido Klaassen
9d41fccc86 Added rudimentary QEMU board for running the test suite binaries 2015-07-13 18:33:11 +02:00
Tido Klaassen
ce70538bfb More cleanup 2015-07-12 18:56:20 +02:00
Tido Klaassen
3cc6b9bea4 README.md: wrote section about adding new boards
Renamed board Makefile fragments to Makefile.include
board_setup.c: initialise NVIC priorities for PendSv and SysTick
General cleanup
2015-07-12 16:28:48 +02:00
Tido Klaassen
ca81d186a7 Added support for Cortex-M0
Added board nucleo-f072rb
2015-07-11 20:08:50 +02:00
tidklaas
68e3ed69d6 Update README.md 2015-07-08 19:21:22 +02:00
Tido Klaassen
aa9dc72a99 - initial commit from private repository 2015-07-07 21:20:20 +02:00
Kelvin Lawson
18477010d0 atomtimer.c: Prevent uninitialised var warning from over-zealous compiler. 2015-03-02 11:29:05 +00:00
Kelvin Lawson
a41291df06 AVR Makefile: Use proper simavr install path. 2015-02-22 22:43:01 +00:00
Kelvin Lawson
de3ac01f0e Use script location for commit-tests.sh. 2015-02-22 19:44:03 +00:00
Kelvin Lawson
5033171ac0 Commit hook to build and run qemu-arm and AVR tests. 2015-02-22 02:27:13 +00:00
Kelvin Lawson
b16177187c dm36x-io.h: Add DMA registers. 2014-12-11 23:03:06 +00:00
Kelvin Lawson
1999fd5ac1 dm36x: Implement interrupt disable. 2014-10-24 22:49:19 +01:00
Kelvin Lawson
99fcf9c9b7 dm36x-io.h: SDIO interrupts. 2014-10-15 01:58:18 +01:00
Kelvin Lawson
e5bafc5fdd dm36x-io.h: Add SDIO registers. 2014-10-14 23:01:33 +01:00
Kelvin Lawson
a30ff645da dm36x-io: Add pullup/down control regs. 2014-10-07 23:42:03 +01:00
Kelvin Lawson
0dfe78922b dm36x-io.h: Add ARM INTMUX, CCERR int. 2014-09-14 23:53:26 +01:00
Kelvin Lawson
fa7ca58ac9 dm36x-io.h: Shadow regs 2014-08-19 23:54:03 +01:00
Kelvin Lawson
b3677dcf73 dm36x-io.h: Add base addresses. 2014-08-06 20:39:53 +01:00
Kelvin Lawson
059584c32d dm36x-io.h: Add base addresses. 2014-08-06 19:20:38 +01:00
Kelvin Lawson
0e988253ed dm36-io.h: Add gamma table addresses. 2014-07-17 00:03:43 +01:00
Kelvin Lawson
1e9942d791 atomtimer: Update callback list tail. 2014-06-28 17:37:35 +01:00
Kelvin Lawson
b31265222a dm36x: Add EDMA vector. 2014-06-28 15:12:09 +01:00
Kelvin Lawson
b367bbbde8 edma3: Add more register macros 2014-06-28 14:57:59 +01:00
Kelvin Lawson
559ca7516c dm36x: Add some DMA register offsets. 2014-06-28 14:22:28 +01:00
Kelvin Lawson
ceac845280 dm36x-io.h: Rename base defines. 2014-06-11 00:24:49 +01:00
Kelvin Lawson
356ced92f0 dm36x-io.h: Add EDMA3 register offsets. 2014-06-11 00:02:13 +01:00
Kelvin Lawson
ae3bedfb4b dm36x-io.h: Add EDMA3 definitions. 2014-06-10 23:28:28 +01:00
Kelvin Lawson
b645f28985 dm36x: Support passing interrupt vector to ISRs. 2014-05-31 23:45:14 +01:00
Kelvin Lawson
f9355b7fb8 dm36x-io.h: Add interrupt vectors. 2014-05-31 20:50:08 +01:00
Kelvin Lawson
1399c905f1 atomsem.h: Whitespace change. 2014-05-31 20:43:08 +01:00
Kelvin Lawson
2f9e816bfa dm36x-io.h: Add SPI PSC numbers. 2014-05-30 21:18:04 +01:00
Kelvin Lawson
23e93609d1 dm36x-io.h: Add SPI register addresses. 2014-05-30 18:52:12 +01:00
Kelvin Lawson
9a03de649e dm36x: Remove -g flag from default build. 2013-12-17 23:05:40 +00:00
Kelvin Lawson
2a25b84538 dm36x: Add PSC regs. 2013-12-12 01:12:40 +00:00
Kelvin Lawson
9dd7f7e8ef dm36x: Add some PSC registers. 2013-12-12 00:59:36 +00:00
Kelvin Lawson
ad00cad986 dm36x: Add PLL registers. 2013-12-10 23:53:36 +00:00
Kelvin Lawson
0f28b36980 dm36x: Add PSC registers. 2013-12-06 01:40:06 +00:00
Kelvin Lawson
5f4a2a8f9f dm36x: Add register. 2013-12-06 01:04:14 +00:00
Kelvin Lawson
0e41e09962 dm36x: Add register. 2013-12-06 00:52:41 +00:00
Kelvin Lawson
03a3b29e6b dm36x: Add PLL registers. 2013-11-17 22:42:55 +00:00
Kelvin Lawson
dac9fdf6e8 dm36x: Add usec timer measurement functions. 2013-11-17 21:49:02 +00:00
Kelvin Lawson
2393a08321 dm36x uart: Allow UART write from interrupt context. 2013-11-14 01:01:06 +00:00
Kelvin Lawson
735b42a182 dm36x: Add more DM365 interrupt vectors. 2013-11-09 01:15:41 +00:00
Kelvin Lawson
39dc800a6e dm36x: ISR install function renamed. 2013-11-02 18:02:54 +00:00
Kelvin Lawson
29a48d310e dm36x: Add interrupt-enable function for application code. 2013-11-02 17:58:28 +00:00
Kelvin Lawson
9f5e709ba2 dm36x: Move ISR registration to header available from application code. 2013-11-02 17:42:49 +00:00
Kelvin Lawson
4cf4d722ea dm36x: Support user-registered interrupt handlers via archISRInstall(). 2013-11-02 17:01:52 +00:00
Kelvin Lawson
71cbd0013e dm36x: Add VPFE register base addresses. 2013-10-31 21:32:37 +00:00
Kelvin Lawson
1494b48edd dm36x: Add SD/MMC registers. 2013-10-22 00:00:08 +01:00
Kelvin Lawson
5d54ff8f9b dm36x: More fully-featured UART driver, does not require previous initialisation by u-boot. 2013-10-21 01:51:42 +01:00
Kelvin Lawson
ae3397deb4 dm36x: Correct sense of timer expiry. 2013-10-21 00:50:37 +01:00
Kelvin Lawson
ebffc439a0 DM36x: Add microsecond accuracy timer. 2013-10-19 01:40:22 +01:00
Kelvin Lawson
aba6c6f5fd DM36X: First draft of archUsleep() timer. 2013-10-18 02:07:59 +01:00
Kelvin Lawson
c8f46a8075 DM36X: First draft of archUsleep() timer. 2013-10-18 02:07:47 +01:00
Kelvin Lawson
f2f262aa55 DM36X: Work in progress, add high-speed hardware timer support. 2013-10-18 01:35:13 +01:00
Kelvin Lawson
d996dd52c7 ARM syscalls.c: Add _exit() stub required by toolchain https://launchpad.net/~terry.guo/+archive/gcc-arm-embedded 2013-10-11 13:23:08 +01:00
Kelvin Lawson
e3c90317a4 atomtimer: Support timer callbacks registering new timers by walking the timer list, and building up a separate list of callbacks to be run later. 2013-10-01 23:47:39 +01:00
Kelvin Lawson
1b8681efa4 atomtimer: Add note regarding timer callback registrations from within timer callbacks. 2013-10-01 21:57:23 +01:00
Kelvin Lawson
0bebd89268 dm36x: Add I2C ICSTR register bitfields. 2013-09-26 23:35:46 +01:00
Kelvin Lawson
702e9dd0b5 dm36x: Add I2C register bitfields. 2013-09-25 01:02:30 +01:00
Kelvin Lawson
bbd8085736 dm36x: Add I2C register offsets. 2013-09-25 00:26:48 +01:00
Kelvin Lawson
ae636f9053 dm36x: Use appropriate memory size for DM368 Leopardboard (128MB). 2013-09-24 23:49:15 +01:00
Kelvin Lawson
342e66da44 dm36x: Cross-platform Makefile. 2013-09-24 23:33:27 +01:00
Kelvin Lawson
25d69cd73f dm36x: Add PINMUX registers and bitfields. 2013-09-24 01:24:32 +01:00
Kelvin Lawson
c10006cf13 dm36x: Add GPIO register addresses. 2013-09-23 23:22:55 +01:00
Kelvin Lawson
4b9022a55e dm36x: Add libatomthreads.a build target for linking to external applications. 2013-09-18 22:56:21 +01:00
Kelvin Lawson
dfe296b01b dm36x: Write README file for DM365/DM368. 2013-09-18 00:17:25 +01:00
Kelvin Lawson
e0c4cba602 dm36x: Add full run of automated test suite via UART + expect. All tests pass on DM36x! 2013-09-17 23:33:18 +01:00
Kelvin Lawson
4e6e30dcb3 dm36x: Ack the timer interrupt before we get the chance to be scheduled out. 2013-09-17 22:38:32 +01:00
Kelvin Lawson
ecffe72257 dm36x: UART convert \n to \r\n 2013-09-17 22:13:27 +01:00
Kelvin Lawson
d9b901c2b4 dm36x: IRQ dispatcher, extra brackets required inside macro. 2013-09-17 20:36:25 +01:00
Kelvin Lawson
e73d2a533c dm36x: Fix IRQENTRY register address. Debug out on spurious interrupts. 2013-09-17 20:17:18 +01:00
Kelvin Lawson
d329e5f631 ARM9: Don't use relative branches from interrupt vector table to support vector vectors a long way from the table in memory. 2013-09-17 19:33:58 +01:00
Kelvin Lawson
5924485def dm36x: Copy vector table from initial 0x80000000 to required location on ARM, 0x00000000. 2013-09-17 17:06:06 +01:00
Kelvin Lawson
8f8eddf6fc dm36x: system.ld, increase stack sizes. 2013-09-17 16:07:32 +01:00
Kelvin Lawson
49dbc3855a dm36x: Reloader timer int period. 2013-09-17 16:01:58 +01:00
Kelvin Lawson
c284a81e0c dm36x: Convert tabs to spaces. 2013-09-17 15:50:00 +01:00
Kelvin Lawson
4b3639916c dm36x: atomport-private.c add INTC setup. Convert tabs to spaces. 2013-09-17 15:48:23 +01:00
Kelvin Lawson
d1ac6d8768 dm36x: uart.c allow easy switch between UART ports. 2013-09-17 15:41:45 +01:00
Kelvin Lawson
59728345e6 dm36x: Fix empty-polling. Switch to UART0. Disable uart_read() temporarily, not used therefore not yet tested. 2013-09-17 15:26:14 +01:00
Kelvin Lawson
45a5e9f5a2 dm36x: Add UART0 and INTC addresses. 2013-09-17 15:24:57 +01:00
Kelvin Lawson
23b533f2a2 dm36x: Use alternative uImage load locations. 2013-09-17 15:23:18 +01:00
Kelvin Lawson
28bfbe74c2 system.ld: Correct memory map. 2013-08-22 02:19:31 +01:00
Kelvin Lawson
8a449559d0 dm36x: Add bin/uImage generation (BIN currently oversized). 2013-08-22 02:16:00 +01:00
Kelvin Lawson
1d25a82de8 Tabs to spaces 2013-08-22 01:49:15 +01:00
Kelvin Lawson
1f2879e03f Add work-in-progress DM36X port. 2013-08-22 01:43:58 +01:00
Kelvin Lawson
5d3f670ac0 Merge new ARM port submitted by navaro, with modifications to fit with the other Atomthreads ports, new folder structure, Makefiles and documentation. Tested on ARM926EJS using IntegratorCP platform emulated by QEMU.
Also minor changes to AVR/STM8 ports to use similar code structure throughout all ports.
2013-07-09 22:06:10 +01:00
94 changed files with 11850 additions and 717 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "ports/cortex-m/libopencm3"]
path = ports/cortex-m/libopencm3
url = https://github.com/libopencm3/libopencm3.git

14
.travis.yml Normal file
View File

@@ -0,0 +1,14 @@
sudo: required
language: c
services:
- docker
before_install:
- docker pull kelvinlawson/atomthreads
- docker pull kelvinlawson/atomthreads-cortex-m
script:
- docker run --rm -v $TRAVIS_BUILD_DIR/:/data -t kelvinlawson/atomthreads /data/tests/commit-tests-arm.sh
- docker run --rm -v $TRAVIS_BUILD_DIR/:/data -t kelvinlawson/atomthreads /data/tests/commit-tests-avr.sh

View File

@@ -1,9 +1,9 @@
---------------------------------------------------------------------------
Library: Atomthreads
Author: Kelvin Lawson <info@atomthreads.com>
Website: http://atomthreads.com
License: BSD Revised
* Library: Atomthreads
* Author: Kelvin Lawson <info@atomthreads.com>
* Website: http://atomthreads.com
* License: BSD Revised
---------------------------------------------------------------------------
@@ -39,9 +39,11 @@ make a software build for the AVR architecture see ports/avr/README.
SOURCE TREE:
* kernel Core kernel sources
* tests Automated test suite
* ports CPU architecture ports
* kernel: Core kernel sources
* tests: Automated test suite
* ports: CPU architecture ports
---------------------------------------------------------------------------
AUTOMATED TESTS STATE:
* Continuous Integration hosted at travis-ci.org: [![Build Status](https://travis-ci.org/kelvinlawson/atomthreads.svg?branch=master)](https://travis-ci.org/kelvinlawson/atomthreads)

View File

@@ -44,10 +44,17 @@ struct atom_tcb;
typedef struct atom_tcb
{
/* Thread's current stack pointer. When a thread is scheduled
* out the architecture port can save*/
/*
* Thread's current stack pointer. When a thread is scheduled
* out the architecture port can save its stack pointer here.
*/
POINTER sp_save_ptr;
/* Thread's port specific private data */
#if defined(THREAD_PORT_PRIV)
THREAD_PORT_PRIV;
#endif
/* Thread priority (0-255) */
uint8_t priority;
@@ -63,6 +70,7 @@ typedef struct atom_tcb
uint8_t suspended; /* TRUE if task is currently suspended */
uint8_t suspend_wake_status; /* Status returned to woken suspend calls */
ATOM_TIMER *suspend_timo_cb; /* Callback registered for suspension timeouts */
uint8_t terminated; /* TRUE if task is being terminated (run to completion) */
/* Details used if thread stack-checking is required */
#ifdef ATOM_STACK_CHECKING

View File

@@ -241,10 +241,11 @@ void atomSched (uint8_t timer_tick)
CRITICAL_START ();
/**
* If the current thread is going into suspension, then
* unconditionally dequeue the next thread for execution.
* If the current thread is going into suspension or is being
* terminated (run to completion), then unconditionally dequeue
* the next thread for execution.
*/
if (curr_tcb->suspended == TRUE)
if ((curr_tcb->suspended == TRUE) || (curr_tcb->terminated == TRUE))
{
/**
* Dequeue the next ready to run thread. There will always be
@@ -331,6 +332,13 @@ void atomSched (uint8_t timer_tick)
*/
static void atomThreadSwitch(ATOM_TCB *old_tcb, ATOM_TCB *new_tcb)
{
/**
* The context switch will shift execution to a different thread. The
* new thread is now ready to run so clear its suspend status in
* preparation for it waking up.
*/
new_tcb->suspended = FALSE;
/**
* Check if the new thread is actually the current one, in which
* case we don't need to do any context switch. This can happen
@@ -345,14 +353,6 @@ static void atomThreadSwitch(ATOM_TCB *old_tcb, ATOM_TCB *new_tcb)
/* Call the architecture-specific context switch */
archContextSwitch (old_tcb, new_tcb);
}
/**
* The context switch shifted execution to a different thread. By the time
* we get back here, we are running in old_tcb context again. Clear its
* suspend status now that we're back.
*/
old_tcb->suspended = FALSE;
}
@@ -404,6 +404,7 @@ uint8_t atomThreadCreate (ATOM_TCB *tcb_ptr, uint8_t priority, void (*entry_poin
/* Set up the TCB initial values */
tcb_ptr->suspended = FALSE;
tcb_ptr->terminated = FALSE;
tcb_ptr->priority = priority;
tcb_ptr->prev_tcb = NULL;
tcb_ptr->next_tcb = NULL;

View File

@@ -37,7 +37,7 @@ extern "C" {
typedef struct atom_sem
{
ATOM_TCB * suspQ; /* Queue of threads suspended on this semaphore */
uint8_t count; /* Semaphore count */
uint8_t count; /* Semaphore count */
} ATOM_SEM;
extern uint8_t atomSemCreate (ATOM_SEM *sem, uint8_t initial_count);

View File

@@ -408,7 +408,8 @@ uint8_t atomTimerDelay (uint32_t ticks)
*/
static void atomTimerCallbacks (void)
{
ATOM_TIMER *prev_ptr, *next_ptr;
ATOM_TIMER *prev_ptr, *next_ptr, *saved_next_ptr;
ATOM_TIMER *callback_list_tail = NULL, *callback_list_head = NULL;
/*
* Walk the list decrementing each timer's remaining ticks count and
@@ -417,6 +418,9 @@ static void atomTimerCallbacks (void)
prev_ptr = next_ptr = timer_queue;
while (next_ptr)
{
/* Save the next timer in the list (we adjust next_ptr for callbacks) */
saved_next_ptr = next_ptr->next_timer;
/* Is this entry due? */
if (--(next_ptr->cb_ticks) == 0)
{
@@ -432,11 +436,29 @@ static void atomTimerCallbacks (void)
prev_ptr->next_timer = next_ptr->next_timer;
}
/* Call the registered callback */
if (next_ptr->cb_func)
/*
* Add this timer to the list of callbacks to run later when
* we've finished walking the list (we shouldn't call callbacks
* now in case they want to register new timers and hence walk
* the timer list.
*
* We reuse the ATOM_TIMER structure's next_ptr to maintain the
* callback list.
*/
if (callback_list_head == NULL)
{
next_ptr->cb_func (next_ptr->cb_data);
/* First callback request in the list */
callback_list_head = callback_list_tail = next_ptr;
}
else
{
/* Add callback request to the list tail */
callback_list_tail->next_timer = next_ptr;
callback_list_tail = callback_list_tail->next_timer;
}
/* Mark this timer as the end of the callback list */
next_ptr->next_timer = NULL;
/* Do not update prev_ptr, we have just removed this one */
@@ -453,8 +475,34 @@ static void atomTimerCallbacks (void)
}
/* Move on to the next in the list */
next_ptr = next_ptr->next_timer;
next_ptr = saved_next_ptr;
}
/*
* Check if any callbacks were due. We call them after we walk the list
* in case they want to register new timers (and hence walk the list).
*/
if (callback_list_head)
{
/* Walk the callback list */
next_ptr = callback_list_head;
while (next_ptr)
{
/*
* Save the next timer in the list (in case the callback
* modifies the list by registering again.
*/
saved_next_ptr = next_ptr->next_timer;
/* Call the registered callback */
if (next_ptr->cb_func)
{
next_ptr->cb_func (next_ptr->cb_data);
}
/* Move on to the next callback in the list */
next_ptr = saved_next_ptr;
}
}
}

1161
ports/arm/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

107
ports/arm/README Normal file
View File

@@ -0,0 +1,107 @@
---------------------------------------------------------------------------
Library: Atomthreads ARM Port
Author: Natie van Rooyen <natie@navaro.nl>
License: BSD Revised
---------------------------------------------------------------------------
ARM PORT
This folder contains a port of the Atomthreads real time kernel for the
ARM processor architecture. This port was tested on the ARMv5 and ARMv7
architectures.
The same common/core port can be used on a wide variety of ARM devices
but platform-specific code has been separated out into multiple "platform"
(BSP) folders. This allows the common ARM code to be shared among several
different ARM platforms and boards. For example, different ARM devices and
platforms might use different interrupt controllers, timer subsystems and
UARTs but share the same core OS context-switching routines etc.
An example platform is in the "platforms/qemu_integratorcp" folder. The
platform-specific folders such as this contain the Makefile to build the
project for that platform, so you may wish to head straight there if you
wish to quickly get started building and running Atomthreads on ARM. The
qemu_integratorcp platform is designed for the Integrator/CP platform with
ARM926EJ-S processor, and can be run within QEMU for quick evaluation of
Atomthreads without real hardware.
---------------------------------------------------------------------------
FILES IN THE COMMON ARM PORT FOLDER
* tests-main.c: Contains a sample Atomthreads application starting at
main() that initialises the operating system and runs the automated test
suite applications. You will normally make your own main() function
suitable for your application, possibly using this as a basis.
* atomport-asm.s: Contains the main assembler code that forms the portion
of the core ARM architecture port that must be implemented in assembler
(e.g. register save/restore for thread context-switching).
* atomport.c: Contains the main C code that forms the portion of the core
ARM architecture port that can be implemented in C (e.g. prefilling the
stack context for new threads).
* syscalls.c: Contains the open/close/read/write/heap-management
functions typically required if you want to do anything with stdio
(e.g. printf() calls etc). This is a very simple implementation that
always writes to the UART regardless of which file is "opened". Use of
printf() and friends with GCC toolchains typically requires a heap, and
thus a heap is supported in this file via the _sbrk() function. Your
linker script should specify where the heap starts and stops using "end"
and "heap_top" definitions respectively. Note that in QEMU environments
this may not be required as some "semi-hosted" toolchains implement
these functions and the UART driver for you. In that case these
functions will be left out of the build because they are defined with
weak linkage.
---------------------------------------------------------------------------
PORTING TO NEW ARM PLATFORMS
To port Atomthreads to your ARM platform you must provide the following
functionality in your platform folder (in all cases example filenames are
from the qemu_integratorcp sample platform):
* Startup code: see Reset_Handler in startup.s. Typically this will be (at
least in the first few instructions) some assembly code, and will set up
the initial stack pointer, perform any copying of segments from flash to
RAM, zero the BSS section etc, before branching to the main application
function (e.g. main()). At some point during initialisation the timer
tick interrupt required by the OS should be started (100 ticks per
second) and this might be done here in the very early startup code. Note
that some compiler toolchains will provide a portion of the C startup
code e.g. the function _mainCRTStartup() provided by some GCC
toolchains.
* Interrupt vector table: see __interrupt_vector_table in startup.s.
Typically this will contain at least an entry for the startup/reset
code, and an entry for the hardware IRQ handler. In order to share
common code amongst all platforms, the hardware IRQ handler
(archIRQHandler()) is actually implemented in the common ARM port
folder but calls back out to a dispatcher function in your platform
folder to determine the source of the interrupt and handle it
appropriately. Your platform folder should contain this dispatcher
function (__interrupt_dispatcher). It must support at least the timer
interrupt service routine (atomTimerTick()) required by the OS. The
dispatcher also handles other hardware interrupt sources; it determines
the source of the IRQ and calls out to the appropriate ISR for that
interrupt.
* Linker script: Here you should specify the location of the interrupt
vector table within RAM, location of code/text segment etc. The
Atomthreads ARM port does not dictate particular section names or
layout unless your toolchain does not provide a suitable syscalls.c and
you wish to use heap. In that case you will (at least initially) be
using the heap implementation _sbrk() in syscalls.c in the common ARM
port which expects "heap_top" and "end" (heap_base) to be defined by the
linker script. These names can be easily changed in ports/arm/syscalls.c
if necessary.
* UART driver: You should provide at least a UART write routine If you
would like to see debug statements, for example to see the results of
running the automated test suite. See uart.c for a simple example. Note
that for QEMU targets some semihosted toolchains will implement this for
you, in which case you won't need either ports/arm/syscalls.c or a UART
driver.
---------------------------------------------------------------------------

223
ports/arm/atomport-asm.s Normal file
View File

@@ -0,0 +1,223 @@
/*
Copyright (c) 2012, Natie van Rooyen. 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.
*/
/**/
.global archIRQHandler
.global contextEnterCritical
.global contextExitCritical
.global contextEnableInterrupts
.global archContextSwitch
.global archFirstThreadRestore
.extern __interrupt_dispatcher
/* When using newlib, reentrancy context needs to be updated on task switch */
.extern _impure_ptr
/**/
.equ USR_MODE, 0x10
.equ FIQ_MODE, 0x11
.equ IRQ_MODE, 0x12
.equ SVC_MODE, 0x13
.equ ABT_MODE, 0x17
.equ UND_MODE, 0x1B
.equ SYS_MODE, 0x1F
.equ I_BIT, 0x80 /* when I bit is set, IRQ is disabled */
.equ F_BIT, 0x40 /* when F bit is set, FIQ is disabled */
.text
.code 32
/**
* \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:
STMFD sp!, {r4 - r11, lr} /* Save registers */
ADD r4, r1, #4 /* Add offset to get address of new_tcb_ptr->reent context (second TCB element) */
LDR r5, = _impure_ptr /* Get address of _impure_ptr into r5 */
STR r4, [r5] /* Store new_tcb_ptr->reent context in _impure_ptr */
STR sp, [r0] /* Save old SP in old_tcb_ptr->sp_save_ptr (first TCB element) */
LDR r1, [r1] /* Load new SP from new_tcb_ptr->sp_save_ptr (first TCB element) */
MOV sp, r1
LDMFD sp!, {r4 - r11, pc} /* Load new registers */
/**
* \b archFirstThreadRestore
*
* Architecture-specific function to restore and start the first thread.
* This is called by atomOSStart() when the OS is starting.
*
* This function will be largely similar to the latter half of
* archContextSwitch(). Its job is to restore the context for the
* first thread, and finally enable interrupts (although we actually
* enable interrupts in thread_shell() for new threads in this port
* rather than doing it explicitly here).
*
* It expects to see the context saved in the same way as if the
* thread has been previously scheduled out, and had its context
* saved. That is, archThreadContextInit() will have been called
* first (via atomThreadCreate()) to create a "fake" context save
* area, containing the relevant register-save values for a thread
* restore.
*
* 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)
*/
archFirstThreadRestore:
ADD r4, r0, #4 /* Add offset to get address of new_tcb_ptr->reent context (second TCB element) */
LDR r5, = _impure_ptr /* Get address of _impure_ptr into r5 */
STR r4, [r5] /* Store new_tcb_ptr->reent context in _impure_ptr */
LDR r0, [r0] /* Get SP (sp_save_ptr is conveniently first element of TCB) */
MOV sp, r0 /* Load new stack pointer */
LDMFD sp!, {r4 - r11, pc} /* Load new registers */
/**
* \b contextEnableInterrupts
*
* Enables interrupts on the processor
*
* @return None
*/
contextEnableInterrupts:
MRS r0, CPSR
MOV r1, #I_BIT
BIC r0, r0, r1
MSR CPSR_c, r0
BX lr
/**
* \b contextExitCritical
*
* Exit critical section (restores interrupt posture)
*
* @param[in] r0 Interrupt Posture
*
* @return None
*/
contextExitCritical:
MSR CPSR_cxsf, r0
BX lr
/**
* \b contextEnterCritical
*
* Enter critical section (disables interrupts)
*
* @return Current interrupt posture
*/
contextEnterCritical:
MRS r0, CPSR
ORR r1, r0, #I_BIT
MSR CPSR_cxsf, r1
BX lr
/**
* \b archIRQHandler
*
* IRQ entry point.
*
* Save the process/thread context onto its own stack before calling __interrupt_dispatcher().
* __interrupt_dispatcher() might switch stacks. On return the same context is popped from the
* stack and control is returned to the process.
*
* @return None
*/
archIRQHandler:
MSR cpsr_c, #(SVC_MODE | I_BIT) /* Save current process context in process stack */
STMFD sp!, {r0 - r3, ip, lr}
MSR cpsr_c, #(IRQ_MODE | I_BIT) /* Save lr_irq and spsr_irq in process stack */
SUB lr, lr, #4
MOV r1, lr
MRS r2, spsr
MSR cpsr_c, #(SVC_MODE | I_BIT)
STMFD sp!, {r1, r2}
BL __interrupt_dispatcher /* Dispatch the interrupt to platform folder for
the timer tick interrupt or a simular function
for other interrupts. Some of those IRQs may
call Atomthreads kernel routines and cause a
thread switch. */
LDMFD sp!, {r1, r2} /* Restore lr_irq and spsr_irq from process stack */
MSR cpsr_c, #(IRQ_MODE | I_BIT)
STMFD sp!, {r1}
MSR spsr_cxsf, r2
MSR cpsr_c, #(SVC_MODE | I_BIT) /* Restore process regs */
LDMFD sp!, {r0 - r3, ip, lr}
MSR cpsr_c, #(IRQ_MODE | I_BIT) /* Exit from IRQ */
LDMFD sp!, {pc}^

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2012, Natie van Rooyen. 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.
*/
#ifndef __ATOM_PORT_PRIVATE_H
#define __ATOM_PORT_PRIVATE_H
/* Function prototypes */
extern void archIRQHandler (void);
/* Platform-specific interrupt dispatcher called on receipt of IRQ */
extern void __interrupt_dispatcher (void);
#endif /* __ATOM_PORT_PRIVATE_H */

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2012, Natie van Rooyen. 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.
*/
#ifndef __ATOM_PORT_TESTS_H
#define __ATOM_PORT_TESTS_H
/* Include Atomthreads kernel API */
#include "atom.h"
/* Include printf for ATOMLOG() */
#include <stdio.h>
/* Logger macro for viewing test results */
#define ATOMLOG printf
/*
* String location macro: for platforms which need to place strings in
* alternative locations, e.g. on avr-gcc strings can be placed in
* program space, saving SRAM. On most platforms this can expand to
* empty.
*/
#define _STR(x) x
/* Default thread stack size (in bytes). Allow plenty for printf(). */
#define TEST_THREAD_STACK_SIZE 4096
/* Uncomment to enable logging of stack usage to UART */
/* #define TESTS_LOG_STACK_USAGE */
#endif /* __ATOM_PORT_TESTS_H */

178
ports/arm/atomport.c Normal file
View File

@@ -0,0 +1,178 @@
/*
* Copyright (c) 2013, Natie van Rooyen. 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.
*/
#include <stdio.h>
#include <string.h>
#include <sys/reent.h>
#include "atom.h"
#include "atomport.h"
/** Functions defined in atomport_s.s */
extern void contextEnableInterrupts (void);
/** Forward declarations */
static void thread_shell (void);
/**
* \b thread_shell
*
* Shell routine which is used to call all thread entry points.
*
* This routine is called whenever a new thread is starting, and
* provides a simple wrapper around the thread entry point that
* allows us to carry out any actions we want to do on thread's
* first starting up, or returning after completion.
*
* We mainly just want to make sure interrupts are enabled when a
* thread is run for the first time. This can be done via stack
* restores when threads are first run, but it's handy to have this
* wrapper anyway to run some common code if threads run to
* completion.
*
* A thread shell is also handy for providing port users with a place
* to do any other initialisation that must be done for each thread
* (e.g. opening stdio files etc).
*
* @return None
*/
static void thread_shell (void)
{
ATOM_TCB *curr_tcb;
/* Get the TCB of the thread being started */
curr_tcb = atomCurrentContext();
/**
* Open a stdout file descriptor so that the thread has its own stdout.
* In theory threads could open stdout to different output drivers
* if syscalls.s supported different output write functions.
*/
stdout = fopen ("/debuguart", "w");
setvbuf (stdout, 0, _IONBF, 0);
/**
* Enable interrupts - these will not be enabled when a thread
* is first restored.
*/
contextEnableInterrupts ();
/* Call the thread entry point */
if (curr_tcb && curr_tcb->entry_point)
{
curr_tcb->entry_point(curr_tcb->entry_param);
}
/* Clean up after thread completion */
fclose (stdout);
_reclaim_reent (&(curr_tcb->port_priv.reent));
/* Thread has run to completion: remove it from the ready list */
curr_tcb->terminated = TRUE;
atomSched (FALSE);
}
/**
* \b archThreadContextInit
*
* Architecture-specific thread context initialisation routine.
*
* This function must set up a thread's context ready for restoring
* and running the thread via archFirstThreadRestore() or
* archContextSwitch().
*
* The layout required to fill the correct register values is
* described in archContextSwitch(). Note that not all registers
* are restored by archContextSwitch() and archFirstThreadRestore()
* as this port takes advantage of the fact that not all registers
* must be stored by ARM gcc C subroutines. This means that we don't
* provide start values for those registers, as they are "don't cares".
*
* @param[in] tcb_ptr Pointer to the TCB of the thread being created
* @param[in] stack_top Pointer to the top of the new thread's stack
* @param[in] entry_point Pointer to the thread entry point function
* @param[in] entry_param Parameter to be passed to the thread entry point
*
* @return None
*/
void archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(uint32_t), uint32_t entry_param)
{
uint32_t *stack_ptr;
/** Start at stack top */
tcb_ptr->sp_save_ptr = stack_ptr = stack_top;
/**
* After restoring all of the context registers, the thread restore
* routines will return to the address of the calling routine on the
* stack. In this case (the first time a thread is run) we "return"
* to the entry point for the thread. That is, we store the thread
* entry point in the place that return will look for the return
* address: the stack.
*
* Note that we are using the thread_shell() routine to start all
* threads, so we actually store the address of thread_shell()
* here. Other ports may store the real thread entry point here
* and call it directly from the thread restore routines.
*
* Because we are filling the stack from top to bottom, this goes
* on the stack first (at the top).
*/
*stack_ptr-- = (uint32_t)thread_shell;
/**
* Store starting register values for R4-R11
*/
*stack_ptr-- = (uint32_t) 0x00001111; /* R11 */
*stack_ptr-- = (uint32_t) 0x00001010; /* R10 */
*stack_ptr-- = (uint32_t) 0x00000909; /* R9 */
*stack_ptr-- = (uint32_t) 0x00000808; /* R8 */
*stack_ptr-- = (uint32_t) 0x00000707; /* R7 */
*stack_ptr-- = (uint32_t) 0x00000606; /* R6 */
*stack_ptr-- = (uint32_t) 0x00000505; /* R5 */
*stack_ptr = (uint32_t) 0x00000404; /* R4 */
/**
* All thread context has now been initialised. Save the current
* stack pointer to the thread's TCB so it knows where to start
* looking when the thread is started.
*/
tcb_ptr->sp_save_ptr = stack_ptr;
/**
* At thread startup (and every time we switch back to a thread)
* we set the global reentrancy pointer to this thread's reent struct
*/
_REENT_INIT_PTR (&(tcb_ptr->port_priv.reent));
}

102
ports/arm/atomport.h Normal file
View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2012, Natie van Rooyen. 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.
*/
#ifndef __ATOM_PORT_H
#define __ATOM_PORT_H
/* Portable uint8_t and friends available from stdint.h on this platform */
#include <stdint.h>
/* Definition of NULL is available from stddef.h on this platform */
#include <stddef.h>
/* Reentrancy structure */
#include <sys/reent.h>
/* Required number of system ticks per second (normally 100 for 10ms tick) */
#define SYSTEM_TICKS_PER_SEC 100
/* Size of each stack entry / stack alignment size (32 bits on this platform) */
#define STACK_ALIGN_SIZE sizeof(uint32_t)
/**
* Architecture-specific types.
* Most of these are available from stdint.h on this platform, which is
* included above.
*/
#define POINTER void *
/**
* Hardware timer functions (optional, not available on all ports)
*/
extern void archUsleep (int32_t microsecs);
extern int32_t archUsleepStart (void);
extern int archUsleepCheckExpired (int32_t start_time, int32_t delay_usecs);
extern int32_t archUsecStart (void);
extern int32_t archUsecDiff (int32_t start_time);
/**
* ISR handler registration (optional, not available on all ports)
*/
typedef void (*ISR_FUNC)(int int_vector);
extern int archIntInstallISR (int int_vector, ISR_FUNC isr_func);
extern int archIntEnable (int int_vector, int enable);
/**
*
* Functions defined in atomport_arm.asm
*
*/
extern uint32_t contextEnterCritical (void) ;
extern void contextExitCritical (uint32_t posture) ;
/**
* Critical region protection: this should disable interrupts
* to protect OS data structures during modification. It must
* allow nested calls, which means that interrupts should only
* be re-enabled when the outer CRITICAL_END() is reached.
*/
#define CRITICAL_STORE uint32_t __atom_critical
#define CRITICAL_START() __atom_critical = contextEnterCritical()
#define CRITICAL_END() contextExitCritical(__atom_critical)
/**
* When using newlib, define port private field in atom_tcb to be a
* struct _reent.
*/
struct arm_port_priv {
struct _reent reent;
};
#define THREAD_PORT_PRIV struct arm_port_priv port_priv
/* Uncomment to enable stack-checking */
/* #define ATOM_STACK_CHECKING */
#endif /* __ATOM_PORT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,161 @@
############
# Settings #
############
# Build all test applications:
# make
#
# Run all tests communicating via UART
# make tests
# Location of build tools and atomthreads sources
KERNEL_DIR=../../../../kernel
TESTS_DIR=../../../../tests
PORT_DIR=../..
CC=arm-none-eabi-gcc
OBJCOPY=arm-none-eabi-objcopy
ARCHIVE=arm-none-eabi-ar
# Folder delete command (OS-specific)
ifeq ($(OS),Windows_NT)
RMDIR=rd /s /q
else
RMDIR=rm -rf
endif
# Location of TFTP root folder for running tests via U-Boot/TFTP.
# Note, you may need to run the Makefile as root in order to write
# to this folder.
TESTS_TFTPROOT=/var/lib/tftpboot
# TTY device and baudrate for automated tests.
TESTS_TTYDEV=/dev/ttyUSB0
TESTS_TTYBAUD=115200
# Enable stack-checking.
#STACK_CHECK=true
# Test programs: Log stack usage to UART (if STACK_CHECK is enabled)
#TESTS_LOG_STACK=true
# Directory for built objects
BUILD_DIR=build
# Platform-specific object files
PLATFORM_OBJECTS = atomport-private.o uart.o timer.o
PLATFORM_ASM_OBJECTS = startup.o
# Port-specific object files
PORT_OBJECTS = atomport.o tests-main.o syscalls.o
PORT_ASM_OBJECTS = atomport-asm.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 = $(PLATFORM_OBJECTS) $(PLATFORM_ASM_OBJECTS) $(PORT_OBJECTS) $(PORT_ASM_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 for each test object
TEST_UIMAGES = $(patsubst %.o,%.uImage,$(TEST_OBJECTS))
TEST_BINS = $(patsubst %.o,%.bin,$(TEST_OBJECTS))
TEST_ELFS = $(patsubst %.o,%.elf,$(TEST_OBJECTS))
# Search build/output directory for dependencies
vpath %.o ./$(BUILD_DIR)
vpath %.elf ./$(BUILD_DIR)
# GCC flags
CFLAGS=-c -mcpu=arm926ej-s -ffreestanding -Wall -Werror -Wno-unused-but-set-variable
AFLAGS=$(CFLAGS) -x assembler-with-cpp
LFLAGS=-mcpu=arm926ej-s -Tsystem.ld -Wall
# Enable stack-checking options (disable if not required)
ifeq ($(STACK_CHECK),true)
CFLAGS += -DATOM_STACK_CHECKING
endif
ifeq ($(TESTS_LOG_STACK),true)
CFLAGS += -DTESTS_LOG_STACK_USAGE
endif
#################
# Build targets #
#################
# All tests
all: $(BUILD_DIR) $(TEST_ELFS) $(TEST_BINS) $(TEST_UIMAGES) Makefile
# Build archive for linking with external application
libatomthreads.a: $(BUILD_DIR) $(ALL_OBJECTS) Makefile
$(ARCHIVE) cr $(BUILD_DIR)/$@ $(BUILT_OBJECTS)
# Make build/output directory
$(BUILD_DIR):
mkdir $(BUILD_DIR)
# Test ELF files (one application build for each test)
$(TEST_ELFS): %.elf: %.o $(ALL_OBJECTS)
$(CC) $(LFLAGS) $(BUILD_DIR)/$(notdir $<) $(BUILT_OBJECTS) --output $(BUILD_DIR)/$@ -Wl,-Map,$(BUILD_DIR)/$(basename $@).map
# Test BIN files (one application build for each test)
$(TEST_BINS): %.bin: %.elf $(TEST_ELFS)
$(OBJCOPY) -O binary $(BUILD_DIR)/$(basename $@).elf $(BUILD_DIR)/$(basename $@).bin
# Test uImage files (one application build for each test)
$(TEST_UIMAGES): %.uImage: %.bin $(TEST_BINS)
gzip -9 -c $(BUILD_DIR)/$(basename $@).bin > $(BUILD_DIR)/$(basename $@).bin.gz
mkimage -A arm -T kernel -C gzip -a 0x80000000 -e 0x80000000 -n "Atomthreads application" -d $(BUILD_DIR)/$(basename $@).bin.gz $(BUILD_DIR)/$(basename $@).uImage
# Kernel objects builder
$(KERNEL_OBJECTS): %.o: $(KERNEL_DIR)/%.c
$(CC) -c $(CFLAGS) -I. -I$(PORT_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Test objects builder
$(TEST_OBJECTS): %.o: $(TESTS_DIR)/%.c
$(CC) -c $(CFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Platform C objects builder
$(PLATFORM_OBJECTS): %.o: ./%.c
$(CC) -c $(CFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) -I$(TESTS_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Platform asm objects builder
$(PLATFORM_ASM_OBJECTS): %.o: ./%.s
$(CC) -c $(AFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Port C objects builder
$(PORT_OBJECTS): %.o: $(PORT_DIR)/%.c
$(CC) -c $(CFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) -I$(TESTS_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Port asm objects builder
$(PORT_ASM_OBJECTS): %.o: $(PORT_DIR)/%.s
$(CC) -c $(AFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# .lst file builder
%.lst: %.c
$(CC) $(CFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) -I$(TESTS_DIR) -Wa,-al $< > $@
# Clean
clean:
$(RMDIR) build
$(RMDIR) doxygen-kernel
$(RMDIR) doxygen-arm
$(RMDIR) doxygen-platform
# Generate Doxygen documentation
doxygen:
doxygen $(KERNEL_DIR)/Doxyfile
doxygen ../../Doxyfile
doxygen ./Doxyfile
# Run tests on target with expect and serial output
phony_test_bins = $(addsuffix .sim, $(TEST_BINS))
tests: $(phony_test_bins)
.PHONY: tests $(phony_test_bins)
$(phony_test_bins):
cp $(BUILD_DIR)/$(basename $@) $(TESTS_TFTPROOT)/test.bin
@echo Running test $(basename $@)
./run_test.exp $(TESTS_TTYDEV) $(TESTS_TTYBAUD)

View File

@@ -0,0 +1,213 @@
---------------------------------------------------------------------------
Library: Atomthreads DaVinci DM365/DM368 Platform.
Author: Kelvin Lawson <info@atomthreads.com>
Website: http://atomthreads.com
License: BSD Revised
---------------------------------------------------------------------------
DaVinci DM36x (ARM926EJ-S) Platform
The "dm36x" platform folder contains sources for building a sample
Atomthreads RTOS application for DaVinci DM365 and DM368 (ARM926EJ-S)
platforms.
This has been tested on a DM368 Leopardboard platform, but will work on any
DM36x-based platform.
---------------------------------------------------------------------------
SOURCE LAYOUT
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. To support multiple ARM boards/platforms using a
single common ARM architecture port, the ARM port contains 'platform'
sub-folders in which the board/platform-specific code is situated. This
allows the sharing of common ARM port code between many different ARM
boards with different interrupt controllers, UARTs etc but which all reuse
the same common core ARM context-switching code.
This platform contains a few key platform-specific files:
* startup.s: Interrupt vector table and basic startup assembly code
* atomport-private.c: Low level initialisation for this platform
* uart.c: Simple UART implementation for debug purposes
The common ARM architecture port that is used across all platforms contains
the basic code for thread-switching on all ARM platforms:
* 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:
* atomport.h: Port-specific header required by the kernel for each port
A couple of additional source files are also included in the common ARM port:
* tests-main.c: Main application file (used for launching automated tests)
* syscalls.c: Simple implementation of open/close/read/write for stdio
Atomthreads includes a suite of automated tests which prove the key OS
functionality, and can be used with any architecture ports. This platform
provides an easy mechanism for building and quickly running the test suite
using a serial port connected to real hardware to prove the OS.
---------------------------------------------------------------------------
GCC TOOLCHAIN
The port works out-of-the-box with the GCC tools (for building). It can be
built on any OS for which GCC is available, and was tested using the
CodeSourcery toolchain (2009q3 non-Linux but others should be supported).
Note that the Makefile for this platform assumes that your GCC binary is
named "arm-none-eabi-gcc".
Currently we assume that the toolchain will provide some header files like
stdint.h. Not all toolchains will include this, in which case you simply
need to add definitions for int32_t and friends in atomport.h, in place of
the include declaration for stdint.h.
---------------------------------------------------------------------------
OTHER PREREQUISITES
Running the entire automated test suite in one command via "make tests"
requires the "expect" program.
".bin" images bootable via U-boot are created as part of the build but if
uImage format is preferred then the "mkimage" application is also
required.
---------------------------------------------------------------------------
BUILDING THE SOURCE
A Makefile is provided for building the kernel, port, platform and
automated tests. Make sure the ARM GCC toolchain is in the path
(e.g. "PATH=$PATH:/opt/arm-2009q3/bin && export path") and carry out the
full build using the following:
* make all
All objects are built into the 'build' folder under
ports/arm/platforms/dm36x. The build process builds separate target
applications for each automated test, and appropriate ELF/BIN files can be
found in the build folder ready for running on the target. 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 port documentation from this folder using:
* make doxygen
---------------------------------------------------------------------------
PLATFORM SPECIFICS
This RTOS port was developed on the DM368 Leopardboard, but there is
currently very little board-specific code present, other than the choice of
UART (the Leopardboard uses UART0 but many boards use UART1). The UART is
used to print out pass/fail indications and other information via a serial
debug cable connected to the board. For other boards using UART1 you may
simply change the UART_BASE definition in uart.c.
---------------------------------------------------------------------------
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.
These can be run on the target using the instructions below.
To view the test results, connect a serial debug cable to your target
platform. 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 longer, 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.
---------------------------------------------------------------------------
RUNNING THE FULL TEST SUITE
It is possible to run the full automated test suite on the target board.
This is very useful for quick verification of the entire test suite after
making any software changes.
A single command runs every single test application on the target, and
automatically parses the UART output to verify that each test case passes.
This requires the "expect" application on your development PC.
To run all tests in one command, type:
* make tests
This will download every single test application to your TFTP folder one at
a time, ready for the target to load via U-Boot, and quit immediately if
any one test fails.
You should set your target board to load the file "test.bin" via TFTP and
hit the reset button after each test has completed (when prompted).
The U-boot "bootcmd" variable should be set as follows:
* setenv 'tftpboot 0x80000000 test.bin; go 0x80000000'
* saveenv
Now when you run "make tests" it will copy each test application binary
into your TFTP root folder one-by-one, and request that you reset the board
to start the next test running. Passes or failures are reported, and the
test suite quits if any test suite failures are encountered.
The ability to run these automated tests in one command allows you to
easily include the OS test suite in your nightly build or continous
integration system and quickly find out if any of your local changes have
caused any of the operating system tests to fail. In order to include them
in a nightly test run you will need to set the test applications to
automatically reset after running each test.
---------------------------------------------------------------------------
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 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.
---------------------------------------------------------------------------

View File

@@ -0,0 +1,305 @@
/*
* Copyright (c) 2013, Kelvin Lawson. 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.
*/
#include <stdio.h>
#include <stdarg.h>
#include "atomport.h"
#include "atomport-private.h"
#include "atom.h"
#include "atomport.h"
#include "dm36x-io.h"
#include "uart.h"
/** Imports required by C startup code */
extern unsigned long _start_vectors, _end_vectors, _end_text, _start_data, _end_data, _start_bss, _end_bss;
extern int main(void);
/** Register access macros */
#define TIMER0_REG(offset) *(volatile uint32_t *)(DM36X_TIMER0_BASE + offset)
#define INTC_REG(offset) *(volatile uint32_t *)(DM36X_INTC_BASE + offset)
/**
* Table of registered ISR handlers: pre-initialised
* with all disabled except the Atomthreads timer tick ISR.
*/
static ISR_FUNC isr_handlers[DM36X_INTC_MAX_VEC + 1] =
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
(void *)atomTimerTick, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
/**
* \b _mainCRTStartup
*
* C startup code for environments without a suitable built-in one.
* May be provided by the compiler toolchain in some cases.
*
*/
extern void _mainCRTStartup (void) __attribute__((weak));
void _mainCRTStartup(void)
{
unsigned long *src;
unsigned long *dst;
// Copy vector table from SRAM to IRAM0 (ARM vector table must be at 0x00000000)
src = &_start_vectors;
dst = (unsigned long *)0x00000000;
while(src < &_end_vectors)
*(dst++) = *(src++);
#ifdef ROM
// Running from ROM: copy data section to RAM
src = &_end_text;
dst = &_start_data;
while(dst < &_end_data)
*(dst++) = *(src++);
#endif
// Clear BSS
src = &_start_bss;
while(src < &_end_bss)
*(src++) = 0;
// Jump to main application entry point
main();
}
/**
* \b low_level_init
*
* Initializes the PIC and starts the system timer tick interrupt.
*
*/
int
low_level_init (void)
{
/* Initialise TIMER0 registers for interrupt 100 times per second */
/* Reset & disable all TIMER0 timers */
TIMER0_REG(DM36X_TIMER_INTCTL_STAT) = 0; /* Disable interrupts */
TIMER0_REG(DM36X_TIMER_TCR) = 0; /* Disable all TIMER0 timers */
TIMER0_REG(DM36X_TIMER_TGCR) = 0; /* Put all TIMER0 timers in reset */
TIMER0_REG(DM36X_TIMER_TIM12) = 0; /* Clear Timer 1:2 */
/* Set up Timer 1:2 in 32-bit unchained mode */
TIMER0_REG(DM36X_TIMER_TGCR) = (1 << 2); /* Select 32-bit unchained mode (TIMMODE) */
TIMER0_REG(DM36X_TIMER_TGCR) |= (1 << 0); /* Remove Timer 1:2 from reset (TIM12RS) */
TIMER0_REG(DM36X_TIMER_PRD12) = (TIMER_CLK / SYSTEM_TICKS_PER_SEC) - 1; /* Set period to 100 ticks per second (PRD12) */
TIMER0_REG(DM36X_TIMER_TCR) |= (0 << 8); /* Select external clock source for Timer 1:2 (CLKSRC12) */
/* Enable interrupts */
TIMER0_REG(DM36X_TIMER_INTCTL_STAT) = (1 << 1) | (1 << 0); /* Enable/ack Compare/Match interrupt for Timer 1:2 */
/* Enable timer */
TIMER0_REG(DM36X_TIMER_TCR) |= (2 << 6); /* Enable Timer 1:2 continuous (ENAMODE12) */
/* Initialise INTC interrupt controller (all at lowest priority 7) */
INTC_REG(DM36X_INTC_PRI0) = 0x77777777;
INTC_REG(DM36X_INTC_PRI1) = 0x77777777;
INTC_REG(DM36X_INTC_PRI2) = 0x77777777;
INTC_REG(DM36X_INTC_PRI3) = 0x77777777;
INTC_REG(DM36X_INTC_PRI4) = 0x77777777;
INTC_REG(DM36X_INTC_PRI5) = 0x77777777;
INTC_REG(DM36X_INTC_PRI6) = 0x77777777;
INTC_REG(DM36X_INTC_PRI7) = 0x77777777;
INTC_REG(DM36X_INTC_INTCTL) = 0;
INTC_REG(DM36X_INTC_EABASE) = 0;
INTC_REG(DM36X_INTC_EINT0) = 0;
INTC_REG(DM36X_INTC_EINT1) = 0;
/* Ack TINT0 IRQ in INTC interrupt controller */
INTC_REG(DM36X_INTC_IRQ1) = (1 << (DM36X_INTC_VEC_TINT0 - 32));
/* Enable TINT0 IRQ in INTC interrupt controller */
INTC_REG(DM36X_INTC_EINT1) |= (1 << (DM36X_INTC_VEC_TINT0 - 32));
return 0 ;
}
/**
* \b archIntInstallISR
*
* Register an interrupt handler to be called if a particular
* interrupt vector occurs.
*
* Note that all registered ISRs are called within atomIntEnter()
* and atomIntExit() calls, which means they can use OS services
* that do not block (e.g. atomSemPut()).
*
* @param[in] int_vector Interrupt vector to install handler for
* @param[in] isr_func Handler to call when specified int occurs
*
* @retval ATOM_OK Success
* @retval ATOM_ERROR Error
*/
int archIntInstallISR (int int_vector, ISR_FUNC isr_func)
{
int status;
/* Check vector is valid */
if ((int_vector < 0) || (int_vector > DM36X_INTC_MAX_VEC))
{
/* Invalid vector number */
status = ATOM_ERROR;
}
else
{
/* Valid vector, install it in the ISR table */
isr_handlers[int_vector] = isr_func;
status = ATOM_OK;
}
return (status);
}
/**
* \b archIntEnable
*
* Enable/unmask an interrupt in the interrupt controller.
* @param[in] int_vector Interrupt vector to enable/disable
* @param[in] enable TRUE=enable, FALSE=disable
*
* @retval ATOM_OK Success
* @retval ATOM_ERROR Error
*/
int archIntEnable (int int_vector, int enable)
{
CRITICAL_STORE;
int status;
/* Check vector is valid */
if ((int_vector < 0) || (int_vector > DM36X_INTC_MAX_VEC))
{
/* Invalid vector number */
status = ATOM_ERROR;
}
else
{
/* Valid vector, mask or unmask it using RMW */
CRITICAL_START();
if (enable)
{
/* Enable/unmask the interrupt */
INTC_REG(((int_vector >= 32) ? DM36X_INTC_EINT1 : DM36X_INTC_EINT0))
|= (1 << ((int_vector >= 32) ? (int_vector - 32) : int_vector));
}
else
{
/* Disable/mask the interrupt */
INTC_REG(((int_vector >= 32) ? DM36X_INTC_EINT1 : DM36X_INTC_EINT0))
&= ~(1 << ((int_vector >= 32) ? (int_vector - 32) : int_vector));
}
CRITICAL_END();
status = ATOM_OK;
}
return (status);
}
/**
* \b __interrupt_dispatcher
*
* Interrupt dispatcher: determines the source of the IRQ and calls
* the appropriate ISR.
*
* Note that any ISRs which call Atomthreads OS routines that can
* cause rescheduling of threads must be surrounded by calls to
* atomIntEnter() and atomIntExit().
*
*/
void
__interrupt_dispatcher (void)
{
uint32_t vector;
uint32_t irqentry;
/* Read IRQENTRY register to determine the source of the interrupt */
irqentry = INTC_REG(DM36X_INTC_IRQENTRY);
/* Check for spurious interrupt */
if (irqentry == 0)
{
/* Spurious interrupt */
uart_write_halt ("Spurious IRQ\n");
}
else
{
/* Translate from vector address to vector number */
vector = (INTC_REG(DM36X_INTC_IRQENTRY) / 4) - 1;
/* Check vector number is valid */
if ((vector > 0) && (vector <= DM36X_INTC_MAX_VEC) && (isr_handlers[vector] != NULL))
{
/* Ack the interrupt immediately, could get scheduled out below */
INTC_REG(((vector >= 32) ? DM36X_INTC_IRQ1 : DM36X_INTC_IRQ0)) = (1 << ((vector >= 32) ? (vector - 32) : vector));
/*
* Let the Atomthreads kernel know we're about to enter an OS-aware
* interrupt handler which could cause scheduling of threads.
*/
atomIntEnter();
/* Call the registered ISR */
isr_handlers[vector](vector);
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}
else
{
/* Unexpected vector */
uart_write_halt ("Unexpected IRQ vector\n");
}
}
}
/**
* \b __null_handler
*
* Handler to catch interrupts at uninitialised vectors.
*
*/
void __null_handler (void)
{
uart_write_halt ("Unhandled interrupt\n");
}

View File

@@ -0,0 +1,596 @@
/*
* Copyright (c) 2013, Kelvin Lawson. 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.
*/
#ifndef __DM36X_IO_H__
#define __DM36X_IO_H__
#include "atomport.h"
/** Timer input clock speed: 24MHz */
#define TIMER_CLK 24000000
/*
* IO Addresses for use with DM36x
*/
/** EDMA3 registers */
#define DM36X_EDMA3_CC_BASE 0x01C00000 /* EDMA3 CC registers */
#define DM36X_EDMA3_PARAM_BASE 0x01C04000 /* EDMA3 PaRAM base */
#define DM36X_EDMA3_TC0_BASE 0x01C10000 /* EDMA3 TC0 registers */
#define DM36X_EDMA3_TC1_BASE 0x01C10400 /* EDMA3 TC1 registers */
#define DM36X_EDMA3_TC2_BASE 0x01C10800 /* EDMA3 TC2 registers */
#define DM36X_EDMA3_TC3_BASE 0x01C10C00 /* EDMA3 TC3 registers */
/* EDMA3 CC global register offsets */
#define DM36X_EDMA3_DMAQNUM0 0x0240 /* Channel/queue mapping 0 */
#define DM36X_EDMA3_DMAQNUM1 0x0244 /* Channel/queue mapping 1 */
#define DM36X_EDMA3_DMAQNUM2 0x0248 /* Channel/queue mapping 2 */
#define DM36X_EDMA3_DMAQNUM3 0x024C /* Channel/queue mapping 3 */
#define DM36X_EDMA3_DMAQNUM4 0x0250 /* Channel/queue mapping 4 */
#define DM36X_EDMA3_DMAQNUM5 0x0254 /* Channel/queue mapping 5 */
#define DM36X_EDMA3_DMAQNUM6 0x0258 /* Channel/queue mapping 6 */
#define DM36X_EDMA3_DMAQNUM7 0x025C /* Channel/queue mapping 7 */
#define DM36X_EDMA3_QDMAQNUM 0x0260 /* QDMA queue mapping */
#define DM36X_EDMA3_QUEPRI 0x0284 /* Queue Priority */
#define DM36X_EDMA3_CC_EMR 0x0300 /* Event missed */
#define DM36X_EDMA3_CC_EMRH 0x0304 /* Event missed high */
#define DM36X_EDMA3_CC_EMCR 0x0308 /* Event missed clear */
#define DM36X_EDMA3_CC_EMCRH 0x030C /* Event missed clear high */
#define DM36X_EDMA3_CC_QEMR 0x0310 /* QDMA Event missed */
#define DM36X_EDMA3_CC_QEMCR 0x0314 /* QDMA Event missed clear */
#define DM36X_EDMA3_CC_CCERR 0x0318 /* EDMA3CC Error */
#define DM36X_EDMA3_CC_CCERRCLR 0x031C /* EDMA3CC Error clear */
#define DM36X_EDMA3_CC_EEVAL 0x0320 /* Error evaluate */
#define DM36X_EDMA3_CC_DRAE0 0x0340 /* Shadow region enable */
#define DM36X_EDMA3_CC_DRAEH0 0x0344 /* Shadow region enable */
#define DM36X_EDMA3_CC_QSTAT0 0x0600 /* Queue 0 status */
#define DM36X_EDMA3_CC_QSTAT1 0x0604 /* Queue 1 status */
#define DM36X_EDMA3_CC_QSTAT2 0x0608 /* Queue 2 status */
#define DM36X_EDMA3_CC_QSTAT3 0x060C /* Queue 3 status */
#define DM36X_EDMA3_CC_CCSTAT 0x0640 /* EDMA3CC Status */
/* EDMA3 CC global channel register offsets */
#define DM36X_EDMA3_CC_ER 0x1000 /* Event */
#define DM36X_EDMA3_CC_ERH 0x1004 /* Event high */
#define DM36X_EDMA3_CC_ECR 0x1008 /* Event clear */
#define DM36X_EDMA3_CC_ECRH 0x100C /* Event clear high */
#define DM36X_EDMA3_CC_ESR 0x1010 /* Event set */
#define DM36X_EDMA3_CC_ESRH 0x1014 /* Event set high */
#define DM36X_EDMA3_CC_CER 0x1018 /* Chained event */
#define DM36X_EDMA3_CC_CERH 0x101C /* Chained event high */
#define DM36X_EDMA3_CC_EER 0x1020 /* Event enable */
#define DM36X_EDMA3_CC_EERH 0x1024 /* Event enable high */
#define DM36X_EDMA3_CC_EECR 0x1028 /* Event enable clear */
#define DM36X_EDMA3_CC_EECRH 0x102C /* Event enable clear high */
#define DM36X_EDMA3_CC_EESR 0x1030 /* Event enable set */
#define DM36X_EDMA3_CC_EESRH 0x1034 /* Event enable set high */
#define DM36X_EDMA3_CC_SER 0x1038 /* Secondary event */
#define DM36X_EDMA3_CC_SERH 0x103C /* Secondary event high */
#define DM36X_EDMA3_CC_SECR 0x1040 /* Secondary event clear */
#define DM36X_EDMA3_CC_SECRH 0x1044 /* Secondary event clear high */
#define DM36X_EDMA3_CC_IER 0x1050 /* Interrupt enable */
#define DM36X_EDMA3_CC_IERH 0x1054 /* Interrupt enable high */
#define DM36X_EDMA3_CC_IECR 0x1058 /* Interrupt enable clear */
#define DM36X_EDMA3_CC_IECRH 0x105C /* Interrupt enable clear high */
#define DM36X_EDMA3_CC_IESR 0x1060 /* Interrupt enable set */
#define DM36X_EDMA3_CC_IESRH 0x1064 /* Interrupt enable set high */
#define DM36X_EDMA3_CC_IPR 0x1068 /* Interrupt pending */
#define DM36X_EDMA3_CC_IPRH 0x106C /* Interrupt pending high */
#define DM36X_EDMA3_CC_ICR 0x1070 /* Interrupt clear */
#define DM36X_EDMA3_CC_ICRH 0x1074 /* Interrupt clear high */
#define DM36X_EDMA3_CC_IEVAL 0x1078 /* Interrupt evaluate */
#define DM36X_EDMA3_CC_QER 0x1080 /* QDMA event */
#define DM36X_EDMA3_CC_QEER 0x1084 /* QDMA event enable */
#define DM36X_EDMA3_CC_QEECR 0x1088 /* QDMA event enable clear */
#define DM36X_EDMA3_CC_QEESR 0x108C /* QDMA event enable set */
#define DM36X_EDMA3_CC_QSER 0x1090 /* QDMA secondary event */
#define DM36X_EDMA3_CC_QSECR 0x1094 /* QDMA secondary event clear */
/* EDMA3 TC register offsets */
#define DM36X_EDMA3_TC_TCSTAT 0x0100 /* EDMA3 TC channel status */
#define DM36X_EDMA3_TC_ERRSTAT 0x0120 /* Error status */
#define DM36X_EDMA3_TC_ERREN 0x0124 /* Error enable */
#define DM36X_EDMA3_TC_ERRCLR 0x0128 /* Error clear */
#define DM36X_EDMA3_TC_ERRDET 0x012C /* Error details */
#define DM36X_EDMA3_TC_RDRATE 0x0140 /* Read rate */
/* EDMA3 channel mapping */
#define DM36X_EDMA3_CHAN_TIMER3_TEVT6 0
#define DM36X_EDMA3_CHAN_TIMER3_TEVT7 1
#define DM36X_EDMA3_CHAN_MCBSP_XEVT 2
#define DM36X_EDMA3_CHAN_MCBSP_REVT 3
#define DM36X_EDMA3_CHAN_VPSS_EVT1 4
#define DM36X_EDMA3_CHAN_VPSS_EVT2 5
#define DM36X_EDMA3_CHAN_VPSS_EVT3 6
#define DM36X_EDMA3_CHAN_VPSS_EVT4 7
#define DM36X_EDMA3_CHAN_TIMER2_TEVT4 8
#define DM36X_EDMA3_CHAN_TIMER2_TEVT5 9
#define DM36X_EDMA3_CHAN_SPI2XEVT 10
#define DM36X_EDMA3_CHAN_SPI2REVT 11
#define DM36X_EDMA3_CHAN_MJCP_IMX0INT 12
#define DM36X_EDMA3_CHAN_MJCP_SEQINT 13
#define DM36X_EDMA3_CHAN_SPI1XEVT 14
#define DM36X_EDMA3_CHAN_SPI1REVT 15
#define DM36X_EDMA3_CHAN_SPI0XEVT 16
#define DM36X_EDMA3_CHAN_SPI0REVT 17
#define DM36X_EDMA3_CHAN_URXEVT0 18
#define DM36X_EDMA3_CHAN_UTXEVT0 19
#define DM36X_EDMA3_CHAN_URXEVT1 20
#define DM36X_EDMA3_CHAN_UTXEVT1 21
#define DM36X_EDMA3_CHAN_TIMER4_TEVT8 22
#define DM36X_EDMA3_CHAN_TIMER4_TEVT9 23
#define DM36X_EDMA3_CHAN_RTOEVT 24
#define DM36X_EDMA3_CHAN_GPINT9 25
#define DM36X_EDMA3_CHAN_MMC0RXEVT 26
#define DM36X_EDMA3_CHAN_MMC0TXEVT 27
#define DM36X_EDMA3_CHAN_ICREVT 28
#define DM36X_EDMA3_CHAN_ICXEVT 29
#define DM36X_EDMA3_CHAN_MMC1RXEVT 30
#define DM36X_EDMA3_CHAN_MMC1TXEVT 31
#define DM36X_EDMA3_CHAN_GPINT0 32
#define DM36X_EDMA3_CHAN_GPINT1 33
#define DM36X_EDMA3_CHAN_GPINT2 34
#define DM36X_EDMA3_CHAN_GPINT3 35
#define DM36X_EDMA3_CHAN_GPINT4 36
#define DM36X_EDMA3_CHAN_GPINT5 37
#define DM36X_EDMA3_CHAN_GPINT6 38
#define DM36X_EDMA3_CHAN_GPINT7 39
#define DM36X_EDMA3_CHAN_GPINT10 40
#define DM36X_EDMA3_CHAN_GPINT11 41
#define DM36X_EDMA3_CHAN_GPINT12 42
#define DM36X_EDMA3_CHAN_GPINT13 43
#define DM36X_EDMA3_CHAN_GPINT14 44
#define DM36X_EDMA3_CHAN_GPINT15 45
#define DM36X_EDMA3_CHAN_ADINT 46
#define DM36X_EDMA3_CHAN_GPINT8 47
#define DM36X_EDMA3_CHAN_TIMER0_TEVT0 48
#define DM36X_EDMA3_CHAN_TIMER0_TEVT1 49
#define DM36X_EDMA3_CHAN_TIMER1_TEVT2 50
#define DM36X_EDMA3_CHAN_TIMER1_TEVT3 51
#define DM36X_EDMA3_CHAN_PWM0 52
#define DM36X_EDMA3_CHAN_PWM1 53
#define DM36X_EDMA3_CHAN_PWM2 54
#define DM36X_EDMA3_CHAN_PWM3 55
#define DM36X_EDMA3_CHAN_MJCP_VLDCINT 56
#define DM36X_EDMA3_CHAN_MJCP_BIMINT 57
#define DM36X_EDMA3_CHAN_MJCP_DCTINT 58
#define DM36X_EDMA3_CHAN_MJCP_QIQINT 59
#define DM36X_EDMA3_CHAN_MJCP_BPSINT 60
#define DM36X_EDMA3_CHAN_MJCP_VLDCERRINT 61
#define DM36X_EDMA3_CHAN_MJCP_RCNTINT 62
#define DM36X_EDMA3_CHAN_MJCP_COPCINT 63
/** System registers */
#define DM36X_SYSTEM_BASE 0x01C40000 /* System base registers */
#define DM36X_SYSTEM_PINMUX0 0x00
#define DM36X_SYSTEM_PINMUX1 0x04
#define DM36X_SYSTEM_PINMUX2 0x08
#define DM36X_SYSTEM_PINMUX3 0x0C
#define DM36X_SYSTEM_PINMUX4 0x10
#define DM36X_SYSTEM_ARM_INTMUX 0x18
#define DM36X_SYSTEM_EDMA_EVTMUX 0x1C
#define DM36X_SYSTEM_PERICLKCTL 0x48
#define DM36X_SYSTEM_PUPDCTL0 0x78
#define DM36X_SYSTEM_PUPDCTL1 0x7C
/* PINMUX0 register bitfields */
#define DM36X_PINMUX0_MMCSD0 24
#define DM36X_PINMUX0_GIO49 23
#define DM36X_PINMUX0_GIO48 22
#define DM36X_PINMUX0_GIO47 21
#define DM36X_PINMUX0_GIO46 20
#define DM36X_PINMUX0_GIO45 19
#define DM36X_PINMUX0_GIO44 18
#define DM36X_PINMUX0_GIO43 16
#define DM36X_PINMUX0_C_WE_FIELD 14
#define DM36X_PINMUX0_VD 13
#define DM36X_PINMUX0_HD 12
#define DM36X_PINMUX0_YIN0 11
#define DM36X_PINMUX0_YIN1 10
#define DM36X_PINMUX0_YIN2 9
#define DM36X_PINMUX0_YIN3 8
#define DM36X_PINMUX0_YIN4 6
#define DM36X_PINMUX0_YIN5 4
#define DM36X_PINMUX0_YIN6 2
#define DM36X_PINMUX0_YIN7 0
/* PINMUX1 register bitfields */
#define DM36X_PINMUX1_VCLK 22
#define DM36X_PINMUX1_EXTCLK 20
#define DM36X_PINMUX1_FIELD 18
#define DM36X_PINMUX1_LCD_OE 17
#define DM36X_PINMUX1_HVSYNC 16
#define DM36X_PINMUX1_COUT0 14
#define DM36X_PINMUX1_COUT1 12
#define DM36X_PINMUX1_COUT2 10
#define DM36X_PINMUX1_COUT3 8
#define DM36X_PINMUX1_COUT4 6
#define DM36X_PINMUX1_COUT5 4
#define DM36X_PINMUX1_COUT6 2
#define DM36X_PINMUX1_COUT7 0
/* PINMUX2 register bitfields */
#define DM36X_PINMUX2_EM_CLK 12
#define DM36X_PINMUX2_EM_ADV 11
#define DM36X_PINMUX2_EM_WAIT 10
#define DM36X_PINMUX2_EM_WE_OE 9
#define DM36X_PINMUX2_EM_CE1 8
#define DM36X_PINMUX2_EM_CE0 7
#define DM36X_PINMUX2_EM_D15_8 6
#define DM36X_PINMUX2_EM_A7 4
#define DM36X_PINMUX2_EM_A3 2
#define DM36X_PINMUX2_EM_AR 0
/* PINMUX3 register bitfields */
#define DM36X_PINMUX3_GIO26 31
#define DM36X_PINMUX3_GIO25 29
#define DM36X_PINMUX3_GIO24 28
#define DM36X_PINMUX3_GIO23 26
#define DM36X_PINMUX3_GIO22 25
#define DM36X_PINMUX3_GIO21 23
#define DM36X_PINMUX3_GIO20 21
#define DM36X_PINMUX3_GIO19 20
#define DM36X_PINMUX3_GIO18 19
#define DM36X_PINMUX3_GIO17 17
#define DM36X_PINMUX3_GIO16 15
#define DM36X_PINMUX3_GIO15 14
#define DM36X_PINMUX3_GIO14 13
#define DM36X_PINMUX3_GIO13 12
#define DM36X_PINMUX3_GIO12 11
#define DM36X_PINMUX3_GIO11 10
#define DM36X_PINMUX3_GIO10 9
#define DM36X_PINMUX3_GIO9 8
#define DM36X_PINMUX3_GIO8 7
#define DM36X_PINMUX3_GIO7 6
#define DM36X_PINMUX3_GIO6 5
#define DM36X_PINMUX3_GIO5 4
#define DM36X_PINMUX3_GIO4 3
#define DM36X_PINMUX3_GIO3 2
#define DM36X_PINMUX3_GIO2 1
#define DM36X_PINMUX3_GIO1 0
/* PINMUX4 register bitfields */
#define DM36X_PINMUX4_GIO42 30
#define DM36X_PINMUX4_GIO41 28
#define DM36X_PINMUX4_GIO40 26
#define DM36X_PINMUX4_GIO39 24
#define DM36X_PINMUX4_GIO38 22
#define DM36X_PINMUX4_GIO37 20
#define DM36X_PINMUX4_GIO36 18
#define DM36X_PINMUX4_GIO35 16
#define DM36X_PINMUX4_GIO34 14
#define DM36X_PINMUX4_GIO33 12
#define DM36X_PINMUX4_GIO32 10
#define DM36X_PINMUX4_GIO31 8
#define DM36X_PINMUX4_GIO30 6
#define DM36X_PINMUX4_GIO29 4
#define DM36X_PINMUX4_GIO28 2
#define DM36X_PINMUX4_GIO27 0
/** PLL registers */
#define DM36X_PLLC1_BASE 0x01C40800 /* PLLC1 base registers */
#define DM36X_PLLC2_BASE 0x01C40C00 /* PLLC2 base registers */
#define DM36X_PLLC_OCSEL 0x104
#define DM36X_PLLC_PLLM 0x110
#define DM36X_PLLC_PREDIV 0x114
#define DM36X_PLLC_PLLDIV1 0x118
#define DM36X_PLLC_PLLDIV2 0x11C
#define DM36X_PLLC_PLLDIV3 0x120
#define DM36X_PLLC_OSCDIV1 0x124
#define DM36X_PLLC_POSTDIV 0x128
#define DM36X_PLLC_CKEN 0x148
#define DM36X_PLLC_CKSTAT 0x14C
#define DM36X_PLLC_PLLDIV4 0x160
#define DM36X_PLLC_PLLDIV5 0x164
#define DM36X_PLLC_PLLDIV6 0x168
#define DM36X_PLLC_PLLDIV7 0x16C
#define DM36X_PLLC_PLLDIV8 0x170
#define DM36X_PLLC_PLLDIV9 0x174
/** Power and sleep controller registers */
#define DM36X_PSC_BASE 0x01C41000 /* PSC registers */
#define DM36X_PSC_EPCPR 0x070
#define DM36X_PSC_PTCMD 0x120
#define DM36X_PSC_PTSTAT 0x128
#define DM36X_PSC_PDSTAT 0x200
#define DM36X_PSC_PDCTL1 0x304
#define DM36X_PSC_MDSTAT_BASE 0x800
#define DM36X_PSC_MDCTL_BASE 0xA00
#define DM36X_PSC_MOD_SPI1 6
#define DM36X_PSC_MOD_MCBSP 8
#define DM36X_PSC_MOD_SPI2 11
#define DM36X_PSC_MOD_I2C 18
#define DM36X_PSC_MOD_SPI0 22
#define DM36X_PSC_MOD_SPI3 38
#define DM36X_PSC_MOD_SPI4 39
/** I2C registers */
#define DM36X_I2C_BASE 0x01C21000 /* I2C */
#define DM36X_I2C_ICOAR 0x00
#define DM36X_I2C_ICIMR 0x04
#define DM36X_I2C_ICSTR 0x08
#define DM36X_I2C_ICCLKL 0x0C
#define DM36X_I2C_ICCLKH 0x10
#define DM36X_I2C_ICCNT 0x14
#define DM36X_I2C_ICDRR 0x18
#define DM36X_I2C_ICSAR 0x1C
#define DM36X_I2C_ICDXR 0x20
#define DM36X_I2C_ICMDR 0x24
#define DM36X_I2C_ICIVR 0x28
#define DM36X_I2C_ICEMDR 0x2C
#define DM36X_I2C_ICPSC 0x30
#define DM36X_I2C_REVID1 0x34
#define DM36X_I2C_REVID2 0x38
#define DM36X_I2C_ICPFUNC 0x48
#define DM36X_I2C_ICPDIR 0x4C
#define DM36X_I2C_ICPDIN 0x50
#define DM36X_I2C_ICPDOUT 0x54
#define DM36X_I2C_ICPDSET 0x58
#define DM36X_I2C_ICPDCLR 0x5C
/** Register bitfields: ICMDR */
#define DM36X_I2C_ICMDR_NACKMOD (1 << 15)
#define DM36X_I2C_ICMDR_FREE (1 << 14)
#define DM36X_I2C_ICMDR_STT (1 << 13)
#define DM36X_I2C_ICMDR_STP (1 << 11)
#define DM36X_I2C_ICMDR_MST (1 << 10)
#define DM36X_I2C_ICMDR_TRX (1 << 9)
#define DM36X_I2C_ICMDR_XA (1 << 8)
#define DM36X_I2C_ICMDR_RM (1 << 7)
#define DM36X_I2C_ICMDR_DLB (1 << 6)
#define DM36X_I2C_ICMDR_IRS (1 << 5)
#define DM36X_I2C_ICMDR_STB (1 << 4)
#define DM36X_I2C_ICMDR_FDF (1 << 3)
#define DM36X_I2C_ICMDR_BC (1 << 0)
/** Register bitfields: ICSTR */
#define DM36X_I2C_ICSTR_SDIR (1 << 14)
#define DM36X_I2C_ICSTR_NACKSNT (1 << 13)
#define DM36X_I2C_ICSTR_BB (1 << 12)
#define DM36X_I2C_ICSTR_RSFULL (1 << 11)
#define DM36X_I2C_ICSTR_XSMT (1 << 10)
#define DM36X_I2C_ICSTR_AAS (1 << 9)
#define DM36X_I2C_ICSTR_AD0 (1 << 8)
#define DM36X_I2C_ICSTR_SCD (1 << 5)
#define DM36X_I2C_ICSTR_ICXRDY (1 << 4)
#define DM36X_I2C_ICSTR_ICRRDY (1 << 3)
#define DM36X_I2C_ICSTR_ARDY (1 << 2)
#define DM36X_I2C_ICSTR_NACK (1 << 1)
#define DM36X_I2C_ICSTR_AL (1 << 0)
/** Timer registers */
#define DM36X_TIMER0_BASE 0x01C21400 /* TIMER0 */
#define DM36X_TIMER1_BASE 0x01C21800 /* TIMER1 */
#define DM36X_TIMER_PID12 0x00
#define DM36X_TIMER_EMUMGT 0x04
#define DM36X_TIMER_TIM12 0x10
#define DM36X_TIMER_TIM34 0x14
#define DM36X_TIMER_PRD12 0x18
#define DM36X_TIMER_PRD34 0x1C
#define DM36X_TIMER_TCR 0x20
#define DM36X_TIMER_TGCR 0x24
#define DM36X_TIMER_WDTCR 0x28
#define DM36X_TIMER_REL12 0x34
#define DM36X_TIMER_REL34 0x38
#define DM36X_TIMER_CAP12 0x3C
#define DM36X_TIMER_CAP34 0x40
#define DM36X_TIMER_INTCTL_STAT 0x44
/** Interrupt controller registers */
#define DM36X_INTC_BASE 0x01C48000 /* Interrupt controller */
#define DM36X_INTC_IRQ0 0x08
#define DM36X_INTC_IRQ1 0x0C
#define DM36X_INTC_FIQENTRY 0x10
#define DM36X_INTC_IRQENTRY 0x14
#define DM36X_INTC_EINT0 0x18
#define DM36X_INTC_EINT1 0x1C
#define DM36X_INTC_INTCTL 0x20
#define DM36X_INTC_EABASE 0x24
#define DM36X_INTC_PRI0 0x30
#define DM36X_INTC_PRI1 0x34
#define DM36X_INTC_PRI2 0x38
#define DM36X_INTC_PRI3 0x3C
#define DM36X_INTC_PRI4 0x40
#define DM36X_INTC_PRI5 0x44
#define DM36X_INTC_PRI6 0x48
#define DM36X_INTC_PRI7 0x4C
/** Interrupt controller vector offsets */
#define DM36X_INTC_VEC_VPSSINT0 0
#define DM36X_INTC_VEC_VPSSINT1 1
#define DM36X_INTC_VEC_VPSSINT2 2
#define DM36X_INTC_VEC_VPSSINT3 3
#define DM36X_INTC_VEC_VPSSINT4 4
#define DM36X_INTC_VEC_VPSSINT5 5
#define DM36X_INTC_VEC_VPSSINT6 6
#define DM36X_INTC_VEC_VPSSINT7 7
#define DM36X_INTC_VEC_VPSSINT8 8
#define DM36X_INTC_VEC_MJCP_SEQINT 9
#define DM36X_INTC_VEC_HDVICP_INT 10
#define DM36X_INTC_VEC_EDMA_CC_INT0 16
#define DM36X_INTC_VEC_SPI1INT0 17
#define DM36X_INTC_VEC_EDMA_CCERRINT 17
#define DM36X_INTC_VEC_SPI2INT0 19
#define DM36X_INTC_VEC_SDIO0INT 23
#define DM36X_INTC_VEC_MMC0INT 26
#define DM36X_INTC_VEC_MMC1INT 27
#define DM36X_INTC_VEC_SDIO1INT 31
#define DM36X_INTC_VEC_TINT0 32
#define DM36X_INTC_VEC_I2CINT 39
#define DM36X_INTC_VEC_UART0INT 40
#define DM36X_INTC_VEC_UART1INT 41
#define DM36X_INTC_VEC_SPI0INT0 42
#define DM36X_INTC_VEC_SPI3INT0 43
#define DM36X_INTC_VEC_GIO0 44
#define DM36X_INTC_VEC_GIO1 45
#define DM36X_INTC_VEC_GIO2 46
#define DM36X_INTC_VEC_GIO3 47
#define DM36X_INTC_VEC_GIO4 48
#define DM36X_INTC_VEC_GIO5 49
#define DM36X_INTC_VEC_GIO6 50
#define DM36X_INTC_VEC_GIO7 51
#define DM36X_INTC_VEC_GIO8 52
#define DM36X_INTC_VEC_GIO9 53
#define DM36X_INTC_VEC_GIO10 54
#define DM36X_INTC_VEC_GIO11 55
#define DM36X_INTC_VEC_GIO12 56
#define DM36X_INTC_VEC_GIO13 57
#define DM36X_INTC_VEC_GIO14 58
#define DM36X_INTC_VEC_GIO15 59
#define DM36X_INTC_MAX_VEC 63
/** UART registers */
#define DM36X_UART0_BASE 0x01C20000 /* UART0 */
#define DM36X_UART1_BASE 0x01D06000 /* UART1 */
/** SPI registers */
#define DM36X_SPI0_BASE 0x01C66000 /* SPI0 */
#define DM36X_SPI1_BASE 0x01C66800 /* SPI1 */
#define DM36X_SPI2_BASE 0x01C67800 /* SPI2 */
#define DM36X_SPI3_BASE 0x01C68000 /* SPI3 */
#define DM36X_SPI4_BASE 0x01C23000 /* SPI4 */
#define DM36X_SPI_SPIGCR0 0x00
#define DM36X_SPI_SPIGCR1 0x04
#define DM36X_SPI_SPIINT 0x08
#define DM36X_SPI_SPILVL 0x0C
#define DM36X_SPI_SPIFLG 0x10
#define DM36X_SPI_SPIPC0 0x14
#define DM36X_SPI_SPIPC2 0x1C
#define DM36X_SPI_SPIDAT1 0x3C
#define DM36X_SPI_SPIBUF 0x40
#define DM36X_SPI_SPIEMU 0x44
#define DM36X_SPI_SPIDELAY 0x48
#define DM36X_SPI_SPIDEF 0x4C
#define DM36X_SPI_SPIFMT0 0x50
#define DM36X_SPI_INTVECT0 0x60
#define DM36X_SPI_INTVECT1 0x64
/** GPIO registers */
#define DM36X_GPIO_BASE 0x01C67000
#define DM36X_GPIO_BINTEN 0x08
#define DM36X_GPIO_DIR01 0x10
#define DM36X_GPIO_OUT01 0x14
#define DM36X_GPIO_SET01 0x18
#define DM36X_GPIO_CLR01 0x1C
#define DM36X_GPIO_IN01 0x20
#define DM36X_GPIO_SET_RIS_TRIG01 0x24
#define DM36X_GPIO_CLR_RIS_TRIG01 0x28
#define DM36X_GPIO_SET_FAL_TRIG01 0x2C
#define DM36X_GPIO_CLR_FAL_TRIG01 0x30
#define DM36X_GPIO_INTSTAT01 0x34
#define DM36X_GPIO_DIR23 0x38
#define DM36X_GPIO_OUT23 0x3C
#define DM36X_GPIO_SET23 0x40
#define DM36X_GPIO_CLR23 0x44
#define DM36X_GPIO_IN23 0x48
#define DM36X_GPIO_DIR45 0x60
#define DM36X_GPIO_OUT45 0x64
#define DM36X_GPIO_SET45 0x68
#define DM36X_GPIO_CLR45 0x6C
#define DM36X_GPIO_IN45 0x70
#define DM36X_GPIO_DIR6 0x88
#define DM36X_GPIO_OUT6 0x8C
#define DM36X_GPIO_SET6 0x90
#define DM36X_GPIO_CLR6 0x94
#define DM36X_GPIO_IN6 0x98
#define DM36X_GPIO_SET_RIS_TRIG6 0x9C
#define DM36X_GPIO_CLR_RIS_TRIG6 0xA0
#define DM36X_GPIO_SET_FAL_TRIG6 0xA4
#define DM36X_GPIO_CLR_FAL_TRIG6 0xA8
#define DM36X_GPIO_INTSTAT6 0xAC
/** VPFE/VPBE registers */
#define DM36X_ISP_BASE 0x01C70000
#define DM36X_RSZ_BASE 0x01C70400
#define DM36X_IPIPE_BASE 0x01C70800
#define DM36X_ISIF_BASE 0x01C71000
#define DM36X_IPIPEIF_BASE 0x01C71200
#define DM36X_H3A_BASE 0x01C71400
#define DM36X_OSD_BASE 0x01C71C00
#define DM36X_VENC_BASE 0x01C71E00
#define DM36x_GAMMA_R_TBL_3 0x01C7A800
#define DM36x_GAMMA_G_TBL_3 0x01C7B000
#define DM36x_GAMMA_B_TBL_3 0x01C7B800
/** SD/MMC registers */
#define DM36X_SD1_BASE 0x01D00000 /* MMC/SD1 */
#define DM36X_SD0_BASE 0x01D11000 /* MMC/SD0 */
#define DM36X_SD_MMCCTL 0x00
#define DM36X_SD_MMCCLK 0x04
#define DM36X_SD_MMCST0 0x08
#define DM36X_SD_MMCST1 0x0C
#define DM36X_SD_MMCIM 0x10
#define DM36X_SD_MMCTOR 0x14
#define DM36X_SD_MMCTOD 0x18
#define DM36X_SD_MMCBLEN 0x1C
#define DM36X_SD_MMCNBLK 0x20
#define DM36X_SD_MMCNBLC 0x24
#define DM36X_SD_MMCDRR 0x28
#define DM36X_SD_MMCDXR 0x2C
#define DM36X_SD_MMCCMD 0x30
#define DM36X_SD_MMCARGHL 0x34
#define DM36X_SD_MMCRSP01 0x38
#define DM36X_SD_MMCRSP23 0x3C
#define DM36X_SD_MMCRSP45 0x40
#define DM36X_SD_MMCRSP67 0x44
#define DM36X_SD_MMCDRSP 0x48
#define DM36X_SD_MMCCIDX 0X50
#define DM36X_SD_SDIOCTL 0X64
#define DM36X_SD_SDIOST0 0X68
#define DM36X_SD_SDIOIEN 0X6C
#define DM36X_SD_SDIOIST 0X70
#define DM36X_SD_MMCFIFOCTL 0x74
/** McBSP registers */
#define DM36X_MCBSP_BASE 0x01D02000 /* McBSP */
#define DM36X_MCBSP_DRR 0x00
#define DM36X_MCBSP_DXR 0x04
#define DM36X_MCBSP_SPCR 0x08
#define DM36X_MCBSP_RCR 0x0C
#define DM36X_MCBSP_XCR 0x10
#define DM36X_MCBSP_SRGR 0x14
#define DM36X_MCBSP_MCR 0x18
#define DM36X_MCBSP_RCERE0 0x1C
#define DM36X_MCBSP_XCERE0 0x20
#define DM36X_MCBSP_PCR 0x24
#define DM36X_MCBSP_RCERE1 0x28
#define DM36X_MCBSP_XCERE1 0x2C
#define DM36X_MCBSP_RCERE2 0x30
#define DM36X_MCBSP_XCERE2 0x34
#define DM36X_MCBSP_RCERE3 0x38
#define DM36X_MCBSP_XCERE3 0x3C
/* Function prototypes */
extern int low_level_init (void) ;
#endif /* __DM36X_IO_H__ */

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env expect
# Expect script to check an automated test's results via a serial port
# and check for successful completion.
#
# You are expected to set the target's U-boot up to automatically load
# the app on your TFTP server called "test.bin". Before this script is
# started the Makefile should have copied the next test binary to the
# file "test.bin" in your TFTP root folder. The user must sit and
# hit the reset button after every test completion in order to make
# the board load and run the next test.bin file.
#
# Arguments: <serial_port_device> <baudrate> <test_bin_file>
#
# Returns 0 on successful test run, 1 on failure
# Set the serial port baudrate
stty [lindex $argv 1] < [lindex $argv 0]
# Start the test
spawn cat [lindex $argv 0]
puts "Ready: reset the target!"
# Expect to see the test starting within 60 seconds (give long enough
# for user to reset the board after running the last test).
set timeout 60
# Wait for the test to start ("Go")
expect {
"Go\r" {
puts "Test started"
# The test could take up to 3 minutes to complete once started
set timeout 180
# Now expect to see "Pass" or "Fail" within 3 minutes
expect {
"Pass\r" { puts "Test passed"; exit 0 }
"Fail\r" { puts "Test failed"; exit 1 }
timeout { puts "Test timed out without completing"; exit 1 }
}
}
timeout {
# Didn't receive "Go" within 10 seconds
puts "Test failed to start ('Go' not seen)"
exit 1
}
}

View File

@@ -0,0 +1,88 @@
.section .vectors, "x"
.global __interrupt_vector_table
.extern __irq_stack_top__
.extern __fiq_stack_top__
.extern __svc_stack_top__
.extern __null_handler
.equ USR_MODE, 0x10
.equ FIQ_MODE, 0x11
.equ IRQ_MODE, 0x12
.equ SVC_MODE, 0x13
.equ ABT_MODE, 0x17
.equ UND_MODE, 0x1B
.equ SYS_MODE, 0x1F
.equ I_BIT, 0x80 /* when I bit is set, IRQ is disabled */
.equ F_BIT, 0x40 /* when F bit is set, FIQ is disabled */
__interrupt_vector_table:
B Reset_Handler /* Reset */
ldr PC,=Exception_Handler /* Undefined */
ldr PC,=Exception_Handler /* SWI */
ldr PC,=Exception_Handler /* Prefetch Abort */
ldr PC,=Exception_Handler /* Data Abort */
ldr PC,=Exception_Handler /* reserved */
ldr PC,=archIRQHandler/* IRQ */
ldr PC,=Exception_Handler /* FIQ */
Reset_Handler:
MSR CPSR_c,#(IRQ_MODE | I_BIT | F_BIT)
LDR sp,=__irq_stack_top__ /* set the IRQ stack pointer */
MSR CPSR_c,#(FIQ_MODE | I_BIT | F_BIT)
LDR sp,=__fiq_stack_top__ /* set the FIQ stack pointer */
MSR CPSR_c,#(SVC_MODE | I_BIT | F_BIT)
LDR sp,=__svc_stack_top__ /* set the SVC stack pointer */
BL low_level_init
BL _mainCRTStartup
/**
* \b Exception_Handler
*
* IRQ entry point.
*
* Save the process/thread context onto its own stack before calling __interrupt_dispatcher().
* __interrupt_dispatcher() might switch stacks. On return the same context is popped from the
* stack and control is returned to the process.
*
* @return None
*/
Exception_Handler:
MSR cpsr_c, #(SVC_MODE | I_BIT) /* Save current process context in process stack */
STMFD sp!, {r0 - r3, ip, lr}
MSR cpsr_c, #(IRQ_MODE | I_BIT) /* Save lr_irq and spsr_irq in process stack */
SUB lr, lr, #4
MOV r1, lr
MRS r2, spsr
MSR cpsr_c, #(SVC_MODE | I_BIT)
STMFD sp!, {r1, r2}
BL __null_handler /* Dispatch the interrupt to platform folder for
the timer tick interrupt or a simular function
for other interrupts. Some of those IRQs may
call Atomthreads kernel routines and cause a
thread switch. */
LDMFD sp!, {r1, r2} /* Restore lr_irq and spsr_irq from process stack */
MSR cpsr_c, #(IRQ_MODE | I_BIT)
STMFD sp!, {r1}
MSR spsr_cxsf, r2
MSR cpsr_c, #(SVC_MODE | I_BIT) /* Restore process regs */
LDMFD sp!, {r0 - r3, ip, lr}
MSR cpsr_c, #(IRQ_MODE | I_BIT) /* Exit from IRQ */
LDMFD sp!, {pc}^
B .

View File

@@ -0,0 +1,87 @@
ENTRY(__interrupt_vector_table)
MEMORY
{
sram (rwx) : ORIGIN = 0x80000000, LENGTH = 0x08000000
}
EXTERN(__interrupt_vector_table);
C_STACK_SIZE = 4096;
IRQ_STACK_SIZE = 4096;
FIQ_STACK_SIZE = 2048;
SVC_STACK_SIZE = 4096;
ABT_STACK_SIZE = 2048;
UND_STACK_SIZE = 2048;
SECTIONS
{
.text :
{
_start_vectors = .;
*(.vectors)
_end_vectors = .;
/* Startup assembly */
*(.startup)
*(.init)
/* Rest of the code (C) */
*(.text)
*(.rodata)
*(.rodata*)
_end_text = .;
_start_data = .;
*(.data)
_end_data = .;
} >sram
.bss :
{
_start_bss = .;
__bss_start__ = . ;
*(.bss)
} >sram
. = ALIGN(4);
_end_bss = .;
__bss_end__ = . ;
. = ALIGN(256);
.stack : {
__stack_start__ = . ;
. += IRQ_STACK_SIZE;
. = ALIGN (4);
__irq_stack_top__ = . ;
. += FIQ_STACK_SIZE;
. = ALIGN (4);
__fiq_stack_top__ = . ;
. += SVC_STACK_SIZE;
. = ALIGN (4);
__svc_stack_top__ = . ;
. += ABT_STACK_SIZE;
. = ALIGN (4);
__abt_stack_top__ = . ;
. += UND_STACK_SIZE;
. = ALIGN (4);
__und_stack_top__ = . ;
. += C_STACK_SIZE;
. = ALIGN (4);
__c_stack_top__ = . ;
__stack_end__ = .;
} >sram
}
__end__ = .;
_end = .;
PROVIDE(end = .);
heap_top = ORIGIN(sram) + LENGTH(sram) - 4;

View File

@@ -0,0 +1,226 @@
/*
* Copyright (c) 2013, Kelvin Lawson. 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.
*/
/**
* \file
* Driver for accurate high-speed hardware timers.
*
* Uses the TIMER1 hardware module of DM36x.
*/
#include "atom.h"
#include "atomport.h"
#include "dm36x-io.h"
/* Constants */
/** Register access macros: using TIMER1 */
#define TIMER_REG(offset) *(volatile uint32_t *)(DM36X_TIMER1_BASE + offset)
/* Local data */
/*
* Initialised flag
*/
static int initialised = FALSE;
/* Forward declarations */
static int timer_init (void);
/**
* \b timer_init
*
* Initialisation of TIMER1 hardware.
*
* @retval ATOM_OK Success
* @retval ATOM_ERROR Failed
*/
static int timer_init (void)
{
int status;
/* Check we are not already initialised */
if (initialised == FALSE)
{
/* Initialise TIMER1 registers for free-running high-speed 24MHz timer */
/* Reset & disable all TIMER1 timers */
TIMER_REG(DM36X_TIMER_INTCTL_STAT) = 0; /* Disable interrupts */
TIMER_REG(DM36X_TIMER_TCR) = 0; /* Disable all TIMER1 timers */
TIMER_REG(DM36X_TIMER_TGCR) = 0; /* Put all TIMER1 timers in reset */
TIMER_REG(DM36X_TIMER_TIM12) = 0; /* Clear Timer 1:2 */
/* Set up Timer 1:2 in 32-bit unchained mode */
TIMER_REG(DM36X_TIMER_TGCR) = (1 << 2); /* Select 32-bit unchained mode (TIMMODE) */
TIMER_REG(DM36X_TIMER_TGCR) |= (1 << 0); /* Remove Timer 1:2 from reset (TIM12RS) */
TIMER_REG(DM36X_TIMER_PRD12) = ~0; /* Set period to free-running 24MHz clock (PRD12) */
TIMER_REG(DM36X_TIMER_TCR) |= (0 << 8); /* Select external clock source for Timer 1:2 (CLKSRC12) */
/* Enable timer */
TIMER_REG(DM36X_TIMER_TCR) |= (2 << 6); /* Enable Timer 1:2 continuous (ENAMODE12) */
/* Success */
initialised = TRUE;
status = ATOM_OK;
}
/* Already initialised */
else
{
/* Success */
status = ATOM_OK;
}
/* Finished */
return (status);
}
/**
* \b archUsleep
*
* Simple spin loop of at least the specified microseconds.
*
* @param[in] microsecs Number of microseconds to sleep
*
* @return None
*
*/
void archUsleep (int32_t microsecs)
{
int32_t start_time, delay_timer_ticks;
/* Check we are initialised */
if (initialised == FALSE)
{
timer_init();
}
/* Get the current 24MHz count */
start_time = TIMER_REG(DM36X_TIMER_TIM12);
/* Translate delay in usecs to delay in 24MHz ticks */
delay_timer_ticks = ((TIMER_CLK / 1000000) * microsecs);
/* Wait in a spin-loop for timer to expire */
while (((int32_t)TIMER_REG(DM36X_TIMER_TIM12) - start_time) < delay_timer_ticks)
;
}
/**
* \b archUsleepStart
*
* Start a usleep timer session.
*
* @retval Start time for use in subsequent archUsleepCheckExpired() calls
*
*/
int32_t archUsleepStart (void)
{
/* Check we are initialised */
if (initialised == FALSE)
{
timer_init();
}
/* Return the current 24MHz count */
return (TIMER_REG(DM36X_TIMER_TIM12));
}
/**
* \b archUsleepCheckExpired
*
* Test whether a usleep timer session has expired.
*
* @param[in] start_time Beginning of timer expiry check session (returned by archUsleepStart())
* @param[in] delay_usecs Number of microsecs to check have expired after start_timE
*
* @retval 1=Timer expired, 0=Not expired
*
*/
int archUsleepCheckExpired (int32_t start_time, int32_t delay_usecs)
{
int32_t delay_timer_ticks;
int status;
/* Translate delay in usecs to delay in 24MHz ticks */
delay_timer_ticks = ((TIMER_CLK / 1000000) * delay_usecs);
/* Check if timer has expired */
status = (((int32_t)TIMER_REG(DM36X_TIMER_TIM12) - start_time) < delay_timer_ticks) ? 0 : 1;
return (status);
}
/**
* \b archUsecStart
*
* Start a usec timer session for use with archUsecDiff() layer.
*
* @retval Start time for use in subsequent archUsecDiff() calls
*
*/
int32_t archUsecStart (void)
{
/* Check we are initialised */
if (initialised == FALSE)
{
timer_init();
}
/* Return the current 24MHz count */
return (TIMER_REG(DM36X_TIMER_TIM12));
}
/**
* \b archUsecDiff
*
* Calculate the usecs that have expired since the passed "start_time".
*
* The 24MHz timer rolls over every 178 seconds. The use of a signed
* integer means that this cannot be used to measure periods over 89 seconds.
*
* @param[in] start_time Beginning of time difference session (returned by archUsecStart())
*
* @retval Number of microseconds expired since start_time
*
*/
int32_t archUsecDiff (int32_t start_time)
{
/* Translate diff in 24MHz ticks to usecs */
return (((int32_t)TIMER_REG(DM36X_TIMER_TIM12) - start_time) / (TIMER_CLK / 1000000));
}

View File

@@ -0,0 +1,333 @@
/*
* Copyright (c) 2013, Kelvin Lawson. 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.
*/
/**
* \file
* Simple polled UART implementation for non-hosted compiler toolchains.
*
*
* This is only required for non-hosted toolchains which don't implement
* stdout automatically for use within QEMU.
*/
#include "atom.h"
#include "atommutex.h"
#include "atomport.h"
#include "dm36x-io.h"
#include "uart.h"
/* Constants */
/** Baudrate */
#define BAUDRATE 115200
/** Select relevant UART for this platform */
#define UART_BASE DM36X_UART0_BASE
/** FR Register bits */
#define UART_FR_RXFE 0x10
#define UART_LSR_TEMT 0x40
/** UART register access macros */
#define UART_RBR(baseaddr) (*(unsigned int *)(baseaddr))
#define UART_THR(baseaddr) (*(unsigned int *)(baseaddr))
#define UART_IER(baseaddr) (*(((unsigned int *)(baseaddr + 0x04))))
#define UART_FCR(baseaddr) (*(((unsigned int *)(baseaddr + 0x08))))
#define UART_LCR(baseaddr) (*(((unsigned int *)(baseaddr + 0x0C))))
#define UART_MCR(baseaddr) (*(((unsigned int *)(baseaddr + 0x10))))
#define UART_LSR(baseaddr) (*(((unsigned int *)(baseaddr + 0x14))))
#define UART_DLL(baseaddr) (*(((unsigned int *)(baseaddr + 0x20))))
#define UART_DLH(baseaddr) (*(((unsigned int *)(baseaddr + 0x24))))
#define UART_PWR(baseaddr) (*(((unsigned int *)(baseaddr + 0x30))))
/* Local data */
/*
* Semaphore for single-threaded access to UART device
*/
static ATOM_MUTEX uart_mutex;
/*
* Initialised flag
*/
static int initialised = FALSE;
/* Forward declarations */
static int uart_init (void);
static void uart_write_char (const char c);
/**
* \b uart_init
*
* Initialisation of UART driver. Creates a mutex that enforces
* single-threaded access to the UART. We poll register bits
* to check when space is available, which would not otherwise
* be thread-safe.
*
* @retval ATOM_OK Success
* @retval ATOM_ERROR Failed to create mutex
*/
static int uart_init (void)
{
int status;
uint32_t dummy;
uint32_t divisor;
/* Check we are not already initialised */
if (initialised == FALSE)
{
/* Create a mutex for single-threaded UART access */
if (atomMutexCreate (&uart_mutex) != ATOM_OK)
{
/* Mutex creation failed */
status = ATOM_ERROR;
}
else
{
/* Reset Tx/Rx in PWREMU_MGMT */
UART_PWR(UART_BASE) = 0x0;
/* Set baudrate */
divisor = (TIMER_CLK / BAUDRATE) / 16;
UART_DLL(UART_BASE) = (divisor & 0xFF);
UART_DLH(UART_BASE) = (divisor >> 8);
/* Clear Tx/Rx FIFOs and enter non-FIFO mode */
UART_FCR(UART_BASE) = 0x7;
UART_FCR(UART_BASE) = 0x0;
/* Set 8N1 */
UART_LCR(UART_BASE) = 0x3;
/* Disable loopback, flow-control, RTS/CTS */
UART_MCR(UART_BASE) = 0x0;
/* Disable interrupts */
UART_IER(UART_BASE) = 0x0;
/* Take Tx/Rx out of reset in PWREMU_MGMT */
UART_PWR(UART_BASE) = 0xE001;
/* Clear any receive characters */
dummy = UART_RBR(UART_BASE);
/* Success */
initialised = TRUE;
status = ATOM_OK;
}
}
/* Already initialised */
else
{
/* Success */
status = ATOM_OK;
}
/* Finished */
return (status);
}
/**
* \b uart_read
*
* Simple polled UART read.
*
* @param[in] ptr Pointer to receive buffer
* @param[in] len Max bytes to read
*
* @retval Number of bytes read
*
*/
int uart_read (char *ptr, int len)
{
int todo = 0;
/* Check we are initialised */
if (initialised == FALSE)
{
uart_init();
}
/* Check parameters */
if ((ptr == NULL) || (len == 0))
{
return 0;
}
/* Block thread on private access to the UART */
if (atomOSStarted && atomMutexGet(&uart_mutex, 0) == ATOM_OK)
{
#if 0
/* Wait for not-empty */
while(UART_FR(UART_BASE) & UART_FR_RXFE)
;
/* Read first byte */
*ptr++ = UART_RBR(UART_BASE);
/* Loop over remaining bytes until empty */
for (todo = 1; todo < len; todo++)
{
/* Quit if receive FIFO empty */
if(UART_FR(UART_BASE) & UART_FR_RXFE)
{
break;
}
/* Read next byte */
*ptr++ = UART_RBR(UART_BASE);
}
#endif
/* Return mutex access */
if (atomOSStarted)
{
atomMutexPut(&uart_mutex);
}
}
/* Return number of bytes read */
return todo;
}
/**
* \b uart_write
*
* Simple polled UART write.
*
* @param[in] ptr Pointer to write buffer
* @param[in] len Number of bytes to write
*
* @retval Number of bytes written
*/
int uart_write (const char *ptr, int len)
{
int todo;
/* Check we are initialised */
if (initialised == FALSE)
{
uart_init();
}
/* Check parameters */
if ((ptr == NULL) || (len == 0))
{
return 0;
}
/* Block thread on private access to the UART unless at interrupt context */
if (atomOSStarted && ((atomCurrentContext() == NULL) || (atomMutexGet(&uart_mutex, 0) == ATOM_OK)))
{
/* Loop through all bytes to write */
for (todo = 0; todo < len; todo++)
{
/* Convert \n to \r\n */
if (*ptr == '\n')
uart_write_char('\r');
/* Write byte to UART */
uart_write_char(*ptr++);
}
/* Return mutex access if not at interrupt context */
if (atomOSStarted && (atomCurrentContext() != NULL))
{
atomMutexPut(&uart_mutex);
}
}
/* Return bytes-written count */
return len;
}
/**
* \b uart_write_halt
*
* Simple polled UART write for handling critical failures
* by printing out a message on the UART and looping forever.
* Can be called from interrupt (unlike the standard
* uart_write()) but is not thread-safe because it cannot
* take the thread-safety mutex, and hence is only useful for
* a last-resort catastrophic debug message.
*
* @param[in] ptr Pointer to write string
*/
void uart_write_halt (const char *ptr)
{
/* Check parameters */
if (ptr != NULL)
{
/* Loop through all bytes until NULL terminator encountered */
while (*ptr != '\0')
{
/* Convert \n to \r\n */
if (*ptr == '\n')
uart_write_char('\r');
/* Write byte to UART */
uart_write_char(*ptr++);
}
}
/* Loop forever */
while (1)
;
}
/**
* \b uart_putchar
*
* Simple polled UART write char.
*
* Assumes that the mutex has already been taken, or
* is not expected to be taken (e.g. on interrupt).
*
* @param[in] c Char to write
*/
static void uart_write_char (const char c)
{
/* Wait for empty */
while ((UART_LSR(UART_BASE) & UART_LSR_TEMT) != UART_LSR_TEMT)
;
/* Write byte to UART */
UART_THR(UART_BASE) = (c & 0xFF);
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2013, Kelvin Lawson. 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.
*/
#ifndef __ATOM_UART_H
#define __ATOM_UART_H
/* UART driver APIs */
extern int uart_read (char *ptr, int len);
extern int uart_write (const char *ptr, int len);
extern void uart_write_halt (const char *ptr);
#endif /* __ATOM_UART_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,134 @@
############
# Settings #
############
# Build all test applications:
# make
#
# Run all tests within QEMU
# make qemutests
# Location of build tools and atomthreads sources
KERNEL_DIR=../../../../kernel
TESTS_DIR=../../../../tests
PORT_DIR=../..
CC=arm-none-eabi-gcc
OBJCOPY=arm-none-eabi-objcopy
ARCHIVE=arm-none-eabi-ar
QEMU=qemu-system-arm
# Enable stack-checking.
#STACK_CHECK=true
# Test programs: Log stack usage to UART (if STACK_CHECK is enabled)
#TESTS_LOG_STACK=true
# Directory for built objects
BUILD_DIR=build
# Platform-specific object files
PLATFORM_OBJECTS = modules.o uart.o
PLATFORM_ASM_OBJECTS = startup.o
# Port-specific object files
PORT_OBJECTS = atomport.o tests-main.o syscalls.o
PORT_ASM_OBJECTS = atomport-asm.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 = $(PLATFORM_OBJECTS) $(PLATFORM_ASM_OBJECTS) $(PORT_OBJECTS) $(PORT_ASM_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 for each test object
TEST_ELFS = $(patsubst %.o,%.elf,$(TEST_OBJECTS))
# Search build/output directory for dependencies
vpath %.o ./$(BUILD_DIR)
vpath %.elf ./$(BUILD_DIR)
# GCC flags
CFLAGS=-g -c -mcpu=arm926ej-s -ffreestanding -Wall -Werror
AFLAGS=$(CFLAGS) -x assembler-with-cpp
LFLAGS=-mcpu=arm926ej-s -Tsystem.ld -Wall
# Enable stack-checking options (disable if not required)
ifeq ($(STACK_CHECK),true)
CFLAGS += -DATOM_STACK_CHECKING
endif
ifeq ($(TESTS_LOG_STACK),true)
CFLAGS += -DTESTS_LOG_STACK_USAGE
endif
#################
# Build targets #
#################
# All tests
all: $(BUILD_DIR) $(TEST_ELFS) Makefile
# Build archive for linking with external application
libatomthreads.a: $(BUILD_DIR) $(ALL_OBJECTS) Makefile
$(ARCHIVE) cr $(BUILD_DIR)/$@ $(BUILT_OBJECTS)
# Make build/output directory
$(BUILD_DIR):
mkdir $(BUILD_DIR)
# Test ELF files (one application build for each test)
$(TEST_ELFS): %.elf: %.o $(ALL_OBJECTS)
$(CC) $(LFLAGS) $(BUILD_DIR)/$(notdir $<) $(BUILT_OBJECTS) --output $(BUILD_DIR)/$@ -Wl,-Map,$(BUILD_DIR)/$(basename $@).map
# Kernel objects builder
$(KERNEL_OBJECTS): %.o: $(KERNEL_DIR)/%.c
$(CC) -c $(CFLAGS) -I. -I$(PORT_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Test objects builder
$(TEST_OBJECTS): %.o: $(TESTS_DIR)/%.c
$(CC) -c $(CFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Platform C objects builder
$(PLATFORM_OBJECTS): %.o: ./%.c
$(CC) -c $(CFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) -I$(TESTS_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Platform asm objects builder
$(PLATFORM_ASM_OBJECTS): %.o: ./%.s
$(CC) -c $(AFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Port C objects builder
$(PORT_OBJECTS): %.o: $(PORT_DIR)/%.c
$(CC) -c $(CFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) -I$(TESTS_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Port asm objects builder
$(PORT_ASM_OBJECTS): %.o: $(PORT_DIR)/%.s
$(CC) -c $(AFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# .lst file builder
%.lst: %.c
$(CC) $(CFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) -I$(TESTS_DIR) -Wa,-al $< > $@
# Clean
clean:
rm -f *.o *.elf *.map *.lst
rm -rf doxygen-kernel
rm -rf doxygen-arm
rm -rf doxygen-platform
rm -rf build
# Generate Doxygen documentation
doxygen:
doxygen $(KERNEL_DIR)/Doxyfile
doxygen ../../Doxyfile
doxygen ./Doxyfile
# Run tests within QEMU simulator
phony_qemu_elfs = $(addsuffix .sim, $(TEST_ELFS))
qemutests: $(phony_qemu_elfs)
.PHONY: qemutests $(phony_qemu_elfs)
$(phony_qemu_elfs):
./run_test.exp $(QEMU) $(BUILD_DIR)/$(basename $@)

View File

@@ -0,0 +1,228 @@
---------------------------------------------------------------------------
Library: Atomthreads QEMU ARM Integrator/CP (ARM926EJ-S) Platform.
Author: Natie van Rooyen <natie@navaro.nl>
Website: http://atomthreads.com
License: BSD Revised
---------------------------------------------------------------------------
QEMU ARM Integrator/CP (ARM926EJ-S) Platform
The "qemu_integratorcp" platform folder contains sources for building a
sample Atomthreads application for the ARM Integrator/CP (ARM926EJ-S)
platform running under QEMU.
---------------------------------------------------------------------------
SOURCE LAYOUT
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. To support multiple ARM boards/platforms using a
single common ARM architecture port, the ARM port contains 'platform'
sub-folders in which the board/platform-specific code is situated. This
allows the sharing of common ARM port code between many different ARM
boards with different interrupt controllers, UARTs etc but which all reuse
the same common core ARM context-switching code.
This platform contains a few key platform-specific files:
* startup.s: Interrupt vector table and basic startup assembly code
* modules.c: Low level initialisation for this platform
* uart.c: Simple UART implementation for debug purposes
The common ARM architecture port that is used across all platforms contains
the basic code for thread-switching on all ARM platforms:
* 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:
* atomport.h: Port-specific header required by the kernel for each port
A couple of additional source files are also included in the common ARM port:
* tests-main.c: Main application file (used for launching automated tests)
* syscalls.c: Simple implementation of open/close/read/write for stdio
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 and quickly running the test suite
using QEMU to prove the OS without requiring any target hardware.
This platform folder has been tested on a variety of GCC ARM toolchains,
including hosted and non-hosted.
---------------------------------------------------------------------------
GCC TOOLCHAIN
The port works out-of-the-box with the GCC tools (for building) and QEMU
(for simulation). It can be built on any OS for which GCC is available, and
was tested using the CodeSourcery toolchain (2009q3 non-Linux but others
should be supported) and self-built toolchains such as hosted toolchains
built by build_arm_toolchain.sh (see http://navaro.nl for details). Note
that the Makefile for this platform assumes that your GCC binary is named
"arm-none-eabi-gcc".
Currently we assume that the toolchain will provide some header files like
stdint.h. Not all toolchains will include this, in which case you simply
need to add definitions for int32_t and friends in atomport.h, in place of
the include declaration for stdint.h.
Some toolchains provide newlib syscalls.c which implement stdio
functionality via open, close, read, write. Hosted toolchains will
automatically provide versions of these which work with QEMU, and no UART
driver will be needed to view the stdio printf()s etc. If these are not
provided by by the compiler toolchain then backup implementations are
implemented within the common ARM port folder (see ports/arm/syscalls.c)
and a UART driver is implemented here in uart.c.
Similarly some toolchains provide startup assembly code via
_mainCRTStartup(). If this is not provided by the toolchain then a backup
version is used within modules.c.
---------------------------------------------------------------------------
OTHER PREREQUISITES
QEMU is used for simulation of the target and versions 0.14.1, 1.2.0 &
1.4.0 were tested.
Running the entire automated test suite in one command via "make qemutests"
also requires the "expect" program.
---------------------------------------------------------------------------
BUILDING THE SOURCE
A Makefile is provided for building the kernel, port, platform and
automated tests. Make sure the ARM GCC toolchain is in the path
(e.g. "PATH=$PATH:/opt/arm-2009q3/bin && export path") as well as QEMU and
carry out the full build using the following:
* make all
All objects are built into the 'build' folder under
ports/arm/platforms/qemu_integrator_cp. The build process builds separate
target applications for each automated test, and appropriate ELF files can
be found in the build folder ready for running on the target or within
QEMU. 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 port documentation from this folder using:
* make doxygen
---------------------------------------------------------------------------
Integrator/CP SPECIFICS
The test applications make use of the Integrator's UART to print out
pass/fail indications and other information. For this you should connect a
serial debug cable to the board or when running in QEMU you will see the
UART messages on the console when running the test applications.
---------------------------------------------------------------------------
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.
These can be run on the target or within QEMU using the instructions below.
To view the test results, connect a serial debug cable to your target
platform or view the console if using QEMU. 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 longer, 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.
---------------------------------------------------------------------------
RUNNING TESTS WITHIN THE QEMU SIMULATOR
It is possible to run the full automated test suite in a simulator without
programming the test applications into real hardware. This is very useful
for quick verification of the entire test suite after making any software
changes, and is much faster than downloading each test application to a
real target.
A single command runs every single test application, and automatically
parses the (simulated) UART output to verify that each test case passes.
This requires two applications on your development PC: expect and QEMU.
To run all tests in one command, type:
* make qemutests
This will run every single test application within the simulator and quit
immediately if any one test fails.
The ability to run these automated tests in one command (and without real
hardware) allows you to easily include the OS test suite in your nightly
build or continous integration system and quickly find out if any of your
local changes have caused any of the operating system tests to fail.
---------------------------------------------------------------------------
DEBUGGING WITH QEMU
You may also use QEMU in combination with GDB to debug your built
applications. To do this you should start QEMU with "-S -s" options e.g.:
* qemu-system-arm -M integratorcp -semihosting -nographic -kernel app.elf
You can now start GDB and attach to the target:
* arm-none-eabi-gdb
* file app.elf
* target remote localhost:1234
---------------------------------------------------------------------------
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 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.
---------------------------------------------------------------------------

View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) 2012, Natie van Rooyen. 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.
*/
#include "modules.h"
#include <stdio.h>
#include <stdarg.h>
#include "atomport.h"
#include "atomport-private.h"
#include "atom.h"
#include "atomport.h"
#include "uart.h"
/** Imports required by C startup code */
extern unsigned long _end_text, _start_data, _end_data, _start_bss, _end_bss;
extern int main(void);
/** Board-specific registers */
ICP_TIMER_T * const board_timer_0 = (ICP_TIMER_T*)BOARD_BASE_ADDRESS_TIMER_0;
ICP_PIC_T * const board_pic = (ICP_PIC_T*)BOARD_BASE_ADDRESS_PIC;
/** TIMER0 clock speed (Hz) */
#define TIMER0_CLOCK_SPEED 40000000
/**
* \b _mainCRTStartup
*
* C startup code for environments without a suitable built-in one.
* May be provided by the compiler toolchain in some cases.
*
*/
extern void _mainCRTStartup (void) __attribute__((weak));
void _mainCRTStartup(void)
{
unsigned long *src;
#ifdef ROM
unsigned long *dst;
#endif
#ifdef ROM
// Running from ROM: copy data section to RAM
src = &_end_text;
dst = &_start_data;
while(dst < &_end_data)
*(dst++) = *(src++);
#endif
// Clear BSS
src = &_start_bss;
while(src < &_end_bss)
*(src++) = 0;
// Jump to main application entry point
main();
}
/**
* \b low_level_init
*
* Initializes the PIC and starts the system timer tick interrupt.
*
*/
int
low_level_init (void)
{
board_pic->IRQ_ENABLECLR = ICP_PIC_IRQ_TIMERINT0 ;
board_timer_0->INTCLR = 1 ;
board_pic->IRQ_ENABLESET |= ICP_PIC_IRQ_TIMERINT0 ;
/* Set the timer to go off 100 times per second (input clock speed is 40MHz) */
board_timer_0->LOAD = TIMER0_CLOCK_SPEED / SYSTEM_TICKS_PER_SEC ;
board_timer_0->BGLOAD = TIMER0_CLOCK_SPEED / SYSTEM_TICKS_PER_SEC ;
board_timer_0->CONTROL = ICP_TIMER_CONTROL_ENABLE |
ICP_TIMER_CONTROL_MODE |
ICP_TIMER_CONTROL_IE |
ICP_TIMER_CONTROL_TIMER_SIZE ;
return 0 ;
}
/**
* \b __interrupt_dispatcher
*
* Interrupt dispatcher: determines the source of the IRQ and calls
* the appropriate ISR.
*
* Currently only the OS system tick ISR is implemented.
*
* Note that any ISRs which call Atomthreads OS routines that can
* cause rescheduling of threads must be surrounded by calls to
* atomIntEnter() and atomIntExit().
*
*/
void
__interrupt_dispatcher (void)
{
unsigned int status;
/* Read STATUS register to determine the source of the interrupt */
status = board_pic->IRQ_STATUS;
/* Timer tick interrupt (call Atomthreads timer tick ISR) */
if (status | ICP_PIC_IRQ_TIMERINT0)
{
/*
* Let the Atomthreads kernel know we're about to enter an OS-aware
* interrupt handler which could cause scheduling of threads.
*/
atomIntEnter();
/* Call the OS system tick handler */
atomTimerTick();
/* Ack the interrupt */
board_timer_0->INTCLR = 0x1;
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}
}
/**
* \b null_handler
*
* Handler to catch interrupts at uninitialised vectors.
*
*/
void null_handler (void)
{
uart_write_halt ("Unhandled interrupt\n");
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2012, Natie van Rooyen. 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.
*/
#ifndef __MODULES_H__
#define __MODULES_H__
/*
* Module definitions to use with the ARM Integrator/CP (ARM926EJ-S)
*/
#include "atomport.h"
/* IO definitions (access restrictions to peripheral registers) */
#define __I volatile /*!< defines 'read only' permissions */
#define __O volatile /*!< defines 'write only' permissions */
#define __IO volatile /*!< defines 'read / write' permissions */
// *****************************************************************************
// INTEGRATORCP TIMER
// *****************************************************************************
typedef struct ICP_TIMER_S {
// offset read/write word size reset Description
__IO uint32_t LOAD ; // 0x0000 Read/write 32 0x00000000 Load value for Timer
__I uint32_t VALUE ; // 0x0004 Read 32 0xFFFFFFFF The current value for Timer
__IO uint8_t CONTROL ; // 0x0008 Read/write 8 0x20 Timer control register
__O uint32_t INTCLR ; // 0x000C Write - - Timer interrupt clear
__I uint32_t RIS ; // 0x0010 Read 1 0x0 Timer raw interrupt status
__I uint32_t MIS ; // 0x0014 Read 1 0x0 Timer masked interrupt status
__IO uint32_t BGLOAD ; // 0x0018 Read/write 32 0x00000000 Background load value for Timer
} ICP_TIMER_T, *PICP_TIMER_T ;
// -------- ICP_TIMER_LOAD : (LOAD Offset: 0x00) Load value for Timer --------
// -------- ICP_TIMER_VALUE : (LOAD Offset: 0x04) The current value for Timer --------
// -------- ICP_TIMER_CONTROL : (CONTROL Offset: 0x04) Timer control register --------
#define ICP_TIMER_CONTROL_MASK ((unsigned int)0x0F << 0) // Timer control mask
#define ICP_TIMER_CONTROL_ENABLE ((unsigned int)0x01 << 7) // Timer enable: 0 = disabled 1 = enabled.
#define ICP_TIMER_CONTROL_MODE ((unsigned int)0x01 << 6) // Timer mode: 0 = free running, counts once and then wraps to 0xFFFF 1 = periodic, reloads from load register at the end of each count..
#define ICP_TIMER_CONTROL_IE ((unsigned int)0x01 << 5) // Interrupt enable.
#define ICP_TIMER_CONTROL_R ((unsigned int)0x01 << 4) // Unused, always write as 0s.
#define ICP_TIMER_CONTROL_PRESCALE_MASK ((unsigned int)0x03 << 2) // Prescale divisor
#define ICP_TIMER_CONTROL_PRESCALE_NONE ((unsigned int)0x00 << 2) //
#define ICP_TIMER_CONTROL_PRESCALE_16 ((unsigned int)0x01 << 2) //
#define ICP_TIMER_CONTROL_PRESCALE_256 ((unsigned int)0x02 << 2) //
#define ICP_TIMER_CONTROL_TIMER_SIZE ((unsigned int)0x01 << 1) // Selects 16/32 bit counter operation: 0 = 16-bit counter (default) 1 = 32-bit counter For 16-bit mode, write the high 16 bits of the 32-bit value as 0.
#define ICP_TIMER_CONTROL_ONE_SHOT ((unsigned int)0x01 << 0) // Selects one-shot or wrapping counter mode: 0 = wrapping mode (default) 1 = one-shot mode
// -------- ICP_TIMER_INTCLR : (INTCLR Offset: 0x0C) Timer interrupt clear --------
// -------- ICP_TIMER_RIS : (RIS Offset: 0x10) Timer raw interrupt status --------
// -------- ICP_TIMER_MIS : (MIS Offset: 0x14) Timer masked interrupt status --------
#define ICP_TIMER_INT ((unsigned int)0x01 << 0) // Interrupt
// -------- ICP_TIMER_BGLOAD : (BGLOAD Offset: 0x18) Timer masked interrupt status --------
// *****************************************************************************
// INTEGRATORCP PIC
// *****************************************************************************
typedef struct ICP_PIC_S {
// offset read/write word size reset Description
__I uint32_t IRQ_STATUS ; // 0x0000 Read 22 IRQ gated interrupt status
__I uint32_t IRQ_RAWSTAT ; // 0x0004 Read 22 IRQ raw interrupt status
__IO uint32_t IRQ_ENABLESET ; // 0x0008 Read/write 22 IRQ enable set
__O uint32_t IRQ_ENABLECLR ; // 0x000C Write 22 IRQ enable clear
__IO uint32_t INT_SOFTSET ; // 0x0010 Read/write 16 Software interrupt set
__O uint32_t INT_SOFTCLR ; // 0x0014 Write 16 Software interrupt clear
uint32_t RESERVED[2] ; // 0x0018
__I uint32_t FIQ_STATUS ; // 0x0020 Read 22 FIQ gated interrupt status
__I uint32_t FIQ_RAWSTAT ; // 0x0024 Read 22 FIQ raw interrupt status
__IO uint32_t FIQ_ENABLESET ; // 0x0028 Read/write 22 FIQ enable set
__O uint32_t FIQ_ENABLECLR ; // 0x002C Write-only 22 FIQ enable clear
} ICP_PIC_T, *PICP_PIC_T ;
// -------- ICP_PIC_IRQ_STATUS : (IRQ_STATUS Offset: 0x00) IRQ gated interrupt status --------
// -------- ICP_PIC_IRQ_RAWSTAT : (IRQ_RAWSTAT Offset: 0x04) IRQ raw interrupt status --------
// -------- ICP_PIC_IRQ_ENABLESET : (IRQ_ENABLESET Offset: 0x08) IRQ enable set --------
// -------- ICP_PIC_IRQ_ENABLECLR : (IRQ_ENABLECLR Offset: 0x0C) IRQ enable clear --------
#define ICP_PIC_IRQ_MASK ((unsigned int)0x3FFFFF << 0) // IRQ mask
#define ICP_PIC_IRQ_TIMERINT2 ((unsigned int)0x01 << 7) // TIMERINT2 Counter-timer 2 interrupt
#define ICP_PIC_IRQ_TIMERINT1 ((unsigned int)0x01 << 6) // TIMERINT1 Counter-timer 1 interrupt
#define ICP_PIC_IRQ_TIMERINT0 ((unsigned int)0x01 << 5) // TIMERINT0 Counter-timer 0 interrupt
#define ICP_PIC_IRQ_SOFTINT ((unsigned int)0x01 << 0) // OFTINT Software interrupt
// -------- ICP_PIC_INT_SOFTSET : (INT_SOFTSET Offset: 0x10) Software interrupt set --------
// -------- ICP_PIC_INT_SOFTCLR : (INT_SOFTCLR Offset: 0x14) Software interrupt clear --------
/* module definitions */
#define BOARD_BASE_ADDRESS_TIMER_0 0x13000000
#define BOARD_BASE_ADDRESS_PIC 0x14000000
extern ICP_TIMER_T* const board_timer_0 ;
extern ICP_PIC_T* const board_pic ;
/* Function prototypes */
extern int low_level_init (void) ;
#endif /* __MODULES_H__ */

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env expect
# Expect script to run an automated test within QEMU and check for successful
# completion.
#
# Arguments: <path_to_qemu> <test_elf_file>
#
# Returns 0 on successful test run within QEMU, 1 on failure
# Start the test
spawn [lindex $argv 0] -M integratorcp -semihosting -nographic -kernel [lindex $argv 1]
# Expect to see the test starting within 10 seconds
set timeout 10
# Wait for the test to start ("Go")
expect {
"Go\r\n" {
puts "Test started"
# The test could take up to 3 minutes to complete once started
set timeout 180
# Now expect to see "Pass" or "Fail" within 3 minutes
expect {
"Pass\r\n" { puts "Test passed"; exit 0 }
"Fail\r\n" { puts "Test failed"; exit 1 }
timeout { puts "Test timed out without completing"; exit 1 }
}
}
timeout {
# Didn't receive "Go" within 10 seconds
puts "Test failed to start ('Go' not seen)"
exit 1
}
}

View File

@@ -0,0 +1,47 @@
.section .vectors, "x"
.global __interrupt_vector_table
.extern __irq_stack_top__
.extern __fiq_stack_top__
.extern __svc_stack_top__
.equ USR_MODE, 0x10
.equ FIQ_MODE, 0x11
.equ IRQ_MODE, 0x12
.equ SVC_MODE, 0x13
.equ ABT_MODE, 0x17
.equ UND_MODE, 0x1B
.equ SYS_MODE, 0x1F
.equ I_BIT, 0x80 /* when I bit is set, IRQ is disabled */
.equ F_BIT, 0x40 /* when F bit is set, FIQ is disabled */
__interrupt_vector_table:
B Reset_Handler /* Reset */
ldr PC,=null_handler /* Undefined */
ldr PC,=null_handler /* SWI */
ldr PC,=null_handler /* Prefetch Abort */
ldr PC,=null_handler /* Data Abort */
ldr PC,=null_handler /* reserved */
ldr PC,=archIRQHandler/* IRQ */
ldr PC,=null_handler /* FIQ */
Reset_Handler:
MSR CPSR_c,#(IRQ_MODE | I_BIT | F_BIT)
LDR sp,=__irq_stack_top__ /* set the IRQ stack pointer */
MSR CPSR_c,#(FIQ_MODE | I_BIT | F_BIT)
LDR sp,=__fiq_stack_top__ /* set the FIQ stack pointer */
MSR CPSR_c,#(SVC_MODE | I_BIT | F_BIT)
LDR sp,=__svc_stack_top__ /* set the SVC stack pointer */
BL low_level_init
BL _mainCRTStartup
B .

View File

@@ -0,0 +1,89 @@
ENTRY(__interrupt_vector_table)
MEMORY
{
flash (rx) : ORIGIN = 0x00000000, LENGTH = 0x00020000
sram (rwx) : ORIGIN = 0x00020000, LENGTH = 0x00020000
}
EXTERN(__interrupt_vector_table);
C_STACK_SIZE = 512;
IRQ_STACK_SIZE = 256;
FIQ_STACK_SIZE = 256;
SVC_STACK_SIZE = 512;
ABT_STACK_SIZE = 256;
UND_STACK_SIZE = 256;
SECTIONS
{
.text :
{
*(.vectors)
/* Startup assembly */
*(.startup)
*(.init)
/* Rest of the code (C) */
*(.text)
*(.rodata)
*(.rodata*)
_end_text = .;
} >flash
.data :
{
_start_data = .;
*(.data)
_end_data = .;
} >sram
.bss :
{
_start_bss = .;
__bss_start__ = . ;
*(.bss)
} >sram
. = ALIGN(4);
_end_bss = .;
__bss_end__ = . ;
. = ALIGN(256);
.stack : {
__stack_start__ = . ;
. += IRQ_STACK_SIZE;
. = ALIGN (4);
__irq_stack_top__ = . ;
. += FIQ_STACK_SIZE;
. = ALIGN (4);
__fiq_stack_top__ = . ;
. += SVC_STACK_SIZE;
. = ALIGN (4);
__svc_stack_top__ = . ;
. += ABT_STACK_SIZE;
. = ALIGN (4);
__abt_stack_top__ = . ;
. += UND_STACK_SIZE;
. = ALIGN (4);
__und_stack_top__ = . ;
. += C_STACK_SIZE;
. = ALIGN (4);
__c_stack_top__ = . ;
__stack_end__ = .;
} >sram
}
__end__ = .;
_end = .;
PROVIDE(end = .);
heap_top = ORIGIN(sram) + LENGTH(sram) - 4;

View File

@@ -0,0 +1,262 @@
/*
* Copyright (c) 2013, Kelvin Lawson. 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.
*/
/**
* \file
* Simple polled UART implementation for non-hosted compiler toolchains.
*
*
* This is only required for non-hosted toolchains which don't implement
* stdout automatically for use within QEMU.
*/
#include "atom.h"
#include "atommutex.h"
#include "atomport.h"
#include "uart.h"
/* Constants */
/** UART0 registers base address */
#define UART0_ADDR 0x16000000
/** FR Register bits */
#define UART_FR_RXFE 0x10
#define UART_FR_TXFF 0x20
/** UART register access macros */
#define UART_DR(baseaddr) (*(unsigned int *)(baseaddr))
#define UART_FR(baseaddr) (*(((unsigned int *)(baseaddr))+6))
/* Local data */
/*
* Semaphore for single-threaded access to UART device
*/
static ATOM_MUTEX uart_mutex;
/*
* Initialised flag
*/
static int initialised = FALSE;
/* Forward declarations */
static int uart_init (void);
/**
* \b uart_init
*
* Initialisation of UART driver. Creates a mutex that enforces
* single-threaded access to the UART. We poll register bits
* to check when space is available, which would not otherwise
* be thread-safe.
*
* @retval ATOM_OK Success
* @retval ATOM_ERROR Failed to create mutex
*/
static int uart_init (void)
{
int status;
/* Check we are not already initialised */
if (initialised == FALSE)
{
/* Create a mutex for single-threaded UART access */
if (atomMutexCreate (&uart_mutex) != ATOM_OK)
{
/* Mutex creation failed */
status = ATOM_ERROR;
}
else
{
/* Success */
initialised = TRUE;
status = ATOM_OK;
}
}
/* Already initialised */
else
{
/* Success */
status = ATOM_OK;
}
/* Finished */
return (status);
}
/**
* \b uart_read
*
* Simple polled UART read.
*
* @param[in] ptr Pointer to receive buffer
* @param[in] len Max bytes to read
*
* @retval Number of bytes read
*
*/
int uart_read (char *ptr, int len)
{
int todo = 0;
/* Check we are initialised */
if (initialised == FALSE)
{
uart_init();
}
/* Check parameters */
if ((ptr == NULL) || (len == 0))
{
return 0;
}
/* Block thread on private access to the UART */
if (atomMutexGet(&uart_mutex, 0) == ATOM_OK)
{
/* Wait for not-empty */
while(UART_FR(UART0_ADDR) & UART_FR_RXFE)
;
/* Read first byte */
*ptr++ = UART_DR(UART0_ADDR);
/* Loop over remaining bytes until empty */
for (todo = 1; todo < len; todo++)
{
/* Quit if receive FIFO empty */
if(UART_FR(UART0_ADDR) & UART_FR_RXFE)
{
break;
}
/* Read next byte */
*ptr++ = UART_DR(UART0_ADDR);
}
/* Return mutex access */
atomMutexPut(&uart_mutex);
}
/* Return number of bytes read */
return todo;
}
/**
* \b uart_write
*
* Simple polled UART write.
*
* @param[in] ptr Pointer to write buffer
* @param[in] len Number of bytes to write
*
* @retval Number of bytes written
*/
int uart_write (const char *ptr, int len)
{
int todo;
/* Check we are initialised */
if (initialised == FALSE)
{
uart_init();
}
/* Check parameters */
if ((ptr == NULL) || (len == 0))
{
return 0;
}
/* Block thread on private access to the UART */
if (atomMutexGet(&uart_mutex, 0) == ATOM_OK)
{
/* Loop through all bytes to write */
for (todo = 0; todo < len; todo++)
{
/* Wait for empty */
while(UART_FR(UART0_ADDR) & UART_FR_TXFF)
;
/* Write byte to UART */
UART_DR(UART0_ADDR) = *ptr++;
}
/* Return mutex access */
atomMutexPut(&uart_mutex);
}
/* Return bytes-written count */
return len;
}
/**
* \b uart_write_halt
*
* Simple polled UART write for handling critical failures
* by printing out a message on the UART and looping forever.
* Can be called from interrupt (unlike the standard
* uart_write()) but is not thread-safe because it cannot
* take the thread-safety mutex, and hence is only useful for
* a last-resort catastrophic debug message.
*
* @param[in] ptr Pointer to write string
*/
void uart_write_halt (const char *ptr)
{
/* Check parameters */
if (ptr != NULL)
{
/* Loop through all bytes until NULL terminator encountered */
while (*ptr != '\0')
{
/* Wait for empty */
while(UART_FR(UART0_ADDR) & UART_FR_TXFF)
;
/* Write byte to UART */
UART_DR(UART0_ADDR) = *ptr++;
}
}
/* Loop forever */
while (1)
;
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2013, Kelvin Lawson. 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.
*/
#ifndef __ATOM_UART_H
#define __ATOM_UART_H
/* UART driver APIs */
extern int uart_read (char *ptr, int len);
extern int uart_write (const char *ptr, int len);
extern void uart_write_halt (const char *ptr);
#endif /* __ATOM_UART_H */

230
ports/arm/syscalls.c Normal file
View File

@@ -0,0 +1,230 @@
/*
* Copyright (c) 2013, Kelvin Lawson. 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.
*/
/**
* \file
* Syscalls implementation for stdio and heap management.
*
*
* Simple implementation of syscalls.c for ARM compiler toolchains built
* without newlib. Allows usage of printf() and friends as well as heap
* allocation.
*
* NOTE: Platform/BSP must implement uart_read() and uart_write().
*
* NOTE: Platform/BSP linker script must define "end" and "heap_top" which are
* the heap base and top respectively.
*
* No file table is implemented. All file read/write operations are carried
* out on the UART driver, regardless of file descriptor.
*
* Mostly based on code from http://balau82.wordpress.com
*
*/
#include <sys/stat.h>
#include "uart.h"
/**
* Define all functions as weak so that the functions in this file will
* only be used if the compiler toolchain doesn't already provide them.
*/
extern int _close(int file) __attribute__((weak));
extern int _fstat(int file, struct stat *st) __attribute__((weak));
extern int _isatty(int file) __attribute__((weak));
extern int _lseek(int file, int ptr, int dir) __attribute__((weak));
extern int _open(const char *name, int flags, int mode) __attribute__((weak));
extern int _read(int file, char *ptr, int len) __attribute__((weak));
extern caddr_t _sbrk(int incr) __attribute__((weak));
extern int _write(int file, char *ptr, int len) __attribute__((weak));
extern int _exit(int val) __attribute__((weak));
/**
* \b _close
*
* Simple stub implementation with no file table. All parameters ignored.
*
*/
int _close(int file)
{
return 0;
}
/**
* \b _fstat
*
* Simple stub implementation. Always return character device.
*
*/
int _fstat(int file, struct stat *st)
{
/* Only UART supported, always return character-oriented device file */
st->st_mode = S_IFCHR;
return 0;
}
/**
* \b _isatty
*
* Simple stub implementation. Only UART supported so TTY always true.
*
*/
int _isatty(int file)
{
return 1;
}
/**
* \b _lseek
*
* Simple stub implementation. All parameters ignored.
*
*/
int _lseek(int file, int ptr, int dir)
{
return 0;
}
/**
* \b _open
*
* Simple stub implementation with no file table. All parameters ignored.
*
* We only support reading/writing to the UART, so we don't bother inspecting
* the filename to decide which underlying device to use, _read() and _write()
* only access the UART driver.
*
* This is currently only called once (each thread opens its own stdout when
* it starts executing).
*
*/
int _open(const char *name, int flags, int mode)
{
return 0;
}
/**
* \b _read
*
* Simple read file implementation. Ignores file descriptor parameter
* and always reads from the UART driver.
*
* @param[in] file File descriptor (parameter ignored)
* @param[in] ptr Pointer to receive buffer
* @param[in] len Max bytes to read
*
* @retval Number of bytes read
*/
int _read(int file, char *ptr, int len)
{
/* Read from the UART driver, regardless of file descriptor */
return (uart_read (ptr, len));
}
/**
* \b _write
*
* Simple write file implementation. Ignores file descriptor parameter
* and always writes to the UART driver.
*
* @param[in] file File descriptor (parameter ignored)
* @param[in] ptr Pointer to write buffer
* @param[in] len Number of bytes to write
*
* @retval Number of bytes written
*/
int _write(int file, char *ptr, int len)
{
/* Write to the UART driver, regardless of file descriptor */
return (uart_write (ptr, len));
}
/**
* \b _sbrk
*
* Simple heap implementation.
*
* The platform/BSP must define "end" and "heap_top" which are the heap
* base and top respectively.
*
* @param[in] incr Chunk size
*
* @retval Pointer to allocated chunk start
*/
caddr_t _sbrk(int incr)
{
extern char end; /* Defined by the linker */
extern char heap_top; /* Defined by the linker */
static char *heap_end = 0;
char *prev_heap_end;
/* First time in, initialise heap base using definition from linker script */
if (heap_end == 0)
{
heap_end = &end;
}
/* Save the previous heap base */
prev_heap_end = heap_end;
/* Check we have not passed the heap top */
if (heap_end + incr > &heap_top)
{
/* Heap top reached, failed to allocate */
return (caddr_t)0;
}
/* New heap base */
heap_end += incr;
/* Return pointer to previous base (where our allocation starts) */
return (caddr_t)prev_heap_end;
}
/**
* \b _exit
*
* Simple stub implementation, exit() not needed or implemented.
*
*/
int _exit(int val)
{
return -1;
}

203
ports/arm/tests-main.c Normal file
View File

@@ -0,0 +1,203 @@
/*
* Copyright (c) 2013, Kelvin Lawson. 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.
*/
#include <stdio.h>
#include "atom.h"
#include "atomport-private.h"
#include "atomtests.h"
#include "atomtimer.h"
/* Constants */
/*
* Idle thread stack size
*
* This needs to be large enough to handle any interrupt handlers
* and callbacks called by interrupt handlers (e.g. user-created
* timer callbacks) as well as the saving of all context when
* switching away from this thread.
*/
#define IDLE_STACK_SIZE_BYTES 512
/*
* Main thread stack size
*
* Note that this is not a required OS kernel thread - you will replace
* this with your own application thread.
*
* In this case the Main thread is responsible for calling out to the
* test routines. Once a test routine has finished, the test status is
* printed out on the UART and the thread remains running in a loop.
*
* The Main thread stack generally needs to be larger than the idle
* thread stack, as not only does it need to store interrupt handler
* stack saves and context switch saves, but the application main thread
* will generally be carrying out more nested function calls and require
* stack for application code local variables etc.
*
* 1KB might be adequate but if using printf() then at least 2KB would be
* prudent otherwise the stdio functions otherwise stack overruns are
* likely. Nearly 2KB was seen to be used on the toolchain used for
* development.
*/
#define MAIN_STACK_SIZE_BYTES 4096
/* Local data */
/* Application threads' TCBs */
static ATOM_TCB main_tcb;
/* Main thread's stack area */
static uint8_t main_thread_stack[MAIN_STACK_SIZE_BYTES];
/* Idle thread's stack area */
static uint8_t idle_thread_stack[IDLE_STACK_SIZE_BYTES];
/* Forward declarations */
static void main_thread_func (uint32_t data);
/**
* \b main
*
* Program entry point.
*
* Creates an application thread and starts the OS.
*/
int main ( void )
{
int8_t status;
/**
* Note: to protect OS structures and data during initialisation,
* interrupts must remain disabled until the first thread
* has been restored. They are reenabled at the very end of
* the first thread restore, at which point it is safe for a
* reschedule to take place.
*/
/**
* Initialise the OS before creating our threads.
*/
status = atomOSInit(&idle_thread_stack[0], IDLE_STACK_SIZE_BYTES, TRUE);
if (status == ATOM_OK)
{
/* Create an application thread */
status = atomThreadCreate(&main_tcb,
TEST_THREAD_PRIO, main_thread_func, 0,
&main_thread_stack[0],
MAIN_STACK_SIZE_BYTES,
TRUE);
if (status == ATOM_OK)
{
/**
* First application thread successfully created. It is
* now possible to start the OS. Execution will not return
* from atomOSStart(), which will restore the context of
* our application thread and start executing it.
*
* Note that interrupts are still disabled at this point.
* They will be enabled as we restore and execute our first
* thread in archFirstThreadRestore().
*/
atomOSStart();
}
}
while (1)
;
/* There was an error starting the OS if we reach here */
return (0);
}
/**
* \b main_thread_func
*
* Entry point for main application thread.
*
* This is the first thread that will be executed when the OS is started.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void main_thread_func (uint32_t data)
{
uint32_t test_status;
/* Put a message out on the UART */
printf ("Go\n");
/* Start test. All tests use the same start API. */
test_status = test_start();
/* Check main thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
if (test_status == 0)
{
uint32_t used_bytes, free_bytes;
/* Check idle thread stack usage */
if (atomThreadStackCheck (&main_tcb, &used_bytes, &free_bytes) == ATOM_OK)
{
/* Check the thread did not use up to the end of stack */
if (free_bytes == 0)
{
printf ("Main stack overflow\n");
test_status++;
}
/* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
printf ("MainUse:%d\n", (int)used_bytes);
#endif
}
}
#endif
/* Log final status */
if (test_status == 0)
{
printf ("Pass\n");
}
else
{
printf ("Fail(%d)\n", (int)test_status);
}
}

View File

@@ -15,7 +15,7 @@ CC=/usr/bin/avr-gcc
OBJCOPY=/usr/bin/avr-objcopy
SIZE=/usr/bin/avr-size
UISP=/usr/bin/uisp
SIMAVR=/tmp/run_avr
SIMAVR=/usr/local/bin/simavr
# Modify this to the device name of the UART used for UISP
UISP_DEV=/dev/ttyUSB0
@@ -36,7 +36,7 @@ PART=atmega16
BUILD_DIR=build
# Port/application object files
APP_OBJECTS = atomport.o uart.o tests-main.o
APP_OBJECTS = atomport.o atomport-private.o uart.o tests-main.o
APP_ASM_OBJECTS = atomport-asm.o
# Kernel object files

View File

@@ -27,7 +27,7 @@ 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
* atomport.h: Port-specific header required by the kernel for each port
A couple of additional source files are also included here:

View File

@@ -148,7 +148,7 @@ archContextSwitch:
mov r28,r24 /* Move old_tcb_ptr param into the Y-regs so we */
mov r29,r25 /* can access the TCB via a pointer. */
st Y,r16 /* Store SPH/SPL to old_tcb_ptr->tcb_save_ptr which */
st Y,r16 /* Store SPH/SPL to old_tcb_ptr->sp_save_ptr which */
std Y+1,r17 /* is conveniently the first member of the TCB. */

View File

@@ -0,0 +1,90 @@
#include <avr/interrupt.h>
#include "atom.h"
#include "atomport-private.h"
/**
* \b avrInitSystemTickTimer
*
* Initialise the system tick timer. Uses the AVR's timer1 facility.
*
* @return None
*/
void avrInitSystemTickTimer ( void )
{
/* Set timer 1 compare match value for configured system tick,
* with a prescaler of 256. We will get a compare match 1A
* interrupt on every system tick, in which we must call the
* OS's system tick handler. */
OCR1A = (AVR_CPU_HZ / 256 / SYSTEM_TICKS_PER_SEC);
/* Enable compare match 1A interrupt */
#ifdef TIMSK
TIMSK = _BV(OCIE1A);
#else
TIMSK1 = _BV(OCIE1A);
#endif
/* Set prescaler 256 */
TCCR1B = _BV(CS12) | _BV(WGM12);
}
/**
*
* System tick ISR.
*
* This is responsible for regularly calling the OS system tick handler.
* The system tick handler checks if any timer callbacks are necessary,
* and runs the scheduler.
*
* The compiler automatically saves all registers necessary before calling
* out to a C routine. This will be (at least) R0, R1, SREG, R18-R27 and
* R30/R31.
*
* The system may decide to schedule in a new thread during the call to
* atomTimerTick(), in which case around half of the thread's context will
* already have been saved here, ready for when we return here when the
* interrupted thread is scheduled back in. The remaining context will be
* saved by the context switch routine.
*
* As with all interrupts, the ISR should call atomIntEnter() and
* atomIntExit() on entry and exit. This serves two purposes:
*
* a) To notify the OS that it is running in interrupt context
* b) To defer the scheduler until after the ISR is completed
*
* We defer all scheduling decisions until after the ISR has completed
* in case the interrupt handler makes more than one thread ready.
*
* @return None
*/
ISR (TIMER1_COMPA_vect)
{
/* Call the interrupt entry routine */
atomIntEnter();
/* Call the OS system tick handler */
atomTimerTick();
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}
/**
*
* Default (no handler installed) ISR.
*
* Installs a default handler to be called if any interrupts occur for
* which we have not registered an ISR. This is empty and has only been
* included to handle user-created code which may enable interrupts. The
* core OS does not enable any interrupts other than the system timer
* tick interrupt.
*
* @return None
*/
ISR (BADISR_vect)
{
/* Empty */
}

View File

@@ -31,9 +31,21 @@
#define __ATOM_PORT_PRIVATE_H
/* CPU Frequency */
#ifdef F_CPU
#define AVR_CPU_HZ F_CPU
#else
#define AVR_CPU_HZ 1000000
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Function prototypes */
void avrInitSystemTickTimer ( void );
#ifdef __cplusplus
}
#endif
#endif /* __ATOM_PORT_PRIVATE_H */

View File

@@ -28,10 +28,7 @@
*/
#include <avr/interrupt.h>
#include "atom.h"
#include "atomport-private.h"
/** Forward declarations */
@@ -111,8 +108,9 @@ static void thread_shell (void)
curr_tcb->entry_point(curr_tcb->entry_param);
}
/* Not reached - threads should never return from the entry point */
/* Thread has run to completion: remove it from the ready list */
curr_tcb->terminated = TRUE;
atomSched (FALSE);
}
@@ -267,89 +265,3 @@ void archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_poi
}
/**
* \b avrInitSystemTickTimer
*
* Initialise the system tick timer. Uses the AVR's timer1 facility.
*
* @return None
*/
void avrInitSystemTickTimer ( void )
{
/* Set timer 1 compare match value for configured system tick,
* with a prescaler of 256. We will get a compare match 1A
* interrupt on every system tick, in which we must call the
* OS's system tick handler. */
OCR1A = (AVR_CPU_HZ / 256 / SYSTEM_TICKS_PER_SEC);
/* Enable compare match 1A interrupt */
#ifdef TIMSK
TIMSK = _BV(OCIE1A);
#else
TIMSK1 = _BV(OCIE1A);
#endif
/* Set prescaler 256 */
TCCR1B = _BV(CS12) | _BV(WGM12);
}
/**
*
* System tick ISR.
*
* This is responsible for regularly calling the OS system tick handler.
* The system tick handler checks if any timer callbacks are necessary,
* and runs the scheduler.
*
* The compiler automatically saves all registers necessary before calling
* out to a C routine. This will be (at least) R0, R1, SREG, R18-R27 and
* R30/R31.
*
* The system may decide to schedule in a new thread during the call to
* atomTimerTick(), in which case around half of the thread's context will
* already have been saved here, ready for when we return here when the
* interrupted thread is scheduled back in. The remaining context will be
* saved by the context switch routine.
*
* As with all interrupts, the ISR should call atomIntEnter() and
* atomIntExit() on entry and exit. This serves two purposes:
*
* a) To notify the OS that it is running in interrupt context
* b) To defer the scheduler until after the ISR is completed
*
* We defer all scheduling decisions until after the ISR has completed
* in case the interrupt handler makes more than one thread ready.
*
* @return None
*/
ISR (TIMER1_COMPA_vect)
{
/* Call the interrupt entry routine */
atomIntEnter();
/* Call the OS system tick handler */
atomTimerTick();
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}
/**
*
* Default (no handler installed) ISR.
*
* Installs a default handler to be called if any interrupts occur for
* which we have not registered an ISR. This is empty and has only been
* included to handle user-created code which may enable interrupts. The
* core OS does not enable any interrupts other than the system timer
* tick interrupt.
*
* @return None
*/
ISR (BADISR_vect)
{
/* Empty */
}

View File

@@ -45,6 +45,8 @@
#endif
/* Local data */
/*
* Semaphore for single-threaded access to UART device
*/

View File

@@ -13,6 +13,9 @@
#include "atom.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Perform UART startup initialization.
@@ -23,3 +26,7 @@ int uart_init(uint32_t baudrate);
* Send one character to the UART.
*/
int uart_putchar(char c, FILE *stream);
#ifdef __cplusplus
}
#endif

395
ports/cortex-m/Makefile Normal file
View File

@@ -0,0 +1,395 @@
################################################
# Toplevel makefile for all Cortex-M targets #
################################################
ifeq ($(V),)
Q := @
# Do not print "Entering directory ...".
MAKEFLAGS += --no-print-directory
endif
# Use the size optimised nano version of newlib.
# This usually is the version of newlib you want to use, although it has some
# limitations, like printf not having support for floating point vars.
# This relies on your newlib installation to provide a working nano.specs
# file. On Debian you will need at least version 2.1.0+git20141201.db59ff3-2
# of package libnewlib-arm-none-eabi
USE_NANO := true
# Debian's libnewlib-arm-none-eabi package version 2.2.0+git20150830.5a3d536-1
# ships with a buggy nano.specs file that does not set up a proper include
# path for finding the nano version of newlib.h.
# Also, the nano version has been built with the -fshort-wchar option, making
# it incompatible with object files using the standard ABI. By enabling this
# option atomthreads and libopencm3 will also be compiled with -fshort-wchar.
#FIX_DEBIAN := true
# Build directory
ifdef O
build_dir=$(shell readlink -f $(O))
else
build_dir=$(CURDIR)/build
endif
# Source directory
src_dir=$(CURDIR)
# Clean object list before including board makefile
objs :=
aobjs :=
# set default board if none is given
ifeq ($(BOARD),)
BOARD = nucleo-f103rb
endif
include $(src_dir)/boards/$(BOARD)/Makefile.include
# Make sure target MCU is set
ifndef TARGET
$(error TARGET undefined)
endif
# Configure toolchain
CROSS_COMPILE ?= arm-none-eabi-
CC := $(CROSS_COMPILE)gcc
CXX := $(CROSS_COMPILE)g++
LD := $(CROSS_COMPILE)gcc
AR := $(CROSS_COMPILE)ar
AS := $(CROSS_COMPILE)as
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
GDB := $(CROSS_COMPILE)gdb
STFLASH = $(shell which st-flash)
LDSCRIPT ?= linker/$(TARGET).ld
# Enable stack-checking. WARNING: the full automated test suite currently
# requires a little over 1KB RAM with stack-checking enabled. If you are
# using a device with 1KB internal SRAM and no external SRAM then you
# must disable stack-checking to run all of the automated tests.
#STACK_CHECK=true
# Location of atomthreads sources
board_dir=$(src_dir)/boards/$(BOARD)
common_dir=$(src_dir)/common
kernel_dir=$(src_dir)/../../kernel
tests_dir=$(src_dir)/../../tests
# Check if user wants to use external opencm3 lib or if we have to build
# it ourselves
ifeq ($(OPENCM3_DIR),)
OPENCM3_DIR = $(src_dir)/libopencm3
build_lib = true
endif
ifneq ($(V),)
$(info Using $(OPENCM3_DIR) as path to opencm3 library)
endif
# Object files needed by all applications
objs += atomport.o
objs += atomport-asm.o
# Kernel object files
objs += atomkernel.o
objs += atomsem.o
objs += atommutex.o
objs += atomtimer.o
objs += atomqueue.o
# Collection of built objects (excluding test applications)
build_objs = $(foreach obj,$(objs),$(build_dir)/$(obj))
# Object needed by all test applications, but not user apps
tmobjs = tests-main.o
build_tmobjs = $(foreach obj,$(tmobjs),$(build_dir)/$(obj))
build_tmobjs += $(build_objs)
# Set up search paths for libopencm3
INCLUDE_DIR = $(OPENCM3_DIR)/include
LIB_DIR = $(OPENCM3_DIR)/lib
SCRIPT_DIR = $(OPENCM3_DIR)/scripts
# GCC flags
CFLAGS = -Os -g
CFLAGS += -Wall -Werror
CFLAGS += -Wredundant-decls -Wstrict-prototypes
CFLAGS += -fno-common -ffunction-sections -fdata-sections
# Enable stack-checking (disable if not required)
ifeq ($(STACK_CHECK),true)
CFLAGS += -DATOM_STACK_CHECKING -DTESTS_LOG_STACK_USAGE
endif
# C & C++ preprocessor common flags
CPPFLAGS += -MD
CPPFLAGS += -Wall -Wundef -Werror
CPPFLAGS += -I$(INCLUDE_DIR) $(DEFS)
CPPFLAGS += -I$(board_dir) -I$(common_dir) -I$(src_dir) -I$(kernel_dir) -I$(tests_dir)
# Assembler flags
ASFLAGS += -D__ASSEMBLY__
ASFLAGS += -D__NEWLIB__
# Linker flags
LDFLAGS += --static -nostartfiles
LDFLAGS += -L$(LIB_DIR)
LDFLAGS += -T$(LDSCRIPT)
LDFLAGS += -Wl,-Map=$(build_dir)/$(*).map
LDFLAGS += -Wl,--gc-sections
LDFLAGS += -Wl,--fatal-warnings
ifeq ($(V),99)
LDFLAGS += -Wl,--print-gc-sections
endif
## Used libraries
# Target specific version libopencm3
LDLIBS += -l$(LIBNAME)
## Gather newlib libraries and set up specfiles.
NEWLIBS += -lc -lgcc
ifneq ($(BOARD),qemu)
ifeq ($(USE_NANO),true)
SPECS := -specs=nano.specs
ifeq ($(FIX_DEBIAN),true)
SPECS += -I/usr/include/newlib/nano
LOCM3_FLAGS += -fshort-wchar
CFLAGS += -fshort-wchar
endif
endif
# Uncomment to link against libnosys if you do not want to use the provided
# stubs.
# Be advised that heap management will probably break in interesting ways.
# This is because libnosys' standard _sbrk() expects the stack to start at
# the top end of memory while the threads' stacks are positioned inside
# the BSS.
#NEWLIBS += -lnosys
else
# Special LDLIBS for qemu target to enable semi-hosting.
# TODO: Check if this is also useful for real hardware
NEWLIBS += -lrdimon
SPECS := -specs=rdimon.specs
endif
# add all required newlib libraries as a group
LDLIBS += -Wl,--start-group $(NEWLIBS) -Wl,--end-group
.PHONY: all
all: build_all
# Generate a direct make target for a test application
define build_test
.PHONY: $(1)
$(1): $(build_dir)/$(1).elf
endef
# Target application filenames .elf for each test object
tobjs = $(notdir $(patsubst %.c,%.o,$(wildcard $(tests_dir)/*.c)))
telfs = $(patsubst %.o,%.elf,$(tobjs))
tbins = $(patsubst %.o,%.bin,$(tobjs))
thexs = $(patsubst %.o,%.hex,$(tobjs))
build_tobjs = $(foreach tobj,$(tobjs),$(build_dir)/$(tobj))
build_telfs = $(foreach telf,$(telfs),$(build_dir)/$(telf))
build_tbins = $(foreach tbin,$(tbins),$(build_dir)/$(tbin))
build_thexs = $(foreach thex,$(thexs),$(build_dir)/$(thex))
# Add a direct make target for every test app
$(foreach test,$(patsubst %.o,%,$(tobjs)),$(eval $(call build_test,$(test))))
# Define an explicit target and linker rule for an application not in the
# test suite. This will be a stand-alone applications located in the board
# or common directory
define build_app
.PHONY: $(1)
$(1): $(build_dir)/$(1).elf
$(build_dir)/$(1).elf $(build_dir)/$(1).map: $(LIB_DIR)/lib$(LIBNAME).a $(build_dir)/$(1).o $(build_objs) $(LDSCRIPT)
$$(Q)mkdir -p `dirname $$@`
$$(if $$(Q), @echo " (ELF) $$(subst $$(build_dir)/,,$$@)")
$$(Q)$$(LD) $$(SPECS) $$(LDFLAGS) $$(ARCH_FLAGS) $$(build_objs) $$(build_dir)/$(1).o $(LDLIBS) -o $$@
endef
# Target application filenames .elf for each user app object
aelfs = $(patsubst %.o,%.elf,$(aobjs))
abins = $(patsubst %.o,%.bin,$(aobjs))
ahexs = $(patsubst %.o,%.hex,$(aobjs))
build_aobjs = $(foreach aobj,$(aobjs),$(build_dir)/$(aobj))
build_aelfs = $(foreach aelf,$(aelfs),$(build_dir)/$(aelf))
build_abins = $(foreach abin,$(abins),$(build_dir)/$(abin))
build_ahexs = $(foreach ahex,$(ahexs),$(build_dir)/$(ahex))
# add a direct make target for every standalone app
$(foreach app,$(patsubst %.o,%,$(aobjs)),$(eval $(call build_app,$(app))))
# Build all test and user applications
all_bins = $(build_tbins) $(build_abins)
all_hexs = $(build_thexs) $(build_ahexs)
all_elfs = $(build_telfs) $(build_aelfs)
all_objs = $(build_tobjs) $(build_aobjs) $(build_tmobjs)
.PHONY: build_all
build_all: $(LIB_DIR)/lib$(LIBNAME).a $(all_bins) $(all_hexs) $(all_elfs) $(all_objs) Makefile $(board_dir)/Makefile.include
# Add build dependency for local libopencm3 if no external libopencm3 is used
ifeq ($(build_lib),true)
$(LIB_DIR)/lib$(LIBNAME).a:
$(Q)if [ ! -f libopencm3/Makefile ] ; then \
printf "######## ERROR ########\n"; \
printf "\tlibopencm3 is not initialized.\n"; \
printf "\tPlease run:\n"; \
printf "\t$$ git submodule init\n"; \
printf "\t$$ git submodule update\n"; \
printf "\tbefore running make.\n"; \
printf "######## ERROR ########\n"; \
exit 1; \
fi
$(Q)$(MAKE) -C libopencm3 V=$(V) CFLAGS=$(LOCM3_FLAGS)
endif
$(build_dir)/%.bin: $(build_dir)/%.elf
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (OBJCOPY) $(subst $(build_dir)/,,$@)")
$(Q)$(OBJCOPY) -O binary $< $@
$(build_dir)/%.hex: $(build_dir)/%.elf
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (OBJCOPY) $(subst $(build_dir)/,,$@)")
$(Q)$(OBJCOPY) -O ihex $< $@
$(build_dir)/%.srec: $(build_dir)/%.elf
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (OBJCOPY) $(subst $(build_dir)/,,$@)")
$(Q)$(OBJCOPY) -O srec $< $@
$(build_dir)/%.list: $(build_dir)/%.elf
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (OBJDUMP) $(subst $(build_dir)/,,$@)")
$(Q)$(OBJDUMP) -S $< > $@
# This is the default rule for linking the test suite applications.
# User applications defined in a board Makefile fragment are linked
# by an explicitly generated rule.
$(build_dir)/%.elf $(build_dir)/%.map: $(LIB_DIR)/lib$(LIBNAME).a $(build_dir)/%.o $(build_tmobjs) $(LDSCRIPT)
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (ELF) $(subst $(build_dir)/,,$@)")
$(Q)$(LD) $(SPECS) $(LDFLAGS) $(ARCH_FLAGS) $(build_tmobjs) $(build_dir)/$(*).o $(LDLIBS) -o $@
$(build_dir)/%.o: $(src_dir)/%.S Makefile $(board_dir)/Makefile.include
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (AS) $(subst $(build_dir)/,,$@)")
$(Q)$(CC) $(SPECS) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) $(ASFLAGS) -I`dirname $<` -c $< -o $@
$(build_dir)/%.o: $(src_dir)/%.c Makefile $(board_dir)/Makefile.include
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (CC) $(subst $(build_dir)/,,$@)")
$(Q)$(CC) $(SPECS) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -I`dirname $<` -c $< -o $@
$(build_dir)/%.o: $(board_dir)/%.S Makefile $(board_dir)/Makefile.include
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (AS) $(subst $(build_dir)/,,$@)")
$(Q)$(CC) $(SPECS) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) $(ASFLAGS) -I`dirname $<` -c $< -o $@
$(build_dir)/%.o: $(board_dir)/%.c Makefile $(board_dir)/Makefile.include
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (CC) $(subst $(build_dir)/,,$@)")
$(Q)$(CC) $(SPECS) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -I`dirname $<` -c $< -o $@
$(build_dir)/%.o: $(common_dir)/%.S Makefile $(board_dir)/Makefile.include
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (AS) $(subst $(build_dir)/,,$@)")
$(Q)$(CC) $(SPECS) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) $(ASFLAGS) -I`dirname $<` -c $< -o $@
$(build_dir)/%.o: $(common_dir)/%.c Makefile $(board_dir)/Makefile.include
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (CC) $(subst $(build_dir)/,,$@)")
$(Q)$(CC) $(SPECS) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -I`dirname $<` -c $< -o $@
$(build_dir)/%.o: $(kernel_dir)/%.c Makefile $(board_dir)/Makefile.include
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (CC) $(subst $(build_dir)/,,$@)")
$(Q)$(CC) $(SPECS) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -I`dirname $<` -c $< -o $@
$(build_dir)/%.o: $(tests_dir)/%.c Makefile $(board_dir)/Makefile.include
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (CC) $(subst $(build_dir)/,,$@)")
$(Q)$(CC) $(SPECS) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -I`dirname $<` -c $< -o $@
# Clean. Remove only atomthread's object files and images
.PHONY: clean
clean:
rm -rf doxygen-kernel
rm -rf doxygen-opencm3
rm -rf $(build_dir)
# Real clean. Also clean libopencm3 if it was built in tree
.PHONY: realclean
realclean: clean
ifeq ($(build_lib),true)
$(Q)$(MAKE) -C libopencm3 V=$(V) clean
endif
# Docs
.PHONY: doxygen
doxygen:
doxygen $(kernel_dir)/Doxyfile
ifeq ($(build_lib),true)
$(Q)$(MAKE) -C libopencm3 V=$(V) doc
endif
#################################################################################
# Target flashing recipes "borrowed" from libopencm3-examples. Mostly untested. #
#################################################################################
%.stlink-flash: $(build_dir)/%.bin
$(if $(Q), @echo " (FLASH) $(subst $(build_dir)/,,$<)")
$(Q)$(STFLASH) write $< 0x8000000
ifeq ($(STLINK_PORT),)
ifeq ($(BMP_PORT),)
ifeq ($(OOCD_SERIAL),)
%.flash: $(build_dir)/%.hex
$(if $(Q), @echo " (FLASH) $(subst $(build_dir)/,,$<)")
@# IMPORTANT: Don't use "resume", only "reset" will work correctly!
-$(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \
-f board/$(OOCD_BOARD).cfg \
-c "init" -c "reset init" \
-c "flash write_image erase $<" \
-c "reset" \
-c "shutdown" $(NULL)
else
%.flash: $(build_dir)/%.hex
$(if $(Q), @echo " (FLASH) $(subst $(build_dir)/,,$<)")
@# IMPORTANT: Don't use "resume", only "reset" will work correctly!
-$(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \
-f board/$(OOCD_BOARD).cfg \
-c "ft2232_serial $(OOCD_SERIAL)" \
-c "init" -c "reset init" \
-c "flash write_image erase $<" \
-c "reset" \
-c "shutdown" $(NULL)
endif
else
%.flash: $(build_dir)/%.elf
$(if $(Q), @echo " (GDB) $(subst $(build_dir)/,,$<)")
$(Q)$(GDB) --batch \
-ex 'target extended-remote $(BMP_PORT)' \
-x $(SCRIPT_DIR)/black_magic_probe_flash.scr \
$<
endif
else
%.flash: $(build_dir)/%.elf
$(if $(Q), @echo " (GDB) $(subst $(build_dir)/,,$<)")
$(Q)$(GDB) --batch \
-ex 'target extended-remote $(STLINK_PORT)' \
-x $(SCRIPT_DIR)/stlink_flash.scr \
$<
endif
# Include auto-generated dependencies
-include $(all_objs:.o=.d)

238
ports/cortex-m/README.md Normal file
View File

@@ -0,0 +1,238 @@
# ARM Cortex-M Port
Author: Tido Klaassen <tido@4gh.eu>
License: BSD Revised. Needs libopencm3, which is LGPLv3.
## Summary and Prerequisites
This port should run on any Cortex-M0/3/4/4F (M0+ not tested).
It uses RedHat's [newlib](https://sourceware.org/newlib/) and [libopencm3]
(https://github.com/libopencm3/libopencm3). You will also need an ARM compiler
toolchain. If you want to flash or debug your target, [openocd](http://openocd.org)
is also a must. For STM32 targets [stlink](https://github.com/texane/stlink)
might be helpful.
On Debian systems, compiler, newlib and openocd can easily be installed by the
package manager (untested, not going to set up a new system just to test this):
```
apt-get install gcc-arm-none-eabi binutils-arm-none-eabi
apt-get install libnewlib-arm-none-eabi libnewlib-dev
apt-get install openocd
```
**N.B.** Usually you will want to compile and link against the size optimised
"nano" version of newlib. This is done by default. If your version
of newlib does not support this (Debian's libnewlib package version before
2.1.0+git20141201.db59ff3-2) you will have to comment out the line
`USE_NANO := true` in the Makefile or pass `USE_NANO=` as
a command line option to make.
**N.B.** Debian's libnewlib-arm-none-eabi version 2.2.0+git20150830.5a3d536-1
ships with broken nano support. To enable necessary workarounds, uncomment
the line `#FIX_DEBIAN := true` in the Makefile or pass `FIX_DEBIAN=true`
as a command line option to make.
If you are using this fix, be advised that when switching between nano
and regular builds, you will have to do a `make realclean` first.
## Code Layout
The "classic" port components (code needed for task set-up and context
switching and the atomport{-private}.h headers) are residing in the
top level port directory.
There are additional subdirectories:
* **boards** contains subdirectories for specific hardware. Each
board needs at least a Makefile fragment, which defines certain variables
describing the hardware used, as well as a list of extra object files needed.
There will usually be at least a `board_setup.c`, which contains code to
initialise the hardware properly (clocks, UART, systick timer, GPIOs, etc.).
* **common** contains code needed by multiple boards, such as
stub functions for newlib or routines shared by multiple boards using the
same family of target MCUs.
* **linker** contains linker script fragments for specific target MCUs. These
just define the target's memory areas (RAM, Flash) and include libopencm3's
main linker script for the appropriate chip family.
* **libopencm3** unless you compile and link against an external installation
of libopencm3, this will be a Git submodule containing, surprise!, libopencm3.
* **build** this is a temporary directory where all object files end up in and
which will be removed by `make clean`.
## Build Preparation
Unless you decide to use an external installation of libopencm3, you will have
to set up the libopencm3 sub-module:
```
git submodule init
git submodule update
```
## Building and Flashing
To build the test suite, run
```
make BOARD=*yourboard* all
```
where *yourboard* is the name of a directory in **boards**. If no BOARD is
given, it defaults to nucleo-f103rb.
To build with an external libopencm3, run
```
make BOARD=*yourboard* OPENCM3_DIR=*/path/to/libopencm3* all
```
Instead of building the whole test suite you can also just build a specific
application image by giving its base name. If, for example, you only want
to build the `queue2` test app, you can do that like this:
```
make BOARD=*yourboard* queue2
```
If your board Makefile also sets up the necessary openocd variables, you can
use it to flash the application image by appending `.flash` to its base name.
```
make BOARD=*yourboard* *yourimage*.flash
```
N.B.: with the ek-lm4f120xl board openocd will report an error after flashing.
I think it is because it can not handle the changed core clock after the
application starts, but I simply can't be bothered to further investigate this.
The application gets flashed and you can ignore the error.
## Adding New Boards
To add support for a new board, you will have to provide at least two parts.
First, a `Makefile.include` to be pulled in by the main Makefile. Second,
some set-up code for your specific hardware. If there is no linker script for
your MCU, you will have to add one, too.
### Board Makefile Fragment
The main Makefile will include the Makefile.include located in the chosen
board's sub-directory. This is where you set compile time options and additional
source files to be used. Here is the one for the nucleo-f103rb:
```
TARGET ?= stm32f103rb
LIBNAME ?= opencm3_stm32f1
DEFS ?= -DSTM32F1
DEFS += -DSTD_CON=USART2
DEFS += -DMST_SIZE=0x400
FP_FLAGS ?= -msoft-float
ARCH_FLAGS ?= -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd
OOCD ?= openocd
OOCD_INTERFACE ?= stlink-v2-1
OOCD_BOARD ?= st_nucleo_f103rb
objs += board_setup.o
objs += stubs.o stm32_con.o
```
* **TARGET** is the name for the actual MCU used on your board. It will be used
to locate the linker script file in the `linker` directory by appending
`.ld` to it.
* **LIBNAME** is the name of the opencm3 library to link your object files
against.
* **DEFS** are flags that will be appended to the CPPFLAGS. You will at least
have to define the opencm3 target family (STM32F1 here), so the build process
will find the right header files to include. If you are using the stub and
console functions provided in the common directory, you will also have to
define the reserved main stack size (MST_SIZE) and which UART to use for stdio
(STD_CON).
* **FP_FLAGS** which floating point format to use. For MCUs without hardware
support for floating point (M0/3, sometimes 4), use `-msoft-float`,
otherwise use `-mfloat-abi=hard -mfpu=fpv4-sp-d16`. You could add these
directly to `ARCH_FLAGS`, but this way it is easily overridden from the
make command line.
* **ARCH_FLAGS** specify the instruction (sub)set and CPU type to compile for,
as well as any quirk tunings needed and the `FP_FLAGS`. These flags are
handed to preprocessor, compiler, assembler and linker.
The following flags are only used for flashing the target with openocd:
* **OOCD** binary to call. Give full path if it is not in your PATH environment
variable.
* **OOCD_INTERFACE** tells open which interface configuration to use
* **OOCD_BOARD** tells openocd which board configuration file to use.
* **objs** here you _append_ object files to include into _all_ binaries
built for this board. The main Makefile will search for matching source files
(*.c and *.S) in the main port directory, the board directory and the common
directory. You will usually have at least a `board_setup.c` specific to
your hardware and pull in the system and stdio stubs provided in the
`common` directory.
* **aobjs** the build system will build one application for each object you
add to this variable. It will do so by linking each of these objects with all
of the kernel-, port- and board-objects (but none of the testsuite-objects).
The source for the app-object should be located in either the board or
common directory and must contain the application's `main()` function.
The `helloworld.c` file in the common directory is provided as an example.
As you will probably know, variables assigned with the `?=` operator are
only altered if they have not been already set. This way you can easily test
different options for a build by providing the variables on the make command
line.
### Board-Specific Set-up
All hardware needs to be initialised to some degree before it is ready to run
atomthread's kernel. At the very least you will have to
1. mask interrupts
2. set up the main clock and configure the systick timer
3. configure console UART
4. configure GPIOs
(Steps 3. and 4. might be optional if you do not plan to let your board
interact with the outside world in any way...)
The test suite programs expect your board set-up code to provide a function
named `int board_setup(void)` to perform this tasks.
### Linker Script
If you are using an hitherto unknown target MCU, you will have to provide a
linker script for it in the `linker` directory. The script's name must
be the same as given to the `TARGET` variable in your Makefile.include,
with the extension `.ld` added. It is recommended that you just define
your MCU's memory regions and include libopencm3's linker file for your
target's product family. Please look at the provided linker files for examples
on how to do this.
## Port Internals
The Cortex-M port is different from the other architectures insofar as it makes
use of two particular features. First, it uses separate stacks for thread and
exception context. When the core enters exception mode, it first pushes xPSR,
PC, LR, r0-r3 and r12 on the currently active stack (probably the thread stack
in PSP) and then switches to the main stack stored in MSP. It also stores a
special EXC_RETURN code in LR which, when loaded into the PC, will determine
if on return program execution continues to use the MSP or switches over to
the PSP and, on cores with an FPU, whether FPU registers need to be restored.
The Cortex-M also implements a nested vectored interrupt controller (NVIC),
which means that a running ISR may be pre-empted by an exception of higher
priority.
The use of separate stacks for thread and exception context has the nice
implication that you do not have to reserve space on every task's stack for
possible use by ISRs. But it also means that it breaks atomthreads concept
of simply swapping task stacks, regardless of if atomSched() was called from
thread or interrupt context. We would have to implement different
archContextSwitch() functions called from thread or exception context and
also do messy stack manipulations depending on whether the task to be
scheduled in was scheduled out in in the same context or not. Yuck!
And don't get me started on nested exceptions calling atomIntExit()...
This is where the second feature comes handy, the PendSV mechanism.
PendSV is an asynchronous exception with the lowest possible priority, which
means that, when triggered, it will be called by the NVIC if there are no
other exceptions pending or running. We use it by having archContextSwitch()
set up a pointer to the TCB that should be scheduled in and then trigger the
PendSv exception. As soon as program flow leaves the critical section or
performs the outermost exception return, the pend_sv_handler() will be called
and the thread context switch takes place.

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#ifndef __ATOM_PORT_ASM_OFFSETS_H
#define __ATOM_PORT_ASM_OFFSETS_H
#define CTX_RUN_OFF 0
#define CTX_NEXT_OFF 4
#define CTX_REENT_OFF 8
#endif /* __ATOM_PORT_ASM_OFFSETS_H */

View File

@@ -0,0 +1,391 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#include "asm_offsets.h"
.syntax unified
/**
* Create more readable defines for usable intruction set and FPU
*/
#undef THUMB_2
#undef WITH_FPU
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
#define THUMB_2
#endif
#if defined(__VFP_FP__) && !defined(__SOFTFP__)
#define WITH_FPU
#endif
/**
* Extern variables needed for context switching and first thread restore
*/
.extern CTX_SW_NFO
.extern vector_table
#if defined(__NEWLIB__)
/**
* When using newlib, reentry context needs to be updated on task switch
*/
.extern _impure_ptr
#endif
/**
* Some bit masks and registers used
*/
.equ FPU_USED, 0x00000010
.equ SCB_ICSR, 0xE000ED04
.equ PENDSVCLR, 0x08000000
.text
.global _archFirstThreadRestore
.func _archFirstThreadRestore
.type _archFirstThreadRestore,%function
.thumb_func
_archFirstThreadRestore:
/**
* Disable interrupts. They should be disabled anyway, but just
* to make sure...
*/
movs r1, #1
msr PRIMASK, r1
/**
* Reset main stack pointer to initial value, which is the first entry
* in the vector table.
*/
ldr r1, = vector_table
ldr r1, [r1, #0]
msr MSP, r1
/* Update ctx_switch_info, set this thread as both running and next */
ldr r1, = CTX_SW_NFO
str r0, [r1, #CTX_RUN_OFF]
str r0, [r1, #CTX_NEXT_OFF]
#if defined(__NEWLIB__)
/**
* Store the thread's reentry context address in _impure_ptr. This
* will have been stored in ctx_switch_info.reent.
*/
ldr r2, [r1, #CTX_REENT_OFF]
ldr r3, = _impure_ptr
str r2, [r3, #0]
#endif
/* Get thread stack pointer from tcb. Conveniently the first element */
ldr r1, [r0, #0]
msr PSP, r1
/**
* Set bit #1 in CONTROL. Causes switch to PSP, so we can work directly
* with SP now and use pop/push.
*/
movs r1, #2
mrs r2, CONTROL
orrs r2, r2, r1
msr CONTROL, r2
/**
* Initialise thread's register context from its stack frame. Since this
* function gets called only once at system start up, execution time is
* not critical. We can get away with using only Thumb-1 instructions that
* will work on all Cortex-M devices.
*
* Initial stack looks like this:
* xPSR
* PC
* lr
* r12
* r3
* r2
* r1
* r0
* exc_ret <- ignored here
* r11
* r10
* r9
* r8
* r7
* r6
* r5
* r4 <- thread's saved_sp points here
*/
/**
*
* Move SP to position of r8 and restore high registers by loading
* them to r4-r7 before moving them to r8-r11
*/
add SP, #16
pop {r4-r7}
mov r8, r4
mov r9, r5
mov r10, r6
mov r11, r7
/* move SP back to top of stack and load r4-r7 */
sub SP, #32
pop {r4-r7}
/*load r12, lr, pc and xpsr to r0-r3 and restore r12 and lr */
add SP, #36
pop {r0-r3}
mov r12, r0
mov lr, r1
/**
* r2 contains the PC and r3 APSR, SP is now at the bottom of the stack. We
* can't initialise APSR now because we will have to do a movs later when
* enabling interrupts, so r3 must not be touched. We also need an extra
* register holding the value that will be moved to PRIMASK. To do this,
* we build a new stack containing only the initial values of r2, r3
* and pc. In the end this will be directly popped into the registers,
* finishing the thread restore and branching to the thread's entry point.
*/
/* Save PC value */
push {r2}
/* Move values for r2 and r3 to lie directly below value for pc */
sub SP, #20
pop {r1-r2}
add SP, #12
push {r1-r2}
/* Load values for r0 and r1 from stack */
sub SP, #20
pop {r0-r1}
/* Move SP to start of our new r2,r3,pc mini stack */
add SP, #12
/* Restore xPSR and enable interrupts */
movs r2, #0
msr APSR_nzcvq, r3
msr PRIMASK, r2
/* Pop r2,r3,pc from stack, thereby jumping to thread entry point */
pop {r2,r3,pc}
nop
.size _archFirstThreadRestore, . - _archFirstThreadRestore
.endfunc
.global pend_sv_handler
.func pend_sv_handler
.type pend_sv_handler,%function
.thumb_func
pend_sv_handler:
/**
* Disable interrupts. No need to check if they were enabled because,
* well, we're an interrupt handler. Duh...
*/
movs r0, #1
msr PRIMASK, r0
/**
* Clear PendSv pending bit. There seems to exist a hardware race condition
* in the NVIC that can prevent automatic clearing of the PENDSVSET. See
* http://embeddedgurus.com/state-space/2011/09/whats-the-state-of-your-cortex/
*/
ldr r0, = SCB_ICSR
ldr r1, = PENDSVCLR
str r1, [r0, #0]
/**
* Check if running and next thread are really different.
* From here on we have
* r0 = &ctx_switch_info
* r1 = ctx_switch_info.running_tcb
* r2 = ctx_switch_info.next_tcb
*
* If r1 == r2 we can skip the context switch. This may theoretically
* happen if the running thread gets scheduled out and in again by
* multiple nested or tail-chained ISRs before the PendSv handler
* gets called.
*/
ldr r0, = CTX_SW_NFO
ldr r1, [r0, #CTX_RUN_OFF]
ldr r2, [r0, #CTX_NEXT_OFF]
cmp r1, r2
beq no_switch
/**
* Copy running thread's process stack pointer to r3 and use it to push
* the thread's register context on its stack
*/
mrs r3, PSP
#if defined(THUMB_2)
/**
* Save old thread's context on Cortex-M[34]
*/
#if defined(WITH_FPU)
/* Check if FPU was used by thread and store registers if necessary */
tst lr, FPU_USED
it eq
vstmdbeq r3!, {s16-s31}
/**
* TODO: Defer stacking FPU context by disabling FPU and using a
* fault handler to store the FPU registers if another thread
* tries using it
*/
#endif // WITH_FPU
/* Push running thread's remaining registers on stack */
stmdb r3!, {r4-r11, lr}
#else // !THUMB2
/**
* Save old thread's register context on Cortex-M0.
* Push running thread's remaining registers on stack.
* Thumb-1 can use stm only on low registers, so we
* have to do this in two steps.
*/
/* Reserve space for r8-r11 + exc_return before storing r4-r7 */
subs r3, r3, #36
stmia r3!, {r4-r7}
/**
* Move r8-r11 to low registers and use store multiple with automatic
* post-increment to push them on the stack
*/
mov r4, r8
mov r5, r9
mov r6, r10
mov r7, r11
stmia r3!, {r4-r7}
/**
* Move lr (contains the exc_return code) to low registers and store it
* on the stack.
*/
mov r4, lr
str r4, [r3, #0]
/* Re-adjust r3 to point at top of stack */
subs r3, r3, #32
#endif // !THUMB_2
/**
* Address of running TCB still in r1. Store thread's current stack top
* into its sp_save_ptr, which is the struct's first element.
*/
str r3, [r1, #0]
/**
* ctx_switch_info.next_tcb is going to become ctx_switch_info.running_tcb,
* so we update the pointer.
*/
str r2, [r0, #CTX_RUN_OFF]
#if defined(__NEWLIB__)
/**
* Store the thread's reentry context address in _impure_ptr. This
* will have been stored in ctx_switch_info.reent.
*/
ldr r4, [r0, #CTX_REENT_OFF]
ldr r3, = _impure_ptr
str r4, [r3, #0]
#endif
/**
* Fetch next thread's stack pointer from its TCB's sp_save_ptr and restore
* the thread's register context.
*/
ldr r3, [r2, #0]
#if defined(THUMB_2)
/* Cortex-M[34], restore thread's task stack frame */
ldmia r3!, {r4-r11, lr}
#if defined(WITH_FPU)
/**
* Check if FPU was used by new thread and restore registers if necessary.
*/
tst lr, FPU_USED
it eq
vldmiaeq r3!, {s16-s31}
/**
* TODO: only restore FPU registers if FPU was used by another thread
* between this thread being scheduled out and now.
*/
#endif // WITH_FPU
#else // !THUMB_2
/**
* Thread restore for Cortex-M0
* Restore thread's task stack frame. Because thumb 1 only supports
* load multiple on low register, we have to do it in two steps and
* adjust the stack pointer manually.
*/
/* Restore high registers */
adds r3, r3, #16
ldmia r3!, {r4-r7}
mov r8, r4
mov r9, r5
mov r10, r6
mov r11, r7
/* Restore lr */
ldr r4, [r3, #0]
mov lr, r4
subs r3, r3, #32
/**
* Restore r4-r7 and adjust r3 to point at the top of the exception
* stack frame.
*/
ldmia r3!, {r4-r7}
adds r3, r3, #20
#endif // !THUMB_2
/* Set process stack pointer to new thread's stack*/
msr PSP, r3
no_switch:
/* Re-enable interrupts */
movs r0, #0
msr PRIMASK, r0
/* Return to new thread */
bx lr
nop
.size pend_sv_handler, . - pend_sv_handler
.endfunc

View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#ifndef __ATOMPORT_PRIVATE_H_
#define __ATOMPORT_PRIVATE_H_
#include "atomport.h"
#include "atom.h"
/**
* context saved automagically by exception entry
*/
struct isr_stack {
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr;
uint32_t pc;
uint32_t psr;
} __attribute__((packed));
struct isr_fpu_stack {
uint32_t s0;
uint32_t s1;
uint32_t s2;
uint32_t s3;
uint32_t s4;
uint32_t s5;
uint32_t s6;
uint32_t s7;
uint32_t s8;
uint32_t s9;
uint32_t s10;
uint32_t s11;
uint32_t s12;
uint32_t s13;
uint32_t s14;
uint32_t s15;
uint32_t fpscr;
} __attribute__((packed));
/**
* remaining context saved by task switch ISR
*/
struct task_stack {
uint32_t r4;
uint32_t r5;
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t exc_ret;
} __attribute__((packed));
struct task_fpu_stack {
uint32_t s16;
uint32_t s17;
uint32_t s18;
uint32_t s19;
uint32_t s20;
uint32_t s21;
uint32_t s22;
uint32_t s23;
uint32_t s24;
uint32_t s25;
uint32_t s26;
uint32_t s27;
uint32_t s28;
uint32_t s29;
uint32_t s30;
uint32_t s31;
} __attribute__((packed));
/**
* Info needed by pend_sv_handler used for delayed task switching.
* Running_tcb is a pointer to the TCB currently running (gosh, really?!)
* next_tcb is a pointer to a TCB that should be running.
* archContextSwitch() will update next_tcb and trigger a pend_sv. The
* pend_sv_handler will be called as soon as all other ISRs have returned,
* do the real context switch and update running_tcb.
*/
struct task_switch_info {
volatile struct atom_tcb *running_tcb;
volatile struct atom_tcb *next_tcb;
#if defined(__NEWLIB__)
struct _reent *reent;
#endif
} __attribute__((packed));
#endif /* __ATOMPORT_PRIVATE_H_ */

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#ifndef __ATOM_PORT_TESTS_H
#define __ATOM_PORT_TESTS_H
/* Include Atomthreads kernel API */
#include <stdio.h>
#include "atom.h"
/* Default thread stack size (in bytes) */
#define TEST_THREAD_STACK_SIZE 1024
/* Uncomment to enable logging of stack usage to UART */
/* #define TESTS_LOG_STACK_USAGE */
#define ATOMLOG printf
#define _STR
#endif /* __ATOM_PORT_TESTS_H */

236
ports/cortex-m/atomport.c Normal file
View File

@@ -0,0 +1,236 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#include <string.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/sync.h>
#include "atomport.h"
#include "atomport-private.h"
#include "asm_offsets.h"
static void thread_shell(void);
struct task_switch_info ctx_switch_info asm("CTX_SW_NFO") =
{
.running_tcb = NULL,
.next_tcb = NULL,
};
extern void _archFirstThreadRestore(ATOM_TCB *);
void archFirstThreadRestore(ATOM_TCB *new_tcb_ptr)
{
#if defined(__NEWLIB__)
ctx_switch_info.reent = &(new_tcb_ptr->port_priv.reent);
__dmb();
#endif
_archFirstThreadRestore(new_tcb_ptr);
}
/**
* We do not perform the context switch directly. Instead we mark the new tcb
* as should-be-running in ctx_switch_info and trigger a PendSv-interrupt.
* The pend_sv_handler will be called when all other pending exceptions have
* returned and perform the actual context switch.
* This way we do not have to worry if we are being called from task or
* interrupt context, which would mean messing with either main or thread
* stack format.
*
* One difference to the other architectures is that execution flow will
* actually continue in the old thread context until interrupts are enabled
* again. From a thread context this should make no difference, as the context
* switch will be performed as soon as the execution flow would return to the
* calling thread. Unless, of course, the thread called atomSched() with
* disabled interrupts, which it should not do anyways...
*/
void __attribute__((noinline))
archContextSwitch(ATOM_TCB *old_tcb_ptr __maybe_unused, ATOM_TCB *new_tcb_ptr)
{
if(likely(ctx_switch_info.running_tcb != NULL)){
ctx_switch_info.next_tcb = new_tcb_ptr;
#if defined(__NEWLIB__)
ctx_switch_info.reent = &(new_tcb_ptr->port_priv.reent);
#endif
__dmb();
SCB_ICSR = SCB_ICSR_PENDSVSET;
}
}
void sys_tick_handler(void)
{
/* Call the interrupt entry routine */
atomIntEnter();
/* Call the OS system tick handler */
atomTimerTick();
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}
/**
* Put chip into infinite loop if NMI or hard fault occurs
*/
void nmi_handler(void)
{
while(1)
;
}
void hard_fault_handler(void)
{
while(1)
;
}
/**
* This function is called when a new thread is scheduled in for the first
* time. It will simply call the threads entry point function.
*/
static void thread_shell(void)
{
ATOM_TCB *task_ptr;
/**
* We "return" to here after being scheduled in by the pend_sv_handler.
* We get a pointer to our TCB from atomCurrentContext()
*/
task_ptr = atomCurrentContext();
/**
* Our thread entry point and parameter are stored in the TCB.
* Call it if it is valid
*/
if(task_ptr && task_ptr->entry_point){
task_ptr->entry_point(task_ptr->entry_param);
}
/**
* Thread returned or entry point was not valid.
* Should never happen... Maybe we should switch MCU into debug mode here
*/
while(1)
;
}
/**
* Initialise a threads stack so it can be scheduled in by
* archFirstThreadRestore or the pend_sv_handler.
*/
void archThreadContextInit(ATOM_TCB *tcb_ptr, void *stack_top,
void (*entry_point)(uint32_t), uint32_t entry_param)
{
struct isr_stack *isr_ctx;
struct task_stack *tsk_ctx;
/**
* Do compile time verification for offsets used in _archFirstThreadRestore
* and pend_sv_handler. If compilation aborts here, you will have to adjust
* the offsets for struct task_switch_info's members in asm-offsets.h
*/
assert_static(offsetof(struct task_switch_info, running_tcb) == CTX_RUN_OFF);
assert_static(offsetof(struct task_switch_info, next_tcb) == CTX_NEXT_OFF);
#if defined(__NEWLIB__)
assert_static(offsetof(struct task_switch_info, reent) == CTX_REENT_OFF);
#endif
/**
* Enforce initial stack alignment
*/
stack_top = STACK_ALIGN(stack_top, STACK_ALIGN_SIZE);
/**
* New threads will be scheduled from an exception handler, so we have to
* set up an exception stack frame as well as task stack frame
*/
isr_ctx = stack_top - sizeof(*isr_ctx);
tsk_ctx = stack_top - sizeof(*isr_ctx) - sizeof(*tsk_ctx);
#if 0
printf("[%s] tcb_ptr: %p stack_top: %p isr_ctx: %p tsk_ctx: %p entry_point: %p, entry_param: 0x%x\n",
__func__, tcb_ptr, stack_top, isr_ctx, tsk_ctx, entry_point, entry_param);
printf("[%s] isr_ctx->r0: %p isr_ctx->psr: %p tsk_ctx->r4: %p tsk_ctx->lr: %p\n",
__func__, &isr_ctx->r0, &isr_ctx->psr, &tsk_ctx->r4, &tsk_ctx->lr);
#endif
/**
* We use the exception return mechanism to jump to our thread_shell()
* function and initialise the PSR to the default value (thumb state
* flag set and nothing else)
*/
isr_ctx->psr = 0x01000000;
isr_ctx->pc = (uint32_t) thread_shell;
/* initialise unused registers to silly value */
isr_ctx->lr = 0xEEEEEEEE;
isr_ctx->r12 = 0xCCCCCCCC;
isr_ctx->r3 = 0x33333333;
isr_ctx->r2 = 0x22222222;
isr_ctx->r1 = 0x11111111;
isr_ctx->r0 = 0x00000000;
/**
* We use this special EXC_RETURN code to switch from main stack to our
* thread stack on exception return
*/
tsk_ctx->exc_ret = 0xFFFFFFFD;
/* initialise unused registers to silly value */
tsk_ctx->r11 = 0xBBBBBBBB;
tsk_ctx->r10 = 0xAAAAAAAA;
tsk_ctx->r9 = 0x99999999;
tsk_ctx->r8 = 0x88888888;
tsk_ctx->r7 = 0x77777777;
tsk_ctx->r6 = 0x66666666;
tsk_ctx->r5 = 0x55555555;
tsk_ctx->r4 = 0x44444444;
/**
* Stack frames have been initialised, save it to the TCB. Also set
* the thread's real entry point and param, so the thread shell knows
* what function to call.
*/
tcb_ptr->sp_save_ptr = tsk_ctx;
tcb_ptr->entry_point = entry_point;
tcb_ptr->entry_param = entry_param;
#if defined(__NEWLIB__)
/**
* Initialise thread's reentry context for newlib
*/
_REENT_INIT_PTR(&(tcb_ptr->port_priv.reent));
#endif
}

85
ports/cortex-m/atomport.h Normal file
View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#ifndef __ATOM_PORT_H
#define __ATOM_PORT_H
#include <stdint.h>
#include <stddef.h>
#include <libopencm3/cm3/cortex.h>
#include <stdlib.h>
/* Required number of system ticks per second (normally 100 for 10ms tick) */
#define SYSTEM_TICKS_PER_SEC 100
/* Size of each stack entry / stack alignment size (4 bytes on Cortex-M without FPU) */
#define STACK_ALIGN_SIZE sizeof(uint32_t)
#define ALIGN(x, a) ((x + (typeof(x))(a) - 1) & ~((typeof(x))(a) - 1))
#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((uint32_t)(p), (a)))
#define STACK_ALIGN(p, a) (typeof(p))((typeof(a))(p) & ~((a) - 1))
#define POINTER void *
#define UINT32 uint32_t
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define __maybe_unused __attribute__((unused))
#define assert_static(e) \
do { \
enum { assert_static__ = 1/(e) }; \
} while (0)
/**
* Critical region protection: this should disable interrupts
* to protect OS data structures during modification. It must
* allow nested calls, which means that interrupts should only
* be re-enabled when the outer CRITICAL_END() is reached.
*/
#define CRITICAL_STORE bool __irq_flags
#define CRITICAL_START() __irq_flags = cm_mask_interrupts(true)
#define CRITICAL_END() (void) cm_mask_interrupts(__irq_flags)
/**
* When using newlib, define port private field in atom_tcb to be a
* struct _reent.
*/
#if defined(__NEWLIB__)
struct cortex_port_priv {
struct _reent reent;
};
#define THREAD_PORT_PRIV struct cortex_port_priv port_priv
#endif
/* Uncomment to enable stack-checking */
/* #define ATOM_STACK_CHECKING */
#endif /* __ATOM_PORT_H */

View File

@@ -0,0 +1,17 @@
TARGET ?= lm4f120xl
LIBNAME ?= opencm3_lm4f
DEFS ?= -DLM4F
DEFS += -DSTD_CON=UART0
DEFS += -DMST_SIZE=0x400
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
ARCH_FLAGS ?= -mthumb -mcpu=cortex-m4 $(FP_FLAGS)
OOCD ?= openocd
OOCD_INTERFACE ?= ti-icdi
OOCD_BOARD ?= ek-lm4f120xl
objs += board_setup.o
objs += stubs.o lm4f_con.o
# aobjs += helloworld.o

View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#include <stdbool.h>
#include <libopencm3/lm4f/rcc.h>
#include <libopencm3/lm4f/gpio.h>
#include <libopencm3/lm4f/uart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>
#include "atomport.h"
static void uart_setup(uint32_t baud)
{
periph_clock_enable(RCC_GPIOA);
gpio_set_af(GPIOA, 1, GPIO0 | GPIO1);
periph_clock_enable(RCC_UART0);
/* We need a brief delay before we can access UART config registers */
__asm__("nop");
/* Disable the UART while we mess with its setings */
uart_disable(UART0);
/* Configure the UART clock source as precision internal oscillator */
uart_clock_from_piosc(UART0);
/* Set communication parameters */
uart_set_baudrate(UART0, baud);
uart_set_databits(UART0, 8);
uart_set_parity(UART0, UART_PARITY_NONE);
uart_set_stopbits(UART0, 1);
/* Now that we're done messing with the settings, enable the UART */
uart_enable(UART0);
}
/**
* initialise and start SysTick counter. This will trigger the
* sys_tick_handler() periodically once interrupts have been enabled
* by archFirstThreadRestore()
*/
static void systick_setup(void)
{
systick_set_frequency(SYSTEM_TICKS_PER_SEC, 80000000);
systick_interrupt_enable();
systick_counter_enable();
}
/**
* Set up the core clock to something other than the internal 16MHz PIOSC.
* Make sure that you use the same clock frequency in systick_setup().
*/
static void clock_setup(void)
{
/**
* set up 400MHz PLL from 16MHz crystal and divide by 5 to get 80MHz
* system clock
*/
rcc_sysclk_config(OSCSRC_MOSC, XTAL_16M, 5);
}
/**
* Set up user LED and provide function for toggling it. This is for
* use by the test suite programs
*/
static void test_led_setup(void)
{
/* LED is connected to GPIO1 on port F */
periph_clock_enable(RCC_GPIOF);
gpio_mode_setup(GPIOF, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO1);
gpio_set_output_config(GPIOF, GPIO_OTYPE_PP, GPIO_DRIVE_2MA, GPIO1);
gpio_set(GPIOF, GPIO1);
}
void test_led_toggle(void)
{
gpio_toggle(GPIOF, GPIO1);
}
/**
* Callback from your main program to set up the board's hardware before
* the kernel is started.
*/
int board_setup(void)
{
/* Disable interrupts. This makes sure that the sys_tick_handler will
* not be called before the first thread has been started.
* Interrupts will be enabled by archFirstThreadRestore().
*/
cm_mask_interrupts(true);
/* configure system clock, user LED and UART */
gpio_enable_ahb_aperture();
clock_setup();
test_led_setup();
uart_setup(115200);
/* Initialise SysTick counter */
systick_setup();
/* Set exception priority levels. Make PendSv the lowest priority and
* SysTick the second to lowest
*/
nvic_set_priority(NVIC_PENDSV_IRQ, 0xFF);
nvic_set_priority(NVIC_SYSTICK_IRQ, 0xFE);
return 0;
}

View File

@@ -0,0 +1,17 @@
TARGET ?= stm32f072rb
LIBNAME ?= opencm3_stm32f0
DEFS ?= -DSTM32F0
DEFS += -DSTD_CON=USART2
DEFS += -DMST_SIZE=0x400
FP_FLAGS ?= -msoft-float
ARCH_FLAGS ?= -mthumb -mcpu=cortex-m0
OOCD ?= openocd
OOCD_INTERFACE ?= stlink-v2-1
OOCD_BOARD ?= st_nucleo_f0
objs += board_setup.o
objs += stubs.o stm32_con.o
# aobjs += helloworld.o

View File

@@ -0,0 +1,134 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#include <stdbool.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>
#include "atomport.h"
/**
* Set up USART2.
* This one is connected via the virtual serial port on the Nucleo Board
*/
static void usart_setup(uint32_t baud)
{
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_USART2);
usart_disable(USART2);
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2 | GPIO3);
gpio_set_af(GPIOA, GPIO_AF1, GPIO2 | GPIO3);
usart_set_baudrate(USART2, baud);
usart_set_databits(USART2, 8);
usart_set_parity(USART2, USART_PARITY_NONE);
usart_set_stopbits(USART2, USART_CR2_STOP_1_0BIT);
usart_set_mode(USART2, USART_MODE_TX_RX);
usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
usart_enable(USART2);
}
/**
* initialise and start SysTick counter. This will trigger the
* sys_tick_handler() periodically once interrupts have been enabled
* by archFirstThreadRestore()
*/
static void systick_setup(void)
{
systick_set_frequency(SYSTEM_TICKS_PER_SEC, 48000000);
systick_interrupt_enable();
systick_counter_enable();
}
/**
* Set up the core clock to something other than the internal 16MHz PIOSC.
* Make sure that you use the same clock frequency in systick_setup().
*/
static void clock_setup(void)
{
/* set core clock to 48MHz, generated from PIOSC */
rcc_clock_setup_in_hsi_out_48mhz();
}
/**
* Set up user LED and provide function for toggling it. This is for
* use by the test suite programs
*/
static void test_led_setup(void)
{
/* LED is connected to GPIO5 on port A */
rcc_periph_clock_enable(RCC_GPIOA);
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO5);
gpio_set(GPIOA, GPIO5);
}
void test_led_toggle(void)
{
gpio_toggle(GPIOA, GPIO5);
}
/**
* Callback from your main program to set up the board's hardware before
* the kernel is started.
*/
int board_setup(void)
{
/* Disable interrupts. This makes sure that the sys_tick_handler will
* not be called before the first thread has been started.
* Interrupts will be enabled by archFirstThreadRestore().
*/
cm_mask_interrupts(true);
/* configure system clock, user LED and UART */
clock_setup();
test_led_setup();
usart_setup(115200);
/* initialise SysTick counter */
systick_setup();
/* Set exception priority levels. Make PendSv the lowest priority and
* SysTick the second to lowest
*/
nvic_set_priority(NVIC_PENDSV_IRQ, 0xFF);
nvic_set_priority(NVIC_SYSTICK_IRQ, 0xFE);
return 0;
}

View File

@@ -0,0 +1,17 @@
TARGET ?= stm32f103rb
LIBNAME ?= opencm3_stm32f1
DEFS ?= -DSTM32F1
DEFS += -DSTD_CON=USART2
DEFS += -DMST_SIZE=0x400
FP_FLAGS ?= -msoft-float
ARCH_FLAGS ?= -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd
OOCD ?= openocd
OOCD_INTERFACE ?= stlink-v2-1
OOCD_BOARD ?= st_nucleo_f103rb
objs += board_setup.o
objs += stubs.o stm32_con.o
# aobjs += helloworld.o

View File

@@ -0,0 +1,138 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#include <stdbool.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>
#include "atomport.h"
/**
* Set up USART2.
* This one is connected via the virtual serial port on the Nucleo Board
*/
static void usart_setup(uint32_t baud)
{
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_AFIO);
rcc_periph_clock_enable(RCC_USART2);
usart_disable(USART2);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,
GPIO_USART2_TX | GPIO_USART2_RX);
usart_set_baudrate(USART2, baud);
usart_set_databits(USART2, 8);
usart_set_stopbits(USART2, USART_STOPBITS_1);
usart_set_parity(USART2, USART_PARITY_NONE);
usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
usart_set_mode(USART2, USART_MODE_TX_RX);
usart_enable(USART2);
}
/**
* initialise and start SysTick counter. This will trigger the
* sys_tick_handler() periodically once interrupts have been enabled
* by archFirstThreadRestore()
*/
static void systick_setup(void)
{
systick_set_frequency(SYSTEM_TICKS_PER_SEC, 72000000);
systick_interrupt_enable();
systick_counter_enable();
}
/**
* Set up the core clock to something other than the internal 16MHz PIOSC.
* Make sure that you use the same clock frequency in systick_setup().
*/
static void clock_setup(void)
{
/* set core clock to 72MHz, generated from external 8MHz crystal */
rcc_clock_setup_in_hse_8mhz_out_72mhz();
}
/**
* Set up user LED and provide function for toggling it. This is for
* use by the test suite programs
*/
static void test_led_setup(void)
{
/* LED is connected to GPIO5 on port A */
rcc_periph_clock_enable(RCC_GPIOA);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO5);
gpio_set(GPIOA, GPIO5);
}
void test_led_toggle(void)
{
gpio_toggle(GPIOA, GPIO5);
}
/**
* Callback from your main program to set up the board's hardware before
* the kernel is started.
*/
int board_setup(void)
{
/* Disable interrupts. This makes sure that the sys_tick_handler will
* not be called before the first thread has been started.
* Interrupts will be enabled by archFirstThreadRestore().
*/
cm_mask_interrupts(true);
/* configure system clock, user LED and UART */
clock_setup();
test_led_setup();
usart_setup(115200);
/* initialise SysTick counter */
systick_setup();
/* Set exception priority levels. Make PendSv the lowest priority and
* SysTick the second to lowest
*/
nvic_set_priority(NVIC_PENDSV_IRQ, 0xFF);
nvic_set_priority(NVIC_SYSTICK_IRQ, 0xFE);
return 0;
}

View File

@@ -0,0 +1,17 @@
TARGET ?= stm32f411re
LIBNAME ?= opencm3_stm32f4
DEFS ?= -DSTM32F4
DEFS += -DSTD_CON=USART2
DEFS += -DMST_SIZE=0x400
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
ARCH_FLAGS ?= -mthumb -mcpu=cortex-m4 $(FP_FLAGS)
OOCD ?= openocd
OOCD_INTERFACE ?= stlink-v2-1
OOCD_BOARD ?= st_nucleo_f4
objs += board_setup.o
objs += stubs.o stm32_con.o
# aobjs += helloworld.o

View File

@@ -0,0 +1,136 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#include <stdbool.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>
#include "atomport.h"
/**
* Set up USART2.
* This one is connected via the virtual serial port on the Nucleo Board
*/
static void usart_setup(uint32_t baud)
{
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_USART2);
usart_disable(USART2);
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2 | GPIO3);
gpio_set_af(GPIOA, GPIO_AF7, GPIO2);
usart_set_baudrate(USART2, baud);
usart_set_databits(USART2, 8);
usart_set_stopbits(USART2, USART_STOPBITS_1);
usart_set_parity(USART2, USART_PARITY_NONE);
usart_set_mode(USART2, USART_MODE_TX_RX);
usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
usart_enable(USART2);
}
/**
* initialise and start SysTick counter. This will trigger the
* sys_tick_handler() periodically once interrupts have been enabled
* by archFirstThreadRestore()
*/
static void systick_setup(void)
{
systick_set_frequency(SYSTEM_TICKS_PER_SEC, 16000000);
systick_interrupt_enable();
systick_counter_enable();
}
/**
* Set up the core clock to something other than the internal 16MHz PIOSC.
* Make sure that you use the same clock frequency in systick_setup().
*/
static void clock_setup(void)
{
/**
* Clock setting for stm32f4 is currently broken in libopencm3.
* Leave at internal 16MHz
*/
// rcc_clock_setup_hse_3v3(CLOCK_3V3_48MHZ);
}
/**
* Set up user LED and provide function for toggling it. This is for
* use by the test suite programs
*/
static void test_led_setup(void)
{
/* LED is connected to GPIO5 on port A */
rcc_periph_clock_enable(RCC_GPIOA);
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO5);
gpio_set(GPIOA, GPIO5);
}
void test_led_toggle(void)
{
gpio_toggle(GPIOA, GPIO5);
}
/**
* Callback from your main program to set up the board's hardware before
* the kernel is started.
*/
int board_setup(void)
{
/* Disable interrupts. This makes sure that the sys_tick_handler will
* not be called before the first thread has been started.
* Interrupts will be enabled by archFirstThreadRestore().
*/
cm_mask_interrupts(true);
/* configure system clock, user LED and UART */
clock_setup();
test_led_setup();
usart_setup(115200);
/* initialise SysTick counter */
systick_setup();
/* Set exception priority levels. Make PendSv the lowest priority and
* SysTick the second to lowest
*/
nvic_set_priority(NVIC_PENDSV_IRQ, 0xFF);
nvic_set_priority(NVIC_SYSTICK_IRQ, 0xFE);
return 0;
}

View File

@@ -0,0 +1,27 @@
TARGET ?= stm32f103rb
LIBNAME ?= opencm3_stm32f1
DEFS ?= -DSTM32F1
DEFS += -DSTD_CON=USART2
DEFS += -DMST_SIZE=0x400
FP_FLAGS ?= -msoft-float
ARCH_FLAGS ?= -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd
OOCD ?= openocd
OOCD_INTERFACE ?= stlink-v2-1
OOCD_BOARD ?= st_nucleo_f103rb
objs += board_setup.o
# aobjs += helloworld.o
# Special requirements for running automated tests with QEMU
QEMU ?= qemu-system-gnuarmeclipse
.DEFAULT_GOAL := all
.SECONDEXPANSION:
.PHONY: qemutests
qemutests: $$(addsuffix .sim, $$(sort $$(build_telfs)))
%.sim: $$(basename $$@)
boards/qemu/run_test.exp $(QEMU) $(*)

View File

@@ -0,0 +1,31 @@
This board is a quick n' dirty copy of nucleo-f103rb, stripped down to run
atomthread's test suite on qemu. Since it must be linked against newlib's
librdimon to enable semi-hosting, the stubs provided in the common directory
can not be used. Do not be surprised if malloc etc. do not work as expected.
The [GNU ARM Eclipse](http://gnuarmeclipse.livius.net/blog/) project maintains
a fork of qemu that is able to emulate a Nucleo-F103RB board. Check out their
gnuarmeclipse-dev branch from [here]
(http://sourceforge.net/p/gnuarmeclipse/qemu/ci/gnuarmeclipse-dev/tree/).
At time of writing (2015-07-13), I had to run configure with
`--disable-werror --target-list="gnuarmeclipse-softmmu"` to build
a usable target.
After installing you can use it to run the test binaries like this:
```
qemu-system-gnuarmeclipse -nographic -monitor null \
-semihosting --machine NUCLEO-F103RB \
--verbose --kernel build/kern1.elf
```
The whole test suite can be run in an automatic way from the build system by
using the tool `expect`.
```
make BOARD=qemu QEMU=/path/to/your/qemu/binary qemutests
```
If your qemu-binary is called `qemu-system-gnuarmeclipse` and is located
in your search path, you can omit the `QEMU=...` part.

View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#include <stdbool.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>
#include "atomport.h"
/**
* initialise and start SysTick counter. This will trigger the
* sys_tick_handler() periodically once interrupts have been enabled
* by archFirstThreadRestore(). Since we did not change the clock source,
* the MCU is still running from 16MHz PIOSC
*/
static void systick_setup(void)
{
systick_set_frequency(SYSTEM_TICKS_PER_SEC, 16000000);
systick_interrupt_enable();
systick_counter_enable();
}
/**
* Set up the core clock to something other than the internal 16MHz PIOSC.
* Make sure that you use the same clock frequency in systick_setup().
*/
/**
* Set up user LED and provide function for toggling it. This is for
* use by the test suite programs
*/
static void test_led_setup(void)
{
/* LED is connected to GPIO5 on port A */
rcc_periph_clock_enable(RCC_GPIOA);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO5);
gpio_set(GPIOA, GPIO5);
}
void test_led_toggle(void)
{
static bool on = true;
/* qemu does not seem to know how to handle gpio_toggle() */
if(on){
gpio_clear(GPIOA, GPIO5);
} else {
gpio_set(GPIOA, GPIO5);
}
on = !on;
}
/**
* Callback from your main program to set up the board's hardware before
* the kernel is started.
*/
extern void initialise_monitor_handles(void);
int board_setup(void)
{
/* initialise semi-hosting */
initialise_monitor_handles();
/* Disable interrupts. This makes sure that the sys_tick_handler will
* not be called before the first thread has been started.
* Interrupts will be enabled by archFirstThreadRestore().
*/
cm_mask_interrupts(true);
/* configure user LED*/
test_led_setup();
/* initialise SysTick counter */
systick_setup();
/* Set exception priority levels. Make PendSv the lowest priority and
* SysTick the second to lowest
*/
nvic_set_priority(NVIC_PENDSV_IRQ, 0xFF);
nvic_set_priority(NVIC_SYSTICK_IRQ, 0xFE);
return 0;
}

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env expect
# Expect script to run an automated test within the simulator (QEMU) and
# check for successful completion.
#
# Arguments: <path_to_qemu> <test_elf_file>
#
# Returns 0 on successful test run within QEMU, 1 on failure
# Start the test
spawn [lindex $argv 0] -nographic -monitor null -semihosting \
--machine NUCLEO-F103RB --kernel [lindex $argv 1]
# Expect to see the test starting within 10 seconds
set timeout 10
# Wait for the test to start ("Go")
expect {
"Go" {
puts "Test started"
# The test could take up to 3 minutes to complete once started
set timeout 180
# Now expect to see "Pass" or "Fail" within 3 minutes
expect {
"Pass" { puts "Test passed"; exit 0 }
"Fail" { puts "Test failed"; exit 1 }
timeout { puts "Test timed out without completing"; exit 1 }
}
}
timeout {
# Didn't receive "Go" within 10 seconds
puts "Test failed to start ('Go' not seen)"
exit 1
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#include <stdio.h>
#include <libopencm3/cm3/nvic.h>
#include "atom.h"
#include "atomport-private.h"
#include "atomtimer.h"
#define STACK_SIZE 1024
#define THREAD_PRIO 42
static ATOM_TCB main_tcb;
static uint8_t thread_stacks[2][STACK_SIZE];
static void main_thread_func(uint32_t data);
/**
* Example for a stand-alone board application
*/
extern int board_setup(void);
int main(void)
{
int8_t status;
uint32_t loop;
/**
* Brief delay to give the debugger a chance to stop the core before we
* muck around with the chip's configuration.
*/
for(loop = 0;loop < 1000000;++loop){
__asm__("nop");
}
board_setup();
/**
* Initialise OS and set up idle thread
*/
status = atomOSInit(&thread_stacks[0][0], STACK_SIZE, FALSE);
if(status == ATOM_OK){
/* Set up main thread */
status = atomThreadCreate(&main_tcb, THREAD_PRIO, main_thread_func, 0,
&thread_stacks[1][0], STACK_SIZE, TRUE);
if(status == ATOM_OK){
atomOSStart();
}
}
while(1)
;
/* We will never get here */
return 0;
}
extern void test_led_toggle(void);
static void main_thread_func(uint32_t data __maybe_unused)
{
/* Print message */
printf("Hello, world!\n");
/* Loop forever and blink the LED */
while(1){
test_led_toggle();
atomTimerDelay(SYSTEM_TICKS_PER_SEC);
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#include <errno.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/lm4f/uart.h>
/**
* _read and _write for LM4F
*
* _read and _write are used by newlib's I/O routines (think printf, etc.)
* If you want to use this code in your binary, you will have to initialise
* the UART in your board's setup code and define STD_CON to your UART's
* name in your board's Makefile
*/
int _read(int fd, void *buf, size_t count)
{
int rcvd;
char *ptr;
if(fd <= 2){
ptr = (char *) buf;
rcvd = 0;
while(count > 0){
*ptr = uart_recv_blocking(STD_CON);
if(*ptr == '\r'){
*ptr = '\n';
}
++rcvd;
--count;
}
}else{
rcvd = -1;
errno = EIO;
}
return rcvd;
}
int _write(int fd, const void *buf, size_t count)
{
int sent;
char *ptr;
if(fd <= 2){
sent = count;
ptr = (char *) buf;
while(count > 0){
if(*ptr == '\n'){
uart_send_blocking(STD_CON, '\r');
}
uart_send_blocking(STD_CON, *ptr++);
++sent;
--count;
}
}else{
errno = EIO;
sent = -1;
}
return sent;
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#include <errno.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/stm32/usart.h>
/**
* _read and _write for STM32
*
* _read and _write are used by newlib's I/O routines (think printf, etc.)
* If you want to use this code in your binary, you will have to initialise
* the UART in your board's setup code and define STD_CON to your UART's
* name in your board's Makefile
*/
int _read(int fd, void *buf, size_t count)
{
int rcvd;
char *ptr;
if(fd <= 2){
ptr = (char *) buf;
rcvd = 0;
while(count > 0){
*ptr = usart_recv_blocking(STD_CON);
if(*ptr == '\r'){
*ptr = '\n';
}
++rcvd;
--count;
}
}else{
rcvd = -1;
errno = EIO;
}
return rcvd;
}
int _write(int fd, const void *buf, size_t count)
{
int sent;
char *ptr;
if(fd <= 2){
sent = count;
ptr = (char *) buf;
while(count > 0){
if(*ptr == '\n'){
usart_send_blocking(STD_CON, '\r');
}
usart_send_blocking(STD_CON, *ptr++);
++sent;
--count;
}
}else{
errno = EIO;
sent = -1;
}
return sent;
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2015, Tido Klaassen. 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.
*/
#include <sys/stat.h>
#include <libopencm3/cm3/vector.h>
#include "atomport.h"
/**
* _sbrk is needed by newlib for heap management.
* The main stack usually starts at the top of RAM and grows downwards,
* while the heap starts at the bottom and grows upwards. To prevent
* the heap from colliding with the main stack, we reserve a certain amount
* of memory and check that growing the heap won't touch that region.
* The size of the protected area is set via the define MST_SIZE in the
* board Makefile
*/
#ifndef MST_SIZE
#error Main stack size not defined. Please define MST_SIZE in board Makefile
#endif
/**
* The vector table is provided by libopencm3/cm3/vector.h and contains
* the initial main stack pointer value
*/
extern vector_table_t vector_table;
/**
* The linker provides the start address of the unused system memory.
* It is exported via the symbol 'end' and will be used as the bottom
* of the heap
*/
extern char end;
static char *heap_end = 0;
caddr_t _sbrk(int incr)
{
char *prev_end;
CRITICAL_STORE;
prev_end = NULL;
CRITICAL_START();
if(unlikely(heap_end == 0)){
heap_end = &end;
}
/* make sure new heap size does not collide with main stack area*/
if(heap_end + incr + MST_SIZE <= (char *) vector_table.initial_sp_value){
prev_end = heap_end;
heap_end += incr;
}
CRITICAL_END();
return (caddr_t) prev_end;
}
/**
* dummy stubs needed by newlib when not linked with libnosys
*/
int _close(int file __maybe_unused)
{
return -1;
}
int _fstat(int file __maybe_unused, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file __maybe_unused)
{
return 1;
}
int _lseek(int file __maybe_unused,
int ptr __maybe_unused,
int dir __maybe_unused)
{
return 0;
}
int _open(const char *name __maybe_unused,
int flags __maybe_unused,
int mode __maybe_unused)
{
return -1;
}

View File

@@ -0,0 +1,10 @@
/* Memory regions for TI Stellaris EX-LM4F120XL evaluation board. */
MEMORY
{
rom (rx) : ORIGIN = 0x00000000, LENGTH = 256K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
/* Include main opencm3 linker script */
INCLUDE libopencm3_lm4f.ld

View File

@@ -0,0 +1,10 @@
/* Memory regions for STM32F072RB, 128K flash, 16K RAM. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
}
/* Include main opencm3 linker script */
INCLUDE libopencm3_stm32f0.ld

View File

@@ -0,0 +1,10 @@
/* Memory regions for STM32F103RB, 128K flash, 20K RAM. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}
/* Include main opencm3 linker script */
INCLUDE libopencm3_stm32f1.ld

View File

@@ -0,0 +1,10 @@
/* Memory regions for STM32F411RE, 512K flash, 128K RAM. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
/* Include main opencm3 linker script */
INCLUDE libopencm3_stm32f4.ld

283
ports/cortex-m/tests-main.c Normal file
View File

@@ -0,0 +1,283 @@
/*
* Copyright (c) 2010, Kelvin Lawson. 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.
*/
#include <stdio.h>
#include <libopencm3/cm3/nvic.h>
#include "atom.h"
#include "atomport-private.h"
#include "atomtests.h"
#include "atomtimer.h"
/* Constants */
/*
* Idle thread stack size
*
* This needs to be large enough to handle any interrupt handlers
* and callbacks called by interrupt handlers (e.g. user-created
* timer callbacks) as well as the saving of all context when
* switching away from this thread.
*
* In this case, the idle stack is allocated on the BSS via the
* idle_thread_stack[] byte array.
*/
#define IDLE_STACK_SIZE_BYTES 512
/*
* Main thread stack size
*
* Note that this is not a required OS kernel thread - you will replace
* this with your own application thread.
*
* In this case the Main thread is responsible for calling out to the
* test routines. Once a test routine has finished, the test status is
* printed out on the UART and the thread remains running in a loop
* flashing a LED.
*
* The Main thread stack generally needs to be larger than the idle
* thread stack, as not only does it need to store interrupt handler
* stack saves and context switch saves, but the application main thread
* will generally be carrying out more nested function calls and require
* stack for application code local variables etc.
*
* With all OS tests implemented to date on the AVR, the Main thread
* stack has not exceeded 201 bytes. To allow all tests to run we set
* a minimum main thread stack size of 204 bytes. This may increase in
* future as the codebase changes but for the time being is enough to
* cope with all of the automated tests.
*/
#define MAIN_STACK_SIZE_BYTES 1024
/*
* Startup code stack
*
* Some stack space is required at initial startup for running the main()
* routine. This stack space is only temporarily required at first bootup
* and is no longer required as soon as the OS is started. By default
* GCC sets this to the top of RAM (RAMEND) and it grows down from there.
* Because we only need this temporarily, though, it would be wasteful to
* set aside a region at the top of RAM which is not used during runtime.
*
* What we do here is to reuse part of the idle thread's stack during
* initial startup. As soon as we enter the main() routine we move the
* stack pointer to half-way down the idle thread's stack. This is used
* temporarily while calls are made to atomOSInit(), atomThreadCreate()
* and atomOSStart(). Once the OS is started this stack area is no
* longer required, and can be used for its original purpose (for the
* idle thread's stack).
*
* This does mean, however, that we cannot monitor the stack usage of the
* idle thread. Stack usage is monitored by prefilling the stack with a
* known value, and we are obliterating some of that prefilled area by
* using it as our startup stack, so we cannot use the stack-checking API
* to get a true picture of idle thread stack usage. If you wish to
* monitor idle thread stack usage for your applications then you are
* free to use a different region for the startup stack (e.g. set aside
* an area permanently, or place it somewhere you know you can reuse
* later in the application). For the time being, this method gives us a
* simple way of reducing the memory consumption without having to add
* any special AVR-specific considerations to the automated test
* applications.
*
* This optimisation was required to allow some of the larger automated
* test modules to run on devices with 1KB of RAM. You should avoid doing
* this if you can afford to set aside 64 bytes or so, or if you are
* writing your own applications in which you have further control over
* where data is located.
*/
/* Local data */
/* Application threads' TCBs */
static ATOM_TCB main_tcb;
/* Main thread's stack area */
static uint8_t main_thread_stack[MAIN_STACK_SIZE_BYTES];
/* Idle thread's stack area */
static uint8_t idle_thread_stack[IDLE_STACK_SIZE_BYTES];
/* Forward declarations */
static void main_thread_func (uint32_t data);
/**
* \b main
*
* Program entry point.
*
* Sets up the AVR hardware resources (system tick timer interrupt) necessary
* for the OS to be started. Creates an application thread and starts the OS.
*/
extern int board_setup(void);
int main ( void )
{
int8_t status;
uint32_t loop;
/**
* Brief delay to give the debugger a chance to stop the core before we
* muck around with the chip's configuration.
*/
for(loop = 0; loop < 1000000; ++loop){
__asm__("nop");
}
/**
* Note: to protect OS structures and data during initialisation,
* interrupts must remain disabled until the first thread
* has been restored. They are reenabled at the very end of
* the first thread restore, at which point it is safe for a
* reschedule to take place.
*/
board_setup();
/**
* Initialise the OS before creating our threads.
*
* Note that we cannot enable stack-checking on the idle thread on
* this platform because we are already using part of the idle
* thread's stack now as our startup stack. Prefilling for stack
* checking would overwrite our current stack.
*
* If you are not reusing the idle thread's stack during startup then
* you are free to enable stack-checking here.
*/
status = atomOSInit(&idle_thread_stack[0], IDLE_STACK_SIZE_BYTES, FALSE);
if (status == ATOM_OK)
{
/* Create an application thread */
status = atomThreadCreate(&main_tcb,
TEST_THREAD_PRIO, main_thread_func, 0,
&main_thread_stack[0],
MAIN_STACK_SIZE_BYTES,
TRUE);
if (status == ATOM_OK)
{
/**
* First application thread successfully created. It is
* now possible to start the OS. Execution will not return
* from atomOSStart(), which will restore the context of
* our application thread and start executing it.
*
* Note that interrupts are still disabled at this point.
* They will be enabled as we restore and execute our first
* thread in archFirstThreadRestore().
*/
atomOSStart();
}
}
while (1)
;
/* There was an error starting the OS if we reach here */
return (0);
}
/**
* \b main_thread_func
*
* Entry point for main application thread.
*
* This is the first thread that will be executed when the OS is started.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
extern void test_led_toggle(void);
static void main_thread_func (uint32_t data __maybe_unused)
{
uint32_t test_status;
int sleep_ticks;
/* Put a message out on the UART */
printf("Go\n");
/* Start test. All tests use the same start API. */
test_status = test_start();
/* Check main thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
if (test_status == 0)
{
uint32_t used_bytes, free_bytes;
/* Check idle thread stack usage */
if (atomThreadStackCheck (&main_tcb, &used_bytes, &free_bytes) == ATOM_OK)
{
/* Check the thread did not use up to the end of stack */
if (free_bytes == 0)
{
printf("Main stack overflow\n");
test_status++;
}
/* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
printf("MainUse: %lu\n", used_bytes);
#endif
}
}
#endif
/* Log final status */
if (test_status == 0)
{
printf("Pass\n");
}
else
{
printf("Fail(%lu)\n", test_status);
}
/* Flash LED once per second if passed, very quickly if failed */
sleep_ticks = (test_status == 0) ? SYSTEM_TICKS_PER_SEC : (SYSTEM_TICKS_PER_SEC/8);
/* Test finished, flash slowly for pass, fast for fail */
while (1)
{
/* Toggle a LED (STK500-specific) */
test_led_toggle();
/* Sleep then toggle LED again */
atomTimerDelay (sleep_ticks);
}
}

199
ports/stm8/README Normal file
View File

@@ -0,0 +1,199 @@
---------------------------------------------------------------------------
Library: Atomthreads
Author: Kelvin Lawson <info@atomthreads.com>
Website: http://atomthreads.com
License: BSD Revised
---------------------------------------------------------------------------
STM8 PORT
This folder contains a port of the Atomthreads real time kernel for the
STM8 processor architecture. These instructions cover compiler-agnostic
aspects of usage of Atomthreads.
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-raisonance.s: 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:
* atomport.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 the SDCC, Cosmic, Raisonance 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 th ecompiler-agnostic aspects of usage of Atomthreads.
Instructions for users of particular compilers are available in README-SDCC,
README-IAR, README-COSMIC and README-RASONANCE.
---------------------------------------------------------------------------
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 RX: CN4 pin 11 (connect to TX at the PC end)
UART TX: CN4 pin 10 (connect to RX 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
raisonance.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.
---------------------------------------------------------------------------
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 95 bytes of stack, and the main test thread has
been seen to consume 163 bytes of stack. At this time the queue9 test is
the largest consumer of test thread stack (95 bytes) and the sem1 test
consumes the largest main thread stack (137 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).
---------------------------------------------------------------------------
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.
---------------------------------------------------------------------------

View File

@@ -13,44 +13,10 @@ This folder contains a port of the Atomthreads real time kernel for the
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
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:
Compiler-agnostic aspects of the usage of Atomthreads can be found in README.
* atomport.c: Those functions which can be written in C
* 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
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)
* stm8_interrupt_vector.c: List of interrupt handlers for vector table
* 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 the Cosmic, Raisonance 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 other compilers are available in README-IAR
and README-RAISONANCE.
Instructions for users of the other compilers are available in README-SDCC,
README-IAR and README-RAISONANCE.
---------------------------------------------------------------------------
@@ -212,49 +178,6 @@ 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 RX: CN4 pin 11 (connect to TX at the PC end)
UART TX: CN4 pin 10 (connect to RX 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
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.
---------------------------------------------------------------------------
RUNNING THE AUTOMATED TESTS
@@ -322,155 +245,6 @@ both Debug and Release builds as follows:
0x7BF for application usage, and 0x7C0 to 0x7FF for startup stack.
---------------------------------------------------------------------------
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 95 bytes of stack, and the main test thread has
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.
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 RAM layout used for the automated test applications is as follows:
RAM Top:
* Startup Stack (64 bytes)
* Data & BSS area (thread stacks, other application data)
RAM Bottom.
This is not prescribed, you may use whichever layout you wish for your
applications.
The startup stack area starts at the top of RAM and is only used for first
initialisation of the OS and main thread. This uses 64 bytes and could be
reused once the OS is started, but for the purposes of the automated test
applications it is not reused. Generally you would ensure that this is
reused in your own application code.
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.
The default layout provided with Atomthreads matches the STM8S-Discovery
with 2KB RAM. The linker file reserves the first 0x7C0 bytes for data
areas. The region from here up to the end of RAM (0x800) is used for the
the 64 byte startup stack.
As mentioned previously, this RAM layout is only the one utilised by the
test applications. You may choose whatever layout you like.
Note that on this platform data can be placed at address 0x0, but the
Atomthreads kernel performs validity checks on pointers to ensure they
are not NULL pointers (point to address 0x0). For this reason the
example projects (STVD and Makefile) force the linker to not use address
0x0 and instead start the page0 space at 0x2. This ensures that the
linker does not place any data at address 0x0, and hence all NULL-ptr
checks are still suitable checks for valid pointers. This does, however,
waste 2 bytes. For your own projects you can force this within STVD by
editing the project linker settings (Input -> Zero Page start at 0x2)
or by editing the linker .LKF file as can be seen in atomthreads.lkf.
---------------------------------------------------------------------------
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.
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

View File

@@ -13,43 +13,10 @@ 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:
Compiler-agnostic aspects of the usage of Atomthreads can be found in README.
* 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 the Cosmic, Raisonance 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 other compilers are available in README-COSMIC and
README-RAISONANCE.
Instructions for users of the other compilers are available in README-SDCC,
README-COSMIC and README-RAISONANCE.
---------------------------------------------------------------------------
@@ -188,50 +155,6 @@ 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 RX: CN4 pin 11 (connect to TX at the PC end)
UART TX: CN4 pin 10 (connect to RX 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
@@ -311,107 +234,6 @@ Add the .C and .S modules from the following folders:
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

View File

@@ -13,43 +13,10 @@ This folder contains a port of the Atomthreads real time kernel for the
STM8 processor architecture. These instructions cover usage of Atomthreads
with the Raisonance compiler (RCSTM8).
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:
Compiler-agnostic aspects of the usage of Atomthreads can be found in README.
* atomport.c: Those functions which can be written in C
* atomport-asm-raisonance.s: 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 the Cosmic, Raisonance 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 Raisonance compiler.
Instructions for users of the other compilers are available in README-IAR
and README-COSMIC.
Instructions for users of the other compilers are available in README-SDCC,
README-IAR and README-COSMIC.
---------------------------------------------------------------------------
@@ -204,49 +171,6 @@ 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 RX: CN4 pin 11 (connect to TX at the PC end)
UART TX: CN4 pin 10 (connect to RX 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
raisonance.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.
---------------------------------------------------------------------------
RUNNING THE AUTOMATED TESTS
@@ -318,106 +242,6 @@ functions in reentrant mode, however it does this by default on the STM8
platform so no user action is required (unlike when targeting the STM7
platform with Raisonance).
---------------------------------------------------------------------------
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 95 bytes of stack, and the main test thread has
been seen to consume 163 bytes of stack. At this time the queue9 test is
the largest consumer of test thread stack (95 bytes) and the sem1 test
consumes the largest main thread stack (137 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).
---------------------------------------------------------------------------
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.
---------------------------------------------------------------------------

61
ports/stm8/README-SDCC Normal file
View File

@@ -0,0 +1,61 @@
---------------------------------------------------------------------------
Author: Dr. Philipp Klaus Krause
---------------------------------------------------------------------------
STM8 PORT - SMALL DEVICE C 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 Small Device C Compiler (SDCC).
This README covers usage of Atomthreads with SDCC.
Instructions for users of the other compilers are available in README-COSMIC,
README-IAR and README-RAISONANCE.
---------------------------------------------------------------------------
PREREQUISITES
The port works out-of-the-box with SDCC and GNU make for
building.
* SDCC 3.6.0 or later
* Programming software (e.g. stm8flash)
---------------------------------------------------------------------------
BUILD VIA MAKEFILE
* make -f sdcc.mak
All objects are built into the 'build-sdcc' folder under ports/stm8.
The build process builds separate target applications for each automated
test, and appropriate .ihx 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 sdcc.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 raisonance.mak doxygen
---------------------------------------------------------------------------
PROGRAMMING MAKEFILE-BUILT APPLICATIONS TO THE TARGET DEVICE
Applications can be written onto the STM8S-Discovery board using:
* stm8flash -c stlink -p stm8s105c6 -w <filename>
---------------------------------------------------------------------------

View File

@@ -0,0 +1,48 @@
; Copyright (c) 2016 Dr. Philipp Klaus Krause
; Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
; The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
.area CODE
; uint8_t get_cc(void);
_get_cc::
push cc
pop a
ret
; void set_cc(uint8_t);
_set_cc::
ld a, (3, sp)
push a
pop cc
ret
; void archContextSwitch (ATOM_TCB *old_tcb_ptr, ATOM_TCB *new_tcb_ptr)
_archContextSwitch::
; save context
ldw x, (3, sp)
ldw y, sp
ldw (x), y
; restore context
ldw x, (5, sp)
ldw x, (x)
ldw sp, x
ret
; void archFirstThreadRestore (ATOM_TCB *new_tcb_ptr)
_archFirstThreadRestore::
; restore context
ldw x, (3, sp)
ldw x, (x)
ldw sp, x
ret

View File

@@ -64,13 +64,18 @@
#define INTERRUPT @far @interrupt @svlreg
#elif defined (__IAR_SYSTEMS_ICC__)
#define INTERRUPT __interrupt
#elif defined(__RCSTM8__)
#elif defined(__RCSTM8__) || defined(__SDCC_stm8)
#define INTERRUPT
#endif
/* Function prototypes */
void archInitSystemTickTimer (void);
#ifndef __SDCC_stm8
INTERRUPT void TIM1_SystemTickISR (void);
#else
void TIM1_SystemTickISR (void) __interrupt(11);
#endif
#endif /* __ATOM_PORT_PRIVATE_H */

View File

@@ -46,7 +46,7 @@
#define _STR
/* Default thread stack size (in bytes) */
#define TEST_THREAD_STACK_SIZE 128
#define TEST_THREAD_STACK_SIZE 192
/* Uncomment to enable logging of stack usage to UART */
#define TESTS_LOG_STACK_USAGE

View File

@@ -95,6 +95,8 @@ static NO_REG_SAVE void thread_shell (void)
rim();
#elif defined(__RCSTM8__)
_rim_();
#elif defined(__SDCC_stm8)
__asm__("rim");
#endif
/* Call the thread entry point */
@@ -293,6 +295,9 @@ void archInitSystemTickTimer ( void )
INTERRUPT void TIM1_SystemTickISR (void)
#if defined(__RCSTM8__)
interrupt 11
#elif defined(__SDCC_stm8)
__interrupt(11)
#endif
{
/* Call the interrupt entry routine */
@@ -307,3 +312,4 @@ interrupt 11
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
* Copyright (c) 2016, Dr. Philipp Klaus Krause.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -45,20 +46,23 @@
/* Required number of system ticks per second (normally 100 for 10ms tick) */
#define SYSTEM_TICKS_PER_SEC 100
/* Size of each stack entry / stack alignment size (8 bits on STM8) */
#define STACK_ALIGN_SIZE sizeof(u8)
/**
* Architecture-specific types.
*/
#if defined(__CSMC__) || defined (__RCSTM8__) /* Cosmic and Raisonance do not have the C99 stdint.h header*/
#define int8_t s8
#define int16_t s16
#define int32_t s32
#define uint8_t u8
#define uint16_t u16
#define uint32_t u32
#else
#include <stdint.h>
#endif
#define POINTER void *
/* Size of each stack entry / stack alignment size (8 bits on STM8) */
#define STACK_ALIGN_SIZE sizeof(uint8_t)
/**
* Critical region protection: this should disable interrupts
@@ -84,6 +88,14 @@
#define CRITICAL_STORE unsigned char ccr
#define CRITICAL_START() ccr = _getCC_(); _sim_()
#define CRITICAL_END() _setCC_(ccr)
/* SDCC: Use custom function */
#elif defined(__SDCC_stm8)
uint8_t get_cc(void);
void set_cc(uint8_t);
#define CRITICAL_STORE uint8_t ccr
#define CRITICAL_START() ccr = get_cc(); __asm__("sim")
#define CRITICAL_END() set_cc(ccr)
#endif
/* Uncomment to enable stack-checking */

107
ports/stm8/sdcc.mak Normal file
View File

@@ -0,0 +1,107 @@
KERNEL_DIR=../../kernel
TESTS_DIR=../../tests
PERIPHS_DIR=stm8s-periphs
CC=sdcc
ASM=sdasstm8
LINK=sdcc
# CPU part number
PART=STM8S105
# Enable stack-checking
STACK_CHECK=true
# Directory for built objects
BUILD_DIR=build-sdcc
# Port/application object files
APP_OBJECTS = atomport.rel tests-main.rel uart.rel
APP_ASM_OBJECTS = atomport-asm-sdcc.rel
# STM8S Peripheral driver object files
PERIPH_OBJECTS = stm8s_gpio.rel stm8s_tim1.rel stm8s_clk.rel stm8s_uart2.rel
# Kernel object files
KERNEL_OBJECTS = atomkernel.rel atomsem.rel atommutex.rel atomtimer.rel atomqueue.rel
# 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,%.rel,$(wildcard $(TESTS_DIR)/*.c)))
# Target application filenames (.elf) for each test object
TEST_HEXS = $(patsubst %.rel,%.ihx,$(TEST_OBJECTS))
TEST_ELFS = $(patsubst %.rel,%.elf,$(TEST_OBJECTS))
# Search build/output directory for dependencies
vpath %.rel .\$(BUILD_DIR)
vpath %.elf .\$(BUILD_DIR)
vpath %.hex .\$(BUILD_DIR)
# Compiler/Assembler flags
CFLAGS= -mstm8 -c -D $(PART) --opt-code-size
DBG_CFLAGS= -mstm8 -c -D $(PART) --opt-code-size
ASMFLAGS= -loff
DBG_ASMFLAGS= -loff
LINKFLAGS= -mstm8
DBG_LINKFLAGS= --debug -mstm8
# Enable stack-checking (disable if not required)
ifeq ($(STACK_CHECK),true)
CFLAGS += -D ATOM_STACK_CHECKING
DBG_CFLAGS += --debug -D ATOM_STACK_CHECKING
endif
#################
# Build targets #
#################
# All tests
all: $(BUILD_DIR) $(TEST_HEXS) sdcc.mak
# Make build/output directory
$(BUILD_DIR):
mkdir $(BUILD_DIR)
# Test HEX files (one application build for each test)
$(TEST_HEXS): %.ihx: %.rel $(KERNEL_OBJECTS) $(PERIPH_OBJECTS) $(APP_OBJECTS) $(APP_ASM_OBJECTS)
$(LINK) $(BUILD_DIR)/$(notdir $<) $(BUILT_OBJECTS) $(LINKFLAGS) -o $(BUILD_DIR)/$@
# Test ELF files (one application build for each test)
$(TEST_ELFS): %.elf: %.rel $(KERNEL_OBJECTS) $(PERIPH_OBJECTS) $(APP_OBJECTS) $(APP_ASM_OBJECTS)
$(LINK) $(BUILD_DIR)/$(notdir $<) $(BUILT_OBJECTS) $(LINKFLAGS) --out-fmt-elf -o $(BUILD_DIR)/$@
# Kernel objects builder
$(KERNEL_OBJECTS): %.rel: $(KERNEL_DIR)/%.c
$(CC) $< $(CFLAGS) -I . -I $(PERIPHS_DIR) -o $(BUILD_DIR)/$*.rel
# Test objects builder
$(TEST_OBJECTS): %.rel: $(TESTS_DIR)/%.c
$(CC) $< $(CFLAGS) -I . -I $(KERNEL_DIR) -I $(PERIPHS_DIR) -o $(BUILD_DIR)/$*.rel
# Peripheral objects builder
$(PERIPH_OBJECTS): %.rel: $(PERIPHS_DIR)/%.c
$(CC) $< $(CFLAGS) -I . -I $(PERIPHS_DIR) -o $(BUILD_DIR)/$*.rel
# Application C objects builder
$(APP_OBJECTS): %.rel: ./%.c
$(CC) $< $(CFLAGS) -I . -I $(KERNEL_DIR) -I $(TESTS_DIR) -I $(PERIPHS_DIR) -o $(BUILD_DIR)/$*.rel
# Application asm objects builder
$(APP_ASM_OBJECTS): %.rel: ./%.s
$(ASM) $(ASMFLAGS) $(BUILD_DIR)/$(notdir $@) $<
# Clean
clean:
rm -f *.o *.elf *.map *.hex *.bin *.lst *.stm8 *.s19
rm -rf doxygen-kernel
rm -rf doxygen-stm8
rm -rf build-sdcc
doxygen:
doxygen $(KERNEL_DIR)/Doxyfile
doxygen ./Doxyfile

View File

@@ -30,15 +30,23 @@
#if defined(__CSMC__)
#undef _RAISONANCE_
#undef _IAR_SYSTEMS_
#undef _SDCC_
#define _COSMIC_
#elif defined(__RCST7__)
#undef _COSMIC_
#undef _IAR_SYSTEMS_
#undef _SDCC_
#define _RAISONANCE_
#elif defined(__IAR_SYSTEMS_ICC__)
#undef _COSMIC_
#undef _RAISONANCE_
#undef _SDCC_
#define _IAR_SYSTEMS_
#elif defined(__SDCC_stm8)
#undef _COSMIC_
#undef _RAISONANCE_
#undef _IAR_SYSTEMS_
#define _SDCC_
#else
#error "Unsupported Compiler!" /* Compiler defines not found */
#endif
@@ -90,6 +98,11 @@
#define __CONST const
#endif
#ifdef _SDCC_
#define NEAR
#define __CONST const
#endif
#ifdef PointerAttr_Far
#define PointerAttr FAR
#else /* PointerAttr_Near */

View File

@@ -39,6 +39,10 @@
* None
* @retval u8 Content of CC register (in A register).
*/
#ifdef __SDCC_stm8
uint8_t get_cc(void);
#endif
u8 ITC_GetCPUCC(void)
{
#ifdef _COSMIC_
@@ -46,6 +50,10 @@ u8 ITC_GetCPUCC(void)
_asm("pop a");
return; /* Ignore compiler warning, the returned value is in A register */
#endif
#ifdef __SDCC_stm8
return get_cc();
#endif
#ifdef _RAISONANCE_
return _getCC_();

View File

@@ -73,12 +73,12 @@
* stack for application code local variables etc.
*
* With all OS tests implemented to date on the STM8, the Main thread
* stack has not exceeded 256 bytes. To allow all tests to run we set
* stack has not exceeded 384 bytes. To allow all tests to run we set
* a minimum main thread stack size of 204 bytes. This may increase in
* future as the codebase changes but for the time being is enough to
* cope with all of the automated tests.
*/
#define MAIN_STACK_SIZE_BYTES 256
#define MAIN_STACK_SIZE_BYTES 384
/*

View File

@@ -154,3 +154,19 @@ size_t __write(int handle, const unsigned char *buf, size_t bufSize)
return (chars_written);
}
#endif /* __IAR_SYSTEMS_ICC__ */
#if defined(__SDCC_stm8)
#if __SDCC_REVISION >= 9624
int putchar (int c)
{
return(uart_putchar(c));
}
#else
void putchar (char c)
{
uart_putchar(c);
}
#endif
#endif

13
tests/commit-tests-arm.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/bash
# Quit on any error
set -e
# Start at top-level directory
cd `dirname $0`/..
# Build qemu-arm and run tests
cd ports/arm/platforms/qemu_integratorcp
make clean
make
make qemutests

13
tests/commit-tests-avr.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/bash
# Quit on any error
set -e
# Start at top-level directory
cd `dirname $0`/..
# Build avr and run tests
cd ports/avr
make clean
make PART=atmega128
make PART=atmega128 simtests

14
tests/commit-tests-cortex-m.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
# Quit on any error
set -e
# Start at top-level directory
cd `dirname $0`/..
# Build qemu-arm-cortex-m and run tests
cd ports/cortex-m
# git submodule?
make clean
make
make BOARD=qemu QEMU=/usr/local/bin/qemu-system-gnuarmeclipse qemutests

140
tests/timer8.c Normal file
View File

@@ -0,0 +1,140 @@
/*
* Copyright (c) 2016, Kelvin Lawson. 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.
*/
#include "atom.h"
#include "atomtimer.h"
#include "atomtests.h"
/* Tick delay before each callback */
#define CALLBACK_TICKS 2
/* Number of re-registrations to make from callbacks */
#define NUM_CALLBACKS (SYSTEM_TICKS_PER_SEC / CALLBACK_TICKS)
/* Test OS objects */
static ATOM_TIMER timer_cb;
/* Global test data */
static int callback_ran_count;
/* Forward declarations */
static void testCallback (POINTER cb_data);
/**
* \b test_start
*
* Start timer test.
*
* This test checks that a timer can be registered from within a timer
* callback context. i.e. checks the kernel timer queue can handle additions
* to the timer queue while already walking the queue during a timer callback.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
/* Default to zero failures */
failures = 0;
/* Clear down the callback count */
callback_ran_count = 0;
/* Fill out timer request structures for 2 ticks from now */
timer_cb.cb_ticks = CALLBACK_TICKS;
timer_cb.cb_func = testCallback;
timer_cb.cb_data = &callback_ran_count;
/* Register timer */
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg\n"));
failures++;
}
/* Timer was successfully created */
else
{
/* Sleep for twice the period we expect the test to take */
atomTimerDelay (2 * CALLBACK_TICKS * NUM_CALLBACKS);
/*
* We should now find that the timer callback has run the correct
* number of times.
*/
if (callback_ran_count != NUM_CALLBACKS)
{
ATOMLOG (_STR("Callback count %d vs %d\n"), callback_ran_count, NUM_CALLBACKS);
failures++;
}
}
/* Quit */
return failures;
}
/**
* \b testCallback
*
* Increment a counut to say we ran. Also register the same timer to occur
* again, up to a fixed number of times. The main test procedure can wait
* and check the count to see that all of the requested callbacks occurred
* (and hence timer registration from within a timer callback worked).
*
* @param[in] cb_data Pointer to counter of callback runs
*/
static void testCallback (POINTER cb_data)
{
int *ran_count_ptr = (int *)cb_data;
/* Callback was called */
*ran_count_ptr += 1;
/* If the test is still running, register the same timer again */
if (*ran_count_ptr < NUM_CALLBACKS)
{
/* Same timer details as previously */
timer_cb.cb_ticks = CALLBACK_TICKS;
timer_cb.cb_func = testCallback;
timer_cb.cb_data = &callback_ran_count;
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("TimerCbReg\n"));
}
}
}