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
125 changed files with 7188 additions and 11575 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

@@ -50,6 +50,11 @@ typedef struct atom_tcb
*/
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;
@@ -65,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
@@ -72,10 +78,6 @@ typedef struct atom_tcb
uint32_t stack_size; /* Size of stack allocation in bytes */
#endif
#ifdef ATOM_TLS
ATOM_TLS /* Thread Local Storage */
#endif
} ATOM_TCB;

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;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,844 +0,0 @@
/**************************************************************************//**
* @file core_cmFunc.h
* @brief CMSIS Cortex-M Core Function Access Header File
* @version V2.01
* @date 06. December 2010
*
* @note
* Copyright (C) 2009-2010 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers. This file can be freely distributed
* within development tools that are supporting such ARM based processors.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#ifndef __CORE_CMFUNC_H__
#define __CORE_CMFUNC_H__
/* ########################### Core Function Access ########################### */
/** \ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions
@{
*/
#if defined ( __CC_ARM ) /*------------------ RealView Compiler ----------------*/
/* ARM armcc specific functions */
/* intrinsic void __enable_irq(); */
/* intrinsic void __disable_irq(); */
/** \brief Get Control Register
This function returns the content of the Control Register.
\return Control Register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_CONTROL(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_CONTROL(void)
{
register uint32_t __regControl __ASM("control");
return(__regControl);
}
#endif /* __ARMCC_VERSION */
/** \brief Set Control Register
This function writes the given value to the Control Register.
\param [in] control Control Register value to set
*/
#if (__ARMCC_VERSION < 400000)
extern void __set_CONTROL(uint32_t control);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE void __set_CONTROL(uint32_t control)
{
register uint32_t __regControl __ASM("control");
__regControl = control;
}
#endif /* __ARMCC_VERSION */
/** \brief Get ISPR Register
This function returns the content of the ISPR Register.
\return ISPR Register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_IPSR(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_IPSR(void)
{
register uint32_t __regIPSR __ASM("ipsr");
return(__regIPSR);
}
#endif /* __ARMCC_VERSION */
/** \brief Get APSR Register
This function returns the content of the APSR Register.
\return APSR Register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_APSR(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_APSR(void)
{
register uint32_t __regAPSR __ASM("apsr");
return(__regAPSR);
}
#endif /* __ARMCC_VERSION */
/** \brief Get xPSR Register
This function returns the content of the xPSR Register.
\return xPSR Register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_xPSR(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_xPSR(void)
{
register uint32_t __regXPSR __ASM("xpsr");
return(__regXPSR);
}
#endif /* __ARMCC_VERSION */
/** \brief Get Process Stack Pointer
This function returns the current value of the Process Stack Pointer (PSP).
\return PSP Register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_PSP(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_PSP(void)
{
register uint32_t __regProcessStackPointer __ASM("psp");
return(__regProcessStackPointer);
}
#endif /* __ARMCC_VERSION */
/** \brief Set Process Stack Pointer
This function assigns the given value to the Process Stack Pointer (PSP).
\param [in] topOfProcStack Process Stack Pointer value to set
*/
#if (__ARMCC_VERSION < 400000)
extern void __set_PSP(uint32_t topOfProcStack);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE void __set_PSP(uint32_t topOfProcStack)
{
register uint32_t __regProcessStackPointer __ASM("psp");
__regProcessStackPointer = topOfProcStack;
}
#endif /* __ARMCC_VERSION */
/** \brief Get Main Stack Pointer
This function returns the current value of the Main Stack Pointer (MSP).
\return MSP Register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_MSP(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_MSP(void)
{
register uint32_t __regMainStackPointer __ASM("msp");
return(__regMainStackPointer);
}
#endif /* __ARMCC_VERSION */
/** \brief Set Main Stack Pointer
This function assigns the given value to the Main Stack Pointer (MSP).
\param [in] topOfMainStack Main Stack Pointer value to set
*/
#if (__ARMCC_VERSION < 400000)
extern void __set_MSP(uint32_t topOfMainStack);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE void __set_MSP(uint32_t topOfMainStack)
{
register uint32_t __regMainStackPointer __ASM("msp");
__regMainStackPointer = topOfMainStack;
}
#endif /* __ARMCC_VERSION */
/** \brief Get Priority Mask
This function returns the current state of the priority mask bit from the Priority Mask Register.
\return Priority Mask value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_PRIMASK(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_PRIMASK(void)
{
register uint32_t __regPriMask __ASM("primask");
return(__regPriMask);
}
#endif /* __ARMCC_VERSION */
/** \brief Set Priority Mask
This function assigns the given value to the Priority Mask Register.
\param [in] priMask Priority Mask
*/
#if (__ARMCC_VERSION < 400000)
extern void __set_PRIMASK(uint32_t priMask);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE void __set_PRIMASK(uint32_t priMask)
{
register uint32_t __regPriMask __ASM("primask");
__regPriMask = (priMask);
}
#endif /* __ARMCC_VERSION */
#if (__CORTEX_M >= 0x03)
/** \brief Enable FIQ
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
#define __enable_fault_irq __enable_fiq
/** \brief Disable FIQ
This function disables FIQ interrupts by setting the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
#define __disable_fault_irq __disable_fiq
/** \brief Get Base Priority
This function returns the current value of the Base Priority register.
\return Base Priority register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_BASEPRI(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_BASEPRI(void)
{
register uint32_t __regBasePri __ASM("basepri");
return(__regBasePri);
}
#endif /* __ARMCC_VERSION */
/** \brief Set Base Priority
This function assigns the given value to the Base Priority register.
\param [in] basePri Base Priority value to set
*/
#if (__ARMCC_VERSION < 400000)
extern void __set_BASEPRI(uint32_t basePri);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE void __set_BASEPRI(uint32_t basePri)
{
register uint32_t __regBasePri __ASM("basepri");
__regBasePri = (basePri & 0xff);
}
#endif /* __ARMCC_VERSION */
/** \brief Get Fault Mask
This function returns the current value of the Fault Mask register.
\return Fault Mask register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_FAULTMASK(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_FAULTMASK(void)
{
register uint32_t __regFaultMask __ASM("faultmask");
return(__regFaultMask);
}
#endif /* __ARMCC_VERSION */
/** \brief Set Fault Mask
This function assigns the given value to the Fault Mask register.
\param [in] faultMask Fault Mask value to set
*/
#if (__ARMCC_VERSION < 400000)
extern void __set_FAULTMASK(uint32_t faultMask);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE void __set_FAULTMASK(uint32_t faultMask)
{
register uint32_t __regFaultMask __ASM("faultmask");
__regFaultMask = (faultMask & 1);
}
#endif /* __ARMCC_VERSION */
#endif /* (__CORTEX_M >= 0x03) */
#if (__CORTEX_M == 0x04)
/** \brief Get FPSCR
This function returns the current value of the Floating Point Status/Control register.
\return Floating Point Status/Control register value
*/
static __INLINE uint32_t __get_FPSCR(void)
{
#if (__FPU_PRESENT == 1)
register uint32_t __regfpscr __ASM("fpscr");
return(__regfpscr);
#else
return(0);
#endif
}
/** \brief Set FPSCR
This function assigns the given value to the Floating Point Status/Control register.
\param [in] fpscr Floating Point Status/Control value to set
*/
static __INLINE void __set_FPSCR(uint32_t fpscr)
{
#if (__FPU_PRESENT == 1)
register uint32_t __regfpscr __ASM("fpscr");
__regfpscr = (fpscr);
#endif
}
#endif /* (__CORTEX_M == 0x04) */
#elif (defined (__ICCARM__)) /*---------------- ICC Compiler ---------------------*/
/* IAR iccarm specific functions */
#if defined (__ICCARM__)
#include <intrinsics.h> /* IAR Intrinsics */
#endif
#pragma diag_suppress=Pe940
/** \brief Enable IRQ Interrupts
This function enables IRQ interrupts by clearing the I-bit in the CPSR.
Can only be executed in Privileged modes.
*/
#define __enable_irq __enable_interrupt
/** \brief Disable IRQ Interrupts
This function disables IRQ interrupts by setting the I-bit in the CPSR.
Can only be executed in Privileged modes.
*/
#define __disable_irq __disable_interrupt
/* intrinsic unsigned long __get_CONTROL( void ); (see intrinsic.h) */
/* intrinsic void __set_CONTROL( unsigned long ); (see intrinsic.h) */
/** \brief Get ISPR Register
This function returns the content of the ISPR Register.
\return ISPR Register value
*/
static uint32_t __get_IPSR(void)
{
__ASM("mrs r0, ipsr");
}
/** \brief Get APSR Register
This function returns the content of the APSR Register.
\return APSR Register value
*/
static uint32_t __get_APSR(void)
{
__ASM("mrs r0, apsr");
}
/** \brief Get xPSR Register
This function returns the content of the xPSR Register.
\return xPSR Register value
*/
static uint32_t __get_xPSR(void)
{
__ASM("mrs r0, psr"); // assembler does not know "xpsr"
}
/** \brief Get Process Stack Pointer
This function returns the current value of the Process Stack Pointer (PSP).
\return PSP Register value
*/
static uint32_t __get_PSP(void)
{
__ASM("mrs r0, psp");
}
/** \brief Set Process Stack Pointer
This function assigns the given value to the Process Stack Pointer (PSP).
\param [in] topOfProcStack Process Stack Pointer value to set
*/
static void __set_PSP(uint32_t topOfProcStack)
{
__ASM("msr psp, r0");
}
/** \brief Get Main Stack Pointer
This function returns the current value of the Main Stack Pointer (MSP).
\return MSP Register value
*/
static uint32_t __get_MSP(void)
{
__ASM("mrs r0, msp");
}
/** \brief Set Main Stack Pointer
This function assigns the given value to the Main Stack Pointer (MSP).
\param [in] topOfMainStack Main Stack Pointer value to set
*/
static void __set_MSP(uint32_t topOfMainStack)
{
__ASM("msr msp, r0");
}
/* intrinsic unsigned long __get_PRIMASK( void ); (see intrinsic.h) */
/* intrinsic void __set_PRIMASK( unsigned long ); (see intrinsic.h) */
#if (__CORTEX_M >= 0x03)
/** \brief Enable FIQ
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
static __INLINE void __enable_fault_irq(void)
{
__ASM ("cpsie f");
}
/** \brief Disable FIQ
This function disables FIQ interrupts by setting the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
static __INLINE void __disable_fault_irq(void)
{
__ASM ("cpsid f");
}
/* intrinsic unsigned long __get_BASEPRI( void ); (see intrinsic.h) */
/* intrinsic void __set_BASEPRI( unsigned long ); (see intrinsic.h) */
/* intrinsic unsigned long __get_FAULTMASK( void ); (see intrinsic.h) */
/* intrinsic void __set_FAULTMASK(unsigned long); (see intrinsic.h) */
#endif /* (__CORTEX_M >= 0x03) */
#if (__CORTEX_M == 0x04)
/** \brief Get FPSCR
This function returns the current value of the Floating Point Status/Control register.
\return Floating Point Status/Control register value
*/
static uint32_t __get_FPSCR(void)
{
#if (__FPU_PRESENT == 1)
__ASM("vmrs r0, fpscr");
#else
return(0);
#endif
}
/** \brief Set FPSCR
This function assigns the given value to the Floating Point Status/Control register.
\param [in] fpscr Floating Point Status/Control value to set
*/
static void __set_FPSCR(uint32_t fpscr)
{
#if (__FPU_PRESENT == 1)
__ASM("vmsr fpscr, r0");
#endif
}
#endif /* (__CORTEX_M == 0x04) */
#pragma diag_default=Pe940
#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/
/* GNU gcc specific functions */
/** \brief Enable IRQ Interrupts
This function enables IRQ interrupts by clearing the I-bit in the CPSR.
Can only be executed in Privileged modes.
*/
__attribute__( ( always_inline ) ) static __INLINE void __enable_irq(void)
{
__ASM volatile ("cpsie i");
}
/** \brief Disable IRQ Interrupts
This function disables IRQ interrupts by setting the I-bit in the CPSR.
Can only be executed in Privileged modes.
*/
__attribute__( ( always_inline ) ) static __INLINE void __disable_irq(void)
{
__ASM volatile ("cpsid i");
}
/** \brief Get Control Register
This function returns the content of the Control Register.
\return Control Register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_CONTROL(void)
{
uint32_t result;
__ASM volatile ("MRS %0, control" : "=r" (result) );
return(result);
}
/** \brief Set Control Register
This function writes the given value to the Control Register.
\param [in] control Control Register value to set
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_CONTROL(uint32_t control)
{
__ASM volatile ("MSR control, %0" : : "r" (control) );
}
/** \brief Get ISPR Register
This function returns the content of the ISPR Register.
\return ISPR Register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_IPSR(void)
{
uint32_t result;
__ASM volatile ("MRS %0, ipsr" : "=r" (result) );
return(result);
}
/** \brief Get APSR Register
This function returns the content of the APSR Register.
\return APSR Register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_APSR(void)
{
uint32_t result;
__ASM volatile ("MRS %0, apsr" : "=r" (result) );
return(result);
}
/** \brief Get xPSR Register
This function returns the content of the xPSR Register.
\return xPSR Register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_xPSR(void)
{
uint32_t result;
__ASM volatile ("MRS %0, xpsr" : "=r" (result) );
return(result);
}
/** \brief Get Process Stack Pointer
This function returns the current value of the Process Stack Pointer (PSP).
\return PSP Register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_PSP(void)
{
register uint32_t result;
__ASM volatile ("MRS %0, psp\n" : "=r" (result) );
return(result);
}
/** \brief Set Process Stack Pointer
This function assigns the given value to the Process Stack Pointer (PSP).
\param [in] topOfProcStack Process Stack Pointer value to set
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_PSP(uint32_t topOfProcStack)
{
__ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) );
}
/** \brief Get Main Stack Pointer
This function returns the current value of the Main Stack Pointer (MSP).
\return MSP Register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_MSP(void)
{
register uint32_t result;
__ASM volatile ("MRS %0, msp\n" : "=r" (result) );
return(result);
}
/** \brief Set Main Stack Pointer
This function assigns the given value to the Main Stack Pointer (MSP).
\param [in] topOfMainStack Main Stack Pointer value to set
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_MSP(uint32_t topOfMainStack)
{
__ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) );
}
/** \brief Get Priority Mask
This function returns the current state of the priority mask bit from the Priority Mask Register.
\return Priority Mask value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_PRIMASK(void)
{
uint32_t result;
__ASM volatile ("MRS %0, primask" : "=r" (result) );
return(result);
}
/** \brief Set Priority Mask
This function assigns the given value to the Priority Mask Register.
\param [in] priMask Priority Mask
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_PRIMASK(uint32_t priMask)
{
__ASM volatile ("MSR primask, %0" : : "r" (priMask) );
}
#if (__CORTEX_M >= 0x03)
/** \brief Enable FIQ
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
__attribute__( ( always_inline ) ) static __INLINE void __enable_fault_irq(void)
{
__ASM volatile ("cpsie f");
}
/** \brief Disable FIQ
This function disables FIQ interrupts by setting the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
__attribute__( ( always_inline ) ) static __INLINE void __disable_fault_irq(void)
{
__ASM volatile ("cpsid f");
}
/** \brief Get Base Priority
This function returns the current value of the Base Priority register.
\return Base Priority register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_BASEPRI(void)
{
uint32_t result;
__ASM volatile ("MRS %0, basepri_max" : "=r" (result) );
return(result);
}
/** \brief Set Base Priority
This function assigns the given value to the Base Priority register.
\param [in] basePri Base Priority value to set
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_BASEPRI(uint32_t value)
{
__ASM volatile ("MSR basepri, %0" : : "r" (value) );
}
/** \brief Get Fault Mask
This function returns the current value of the Fault Mask register.
\return Fault Mask register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_FAULTMASK(void)
{
uint32_t result;
__ASM volatile ("MRS %0, faultmask" : "=r" (result) );
return(result);
}
/** \brief Set Fault Mask
This function assigns the given value to the Fault Mask register.
\param [in] faultMask Fault Mask value to set
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_FAULTMASK(uint32_t faultMask)
{
__ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) );
}
#endif /* (__CORTEX_M >= 0x03) */
#if (__CORTEX_M == 0x04)
/** \brief Get FPSCR
This function returns the current value of the Floating Point Status/Control register.
\return Floating Point Status/Control register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_FPSCR(void)
{
#if (__FPU_PRESENT == 1)
uint32_t result;
__ASM volatile ("MRS %0, fpscr" : "=r" (result) );
return(result);
#else
return(0);
#endif
}
/** \brief Set FPSCR
This function assigns the given value to the Floating Point Status/Control register.
\param [in] fpscr Floating Point Status/Control value to set
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_FPSCR(uint32_t fpscr)
{
#if (__FPU_PRESENT == 1)
__ASM volatile ("MSR fpscr, %0" : : "r" (fpscr) );
#endif
}
#endif /* (__CORTEX_M == 0x04) */
#elif (defined (__TASKING__)) /*--------------- TASKING Compiler -----------------*/
/* TASKING carm specific functions */
/*
* The CMSIS functions have been implemented as intrinsics in the compiler.
* Please use "carm -?i" to get an up to date list of all instrinsics,
* Including the CMSIS ones.
*/
#endif
/*@} end of CMSIS_Core_RegAccFunctions */
#endif /* __CORE_CMFUNC_H__ */

View File

@@ -1,775 +0,0 @@
/**************************************************************************//**
* @file core_cmInstr.h
* @brief CMSIS Cortex-M Core Instruction Access Header File
* @version V2.01
* @date 06. December 2010
*
* @note
* Copyright (C) 2009-2010 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers. This file can be freely distributed
* within development tools that are supporting such ARM based processors.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#ifndef __CORE_CMINSTR_H__
#define __CORE_CMINSTR_H__
/* ########################## Core Instruction Access ######################### */
/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface
Access to dedicated instructions
@{
*/
#if defined ( __CC_ARM ) /*------------------ RealView Compiler ----------------*/
/* ARM armcc specific functions */
/** \brief No Operation
No Operation does nothing. This instruction can be used for code alignment purposes.
*/
#define __NOP __nop
/** \brief Wait For Interrupt
Wait For Interrupt is a hint instruction that suspends execution
until one of a number of events occurs.
*/
#define __WFI __wfi
/** \brief Wait For Event
Wait For Event is a hint instruction that permits the processor to enter
a low-power state until one of a number of events occurs.
*/
#define __WFE __wfe
/** \brief Send Event
Send Event is a hint instruction. It causes an event to be signaled to the CPU.
*/
#define __SEV __sev
/** \brief Instruction Synchronization Barrier
Instruction Synchronization Barrier flushes the pipeline in the processor,
so that all instructions following the ISB are fetched from cache or
memory, after the instruction has been completed.
*/
#define __ISB() __isb(0xF)
/** \brief Data Synchronization Barrier
This function acts as a special kind of Data Memory Barrier.
It completes when all explicit memory accesses before this instruction complete.
*/
#define __DSB() __dsb(0xF)
/** \brief Data Memory Barrier
This function ensures the apparent order of the explicit memory operations before
and after the instruction, without ensuring their completion.
*/
#define __DMB() __dmb(0xF)
/** \brief Reverse byte order (32 bit)
This function reverses the byte order in integer value.
\param [in] value Value to reverse
\return Reversed value
*/
#define __REV __rev
/** \brief Reverse byte order (16 bit)
This function reverses the byte order in two unsigned short values.
\param [in] value Value to reverse
\return Reversed value
*/
#if (__ARMCC_VERSION < 400677)
extern uint32_t __REV16(uint32_t value);
#else /* (__ARMCC_VERSION >= 400677) */
static __INLINE __ASM uint32_t __REV16(uint32_t value)
{
rev16 r0, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Reverse byte order in signed short value
This function reverses the byte order in a signed short value with sign extension to integer.
\param [in] value Value to reverse
\return Reversed value
*/
#if (__ARMCC_VERSION < 400677)
extern int32_t __REVSH(int32_t value);
#else /* (__ARMCC_VERSION >= 400677) */
static __INLINE __ASM int32_t __REVSH(int32_t value)
{
revsh r0, r0
bx lr
}
#endif /* __ARMCC_VERSION */
#if (__CORTEX_M >= 0x03)
/** \brief Reverse bit order of value
This function reverses the bit order of the given value.
\param [in] value Value to reverse
\return Reversed value
*/
#define __RBIT __rbit
/** \brief LDR Exclusive (8 bit)
This function performs a exclusive LDR command for 8 bit value.
\param [in] ptr Pointer to data
\return value of type uint8_t at (*ptr)
*/
#define __LDREXB(ptr) ((uint8_t ) __ldrex(ptr))
/** \brief LDR Exclusive (16 bit)
This function performs a exclusive LDR command for 16 bit values.
\param [in] ptr Pointer to data
\return value of type uint16_t at (*ptr)
*/
#define __LDREXH(ptr) ((uint16_t) __ldrex(ptr))
/** \brief LDR Exclusive (32 bit)
This function performs a exclusive LDR command for 32 bit values.
\param [in] ptr Pointer to data
\return value of type uint32_t at (*ptr)
*/
#define __LDREXW(ptr) ((uint32_t ) __ldrex(ptr))
/** \brief STR Exclusive (8 bit)
This function performs a exclusive STR command for 8 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
#define __STREXB(value, ptr) __strex(value, ptr)
/** \brief STR Exclusive (16 bit)
This function performs a exclusive STR command for 16 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
#define __STREXH(value, ptr) __strex(value, ptr)
/** \brief STR Exclusive (32 bit)
This function performs a exclusive STR command for 32 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
#define __STREXW(value, ptr) __strex(value, ptr)
/** \brief Remove the exclusive lock
This function removes the exclusive lock which is created by LDREX.
*/
#if (__ARMCC_VERSION < 400000)
extern void __CLREX(void);
#else /* (__ARMCC_VERSION >= 400000) */
#define __CLREX __clrex
#endif /* __ARMCC_VERSION */
/** \brief Signed Saturate
This function saturates a signed value.
\param [in] value Value to be saturated
\param [in] sat Bit position to saturate to (1..32)
\return Saturated value
*/
#define __SSAT __ssat
/** \brief Unsigned Saturate
This function saturates an unsigned value.
\param [in] value Value to be saturated
\param [in] sat Bit position to saturate to (0..31)
\return Saturated value
*/
#define __USAT __usat
/** \brief Count leading zeros
This function counts the number of leading zeros of a data value.
\param [in] value Value to count the leading zeros
\return number of leading zeros in value
*/
#define __CLZ __clz
#endif /* (__CORTEX_M >= 0x03) */
#elif (defined (__ICCARM__)) /*---------------- ICC Compiler ---------------------*/
/* IAR iccarm specific functions */
#include <intrinsics.h> /* IAR Intrinsics */
#pragma diag_suppress=Pe940
/** \brief No Operation
No Operation does nothing. This instruction can be used for code alignment purposes.
*/
#define __NOP __no_operation
/** \brief Wait For Interrupt
Wait For Interrupt is a hint instruction that suspends execution
until one of a number of events occurs.
*/
static __INLINE void __WFI(void)
{
__ASM ("wfi");
}
/** \brief Wait For Event
Wait For Event is a hint instruction that permits the processor to enter
a low-power state until one of a number of events occurs.
*/
static __INLINE void __WFE(void)
{
__ASM ("wfe");
}
/** \brief Send Event
Send Event is a hint instruction. It causes an event to be signaled to the CPU.
*/
static __INLINE void __SEV(void)
{
__ASM ("sev");
}
/* intrinsic void __ISB(void) (see intrinsics.h) */
/* intrinsic void __DSB(void) (see intrinsics.h) */
/* intrinsic void __DMB(void) (see intrinsics.h) */
/* intrinsic uint32_t __REV(uint32_t value) (see intrinsics.h) */
/* intrinsic __SSAT (see intrinsics.h) */
/* intrinsic __USAT (see intrinsics.h) */
/** \brief Reverse byte order (16 bit)
This function reverses the byte order in two unsigned short values.
\param [in] value Value to reverse
\return Reversed value
*/
static uint32_t __REV16(uint32_t value)
{
__ASM("rev16 r0, r0");
}
/* intrinsic uint32_t __REVSH(uint32_t value) (see intrinsics.h */
#if (__CORTEX_M >= 0x03)
/** \brief Reverse bit order of value
This function reverses the bit order of the given value.
\param [in] value Value to reverse
\return Reversed value
*/
static uint32_t __RBIT(uint32_t value)
{
__ASM("rbit r0, r0");
}
/** \brief LDR Exclusive (8 bit)
This function performs a exclusive LDR command for 8 bit value.
\param [in] ptr Pointer to data
\return value of type uint8_t at (*ptr)
*/
static uint8_t __LDREXB(volatile uint8_t *addr)
{
__ASM("ldrexb r0, [r0]");
}
/** \brief LDR Exclusive (16 bit)
This function performs a exclusive LDR command for 16 bit values.
\param [in] ptr Pointer to data
\return value of type uint16_t at (*ptr)
*/
static uint16_t __LDREXH(volatile uint16_t *addr)
{
__ASM("ldrexh r0, [r0]");
}
/** \brief LDR Exclusive (32 bit)
This function performs a exclusive LDR command for 32 bit values.
\param [in] ptr Pointer to data
\return value of type uint32_t at (*ptr)
*/
/* intrinsic unsigned long __LDREX(unsigned long *) (see intrinsics.h) */
static uint32_t __LDREXW(volatile uint32_t *addr)
{
__ASM("ldrex r0, [r0]");
}
/** \brief STR Exclusive (8 bit)
This function performs a exclusive STR command for 8 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
static uint32_t __STREXB(uint8_t value, volatile uint8_t *addr)
{
__ASM("strexb r0, r0, [r1]");
}
/** \brief STR Exclusive (16 bit)
This function performs a exclusive STR command for 16 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
static uint32_t __STREXH(uint16_t value, volatile uint16_t *addr)
{
__ASM("strexh r0, r0, [r1]");
}
/** \brief STR Exclusive (32 bit)
This function performs a exclusive STR command for 32 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
/* intrinsic unsigned long __STREX(unsigned long, unsigned long) (see intrinsics.h )*/
static uint32_t __STREXW(uint32_t value, volatile uint32_t *addr)
{
__ASM("strex r0, r0, [r1]");
}
/** \brief Remove the exclusive lock
This function removes the exclusive lock which is created by LDREX.
*/
static __INLINE void __CLREX(void)
{
__ASM ("clrex");
}
/* intrinsic unsigned char __CLZ( unsigned long ) (see intrinsics.h) */
#endif /* (__CORTEX_M >= 0x03) */
#pragma diag_default=Pe940
#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/
/* GNU gcc specific functions */
/** \brief No Operation
No Operation does nothing. This instruction can be used for code alignment purposes.
*/
__attribute__( ( always_inline ) ) static __INLINE void __NOP(void)
{
__ASM volatile ("nop");
}
/** \brief Wait For Interrupt
Wait For Interrupt is a hint instruction that suspends execution
until one of a number of events occurs.
*/
__attribute__( ( always_inline ) ) static __INLINE void __WFI(void)
{
__ASM volatile ("wfi");
}
/** \brief Wait For Event
Wait For Event is a hint instruction that permits the processor to enter
a low-power state until one of a number of events occurs.
*/
__attribute__( ( always_inline ) ) static __INLINE void __WFE(void)
{
__ASM volatile ("wfe");
}
/** \brief Send Event
Send Event is a hint instruction. It causes an event to be signaled to the CPU.
*/
__attribute__( ( always_inline ) ) static __INLINE void __SEV(void)
{
__ASM volatile ("sev");
}
/** \brief Instruction Synchronization Barrier
Instruction Synchronization Barrier flushes the pipeline in the processor,
so that all instructions following the ISB are fetched from cache or
memory, after the instruction has been completed.
*/
__attribute__( ( always_inline ) ) static __INLINE void __ISB(void)
{
__ASM volatile ("isb");
}
/** \brief Data Synchronization Barrier
This function acts as a special kind of Data Memory Barrier.
It completes when all explicit memory accesses before this instruction complete.
*/
__attribute__( ( always_inline ) ) static __INLINE void __DSB(void)
{
__ASM volatile ("dsb");
}
/** \brief Data Memory Barrier
This function ensures the apparent order of the explicit memory operations before
and after the instruction, without ensuring their completion.
*/
__attribute__( ( always_inline ) ) static __INLINE void __DMB(void)
{
__ASM volatile ("dmb");
}
/** \brief Reverse byte order (32 bit)
This function reverses the byte order in integer value.
\param [in] value Value to reverse
\return Reversed value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __REV(uint32_t value)
{
uint32_t result;
__ASM volatile ("rev %0, %1" : "=r" (result) : "r" (value) );
return(result);
}
/** \brief Reverse byte order (16 bit)
This function reverses the byte order in two unsigned short values.
\param [in] value Value to reverse
\return Reversed value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __REV16(uint32_t value)
{
uint32_t result;
__ASM volatile ("rev16 %0, %1" : "=r" (result) : "r" (value) );
return(result);
}
/** \brief Reverse byte order in signed short value
This function reverses the byte order in a signed short value with sign extension to integer.
\param [in] value Value to reverse
\return Reversed value
*/
__attribute__( ( always_inline ) ) static __INLINE int32_t __REVSH(int32_t value)
{
uint32_t result;
__ASM volatile ("revsh %0, %1" : "=r" (result) : "r" (value) );
return(result);
}
#if (__CORTEX_M >= 0x03)
/** \brief Reverse bit order of value
This function reverses the bit order of the given value.
\param [in] value Value to reverse
\return Reversed value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __RBIT(uint32_t value)
{
uint32_t result;
__ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) );
return(result);
}
/** \brief LDR Exclusive (8 bit)
This function performs a exclusive LDR command for 8 bit value.
\param [in] ptr Pointer to data
\return value of type uint8_t at (*ptr)
*/
__attribute__( ( always_inline ) ) static __INLINE uint8_t __LDREXB(volatile uint8_t *addr)
{
uint8_t result;
__ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) );
return(result);
}
/** \brief LDR Exclusive (16 bit)
This function performs a exclusive LDR command for 16 bit values.
\param [in] ptr Pointer to data
\return value of type uint16_t at (*ptr)
*/
__attribute__( ( always_inline ) ) static __INLINE uint16_t __LDREXH(volatile uint16_t *addr)
{
uint16_t result;
__ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) );
return(result);
}
/** \brief LDR Exclusive (32 bit)
This function performs a exclusive LDR command for 32 bit values.
\param [in] ptr Pointer to data
\return value of type uint32_t at (*ptr)
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __LDREXW(volatile uint32_t *addr)
{
uint32_t result;
__ASM volatile ("ldrex %0, [%1]" : "=r" (result) : "r" (addr) );
return(result);
}
/** \brief STR Exclusive (8 bit)
This function performs a exclusive STR command for 8 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr)
{
uint32_t result;
__ASM volatile ("strexb %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
return(result);
}
/** \brief STR Exclusive (16 bit)
This function performs a exclusive STR command for 16 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr)
{
uint32_t result;
__ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
return(result);
}
/** \brief STR Exclusive (32 bit)
This function performs a exclusive STR command for 32 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr)
{
uint32_t result;
__ASM volatile ("strex %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
return(result);
}
/** \brief Remove the exclusive lock
This function removes the exclusive lock which is created by LDREX.
*/
__attribute__( ( always_inline ) ) static __INLINE void __CLREX(void)
{
__ASM volatile ("clrex");
}
/** \brief Signed Saturate
This function saturates a signed value.
\param [in] value Value to be saturated
\param [in] sat Bit position to saturate to (1..32)
\return Saturated value
*/
#define __SSAT(ARG1,ARG2) \
({ \
uint32_t __RES, __ARG1 = (ARG1); \
__ASM ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \
__RES; \
})
/** \brief Unsigned Saturate
This function saturates an unsigned value.
\param [in] value Value to be saturated
\param [in] sat Bit position to saturate to (0..31)
\return Saturated value
*/
#define __USAT(ARG1,ARG2) \
({ \
uint32_t __RES, __ARG1 = (ARG1); \
__ASM ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \
__RES; \
})
/** \brief Count leading zeros
This function counts the number of leading zeros of a data value.
\param [in] value Value to count the leading zeros
\return number of leading zeros in value
*/
__attribute__( ( always_inline ) ) static __INLINE uint8_t __CLZ(uint32_t value)
{
uint8_t result;
__ASM volatile ("clz %0, %1" : "=r" (result) : "r" (value) );
return(result);
}
#endif /* (__CORTEX_M >= 0x03) */
#elif (defined (__TASKING__)) /*--------------- TASKING Compiler -----------------*/
/* TASKING carm specific functions */
/*
* The CMSIS functions have been implemented as intrinsics in the compiler.
* Please use "carm -?i" to get an up to date list of all instrinsics,
* Including the CMSIS ones.
*/
#endif
/*@}*/ /* end of group CMSIS_Core_InstructionInterface */
#endif /* __CORE_CMINSTR_H__ */

View File

@@ -1,64 +0,0 @@
/**************************************************************************//**
* @file system_LPC17xx.h
* @brief CMSIS Cortex-M3 Device Peripheral Access Layer Header File
* for the NXP LPC17xx Device Series
* @version V1.02
* @date 08. September 2009
*
* @note
* Copyright (C) 2009 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers. This file can be freely distributed
* within development tools that are supporting such ARM based processors.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#ifndef __SYSTEM_LPC17xx_H
#define __SYSTEM_LPC17xx_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
/**
* Initialize the system
*
* @param none
* @return none
*
* @brief Setup the microcontroller system.
* Initialize the System and update the SystemCoreClock variable.
*/
extern void SystemInit (void);
/**
* Update SystemCoreClock variable
*
* @param none
* @return none
*
* @brief Updates the SystemCoreClock with current core Clock
* retrieved from cpu registers.
*/
extern void SystemCoreClockUpdate (void);
#ifdef __cplusplus
}
#endif
#endif /* __SYSTEM_LPC17xx_H */

View File

@@ -1,339 +0,0 @@
/**************************************************************************//**
* @file core_cm3.c
* @brief CMSIS Cortex-M3 Core Peripheral Access Layer Source File
* @version V2.00
* @date 13. September 2010
*
* @note
* Copyright (C) 2009-2010 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers. This file can be freely distributed
* within development tools that are supporting such ARM based processors.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#include <stdint.h>
/* define compiler specific symbols */
#if defined ( __CC_ARM )
#define __ASM __asm /*!< asm keyword for ARM Compiler */
#define __INLINE __inline /*!< inline keyword for ARM Compiler */
#elif defined ( __ICCARM__ )
#define __ASM __asm /*!< asm keyword for IAR Compiler */
#define __INLINE inline /*!< inline keyword for IAR Compiler. Only avaiable in High optimization mode! */
#elif defined ( __GNUC__ )
#define __ASM __asm /*!< asm keyword for GNU Compiler */
#define __INLINE inline /*!< inline keyword for GNU Compiler */
#elif defined ( __TASKING__ )
#define __ASM __asm /*!< asm keyword for TASKING Compiler */
#define __INLINE inline /*!< inline keyword for TASKING Compiler */
#endif
/* ########################## Core Instruction Access ######################### */
#if defined ( __CC_ARM ) /*------------------ RealView Compiler ----------------*/
/** \brief Reverse byte order (16 bit)
This function reverses the byte order in two unsigned short values.
\param [in] value Value to reverse
\return Reversed value
*/
#if (__ARMCC_VERSION < 400677)
__ASM uint32_t __REV16(uint32_t value)
{
rev16 r0, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Reverse byte order in signed short value
This function reverses the byte order in a signed short value with sign extension to integer.
\param [in] value Value to reverse
\return Reversed value
*/
#if (__ARMCC_VERSION < 400677)
__ASM int32_t __REVSH(int32_t value)
{
revsh r0, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Remove the exclusive lock
This function removes the exclusive lock which is created by LDREX.
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __CLREX(void)
{
clrex
}
#endif /* __ARMCC_VERSION */
#elif (defined (__ICCARM__)) /*---------------- ICC Compiler ---------------------*/
/* obsolete */
#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/
/* obsolete */
#elif (defined (__TASKING__)) /*--------------- TASKING Compiler -----------------*/
/* obsolete */
#endif
/* ########################### Core Function Access ########################### */
#if defined ( __CC_ARM ) /*------------------ RealView Compiler ----------------*/
/** \brief Get Control Register
This function returns the content of the Control Register.
\return Control Register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_CONTROL(void)
{
mrs r0, control
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Set Control Register
This function writes the given value to the Control Register.
\param [in] control Control Register value to set
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __set_CONTROL(uint32_t control)
{
msr control, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get ISPR Register
This function returns the content of the ISPR Register.
\return ISPR Register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_IPSR(void)
{
mrs r0, ipsr
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get APSR Register
This function returns the content of the APSR Register.
\return APSR Register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_APSR(void)
{
mrs r0, apsr
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get xPSR Register
This function returns the content of the xPSR Register.
\return xPSR Register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_xPSR(void)
{
mrs r0, xpsr
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get Process Stack Pointer
This function returns the current value of the Process Stack Pointer (PSP).
\return PSP Register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_PSP(void)
{
mrs r0, psp
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Set Process Stack Pointer
This function assigns the given value to the Process Stack Pointer (PSP).
\param [in] topOfProcStack Process Stack Pointer value to set
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __set_PSP(uint32_t topOfProcStack)
{
msr psp, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get Main Stack Pointer
This function returns the current value of the Main Stack Pointer (MSP).
\return MSP Register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_MSP(void)
{
mrs r0, msp
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Set Main Stack Pointer
This function assigns the given value to the Main Stack Pointer (MSP).
\param [in] topOfMainStack Main Stack Pointer value to set
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __set_MSP(uint32_t mainStackPointer)
{
msr msp, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get Base Priority
This function returns the current value of the Base Priority register.
\return Base Priority register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_BASEPRI(void)
{
mrs r0, basepri
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Set Base Priority
This function assigns the given value to the Base Priority register.
\param [in] basePri Base Priority value to set
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __set_BASEPRI(uint32_t basePri)
{
msr basepri, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get Priority Mask
This function returns the current state of the priority mask bit from the Priority Mask Register.
\return Priority Mask value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_PRIMASK(void)
{
mrs r0, primask
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Set Priority Mask
This function assigns the given value to the Priority Mask Register.
\param [in] priMask Priority Mask
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __set_PRIMASK(uint32_t priMask)
{
msr primask, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get Fault Mask
This function returns the current value of the Fault Mask Register.
\return Fault Mask value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_FAULTMASK(void)
{
mrs r0, faultmask
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Set the Fault Mask
This function assigns the given value to the Fault Mask Register.
\param [in] faultMask Fault Mask value value to set
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __set_FAULTMASK(uint32_t faultMask)
{
msr faultmask, r0
bx lr
}
#endif /* __ARMCC_VERSION */
#elif (defined (__ICCARM__)) /*---------------- ICC Compiler ---------------------*/
/* obsolete */
#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/
/* obsolete */
#elif (defined (__TASKING__)) /*--------------- TASKING Compiler -----------------*/
/* obsolete */
#endif

View File

@@ -1,532 +0,0 @@
/**************************************************************************//**
* @file system_LPC17xx.c
* @brief CMSIS Cortex-M3 Device Peripheral Access Layer Source File
* for the NXP LPC17xx Device Series
* @version V1.08
* @date 12. May 2010
*
* @note
* Copyright (C) 2009 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers. This file can be freely distributed
* within development tools that are supporting such ARM based processors.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#include <stdint.h>
#include "LPC17xx.h"
/*
//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------
*/
/*--------------------- Clock Configuration ----------------------------------
//
// <e> Clock Configuration
// <h> System Controls and Status Register (SCS)
// <o1.4> OSCRANGE: Main Oscillator Range Select
// <0=> 1 MHz to 20 MHz
// <1=> 15 MHz to 24 MHz
// <e1.5> OSCEN: Main Oscillator Enable
// </e>
// </h>
//
// <h> Clock Source Select Register (CLKSRCSEL)
// <o2.0..1> CLKSRC: PLL Clock Source Selection
// <0=> Internal RC oscillator
// <1=> Main oscillator
// <2=> RTC oscillator
// </h>
//
// <e3> PLL0 Configuration (Main PLL)
// <h> PLL0 Configuration Register (PLL0CFG)
// <i> F_cco0 = (2 * M * F_in) / N
// <i> F_in must be in the range of 32 kHz to 50 MHz
// <i> F_cco0 must be in the range of 275 MHz to 550 MHz
// <o4.0..14> MSEL: PLL Multiplier Selection
// <6-32768><#-1>
// <i> M Value
// <o4.16..23> NSEL: PLL Divider Selection
// <1-256><#-1>
// <i> N Value
// </h>
// </e>
//
// <e5> PLL1 Configuration (USB PLL)
// <h> PLL1 Configuration Register (PLL1CFG)
// <i> F_usb = M * F_osc or F_usb = F_cco1 / (2 * P)
// <i> F_cco1 = F_osc * M * 2 * P
// <i> F_cco1 must be in the range of 156 MHz to 320 MHz
// <o6.0..4> MSEL: PLL Multiplier Selection
// <1-32><#-1>
// <i> M Value (for USB maximum value is 4)
// <o6.5..6> PSEL: PLL Divider Selection
// <0=> 1
// <1=> 2
// <2=> 4
// <3=> 8
// <i> P Value
// </h>
// </e>
//
// <h> CPU Clock Configuration Register (CCLKCFG)
// <o7.0..7> CCLKSEL: Divide Value for CPU Clock from PLL0
// <1-256><#-1>
// </h>
//
// <h> USB Clock Configuration Register (USBCLKCFG)
// <o8.0..3> USBSEL: Divide Value for USB Clock from PLL0
// <0-15>
// <i> Divide is USBSEL + 1
// </h>
//
// <h> Peripheral Clock Selection Register 0 (PCLKSEL0)
// <o9.0..1> PCLK_WDT: Peripheral Clock Selection for WDT
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.2..3> PCLK_TIMER0: Peripheral Clock Selection for TIMER0
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.4..5> PCLK_TIMER1: Peripheral Clock Selection for TIMER1
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.6..7> PCLK_UART0: Peripheral Clock Selection for UART0
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.8..9> PCLK_UART1: Peripheral Clock Selection for UART1
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.12..13> PCLK_PWM1: Peripheral Clock Selection for PWM1
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.14..15> PCLK_I2C0: Peripheral Clock Selection for I2C0
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.16..17> PCLK_SPI: Peripheral Clock Selection for SPI
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.20..21> PCLK_SSP1: Peripheral Clock Selection for SSP1
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.22..23> PCLK_DAC: Peripheral Clock Selection for DAC
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.24..25> PCLK_ADC: Peripheral Clock Selection for ADC
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.26..27> PCLK_CAN1: Peripheral Clock Selection for CAN1
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 6
// <o9.28..29> PCLK_CAN2: Peripheral Clock Selection for CAN2
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 6
// <o9.30..31> PCLK_ACF: Peripheral Clock Selection for ACF
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 6
// </h>
//
// <h> Peripheral Clock Selection Register 1 (PCLKSEL1)
// <o10.0..1> PCLK_QEI: Peripheral Clock Selection for the Quadrature Encoder Interface
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.2..3> PCLK_GPIO: Peripheral Clock Selection for GPIOs
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.4..5> PCLK_PCB: Peripheral Clock Selection for the Pin Connect Block
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.6..7> PCLK_I2C1: Peripheral Clock Selection for I2C1
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.10..11> PCLK_SSP0: Peripheral Clock Selection for SSP0
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.12..13> PCLK_TIMER2: Peripheral Clock Selection for TIMER2
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.14..15> PCLK_TIMER3: Peripheral Clock Selection for TIMER3
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.16..17> PCLK_UART2: Peripheral Clock Selection for UART2
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.18..19> PCLK_UART3: Peripheral Clock Selection for UART3
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.20..21> PCLK_I2C2: Peripheral Clock Selection for I2C2
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.22..23> PCLK_I2S: Peripheral Clock Selection for I2S
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.26..27> PCLK_RIT: Peripheral Clock Selection for the Repetitive Interrupt Timer
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.28..29> PCLK_SYSCON: Peripheral Clock Selection for the System Control Block
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.30..31> PCLK_MC: Peripheral Clock Selection for the Motor Control PWM
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// </h>
//
// <h> Power Control for Peripherals Register (PCONP)
// <o11.1> PCTIM0: Timer/Counter 0 power/clock enable
// <o11.2> PCTIM1: Timer/Counter 1 power/clock enable
// <o11.3> PCUART0: UART 0 power/clock enable
// <o11.4> PCUART1: UART 1 power/clock enable
// <o11.6> PCPWM1: PWM 1 power/clock enable
// <o11.7> PCI2C0: I2C interface 0 power/clock enable
// <o11.8> PCSPI: SPI interface power/clock enable
// <o11.9> PCRTC: RTC power/clock enable
// <o11.10> PCSSP1: SSP interface 1 power/clock enable
// <o11.12> PCAD: A/D converter power/clock enable
// <o11.13> PCCAN1: CAN controller 1 power/clock enable
// <o11.14> PCCAN2: CAN controller 2 power/clock enable
// <o11.15> PCGPIO: GPIOs power/clock enable
// <o11.16> PCRIT: Repetitive interrupt timer power/clock enable
// <o11.17> PCMC: Motor control PWM power/clock enable
// <o11.18> PCQEI: Quadrature encoder interface power/clock enable
// <o11.19> PCI2C1: I2C interface 1 power/clock enable
// <o11.21> PCSSP0: SSP interface 0 power/clock enable
// <o11.22> PCTIM2: Timer 2 power/clock enable
// <o11.23> PCTIM3: Timer 3 power/clock enable
// <o11.24> PCUART2: UART 2 power/clock enable
// <o11.25> PCUART3: UART 3 power/clock enable
// <o11.26> PCI2C2: I2C interface 2 power/clock enable
// <o11.27> PCI2S: I2S interface power/clock enable
// <o11.29> PCGPDMA: GP DMA function power/clock enable
// <o11.30> PCENET: Ethernet block power/clock enable
// <o11.31> PCUSB: USB interface power/clock enable
// </h>
//
// <h> Clock Output Configuration Register (CLKOUTCFG)
// <o12.0..3> CLKOUTSEL: Selects clock source for CLKOUT
// <0=> CPU clock
// <1=> Main oscillator
// <2=> Internal RC oscillator
// <3=> USB clock
// <4=> RTC oscillator
// <o12.4..7> CLKOUTDIV: Selects clock divider for CLKOUT
// <1-16><#-1>
// <o12.8> CLKOUT_EN: CLKOUT enable control
// </h>
//
// </e>
*/
#define CLOCK_SETUP 1
#define SCS_Val 0x00000020
#define CLKSRCSEL_Val 0x00000001
#define PLL0_SETUP 1
#define PLL0CFG_Val 0x00050063
#define PLL1_SETUP 1
#define PLL1CFG_Val 0x00000023
#define CCLKCFG_Val 0x00000003
#define USBCLKCFG_Val 0x00000000
#define PCLKSEL0_Val 0x00000000
#define PCLKSEL1_Val 0x00000000
#define PCONP_Val 0x042887DE
#define CLKOUTCFG_Val 0x00000000
/*--------------------- Flash Accelerator Configuration ----------------------
//
// <e> Flash Accelerator Configuration
// <o1.12..15> FLASHTIM: Flash Access Time
// <0=> 1 CPU clock (for CPU clock up to 20 MHz)
// <1=> 2 CPU clocks (for CPU clock up to 40 MHz)
// <2=> 3 CPU clocks (for CPU clock up to 60 MHz)
// <3=> 4 CPU clocks (for CPU clock up to 80 MHz)
// <4=> 5 CPU clocks (for CPU clock up to 100 MHz)
// <5=> 6 CPU clocks (for any CPU clock)
// </e>
*/
#define FLASH_SETUP 0
#define FLASHCFG_Val 0x00004000
/*
//-------- <<< end of configuration section >>> ------------------------------
*/
/*----------------------------------------------------------------------------
Check the register settings
*----------------------------------------------------------------------------*/
#define CHECK_RANGE(val, min, max) ((val < min) || (val > max))
#define CHECK_RSVD(val, mask) (val & mask)
/* Clock Configuration -------------------------------------------------------*/
#if (CHECK_RSVD((SCS_Val), ~0x00000030))
#error "SCS: Invalid values of reserved bits!"
#endif
#if (CHECK_RANGE((CLKSRCSEL_Val), 0, 2))
#error "CLKSRCSEL: Value out of range!"
#endif
#if (CHECK_RSVD((PLL0CFG_Val), ~0x00FF7FFF))
#error "PLL0CFG: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((PLL1CFG_Val), ~0x0000007F))
#error "PLL1CFG: Invalid values of reserved bits!"
#endif
#if (PLL0_SETUP) /* if PLL0 is used */
#if (CCLKCFG_Val < 2) /* CCLKSEL must be greater then 1 */
#error "CCLKCFG: CCLKSEL must be greater then 1 if PLL0 is used!"
#endif
#endif
#if (CHECK_RANGE((CCLKCFG_Val), 2, 255))
#error "CCLKCFG: Value out of range!"
#endif
#if (CHECK_RSVD((USBCLKCFG_Val), ~0x0000000F))
#error "USBCLKCFG: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((PCLKSEL0_Val), 0x000C0C00))
#error "PCLKSEL0: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((PCLKSEL1_Val), 0x03000300))
#error "PCLKSEL1: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((PCONP_Val), 0x10100821))
#error "PCONP: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((CLKOUTCFG_Val), ~0x000001FF))
#error "CLKOUTCFG: Invalid values of reserved bits!"
#endif
/* Flash Accelerator Configuration -------------------------------------------*/
#if (CHECK_RSVD((FLASHCFG_Val), ~0x0000F000))
#error "FLASHCFG: Invalid values of reserved bits!"
#endif
/*----------------------------------------------------------------------------
DEFINES
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
Define clocks
*----------------------------------------------------------------------------*/
#define XTAL (12000000UL) /* Oscillator frequency */
#define OSC_CLK ( XTAL) /* Main oscillator frequency */
#define RTC_CLK ( 32000UL) /* RTC oscillator frequency */
#define IRC_OSC ( 4000000UL) /* Internal RC oscillator frequency */
/* F_cco0 = (2 * M * F_in) / N */
#define __M (((PLL0CFG_Val ) & 0x7FFF) + 1)
#define __N (((PLL0CFG_Val >> 16) & 0x00FF) + 1)
#define __FCCO(__F_IN) ((2/*ULL*/ * __M * __F_IN) / __N)
#define __CCLK_DIV (((CCLKCFG_Val ) & 0x00FF) + 1)
/* Determine core clock frequency according to settings */
#if (PLL0_SETUP)
#if ((CLKSRCSEL_Val & 0x03) == 1)
#define __CORE_CLK (__FCCO(OSC_CLK) / __CCLK_DIV)
#elif ((CLKSRCSEL_Val & 0x03) == 2)
#define __CORE_CLK (__FCCO(RTC_CLK) / __CCLK_DIV)
#else
#define __CORE_CLK (__FCCO(IRC_OSC) / __CCLK_DIV)
#endif
#else
#if ((CLKSRCSEL_Val & 0x03) == 1)
#define __CORE_CLK (OSC_CLK / __CCLK_DIV)
#elif ((CLKSRCSEL_Val & 0x03) == 2)
#define __CORE_CLK (RTC_CLK / __CCLK_DIV)
#else
#define __CORE_CLK (IRC_OSC / __CCLK_DIV)
#endif
#endif
/*----------------------------------------------------------------------------
Clock Variable definitions
*----------------------------------------------------------------------------*/
uint32_t SystemCoreClock = __CORE_CLK;/*!< System Clock Frequency (Core Clock)*/
/*----------------------------------------------------------------------------
Clock functions
*----------------------------------------------------------------------------*/
void SystemCoreClockUpdate (void) /* Get Core Clock Frequency */
{
/* Determine clock frequency according to clock register values */
if (((LPC_SC->PLL0STAT >> 24) & 3) == 3) { /* If PLL0 enabled and connected */
switch (LPC_SC->CLKSRCSEL & 0x03) {
case 0: /* Int. RC oscillator => PLL0 */
case 3: /* Reserved, default to Int. RC */
SystemCoreClock = (IRC_OSC *
((2/*ULL*/ * ((LPC_SC->PLL0STAT & 0x7FFF) + 1))) /
(((LPC_SC->PLL0STAT >> 16) & 0xFF) + 1) /
((LPC_SC->CCLKCFG & 0xFF)+ 1));
break;
case 1: /* Main oscillator => PLL0 */
SystemCoreClock = (OSC_CLK *
((2/*ULL*/ * ((LPC_SC->PLL0STAT & 0x7FFF) + 1))) /
(((LPC_SC->PLL0STAT >> 16) & 0xFF) + 1) /
((LPC_SC->CCLKCFG & 0xFF)+ 1));
break;
case 2: /* RTC oscillator => PLL0 */
SystemCoreClock = (RTC_CLK *
((2/*ULL*/ * ((LPC_SC->PLL0STAT & 0x7FFF) + 1))) /
(((LPC_SC->PLL0STAT >> 16) & 0xFF) + 1) /
((LPC_SC->CCLKCFG & 0xFF)+ 1));
break;
}
} else {
switch (LPC_SC->CLKSRCSEL & 0x03) {
case 0: /* Int. RC oscillator => PLL0 */
case 3: /* Reserved, default to Int. RC */
SystemCoreClock = IRC_OSC / ((LPC_SC->CCLKCFG & 0xFF)+ 1);
break;
case 1: /* Main oscillator => PLL0 */
SystemCoreClock = OSC_CLK / ((LPC_SC->CCLKCFG & 0xFF)+ 1);
break;
case 2: /* RTC oscillator => PLL0 */
SystemCoreClock = RTC_CLK / ((LPC_SC->CCLKCFG & 0xFF)+ 1);
break;
}
}
}
/**
* Initialize the system
*
* @param none
* @return none
*
* @brief Setup the microcontroller system.
* Initialize the System.
*/
void SystemInit (void)
{
#if (CLOCK_SETUP) /* Clock Setup */
LPC_SC->SCS = SCS_Val;
if (SCS_Val & (1 << 5)) { /* If Main Oscillator is enabled */
while ((LPC_SC->SCS & (1<<6)) == 0);/* Wait for Oscillator to be ready */
}
LPC_SC->CCLKCFG = CCLKCFG_Val; /* Setup Clock Divider */
LPC_SC->PCLKSEL0 = PCLKSEL0_Val; /* Peripheral Clock Selection */
LPC_SC->PCLKSEL1 = PCLKSEL1_Val;
LPC_SC->CLKSRCSEL = CLKSRCSEL_Val; /* Select Clock Source for PLL0 */
#if (PLL0_SETUP)
LPC_SC->PLL0CFG = PLL0CFG_Val; /* configure PLL0 */
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
LPC_SC->PLL0CON = 0x01; /* PLL0 Enable */
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
while (!(LPC_SC->PLL0STAT & (1<<26)));/* Wait for PLOCK0 */
LPC_SC->PLL0CON = 0x03; /* PLL0 Enable & Connect */
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
while (!(LPC_SC->PLL0STAT & ((1<<25) | (1<<24))));/* Wait for PLLC0_STAT & PLLE0_STAT */
#endif
#if (PLL1_SETUP)
LPC_SC->PLL1CFG = PLL1CFG_Val;
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
LPC_SC->PLL1CON = 0x01; /* PLL1 Enable */
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
while (!(LPC_SC->PLL1STAT & (1<<10)));/* Wait for PLOCK1 */
LPC_SC->PLL1CON = 0x03; /* PLL1 Enable & Connect */
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
while (!(LPC_SC->PLL1STAT & ((1<< 9) | (1<< 8))));/* Wait for PLLC1_STAT & PLLE1_STAT */
#else
LPC_SC->USBCLKCFG = USBCLKCFG_Val; /* Setup USB Clock Divider */
#endif
LPC_SC->PCONP = PCONP_Val; /* Power Control for Peripherals */
LPC_SC->CLKOUTCFG = CLKOUTCFG_Val; /* Clock Output Configuration */
#endif
#if (FLASH_SETUP == 1) /* Flash Accelerator Setup */
LPC_SC->FLASHCFG = (LPC_SC->FLASHCFG & ~0x0000F000) | FLASHCFG_Val;
#endif
}

View File

@@ -1,94 +0,0 @@
ifeq ($(TARGET_NAME),)
TARGET_NAME=boot
endif
ifeq ($(ATOMTHREADS),)
ATOMTHREADS = $(shell pwd)/../../
endif
ifeq ($(TEST_NAME),)
TEST_NAME = kern1
endif
CC = arm-none-eabi-gcc
LN = arm-none-eabi-gcc
AS = arm-none-eabi-gcc
CFLAGS := $(CFLAGS) -O3 -Os -g3 -Wall -c -mcpu=cortex-m3 -mthumb
AFLAGS := $(AFLAGS) -O3 -Os -g3 -Wall -c -fmessage-length=0 -fno-builtin -ffunction-sections -fdata-sections -mcpu=cortex-m3 -mthumb
LFLAGS := $(LFLAGS) -O3 -Os -Wall -mcpu=cortex-m3 -mthumb -Wl,-Map=system.map -Tsystem.ld
CDEFS := $(CDEFS) -DATOMTHREADS_TEST='"$(TEST_NAME)"' -DBOARD_MBED_LP1768
ADEFS := $(ADEFS) -D__thumb2__ -DARM_RDI_MONITOR
LLIBS := $(LLIBS)
SRCS := $(SRCS) \
./CMSISv2p00_LPC17xx/src/core_cm3.c \
./CMSISv2p00_LPC17xx/src/system_LPC17xx.c \
./drivers/lpc17xx_uart.c \
startup.c \
modules.c \
$(ATOMTHREADS)/tests/$(TEST_NAME).c \
main.c \
ASMS := $(ASMS) \
INCLUDES := $(INCLUDES) \
-I$(ATOMTHREADS)/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc \
-I$(ATOMTHREADS)/platforms/lpc17xx \
-I$(ATOMTHREADS)
include $(ATOMTHREADS)/ports/cortex_m/Makefile
OBJS = $(SRCS:.c=.o) $(ASMS:.S=.o)
include ../rules.mk
run_test: clean all
cp boot.bin bin/$(TEST_NAME).bin
all_tests:
echo "Starting atomthreads test suite"
make run_test "TEST_NAME=mutex1"
make run_test "TEST_NAME=mutex2"
make run_test "TEST_NAME=mutex3"
make run_test "TEST_NAME=mutex4"
make run_test "TEST_NAME=mutex5"
make run_test "TEST_NAME=mutex6"
make run_test "TEST_NAME=mutex7"
make run_test "TEST_NAME=mutex8"
make run_test "TEST_NAME=mutex9"
make run_test "TEST_NAME=kern1"
make run_test "TEST_NAME=kern2"
make run_test "TEST_NAME=kern3"
make run_test "TEST_NAME=kern4"
make run_test "TEST_NAME=timer1"
make run_test "TEST_NAME=timer2"
make run_test "TEST_NAME=timer3"
make run_test "TEST_NAME=timer4"
make run_test "TEST_NAME=timer5"
make run_test "TEST_NAME=timer6"
make run_test "TEST_NAME=timer7"
make run_test "TEST_NAME=queue1"
make run_test "TEST_NAME=queue2"
make run_test "TEST_NAME=queue3"
make run_test "TEST_NAME=queue4"
make run_test "TEST_NAME=queue5"
make run_test "TEST_NAME=queue6"
make run_test "TEST_NAME=queue7"
make run_test "TEST_NAME=queue8"
make run_test "TEST_NAME=queue9"
make run_test "TEST_NAME=sem1"
make run_test "TEST_NAME=sem2"
make run_test "TEST_NAME=sem3"
make run_test "TEST_NAME=sem4"
make run_test "TEST_NAME=sem5"
make run_test "TEST_NAME=sem6"
make run_test "TEST_NAME=sem7"
make run_test "TEST_NAME=sem8"
make run_test "TEST_NAME=sem9"

View File

@@ -1,24 +0,0 @@
---------------------------------------------------------------------------
Library: Atomthreads NXP LPC17xx Platform.
Author: Natie van Rooyen <natie@navaro.nl>
License: BSD Revised
---------------------------------------------------------------------------
NXP LPC17xx Platform
The "lpc17xx" platform contains sources for building the Atomthreads test
suite for the NXP LPC17xx microcontroller.
The build was tested on the "mbed NXP LPC1768" board (http://www.mbed.org)
but it should work on any LPC17xx development board where UART0 can be used
to monitor the output of the test.
The NXP LPC17xx microcontrollers use the ARM Cortex M3 processor core. The
source code in this example uses the ARM CMSIS Cortex-M Access Library V2.01
to initialize the platform and Newlib as the runtime library. Also it uses a
driver provided by NXP for the UART. The CMSIS library and the UART driver
are provided as source with the sample and Newlib is expected to be installed
together with the GNU ARM tool chain.

File diff suppressed because it is too large Load Diff

View File

@@ -1,179 +0,0 @@
/**************************************************************************//**
* @file lpc17xx_uart.c
* @brief Drivers for UART peripheral in lpc17xx.
* @version 1.0
* @date 18. Nov. 2010
*
* @note
* Copyright (C) 2010 NXP Semiconductors(NXP). All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
******************************************************************************/
#include <stdarg.h>
#include <stdio.h>
#include "lpc17xx_uart.h"
#include "lpc17xx.h"
/**
* @brief Initializes the UART0.
*
* @param baudrate: Specifies the baud rate
* @retval None
*/
void LPC17xx_UART_Init(uint32_t baudrate)
{
uint32_t Fdiv;
uint32_t pclkdiv, pclk;
/***/
LPC_PINCON->PINSEL0 &= ~0x000000F0;
LPC_PINCON->PINSEL0 |= 0x00000050; /* RxD0 and TxD0 */
/* PCLK_UART0=CCLK/2 */
//**LPC_SC->PCLKSEL1 &= ~(3<<6); /* PCLK_UART0 = CCLK/4 (18MHz) */
//**LPC_SC->PCLKSEL1 |= (2<<6); /* PCLK_UART0 = CCLK/2 (36MHz) */
//**pclk = SystemCoreClock/2;
/* By default, the PCLKSELx value is zero, thus, the PCLK for
all the peripherals is 1/4 of the SystemFrequency. */
/* Bit 6~7 is for UART0 */
pclkdiv = (LPC_SC->PCLKSEL0 >> 6) & 0x03;
switch ( pclkdiv )
{
case 0x00:
default:
pclk = SystemCoreClock/4;
break;
case 0x01:
pclk = SystemCoreClock;
break;
case 0x02:
pclk = SystemCoreClock/2;
break;
case 0x03:
pclk = SystemCoreClock/8;
break;
}
LPC_UART0->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */
Fdiv = ( pclk / 16 ) / baudrate ; /*baud rate */
LPC_UART0->DLM = Fdiv / 256;
LPC_UART0->DLL = Fdiv % 256;
LPC_UART0->LCR = 0x03; /* DLAB = 0 */
LPC_UART0->FCR = 0x07; /* Enable and reset TX and RX FIFO. */
}
/**
* @brief Write one character to UART0.
*
* @param ch: Character to be written
* @retval None
*/
void LPC17xx_UART_PutChar (uint8_t ch)
{
while (!(LPC_UART0->LSR & 0x20));
LPC_UART0->THR = ch;
}
/**
* @brief Read one character from UART0 (blocking read).
*
* @param None
* @retval Received character
*/
uint8_t LPC17xx_UART_GetChar (void)
{
while (!(LPC_UART0->LSR & 0x01));
return (LPC_UART0->RBR);
}
/**
* @brief Read one character from UART0 (non blocking read).
*
* @param None
* @retval Received character
*/
uint8_t LPC17xx_UART_GetChar_nb (void)
{
if (LPC_UART0->LSR & 0x01)
return (LPC_UART0->RBR);
else
return 0;
}
/**
* @brief Write a string to UART0.
*
* @param str: NULL-terminated char string to be written
* @retval None
*/
void LPC17xx_UART_PutString (uint8_t *str)
{
/* usage: LPC1700_UART_Printf("xxx\n\r");*/
#if 1
while (*str != 0)
{
LPC17xx_UART_PutChar(*str++);
}
#else
/* usage: LPC1700_UART_Printf("xxx\n");*/
while ((*str) != 0) {
if (*str == '\n') {
LPC17xx_UART_PutChar(*str++);
LPC17xx_UART_PutChar('\r');
} else {
LPC17xx_UART_PutChar(*str++);
}
}
#endif
}
/**
* @brief Write a buffer to UART0.
*
* @param buffer: buffer to be written
* @retval None
*/
void LPC17xx_UART_WriteBuffer (uint8_t *buffer, uint32_t len)
{
while (len-- != 0) {
LPC17xx_UART_PutChar(*buffer++);
}
}
/**
* @brief Print formatted string. This function takes variable length arguments.
*
* @param format
* @param ...
* @retval None
*
* Note: using library functions "vsprintf" will increase the RO size by about 6KB
*/
//void LPC17xx_UART_Printf (const uint8_t *format, ...)
//{
// static uint8_t buffer[40 + 1];
// va_list vArgs;
//
// va_start(vArgs, format);
// vsprintf((char *)buffer, (char const *)format, vArgs);
// va_end(vArgs);
// LPC17xx_UART_PutString((uint8_t *) buffer);
//}
/* --------------------------------- End Of File ------------------------------ */

View File

@@ -1,37 +0,0 @@
/**************************************************************************//**
* @file lpc17xx_uart.h
* @brief Header file for lpc17xx_uart.c.
* @version 1.0
* @date 18. Nov. 2010
*
* @note
* Copyright (C) 2010 NXP Semiconductors(NXP). All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
******************************************************************************/
#ifndef __LPC17xx_UART_H_
#define __LPC17xx_UART_H_
#include <stdint.h>
/* external functions */
void LPC17xx_UART_PutChar (uint8_t);
uint8_t LPC17xx_UART_GetChar (void);
void LPC17xx_UART_Init(uint32_t baudrate);
void LPC17xx_UART_PutString (uint8_t *str) ;
void LPC17xx_UART_WriteBuffer (uint8_t *buffer, uint32_t len) ;
#endif // __LPC17xx_UART_H_
/* --------------------------------- End Of File ------------------------------ */

View File

@@ -1,122 +0,0 @@
/*
* 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 <stdio.h>
#include "LPC17xx.h"
#include "drivers/lpc17xx_uart.h"
#include "modules.h"
#include "atom.h"
#include "tests/atomtests.h"
#ifndef ATOMTHREADS_TEST
#define ATOMTHREADS_TEST "kern1"
#endif
// for mbed board
#define MBED_LED1_GPIO (1 << 18)
#define MBED_LED2_GPIO (1 << 20)
#define MBED_LED3_GPIO (1 << 21)
#define MBED_LED4_GPIO (1 << 23)
#define MBED_LED_GET(led) (LPC_GPIO1->FIOSET & led)
#define MBED_LED_SET(led, on) { if (on) LPC_GPIO1->FIOSET = led ; else LPC_GPIO1->FIOCLR = led ; }
#define MBED_LED_TOGGLE(led) MBED_LED_SET(led, !MBED_LED_GET(led))
#define MBED_LED_COUNT(count) MBED_LED_SET(MBED_LED1_GPIO, count & 1) ; MBED_LED_SET(MBED_LED2_GPIO, count & 2) ; \
MBED_LED_SET(MBED_LED3_GPIO, count & 4) ; MBED_LED_SET(MBED_LED4_GPIO, count & 8) ;
#define TEST_STACK_BYTE_SIZE 512
#define IDLE_STACK_BYTE_SIZE 128
static unsigned char test_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char idle_stack[IDLE_STACK_BYTE_SIZE] ;
ATOM_TCB test_tcb ;
/**
* \b test_thread
*
* Function calling the test function of the Atomthreads test suite.
*
*/
void
test_thread (uint32_t param)
{
uint32_t failures ;
CRITICAL_STORE ;
failures = test_start () ;
atomTimerDelay (10) ;
CRITICAL_START() ;
dbg_format_msg ("%s %s\r\n", ATOMTHREADS_TEST, failures ? "FAIL" : "PASS") ;
CRITICAL_END() ;
while(1) {
#ifdef BOARD_MBED_LP1768
MBED_LED_TOGGLE(MBED_LED1_GPIO) ;
#endif
atomTimerDelay (65) ;
}
}
/**
* \b main
*
* Initialize atomthreads and start a test_thread to run the Atomthreads test suite.
*
*/
int
main(void)
{
#ifdef BOARD_MBED_LP1768
LPC_GPIO1->FIODIR |= MBED_LED1_GPIO | MBED_LED2_GPIO | MBED_LED3_GPIO | MBED_LED4_GPIO ;
MBED_LED_SET(MBED_LED1_GPIO | MBED_LED2_GPIO | MBED_LED3_GPIO | MBED_LED4_GPIO, 1);
#endif
dbg_format_msg ("\r\nLPC17xx SystemCoreClock = %d\r\n",SystemCoreClock) ;
//atomthreads_stress_test (36) ;
dbg_format_msg ("Atomthreads starting %s... \r\n", ATOMTHREADS_TEST) ;
atomOSInit(&idle_stack[0], IDLE_STACK_BYTE_SIZE, TRUE) ;
atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0,
&test_stack[0], TEST_STACK_BYTE_SIZE, TRUE);
atomOSStart() ;
while(1) ;
return 0 ;
}

View File

@@ -1,179 +0,0 @@
/*
* 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_private.h"
#include "atom.h"
#include "atomport.h"
/**
* \b dbg_format_msg
*
* Same as printf.
*
*/
void
dbg_format_msg (char *format, ...)
{
va_list args;
static char msg[256] ;
//CRITICAL_STORE ;
va_start (args, format) ;
//CRITICAL_START() ;
vsniprintf ((char*)msg, 256, (char*)format, args) ;
LPC17xx_UART_PutString (msg) ;
//CRITICAL_END() ;
}
/**
* \b low_level_init
*
* Initializes the PIC and start the system timer tick intrerupt.
*
*/
int
low_level_init (void)
{
SystemInit () ;
SystemCoreClockUpdate ();
//contextInit () ;
NVIC_SetPriority (PendSV_IRQn, 0xFF) ;
LPC17xx_UART_Init (115200) ;
SysTick_Config (1000000) ;
return 0 ;
}
/**
* \b __context_preempt_handler
*
* System timer tic interupt handler.
*
*/
void
__context_tick_handler (void)
{
/* Call the interrupt enter routine */
atomIntEnter();
/* Call the OS system tick handler */
atomTimerTick();
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}
/**
* \b dbg_mem_dump_40
*
* Dumps size bytes of memory from data.
*
*/
void dbg_mem_dump_40 (unsigned int* data, int size)
{
int j ;
dbg_format_msg ("Dump %d bytes at %.8X:\r\n",size * 4, (unsigned int)data) ;
data = (unsigned int*)((unsigned int)data & ~0x3) ;
for (j=0; j<size-3; j+=4) {
dbg_format_msg (" :%.8X: %.8X %.8X %.8X %.8X\r\n", (unsigned int)&data[j], data[j+0], data[j+1], data[j+2], data[j+3]) ;
}
if (size-j == 3) {
dbg_format_msg (" :%.8X: %.8X %.8X %.8X\r\n", (unsigned int)&data[j], data[j+0], data[j+1], data[j+2]) ;
} else if (size-j == 2) {
dbg_format_msg (" :%.8X: %.8X %.8X\r\n", (unsigned int)&data[j], data[j+0], data[j+1]) ;
} else if (size-j == 1) {
dbg_format_msg (" :%.8X: %.8X\r\n", (unsigned int)&data[j], data[j+0]) ;
}
}
/**
* \b dbg_fault_handler
*
* Prints cortex m exception debug information.
*
*/
void
dbg_fault_handler (unsigned int * hardfault_args)
{
unsigned int stacked_r0;
unsigned int stacked_r1;
unsigned int stacked_r2;
unsigned int stacked_r3;
unsigned int stacked_r12;
unsigned int stacked_lr;
unsigned int stacked_pc;
unsigned int stacked_psr;
stacked_r0 = ((unsigned long) hardfault_args[0]);
stacked_r1 = ((unsigned long) hardfault_args[1]);
stacked_r2 = ((unsigned long) hardfault_args[2]);
stacked_r3 = ((unsigned long) hardfault_args[3]);
stacked_r12 = ((unsigned long) hardfault_args[4]);
stacked_lr = ((unsigned long) hardfault_args[5]);
stacked_pc = ((unsigned long) hardfault_args[6]);
stacked_psr = ((unsigned long) hardfault_args[7]);
dbg_format_msg ("\r\n\r\n[Hard fault handler - all numbers in hex]\r\n");
dbg_format_msg ("SP = 0x%x\r\n", hardfault_args);
dbg_format_msg ("R0 = 0x%x\r\n", stacked_r0);
dbg_format_msg ("R1 = 0x%x\r\n", stacked_r1);
dbg_format_msg ("R2 = 0x%x\r\n", stacked_r2);
dbg_format_msg ("R3 = 0x%x\r\n", stacked_r3);
dbg_format_msg ("R12 = 0x%x\r\n", stacked_r12);
dbg_format_msg ("LR [R14] = 0x%x subroutine call return address\r\n", stacked_lr);
dbg_format_msg ("PC [R15] = 0x%x program counter\r\n", stacked_pc);
dbg_format_msg ("PSR = 0x%x\r\n", stacked_psr);
//printf ("BFAR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED38))));
//printf ("CFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED28))));
//printf ("HFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED2C))));
//printf ("DFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED30))));
//printf ("AFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED3C))));
// printf ("SCB_SHCSR = %x\n", SCB->SHCSR);
dbg_mem_dump_40 (hardfault_args, 0x40) ;
while (1);
}

View File

@@ -1,297 +0,0 @@
/**************************************************************************//**
* @file startup.c
* @brief
* @version
* @date
*
* @note
* Copyright (C) 2010 NXP Semiconductors(NXP). All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
******************************************************************************/
#define WEAK __attribute__ ((weak))
#define ALIAS(f) __attribute__ ((weak, alias (#f)))
#include "system_LPC17xx.h"
#include "atomport_private.h"
void ResetISR(void);
WEAK void NMI_Handler(void);
WEAK void HardFault_Handler(void);
WEAK void MemManage_Handler(void);
WEAK void BusFault_Handler(void);
WEAK void UsageFault_Handler(void);
WEAK void SVC_Handler(void);
WEAK void DebugMon_Handler(void);
WEAK void PendSV_Handler(void);
WEAK void SysTick_Handler(void);
WEAK void IntDefault_Handler(void);
//*****************************************************************************
//
// The entry point for the application.
// __main() is the entry point for Redlib based applications
// main() is the entry point for Newlib based applications
//
//*****************************************************************************
extern int main(void);
extern void low_level_init(void);
//*****************************************************************************
//
// External declaration for the pointer to the stack top from the Linker Script
//
//*****************************************************************************
extern void _vStackTop(void);
//*****************************************************************************
//
// The vector table.
// This relies on the linker script to place at correct location in memory.
//
//*****************************************************************************
extern void (* const g_pfnVectors[])(void);
__attribute__ ((section(".isr_vector")))
void (* const g_pfnVectors[])(void) = {
// Core Level - CM3
&_vStackTop, // The initial stack pointer
ResetISR, // The reset handler
NMI_Handler, // The NMI handler
HardFault_Handler, // The hard fault handler
MemManage_Handler, // The MPU fault handler
BusFault_Handler, // The bus fault handler
UsageFault_Handler, // The usage fault handler
0, // Reserved
0, // Reserved
0, // Reserved
0, // Reserved
SVC_Handler, // SVCall handler
DebugMon_Handler, // Debug monitor handler
0, // Reserved
archPendSVHandler, // The PendSV handler
archTickHandler /*SysTick_Handler*/, // The SysTick handler
// Chip Level - LPC17
IntDefault_Handler, // 16, 0x40 - WDT
IntDefault_Handler, // 17, 0x44 - TIMER0
IntDefault_Handler, // 18, 0x48 - TIMER1
IntDefault_Handler, // 19, 0x4c - TIMER2
IntDefault_Handler, // 20, 0x50 - TIMER3
IntDefault_Handler, // 21, 0x54 - UART0
IntDefault_Handler, // 22, 0x58 - UART1
IntDefault_Handler, // 23, 0x5c - UART2
IntDefault_Handler, // 24, 0x60 - UART3
IntDefault_Handler, // 25, 0x64 - PWM1
IntDefault_Handler, // 26, 0x68 - I2C0
IntDefault_Handler, // 27, 0x6c - I2C1
IntDefault_Handler, // 28, 0x70 - I2C2
IntDefault_Handler, // 29, 0x74 - SPI
IntDefault_Handler, // 30, 0x78 - SSP0
IntDefault_Handler, // 31, 0x7c - SSP1
IntDefault_Handler, // 32, 0x80 - PLL0 (Main PLL)
IntDefault_Handler, // 33, 0x84 - RTC
IntDefault_Handler, // 34, 0x88 - EINT0
IntDefault_Handler, // 35, 0x8c - EINT1
IntDefault_Handler, // 36, 0x90 - EINT2
IntDefault_Handler, // 37, 0x94 - EINT3
IntDefault_Handler, // 38, 0x98 - ADC
IntDefault_Handler, // 39, 0x9c - BOD
IntDefault_Handler, // 40, 0xA0 - USB
IntDefault_Handler, // 41, 0xa4 - CAN
IntDefault_Handler, // 42, 0xa8 - GP DMA
IntDefault_Handler, // 43, 0xac - I2S
IntDefault_Handler, // 44, 0xb0 - Ethernet
IntDefault_Handler, // 45, 0xb4 - RITINT
IntDefault_Handler, // 46, 0xb8 - Motor Control PWM
IntDefault_Handler, // 47, 0xbc - Quadrature Encoder
IntDefault_Handler, // 48, 0xc0 - PLL1 (USB PLL)
IntDefault_Handler, // 49, 0xc4 - USB Activity interrupt to wakeup
IntDefault_Handler, // 50, 0xc8 - CAN Activity interrupt to wakeup
};
//*****************************************************************************
// Functions to carry out the initialization of RW and BSS data sections. These
// are written as separate functions rather than being inlined within the
// ResetISR() function in order to cope with MCUs with multiple banks of
// memory.
//*****************************************************************************
__attribute__ ((section(".after_vectors")))
void data_init(unsigned int romstart, unsigned int start, unsigned int len) {
unsigned int *pulDest = (unsigned int*) start;
unsigned int *pulSrc = (unsigned int*) romstart;
unsigned int loop;
for (loop = 0; loop < len; loop = loop + 4)
*pulDest++ = *pulSrc++;
}
__attribute__ ((section(".after_vectors")))
void bss_init(unsigned int start, unsigned int len) {
unsigned int *pulDest = (unsigned int*) start;
unsigned int loop;
for (loop = 0; loop < len; loop = loop + 4)
*pulDest++ = 0;
}
//*****************************************************************************
// The following symbols are constructs generated by the linker, indicating
// the location of various points in the "Global Section Table". This table is
// created by the linker via the Code Red managed linker script mechanism. It
// contains the load address, execution address and length of each RW data
// section and the execution and length of each BSS (zero initialized) section.
//*****************************************************************************
extern unsigned int __data_section_table;
extern unsigned int __data_section_table_end;
extern unsigned int __bss_section_table;
extern unsigned int __bss_section_table_end;
//*****************************************************************************
// Reset entry point for your code.
// Sets up a simple runtime environment and initializes the C/C++
// library.
//*****************************************************************************
__attribute__ ((section(".after_vectors")))
void
ResetISR(void) {
//
// Copy the data sections from flash to SRAM.
//
unsigned int LoadAddr, ExeAddr, SectionLen;
unsigned int *SectionTableAddr;
// Load base address of Global Section Table
SectionTableAddr = &__data_section_table;
// Copy the data sections from flash to SRAM.
while (SectionTableAddr < &__data_section_table_end) {
LoadAddr = *SectionTableAddr++;
ExeAddr = *SectionTableAddr++;
SectionLen = *SectionTableAddr++;
data_init(LoadAddr, ExeAddr, SectionLen);
}
// At this point, SectionTableAddr = &__bss_section_table;
// Zero fill the bss segment
while (SectionTableAddr < &__bss_section_table_end) {
ExeAddr = *SectionTableAddr++;
SectionLen = *SectionTableAddr++;
bss_init(ExeAddr, SectionLen);
}
low_level_init();
main();
//
// main() shouldn't return, but if it does, we'll just enter an infinite loop
//
while (1) ;
}
//*****************************************************************************
// Default exception handlers. Override the ones here by defining your own
// handler routines in your application code.
//*****************************************************************************
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void NMI_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void HardFault_Handler(void)
{
__asm volatile
(
" tst lr, #4 \n"
" ite eq \n"
" mrseq r0, msp \n"
" mrsne r0, psp \n"
" b dbg_fault_handler \n"
);
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void MemManage_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void BusFault_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void UsageFault_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void SVC_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void DebugMon_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void PendSV_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void SysTick_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void IntDefault_Handler(void)
{
while(1) ;
}

View File

@@ -1,148 +0,0 @@
/**************************************************************************//**
* @file system.ld
* @brief
* @version
* @date
*
* @note
* Copyright (C) 2010 NXP Semiconductors(NXP). All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
******************************************************************************/
MEMORY
{
/* Define each memory region */
MFlash512 (rx) : ORIGIN = 0x0, LENGTH = 0x80000 /* 512k */
RamLoc32 (rwx) : ORIGIN = 0x10000000, LENGTH = 0x8000 /* 32k */
RamAHB32 (rwx) : ORIGIN = 0x2007c000, LENGTH = 0x8000 /* 32k */
}
/* Define a symbol for the top of each memory region */
__top_MFlash512 = 0x0 + 0x80000;
__top_RamLoc32 = 0x10000000 + 0x8000;
__top_RamAHB32 = 0x2007c000 + 0x8000;
ENTRY(ResetISR)
SECTIONS
{
/* MAIN TEXT SECTION */
.text : ALIGN(4)
{
FILL(0xff)
KEEP(*(.isr_vector))
/* Global Section Table */
. = ALIGN(4) ;
__section_table_start = .;
__data_section_table = .;
LONG(LOADADDR(.data));
LONG( ADDR(.data)) ;
LONG( SIZEOF(.data));
LONG(LOADADDR(.data_RAM2));
LONG( ADDR(.data_RAM2)) ;
LONG( SIZEOF(.data_RAM2));
__data_section_table_end = .;
__bss_section_table = .;
LONG( ADDR(.bss));
LONG( SIZEOF(.bss));
LONG( ADDR(.bss_RAM2));
LONG( SIZEOF(.bss_RAM2));
__bss_section_table_end = .;
__section_table_end = . ;
/* End of Global Section Table */
*(.after_vectors*)
*(.text*)
*(.rodata .rodata.*)
. = ALIGN(4);
} > MFlash512
/*
* for exception handling/unwind - some Newlib functions (in common
* with C++ and STDC++) use this.
* Use KEEP so not discarded with --gc-sections
*/
.ARM.extab : ALIGN(4)
{
KEEP(*(.ARM.extab* .gnu.linkonce.armextab.*))
} > MFlash512
__exidx_start = .;
.ARM.exidx : ALIGN(4)
{
KEEP(*(.ARM.exidx* .gnu.linkonce.armexidx.*))
} > MFlash512
__exidx_end = .;
_etext = .;
.data_RAM2 : ALIGN(4)
{
FILL(0xff)
*(.data.$RAM2*)
*(.data.$RamAHB32*)
. = ALIGN(4) ;
} > RamAHB32 AT>MFlash512
/* MAIN DATA SECTION */
.uninit_RESERVED : ALIGN(4)
{
KEEP(*(.bss.$RESERVED*))
. = ALIGN(4) ;
_end_uninit_RESERVED = .;
} > RamLoc32
.data : ALIGN(4)
{
FILL(0xff)
_data = .;
*(vtable)
*(.data*)
. = ALIGN(4) ;
_edata = .;
} > RamLoc32 AT>MFlash512
.bss_RAM2 : ALIGN(4)
{
*(.bss.$RAM2*)
*(.bss.$RamAHB32*)
. = ALIGN(4) ;
} > RamAHB32
/* MAIN BSS SECTION */
.bss : ALIGN(4)
{
__bss_start__ = . ;
_bss = .;
*(.bss*)
*(COMMON)
. = ALIGN(4) ;
__bss_end__ = . ;
_ebss = .;
PROVIDE(end = .);
} > RamLoc32
PROVIDE(_pvHeapStart = .);
PROVIDE(_vStackTop = __top_RamLoc32 - 0);
}

View File

@@ -1,96 +0,0 @@
ifeq ($(TARGET_NAME),)
TARGET_NAME=boot
endif
ifeq ($(ATOMTHREADS),)
ATOMTHREADS = $(shell pwd)/../../
endif
ifeq ($(TEST_NAME),)
TEST_NAME = kern1
endif
CC = arm-none-eabi-gcc
LN = arm-none-eabi-gcc
AS = arm-none-eabi-gcc
CFLAGS := $(CFLAGS) -Wall -g -c -mcpu=cortex-m3 -mthumb -mthumb-interwork -ffreestanding
AFLAGS := $(AFLAGS) -Wall -g -c -mcpu=cortex-m3 -mthumb -mthumb-interwork -ffreestanding
LFLAGS := $(LFLAGS) -Wall -mcpu=cortex-m3 -mthumb -Wl,-Map=system.map -Tsystem.ld
CDEFS := $(CDEFS) -DATOMTHREADS_TEST='"$(TEST_NAME)"' -DPLATFORM_QEMU_LM3S_HACK
ADEFS := $(ADEFS) -D__thumb2__ -DARM_RDI_MONITOR -DPLATFORM_QEMU_LM3S_HACK
LLIBS := $(LLIBS)
SRCS := $(SRCS) \
modules.c \
main.c \
$(ATOMTHREADS)/tests/$(TEST_NAME).c \
ASMS := $(ASMS) \
startup.S \
INCLUDES := $(INCLUDES) \
-I$(ATOMTHREADS)
include $(ATOMTHREADS)/ports/cortex_m/Makefile
OBJS = $(SRCS:.c=.o) $(ASMS:.S=.o)
include ../rules.mk
run_test: clean all
echo "START TEST $(TEST_NAME)"
qemu-system-arm -M lm3s6965evb -kernel boot.elf -semihosting >> atomthreads_test.out
all_tests:
echo "Starting atomthreads test suite" > atomthreads_test.out
make run_test "TEST_NAME=mutex1"
make run_test "TEST_NAME=mutex2"
make run_test "TEST_NAME=mutex3"
make run_test "TEST_NAME=mutex5"
make run_test "TEST_NAME=mutex6"
make run_test "TEST_NAME=mutex7"
make run_test "TEST_NAME=mutex8"
make run_test "TEST_NAME=mutex9"
make run_test "TEST_NAME=kern1"
make run_test "TEST_NAME=kern2"
make run_test "TEST_NAME=kern3"
make run_test "TEST_NAME=kern4"
make run_test "TEST_NAME=timer1"
make run_test "TEST_NAME=timer2"
make run_test "TEST_NAME=timer3"
make run_test "TEST_NAME=timer5"
make run_test "TEST_NAME=timer6"
make run_test "TEST_NAME=timer7"
make run_test "TEST_NAME=queue1"
make run_test "TEST_NAME=queue2"
make run_test "TEST_NAME=queue3"
make run_test "TEST_NAME=queue4"
make run_test "TEST_NAME=queue5"
make run_test "TEST_NAME=queue6"
make run_test "TEST_NAME=queue7"
make run_test "TEST_NAME=queue8"
make run_test "TEST_NAME=queue9"
make run_test "TEST_NAME=sem1"
make run_test "TEST_NAME=sem2"
make run_test "TEST_NAME=sem3"
make run_test "TEST_NAME=sem5"
make run_test "TEST_NAME=sem6"
make run_test "TEST_NAME=sem7"
make run_test "TEST_NAME=sem8"
make run_test "TEST_NAME=sem9"
fail_tests:
make run_test "TEST_NAME=mutex4"
make run_test "TEST_NAME=timer4"
make run_test "TEST_NAME=sem4"
run_last:
qemu-system-arm -M lm3s6965evb -kernel boot.elf -semihosting

View File

@@ -1,37 +0,0 @@
---------------------------------------------------------------------------
Library: Atomthreads QEMU Stellaris LM3S6965 Platform.
Author: Natie van Rooyen <natie@navaro.nl>
License: BSD Revised
---------------------------------------------------------------------------
QEMU Stellaris LM3S6965 Platform
The "qemu_lm3s" platform contains sources for building a sample Atomthreads
application for the Stellaris LM3S6965 platform.
ISSUES:
There seems to be several problems for the QEMU Cortex M3 processor. The
platform and port contains specific hacks to make it work on the QEMU 1.2.0
release it was tested on. Also see the latest patches for QEMU.
Fixes implemented for the QEMU 1.2.0 release:
1. Install the patch http://patchwork.ozlabs.org/patch/180315/
2. Use the PLATFORM_QEMU_LM3S_HACK define in the Makefile:
- Disabling interrupts on the processor does not work (verified).
- Disabling interrupts of the Cortex M Sys Tick Interrupt does not
work (verified).
- NVIC Interrupt priorities not implemented correctly (not verified).
Because of the problems with the Sys Tick Interrupt the The Stellaris
General-Purpose Timer Module (GPTM) was used to generate the system timer
tick.
BUGS:
mutex4 testcase fails.
sem4 testcase fails.

View File

@@ -1,164 +0,0 @@
/*
* 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_private.h"
#include "atom.h"
#include "atomport.h"
#include "types.h"
SYSTICK_T* const board_systick = (SYSTICK_T*) BOARD_BASE_ADDRESS_SYSTICK ;
NVIC_T* const board_nvic = (NVIC_T*) BOARD_BASE_ADDRESS_NVIC ;
SCB_T * const board_scb = (SCB_T*) BOARD_BASE_ADDRESS_SCB ;
GPTM_TIMER_T * const board_gptm0 = (GPTM_TIMER_T*) BOARD_BASE_ADDRESS_GPTIMER0 ;
/**
* \b dbg_format_msg
*
* Same as printf.
*
*/
void
dbg_format_msg (char *format, ...)
{
va_list args;
static char msg[256] ;
CRITICAL_STORE ;
va_start (args, format) ;
CRITICAL_START() ;
vsnprintf ((char*)msg, 256, (char*)format, args) ;
printf (msg) ;
CRITICAL_END() ;
}
/**
* \b low_level_init
*
* Initializes the PIC and start the system timer tick intrerupt.
*
*/
int
low_level_init (void)
{
contextInit () ;
//board_systick->STRELOAD = 0x010000 ;
//board_systick->STCTRL = NVIC_STCTRL_CLK |
// NVIC_STCTRL_INTEN |
// NVIC_STCTRL_ENABLE ;
board_gptm0->CTL &= ~GPTM_TIMER_CTL_TAEN ;
board_gptm0->CFG = 0 ;
board_gptm0->TAMR = GPTM_TIMER_TMR_TMR_PERIODIC ;
board_gptm0->TAILR = 0x10000 ;
board_gptm0->IMR |= GPTM_TIMER_INT_TATOIM ;
board_gptm0->CTL |= GPTM_TIMER_CTL_TAEN ;
// board_nvic->ISER[0] = 0x80000 ;
return 0 ;
}
/**
* \b __context_tick_handler
*
* System timer tic interupt handler.
*
*/
void
__context_tick_handler (void)
{
atomIntEnter();
/* Call the OS system tick handler */
atomTimerTick();
board_gptm0->ICR |= GPTM_TIMER_INT_TATOIM ;
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}
/**
* \b dbg_hard_fault_handler_c
*
* Dumps the registers pushed on the stack after a fault.
*
*/
void
dbg_hard_fault_handler_c (unsigned int * hardfault_args)
{
unsigned int stacked_r0;
unsigned int stacked_r1;
unsigned int stacked_r2;
unsigned int stacked_r3;
unsigned int stacked_r12;
unsigned int stacked_lr;
unsigned int stacked_pc;
unsigned int stacked_psr;
stacked_r0 = ((unsigned long) hardfault_args[0]);
stacked_r1 = ((unsigned long) hardfault_args[1]);
stacked_r2 = ((unsigned long) hardfault_args[2]);
stacked_r3 = ((unsigned long) hardfault_args[3]);
stacked_r12 = ((unsigned long) hardfault_args[4]);
stacked_lr = ((unsigned long) hardfault_args[5]);
stacked_pc = ((unsigned long) hardfault_args[6]);
stacked_psr = ((unsigned long) hardfault_args[7]);
printf ("\r\n\r\n[Hard fault handler - all numbers in hex]\r\n");
printf ("SP = 0x%x\r\n", hardfault_args);
printf ("R0 = 0x%x\r\n", stacked_r0);
printf ("R1 = 0x%x\r\n", stacked_r1);
printf ("R2 = 0x%x\r\n", stacked_r2);
printf ("R3 = 0x%x\r\n", stacked_r3);
printf ("R12 = 0x%x\r\n", stacked_r12);
printf ("LR [R14] = 0x%x subroutine call return address\r\n", stacked_lr);
printf ("PC [R15] = 0x%x program counter\r\n", stacked_pc);
printf ("PSR = 0x%x\r\n", stacked_psr);
//printf ("BFAR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED38))));
//printf ("CFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED28))));
//printf ("HFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED2C))));
//printf ("DFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED30))));
//printf ("AFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED3C))));
// printf ("SCB_SHCSR = %x\n", SCB->SHCSR);
while (1);
}

View File

@@ -1,208 +0,0 @@
/*
* 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 Stellaris LM3S6965 Microcontroller
*/
#include "atomport.h"
// *****************************************************************************
// The Stellaris General-Purpose Timer Module (GPTM)
// *****************************************************************************
typedef struct GPTM_TIMER_S {
// offset read/write reset Description
__IO uint32_t CFG ; // 0x000 R/W 0x00000000 GPTM Configuration 345
__IO uint32_t TAMR ; // 0x004 R/W 0x00000000 GPTM TimerA Mode 346
__IO uint32_t TBMR ; // 0x008 R/W 0x00000000 GPTM TimerB Mode 348
__IO uint32_t CTL ; // 0x00C R/W 0x00000000 GPTM Control 350
uint32_t Reserved[2] ; // 0x010
__IO uint32_t IMR ; // 0x018 R/W 0x00000000 GPTM Interrupt Mask 353
__I uint32_t RIS ; // 0x01C RO 0x00000000 GPTM Raw Interrupt Status 355
__I uint32_t MIS ; // 0x020 RO 0x00000000 GPTM Masked Interrupt Status 356
__O uint32_t ICR ; // 0x024 W1C 0x00000000 GPTM Interrupt Clear 357
__IO uint32_t TAILR ; // 0x028 R/W 0xFFFFFFFF GPTM TimerA Interval Load 359
__IO uint32_t TBILR ; // 0x02C R/W 0x0000FFFF GPTM TimerB Interval Load 360
__IO uint32_t TAMATCHR ; // 0x030 R/W 0xFFFFFFFF GPTM TimerA Match 361
__IO uint32_t TBMATCHR ; // 0x034 R/W 0x0000FFFF GPTM TimerB Match 362
__IO uint32_t TAPR ; // 0x038 R/W 0x00000000 GPTM TimerA Prescale 363
__IO uint32_t TBPR ; // 0x03C R/W 0x00000000 GPTM TimerB Prescale 364
__IO uint32_t TAPMR ; // 0x040 R/W 0x00000000 GPTM TimerA Prescale Match 365
__IO uint32_t TBPMR ; // 0x044 R/W 0x00000000 GPTM TimerB Prescale Match 366
__I uint32_t TAR ; // 0x048 RO 0xFFFFFFFF GPTM TimerA 367
__I uint32_t TBR ; // 0x04C RO 0x0000FFFF GPTM TimerB 368
} GPTM_TIMER_T, *PGPTM_TIMER_T ;
// -------- GPTM_TIMER_CFG : (CFG Offset: 0x00) This register configures the global operation of the GPTM module --------
#define GPTM_TIMER_CFG_MASK ((unsigned int)0x07 << 0) //
#define GPTM_TIMER_CFG_32BIT ((unsigned int)0x00 << 0) // 32-bit timer configuration
#define GPTM_TIMER_CFG_32BIT_RT ((unsigned int)0x01 << 0) // 32-bit real-time clock (RTC) counter configuration
// -------- GPTM_TIMER_TAMR : (TAMR Offset: 0x04) This register configures the GPTM based on the configuration selected in the GPTMCFG register --------
// -------- GPTM_TIMER_TBMR : (TBMR Offset: 0x08) This register configures the GPTM based on the configuration selected in the GPTMCFG register --------
#define GPTM_TIMER_TMR_TAMS ((unsigned int)0x01 << 3) // GPTM TimerA Alternate Mode Select. 0 Capture mode is enabled. 1 PWM mode is enabled
#define GPTM_TIMER_TMR_TCMR ((unsigned int)0x01 << 2) // GPTM TimerA Capture Mode. 0 Edge-Count mode. 1 Edge-Time mode.
#define GPTM_TIMER_TMR_TMR_ONE_SHOT ((unsigned int)0x01 << 0) // One-Shot Timer mode
#define GPTM_TIMER_TMR_TMR_PERIODIC ((unsigned int)0x02 << 0) // Periodic Timer mode
#define GPTM_TIMER_TMR_TMR_CAPTURE ((unsigned int)0x03 << 0) // Capture mode
// -------- GPTM_TIMER_CTL : (CTL Offset: 0x0C) This register is used alongside the GPTMCFG and GMTMTnMR registers to fine-tune the timer configuration --------
#define GPTM_TIMER_CTL_TBPWML ((unsigned int)0x01 << 14) // GPTM TimerB PWM Output Level. 0 Output is unaffected. 1 Output is inverted.
#define GPTM_TIMER_CTL_TBOTE ((unsigned int)0x01 << 13) // GPTM TimerB Output Trigger Enable. 0 The output TimerB ADC trigger is disabled. 1 The output TimerB ADC trigger is enabled.
#define GPTM_TIMER_CTL_TBEVENT_MASK ((unsigned int)0x03 << 10) // GPTM TimerB Event Mode
#define GPTM_TIMER_CTL_TBEVENT_PE ((unsigned int)0x00 << 10) // Positive edge
#define GPTM_TIMER_CTL_TBEVENT_NE ((unsigned int)0x01 << 10) // Negative edge
#define GPTM_TIMER_CTL_TBEVENT ((unsigned int)0x03 << 10) // Both edges
#define GPTM_TIMER_CTL_TBSTALL ((unsigned int)0x01 << 9) // GPTM Timer B Stall Enable. 0 Timer B continues counting while the processor is halted by the debugger
#define GPTM_TIMER_CTL_TBEN ((unsigned int)0x01 << 8) // GPTM TimerB Enable
// --------
#define GPTM_TIMER_CTL_TAPWML ((unsigned int)0x01 << 6) // GPTM TimerA PWM Output Level. 0 Output is unaffected. 1 Output is inverted.
#define GPTM_TIMER_CTL_TAOTE ((unsigned int)0x01 << 5) // GPTM TimerA Output Trigger Enable. 0 The output TimerB ADC trigger is disabled. 1 The output TimerB ADC trigger is enabled.
#define GPTM_TIMER_CTL_RTCEN ((unsigned int)0x01 << 4) // GPTM RTC Enable
#define GPTM_TIMER_CTL_TAEVENT_MASK ((unsigned int)0x03 << 2) // GPTM TimerA Event Mode
#define GPTM_TIMER_CTL_TAEVENT_PE ((unsigned int)0x00 << 2) // Positive edge
#define GPTM_TIMER_CTL_TAEVENT_NE ((unsigned int)0x01 << 2) // Negative edge
#define GPTM_TIMER_CTL_TAEVENT ((unsigned int)0x03 << 2) // Both edges
#define GPTM_TIMER_CTL_TASTALL ((unsigned int)0x01 << 1) // GPTM Timer A Stall Enable. 0 Timer B continues counting while the processor is halted by the debugger
#define GPTM_TIMER_CTL_TAEN ((unsigned int)0x01 << 0) // GPTM TimerA Enable
// -------- GPTM_TIMER_IMR : (IMR Offset: 0x18) This register allows software to enable/disable GPTM controller-level interrupts. --------
// -------- GPTM_TIMER_RIS : (RIS Offset: 0x1C) This register shows the state of the GPTM's internal interrupt signal. --------
// -------- GPTM_TIMER_MIS : (MIS Offset: 0x20) This register show the state of the GPTM's controller-level interrupt. --------
// -------- GPTM_TIMER_ICR : (ICR Offset: 0x24) This register is used to clear the status bits in the GPTMRIS and GPTMMIS registers. --------
#define GPTM_TIMER_INT_CBEIM ((unsigned int)0x01 << 10) // GPTM CaptureB Event Interrupt Mask
#define GPTM_TIMER_INT_CBMIM ((unsigned int)0x01 << 9) // GPTM CaptureB Match Interrupt Mask
#define GPTM_TIMER_INT_TBTOIM ((unsigned int)0x01 << 8) // GPTM TimerB Time-Out Interrupt Mask
// --------
#define GPTM_TIMER_INT_RTCIM ((unsigned int)0x01 << 3) // GPTM RTC Interrupt Mask
#define GPTM_TIMER_INT_CAEIM ((unsigned int)0x01 << 2) // GPTM CaptureA Event Interrupt Mask
#define GPTM_TIMER_INT_CAMIM ((unsigned int)0x01 << 1) // GPTM CaptureA Match Interrupt Mask
#define GPTM_TIMER_INT_TATOIM ((unsigned int)0x01 << 0) // GPTM TimerA Time-Out Interrupt Mask
// *****************************************************************************
// Cortex M System Timer (SysTick)
// *****************************************************************************
typedef struct SYSTICK_S {
uint32_t Res0[1] ; // 0xE000E000
__IO uint32_t ICT ; // 0xE000E004
uint32_t Res1[2] ; // 0xE000E008
__IO uint32_t STCTRL ; // 0xE000E010
__IO uint32_t STRELOAD ; // 0xE000E014
__IO uint32_t STCURRENT; // 0xE000E018
__IO uint32_t STCALIB ; // 0xE000E01C
uint32_t Res2[56] ; // 0xE000E020
} SYSTICK_T, *PSYSTICK_T ;
// -------- SYSTICK_STCTRL : (STCTRL Offset: 0xE000E010) SysTick Control and Status Register --------
#define SYSTICK_STCTRL_COUNT ((unsigned int)0x1 << 16) // 0 - The SysTick timer has not counted to 0 since the last time this bit was read.
#define SYSTICK_STCTRL_CLK ((unsigned int)0x1 << 2) // 1 - System clock
#define SYSTICK_STCTRL_INTEN ((unsigned int)0x1 << 1) // 1 - An interrupt is generated to the NVIC when SysTick counts to 0.
#define SYSTICK_STCTRL_ENABLE ((unsigned int)0x1 << 1) // Enables SysTick to operate in a multi-shot way.
// -------- SYSTICK_STRELOAD : (STRELOAD Offset: 0xE000E014) Reload Value --------
#define SYSTICK_STRELOAD_MASK ((unsigned int)0xFFFFFF << 0) // IRQ mask
// -------- SYSTICK_STCURRENT : (STCURRENT Offset: 0xE000E018) SysTick Current Value Register --------
// *****************************************************************************
// Cortex M Nested Vectored Interrupt Controller
// *****************************************************************************
typedef struct NVIC_S {
__IO uint32_t ISER[2] ; // 0xE000E100
uint32_t Res3[30] ; // 0xE000E120
__IO uint32_t ICER[2] ; // 0xE000E180
uint32_t Res4[30] ; // 0xE000E1A0
__IO uint32_t ISPR[2] ; // 0xE000E200
uint32_t Res5[30] ; // 0xE000E220
__IO uint32_t ICPR[2] ; // 0xE000E280
uint32_t Res6[30] ; // 0xE000E2A0
__IO uint32_t IABR[2] ; // 0xE000E300
uint32_t Res7[64] ; // 0xE000E320
__IO uint32_t IPR[2] ; // 0xE000E400
// uint32_t Res7[515] ; // 0xE000E4F4
} NVIC_T, *PNVIC_T ;
#define NVIC_EXCEPTION_RESET 1
#define NVIC_EXCEPTION_NMI 2
#define NVIC_EXCEPTION_HARD_FAULT 3
#define NVIC_EXCEPTION_MEM_MANAGEMENT 4
#define NVIC_EXCEPTION_BUS_FAULT 5
#define NVIC_EXCEPTION_USAGE_FAULT 6
#define NVIC_EXCEPTION_SVCALL 11
#define NVIC_EXCEPTION_DEBUG_MON 12
#define NVIC_EXCEPTION_PEND_SV 14
#define NVIC_EXCEPTION_SYS_TICK 15
// *****************************************************************************
// System Control Block (SCB) Registers
// *****************************************************************************
typedef struct SCB_S {
__IO uint32_t CPUID ; // 0xE000ED00
__IO uint32_t ICSR ; // 0xE000ED04
__IO uint32_t VTOR ; // 0xE000ED08
__IO uint32_t AIRCR ; // 0xE000ED0C
__IO uint32_t SCR ; // 0xE000ED10
__IO uint32_t CCR ; // 0xE000ED14
__IO uint32_t SYS_PRIO[3] ; // 0xE000ED18
__IO uint32_t SYSHNDCTRL ; // 0xE000ED24
//__IO uint32_t FAULTSTAT ; // 0xE000ED28
//__IO uint32_t HFAULTSTAT ; // 0xE000ED2C
} SCB_T, *PSCB_T ;
/* module definitions */
#define BOARD_BASE_ADDRESS_SYSTICK 0xE000E000
#define BOARD_BASE_ADDRESS_NVIC 0xE000E100
#define BOARD_BASE_ADDRESS_SCB 0xE000ED00
#define BOARD_BASE_ADDRESS_GPTIMER0 0x40030000
extern SYSTICK_T* const board_systick ;
extern NVIC_T* const board_nvic ;
extern SCB_T* const board_scb ;
extern GPTM_TIMER_T* const board_gptm0 ;
/* Function prototypes */
extern int low_level_init (void) ;
extern void dbg_format_msg (char *format, ...) ;
extern void dbg_hard_fault_handler_c (unsigned int * hardfault_args) ;
#define DBG_MESSAGE(fmt_str) { dbg_format_msg fmt_str ; }
#endif /* __MODULES_H__ */

View File

@@ -1,215 +0,0 @@
/*
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.
*/
/* lm3s Startup Script */
.section .vectors,"x",%progbits
.syntax unified
.thumb
.global __interrupt_vector_table
.extern archTickHandler
.extern archPendSVHandler
.extern dbg_hard_fault_handler_c
/**
* \b __interrupt_vector_table
*
*/
__interrupt_vector_table:
.long __c_stack_top__
.long reset_Handler
.long fault_Handler
.long fault_Handler
.long fault_Handler
.long fault_Handler
.long fault_Handler
.long 0
.long 0
.long 0
.long 0
.long sys_Handler
.long sys_Handler
.long 0
.long archPendSVHandler
.long sys_Handler
/* External interrupts */
.long default_Handler // GPIO Port A
.long default_Handler // GPIO Port B
.long default_Handler // GPIO Port C
.long default_Handler // GPIO Port D
.long default_Handler // GPIO Port E
.long default_Handler // UART0 Rx and Tx
.long default_Handler // UART1 Rx and Tx
.long default_Handler // SSI0 Rx and Tx
.long default_Handler // I2C0 Master and Slave
.long default_Handler // PWM Fault
.long default_Handler // PWM Generator 0
.long default_Handler // PWM Generator 1
.long default_Handler // PWM Generator 2
.long default_Handler // Quadrature Encoder 0
.long default_Handler // ADC Sequence 0
.long default_Handler // ADC Sequence 1
.long default_Handler // ADC Sequence 2
.long default_Handler // ADC Sequence 3
.long default_Handler // Watchdog timer
.long archTickHandler // Timer 0 subtimer A
.long default_Handler // Timer 0 subtimer B
.long default_Handler // Timer 1 subtimer A
.long default_Handler // Timer 1 subtimer B
.long default_Handler // Timer 2 subtimer A
.long default_Handler // Timer 2 subtimer B
.long default_Handler // Analog Comparator 0
.long default_Handler // Analog Comparator 1
.long default_Handler // Analog Comparator 2
.long default_Handler // System Control (PLL, OSC, BO)
.long default_Handler // FLASH Control
.long default_Handler // GPIO Port F
.long default_Handler // GPIO Port G
.long default_Handler // GPIO Port H
.long default_Handler // UART2 Rx and Tx
.long default_Handler // SSI1 Rx and Tx
.long default_Handler // Timer 3 subtimer A
.long default_Handler // Timer 3 subtimer B
.long default_Handler // I2C1 Master and Slave
.long default_Handler // Quadrature Encoder 1
.long default_Handler // CAN0
.long default_Handler // CAN1
.long default_Handler // CAN2
.long default_Handler // Ethernet
.long default_Handler // Hibernate
/**
* \b sys_Handler
*
* @return None
*/
.thumb_func
sys_Handler:
B .
/**
* \b default_Handler
*
* @return None
*/
.thumb_func
default_Handler:
B .
/**
* \b fault_Handler
*
* @return None
*/
.thumb_func
fault_Handler:
tst lr, #4
ite eq
mrseq r0, MSP
mrsne r0, PSP
b dbg_hard_fault_handler_c
.section .startup,"x",%progbits
.syntax unified
.thumb
.global reset_Handler
.extern initialise_monitor_handles
.extern low_level_init
.extern main
/**
* \b reset_Handler
*
*
*
* @return None
*/
.thumb_func
reset_Handler:
/*
* Initialize the data and bss sections.
*/
init_data:
ldr r0, .ETEXT
ldr r1, .DATA
ldr r2, .EDATA
sub r2, r2, r1
cmp r2, #0
beq init_bss
init_data_copy:
ldrb r4, [r0], #1
strb r4, [r1], #1
subs r2, r2, #1
bne init_data_copy
init_bss:
mov r0, #0
ldr r1, = .BSS
ldr r2, = .EBSS
sub r2, r2, r1
cmp r2, #0
beq init_done
init_bss_zero:
strb r0, [r1], #1
subs r2, r2, #1
bne init_bss_zero
init_done:
/*
* The following call initializes the function pointers for stdio etc.
* These are used by the semihosting interface.
*
* This function is implemented in newlib.
*/
bl initialise_monitor_handles
/*
* Platform specific low level initialization.
*/
bl low_level_init
/*
* Call the application's entry point.
*/
bl main
.BSS: .long _bss
.EBSS: .long _ebss
.ETEXT: .long _etext
.DATA: .long _data
.EDATA: .long _edata
.end

View File

@@ -1,72 +0,0 @@
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00010000
}
SECTIONS
{
_vRamTop = 0x20000000 + 0x00010000;
.text :
{
KEEP(*(.vectors))
*(.startup)
*(.text*)
*(.rodata*)
} > FLASH
/*
* for exception handling/unwind - some Newlib functions (in common with
* C++ and STDC++) use this.
*/
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
_etext = .;
.data : AT (__exidx_end)
{
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > SRAM
/* zero initialized data */
.bss :
{
__bss_start__ = . ;
_bss = .;
*(.bss*)
*(COMMON)
__bss_end__ = . ;
_ebss = .;
} > SRAM
/* Where we put the heap with cr_clib */
.cr_heap :
{
end = .;
_pvHeapStart = .;
} > SRAM
_vStackTop = _vRamTop - 16;
.stack _vStackTop :
{
__c_stack_top__ = . ;
}
}

View File

@@ -1,62 +0,0 @@
#
# The following part of the makefile is generic; it can be used to
# build any executable just by changing the definitions above and by
# deleting dependencies appended to the file from 'make depend'
#
.SUFFIXES: .asm .elf .hex .lst .o .S .s .c .cpp
.PHONY: depend clean
dump:
@echo "Target: "
@echo $(TARGET_NAME)
@echo "Source files: "
@echo $(SRCS)
@echo $(ASMS)
@echo "Object files: "
@echo $(OBJS)
all: target
target: $(OBJS)
$(LN) $(LFLAGS) $(LIBFLAGS) $(OBJS) $(LLIBS) -o $(TARGET_NAME).elf
@echo $(TARGET_NAME).elf was compiled
arm-none-eabi-objcopy -O binary $(TARGET_NAME).elf $(TARGET_NAME).bin
arm-none-eabi-objdump -dxS $(TARGET_NAME).elf > $(TARGET_NAME).out
clean:
rm -f $(OBJS)
# this is a suffix replacement rule for building .o's from .c's
# it uses automatic variables $<: the name of the prerequisite of
# the rule(a .c file) and $@: the name of the target of the rule (a .o file)
# (see the gnu make manual section about automatic variables)
.c.o:
$(CC) $(CDEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@
.cpp.o:
$(CC) $(CDEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@
.S.o:
$(AS) $(ADEFS) $(AFLAGS) $(INCLUDES) -c $< -o $@
.s.o:
$(AS) $(ADEFS) $(AFLAGS) $(INCLUDES) -c $< -o $@
DEPFILE=.depends
DEPTOKEN='\# MAKEDEPENDS'
DEPFLAGS=-Y -f $(DEPFILE) -s $(DEPTOKEN) -p $(OUTDIR)/
depend:
rm -f $(DEPFILE)
make $(DEPFILE)
$(DEPFILE):
@echo $(DEPTOKEN) > $(DEPFILE)
makedepend $(DEPFLAGS) -- $(CFLAGS) -- $(SRCS) >&/dev/null
# put this file in the last line of your Makefile
sinclude $(DEPFILE)

View File

@@ -43,6 +43,10 @@
.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
@@ -60,7 +64,7 @@
.code 32
/*
/**
* \b archContextSwitch
*
* Architecture-specific context switch routine.
@@ -80,6 +84,10 @@
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
@@ -120,6 +128,11 @@ archContextSwitch:
* 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 */

View File

@@ -30,7 +30,6 @@
#ifndef __ATOM_PORT_PRIVATE_H
#define __ATOM_PORT_PRIVATE_H
/* Function prototypes */
extern void archIRQHandler (void);

View File

@@ -27,6 +27,10 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <sys/reent.h>
#include "atom.h"
#include "atomport.h"
@@ -68,6 +72,14 @@ static void thread_shell (void)
/* 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.
@@ -80,8 +92,12 @@ static void thread_shell (void)
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->suspended = TRUE;
curr_tcb->terminated = TRUE;
atomSched (FALSE);
}
@@ -153,5 +169,10 @@ void archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_poi
*/
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));
}

View File

@@ -36,10 +36,12 @@
/* 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)
@@ -50,7 +52,23 @@
*/
#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
*
@@ -58,7 +76,6 @@
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
@@ -69,6 +86,15 @@ extern void contextExitCritical (uint32_t posture) ;
#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 */

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

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
* 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
@@ -27,15 +27,12 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_PORT_PRIVATE_H__
#define __ATOM_PORT_PRIVATE_H__
#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);
/* Function prototypes */
extern void archPendSVHandler (void) ;
extern void archTickHandler (void) ;
/* required interface */
extern void __context_tick_handler (void) ;
#endif /* __ATOM_PORT_PRIVATE_H__ */
#endif /* __ATOM_UART_H */

View File

@@ -14,6 +14,7 @@ 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.
@@ -71,6 +72,10 @@ endif
# 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)
@@ -121,7 +126,7 @@ doxygen:
doxygen ../../Doxyfile
doxygen ./Doxyfile
# Run tests within simavr simulator
# Run tests within QEMU simulator
phony_qemu_elfs = $(addsuffix .sim, $(TEST_ELFS))
qemutests: $(phony_qemu_elfs)
.PHONY: qemutests $(phony_qemu_elfs)

View File

@@ -13,6 +13,11 @@ 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

View File

@@ -21,13 +21,13 @@
__interrupt_vector_table:
B Reset_Handler /* Reset */
B Null_Handler /* Undefined */
B Null_Handler /* SWI */
B Null_Handler /* Prefetch Abort */
B Null_Handler /* Data Abort */
B Null_Handler /* reserved */
B IRQ_Handler /* IRQ */
B Null_Handler /* FIQ */
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:
@@ -45,10 +45,3 @@ Reset_Handler:
B .
IRQ_Handler:
B archIRQHandler
Null_Handler:
B null_handler

View File

@@ -106,6 +106,13 @@ static int uart_init (void)
}
}
/* Already initialised */
else
{
/* Success */
status = ATOM_OK;
}
/* Finished */
return (status);
}

View File

@@ -65,6 +65,7 @@ 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));
/**
@@ -75,7 +76,7 @@ extern int _write(int file, char *ptr, int len) __attribute__((weak));
*/
int _close(int file)
{
return -1;
return 0;
}
@@ -122,10 +123,17 @@ int _lseek(int file, int ptr, int dir)
*
* 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 -1;
return 0;
}
@@ -209,3 +217,14 @@ caddr_t _sbrk(int incr)
return (caddr_t)prev_heap_end;
}
/**
* \b _exit
*
* Simple stub implementation, exit() not needed or implemented.
*
*/
int _exit(int val)
{
return -1;
}

View File

@@ -1,40 +0,0 @@
---------------------------------------------------------------------------
Library: Atomvn
Author: Natie van Rooyen <natie@navaro.nl>
License: BSD Revised
---------------------------------------------------------------------------
Atomvm is a tiny virtual machine that runs on Windows and can be debugged
from an IDE like Microsoft Visual C++ Express. The primary purpose of this
virtual machine is for the evaluation of Real Time Operating Systems like
Atomthreads and the development and testing of programs for it on a Windows
machine.
Atomvm makes use of the Windows API functions GetThreadContext() and
SetThreadContext() to create multiple virtual contexts or threads inside a
single Windows thread. Atomvm also simulates interrupts with an interrupt
mask accessible from the Atomvm threads. External events can be queued as
interrupts to Atomvm, for example a timer loop generating system timer tick
interrupts for a Real Time Operating System ported to Atomvm.
---------------------------------------------------------------------------
BUILDING THE SOURCE
To test this project, just add all the files from the "atomthreads/kernel"
directory and the "atomthreads/ports/atomvm" directory as well as the test
program "atomthreads/ports/atomvm/test/main.c" to your project. Add both the
before mentioned directories to the include paths of your project and compile.
Atomvm was designed for multi core systems but also runs fine on any single
core system.
---------------------------------------------------------------------------
RUNNING THE TESTS
The test, main.c, is intentioned to stress the virtual machine.

View File

@@ -1,36 +0,0 @@
---------------------------------------------------------------------------
Library: Atomvn
Author: Natie van Rooyen <natie@navaro.nl>
License: BSD Revised
---------------------------------------------------------------------------
Atomvm is a tiny virtual machine that can run on Windows inside an IDE with a
debugger like Microsoft Visual C++ Express. The primary purpose of this virtual
machine is for the evaluation of Real Time Operating Systems (like atomthreads)
and the development and testing of modules for this Real Time Operating System
in a user friendly environment.
---------------------------------------------------------------------------
BUILDING THE SOURCE
To test this project, just add all the files from the "atomthreads/kernel"
directory and the "atomthreads/ports/atomvm" directory as well as the test
program "atomthreads/ports/atomvm/test/main.c" to your project. Add both the
before mentioned directories to the include paths of your project and compile.
Atomvm was designed for multi core systems but also runs fine on any single
core system.
---------------------------------------------------------------------------
RUNNING THE TESTS
The test, main.c, is intentioned to stress the virtual machine as opposed to
testing the Real Time Operating System. However, this test can also run the
unit tests of atomthreads by using the preprocessor directive "UNIT_TESTS" and
linking in the desired unit test into the project.

View File

@@ -1,159 +0,0 @@
/*
* 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 "atom.h"
#include "atomport.h"
#include "atomvm.h"
#include "windows.h"
/** Forward declarations */
DWORD WINAPI cntrl_thread_proc (LPVOID lpParameter) ;
/* Global data */
HATOMVM the_atomvm ;
/* Local data */
static HANDLE cntrl_thread ;
/**
* \b atomvmRun
*
* Starts the atom vm. atomvmRun creates a thread from where the atomvmCtrlRun function
* will be called. atomvmCtrlRun never returns and this thread becomes the controll
* thread of the vm.
*
*/
void
atomvmRun (void)
{
atomvmCtrlCreate (&the_atomvm) ;
cntrl_thread = CreateThread (NULL, 0, cntrl_thread_proc, (uint32_t*)the_atomvm, CREATE_SUSPENDED, NULL) ;
ResumeThread (cntrl_thread) ;
}
DWORD WINAPI
cntrl_thread_proc (LPVOID lpParameter)
{
atomvmCtrlRun ((HATOMVM)lpParameter, 0) ;
return 0 ;
}
/**
* \b thread_shell
*
* Documented in atomThreads.
*
*/
void
thread_shell (uint32_t arg)
{
ATOM_TCB *curr_tcb;
/* Get the TCB of the thread being started */
curr_tcb = atomCurrentContext();
/**
* Enable interrupts - these will not be enabled when a thread
* is first restored.
*/
// sei();
//atomvmExitCritical () ;
atomvmInterruptMask (0) ;
/* Call the thread entry point */
if (curr_tcb && curr_tcb->entry_point)
{
curr_tcb->entry_point(curr_tcb->entry_param);
}
/* Not reached - threads should never return from the entry point */
}
/**
* \b archThreadContextInit
*
* Documented in atomThreads.
*
*/
void
archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(uint32_t), uint32_t entry_param)
{
tcb_ptr->sp_save_ptr = stack_top;
tcb_ptr->entry_param = entry_param ;
tcb_ptr->entry_point = entry_point ;
tcb_ptr->context = atomvmContextCreate (1) ;
atomvmContextInit (tcb_ptr->context, (unsigned int *)stack_top, thread_shell, entry_param, 0) ;
}
/**
* \b archFirstThreadRestore
*
* Documented in atomThreads.
*
*/
void
archFirstThreadRestore(ATOM_TCB * p_sp_new)
{
atomvmContextSwitch (0, p_sp_new->context) ;
}
/**
* \b archContextSwitch
*
* Documented in atomThreads.
*
*/
void
archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new)
{
atomvmContextSwitch (p_sp_old->context, p_sp_new->context) ;
}
/**
* \b archTimerTickIrqHandler
*
* System timer tick interrupt handler.
*
*/
void archTimerTickIrqHandler (void)
{
atomIntEnter();
/* Call the OS system tick handler */
atomTimerTick();
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}

View File

@@ -1,62 +0,0 @@
/*
* 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__
#include "atomvm.h"
#define SYSTEM_TICKS_PER_SEC 100
/* Size of each stack entry / stack alignment size (e.g. 32 bits) */
#define STACK_ALIGN_SIZE sizeof(unsigned int)
/**
* Architecture-specific types.
* Most of these are available from stdint.h on this platform, which is
* included above.
*/
#define POINTER void *
#define ATOM_TLS HATOMVM_CONTEXT context ;
/* Critical region protection */
#define CRITICAL_STORE unsigned int __atom_int_mask
#define CRITICAL_START() __atom_int_mask = atomvmInterruptMask(1)
#define CRITICAL_END() atomvmInterruptMask(__atom_int_mask)
#define ATOM_TLS HATOMVM_CONTEXT context ;
/* Function prototypes */
extern void atomvmRun (void) ;
extern void archTimerTickIrqHandler (void) ;
/* The instance of the atomvm for this port */
extern HATOMVM the_atomvm ;
#endif /* __ATOM_PORT_H__ */

View File

@@ -1,63 +0,0 @@
/*
* 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.
*/
#if 1
#ifndef __ATOM_USER_H__
#define __ATOM_USER_H__
/* Portable uint8_t and friends not available from stdint.h on this platform */
#include <windows.h>
#define SYSTEM_MEMALIGN sizeof (unsigned int)
typedef unsigned int uintptr_t ;
typedef int intptr_t ;
typedef unsigned int uint32_t ;
typedef unsigned short uint16_t ;
typedef unsigned char uint8_t ;
typedef int int32_t ;
typedef short int16_t ;
typedef char int8_t ;
/**
* Architecture-specific types.
* Most of these are available from stdint.h on this platform, which is
* included above.
*/
#define POINTER void *
#define ATOM_TLS HATOMVM_CONTEXT context ;
#endif /* __ATOM_USER_H__ */
#endif

View File

@@ -1,852 +0,0 @@
/*
* Copyright (c) 2010, 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.
*/
/**
* \file
* Atom Virtual Machine.
*
*
* This module implements the virtual machine.
*
*
* \b Functions contained in this module:\n
*
* \b Function prototypes used for controlling the atom virtual machine: \n
*
* \li atomvmCtrlCreate(): .
* \li atomvmCtrlRun(): .
* \li atomvmCtrlIntRequest(): .
* \li atomvmCtrlClose(): .
*
* \b Function prototypes for use by the atom virtual machine: \n
*
* \li atomvmInterruptMask(): .
* \li atomvmContextCreate(): .
* \li atomvmContextSwitch(): .
* \li atomvmContextDesrtroy(): .
* \li atomvmWriteThreadId(): .
* \li atomvmReadThreadId(): .
* \li atomvmInterruptWait(): .
* \li atomvmGetVmId(): .
*
* \b Function prototypes to be implemted in the atom virtual machine: \n
*
* \li __atomvmReset(): .
* \li __atomvmClose(): .
*
*/
#include "atomvm.h"
#include <string.h>
#include <windows.h>
#define CONTEXT_VM (CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS)
/* Data types */
/* Forward declarations */
typedef struct ATOMVM_S * PATOMVM ;
typedef struct ATOMVM_CALLBACK_S * PATOMVM_CALLBACK ;
typedef struct ATOMVM_CONTEXT_S * PATOMVM_CONTEXT ;
typedef uint32_t (*ATOMVM_CALLBACK_F) (PATOMVM, PATOMVM_CALLBACK) ;
typedef struct ATOMVM_CALLBACK_S {
/* Address of callback function */
volatile ATOMVM_CALLBACK_F callback ;
/* Synchronization lock, the virtual machine will be suspended during
the callback. Regular WIN32 synchronization methods cant be used
because SuspendThread() is used on the vm thread. */
volatile uint32_t lock ;
/* Result of the call */
volatile uint32_t result ;
} ATOMVM_CALLBACK, *PATOMVM_CALLBACK ;
/* ATOMVM_CALLBACK_CONTEXT is the parameter for a ATOMVM_CALLBACK_F call
that take as parameter a pointer to a ATOMVM_CONTEXT to operate on */
typedef struct ATOMVM_CALLBACK_CONTEXT_S {
ATOMVM_CALLBACK callback ;
/* Context the callback function will operate on */
volatile PATOMVM_CONTEXT pcontext ;
} ATOMVM_CALLBACK_CONTEXT, *PATOMVM_CALLBACK_CONTEXT ;
/* ATOMVM_CALLBACK_CONTEXT_SWITCH is the parameter for a ATOMVM_CALLBACK_F call
that take as parameter a pointer to a ATOMVM_CONTEXT to operate on */
typedef struct ATOMVM_CALLBACK_CONTEXT_SWITCH_S {
ATOMVM_CALLBACK callback ;
/* Context the callback function will operate on */
volatile PATOMVM_CONTEXT p_old_context ;
volatile PATOMVM_CONTEXT p_new_context ;
} ATOMVM_CALLBACK_CONTEXT_SWITCH, *PATOMVM_CALLBACK_CONTEXT_SWITCH ;
/* ATOMVM_CALLBACK_INT_REQUEST is the parameter for a ATOMVM_CALLBACK_F call
that take as parameter a pointer to to the function that will be called in
an interrupt context */
typedef struct ATOMVM_CALLBACK_INT_REQUEST_S {
ATOMVM_CALLBACK callback ;
/* Function pointer the callback will call */
void (*isr) (void) ;
} ATOMVM_CALLBACK_INT_REQUEST, *PATOMVM_CALLBACK_INT_REQUEST ;
/* ATOMVM_CONTEXT saves the state of a context created by
atomvmContextCreate() and sheduled by atomvmContextSwitch(). */
typedef struct ATOMVM_CONTEXT_S {
/* A virtual machine thread context. These are saved and restored
during context initialization and context switches */
CONTEXT context ;
/* When entering a critical section the interrupt_mask is
set for the context. Interrupts will only occur while
the interrupt_mask is zero. */
volatile uint32_t interrupt_mask ;
uint32_t thread_id ;
} ATOMVM_CONTEXT, *PATOMVM_CONTEXT ;
/* ATOMVM defines the state of an instance to an atomvm. It is created
by a call to atomvmCtrlCreate(). */
typedef struct ATOMVM_S {
uint32_t atomvm_id ;
/* Thread the virtual machine will run in */
HANDLE vm_thread ;
/* Handles to events and mutexes used for synchronization */
HANDLE atomvm_call ;
HANDLE atomvm_int ;
HANDLE atomvm_int_complete ;
HANDLE atomvm_close ;
/* next ISR */
volatile void (*isr)(void) ;
/* True if in an ISR */
volatile uint32_t status_isr ;
/* The current context that was scheduled by a call
to atomvmContextSwitch() */
PATOMVM_CONTEXT current_context ;
/* Service call address, synchronization lock, parameters
and, return value for the current service call */
PATOMVM_CALLBACK service_call ;
/* Context for startup, before any context was scheduled */
ATOMVM_CONTEXT atom_init_context ;
} ATOMVM, *PATOMVM ;
/* Global declarations */
volatile uint32_t g_atomvm_id = 0 ;
volatile DWORD g_atomvm_tls_idx ;
/* Forward declaration for the atom virtual machine thread */
static DWORD WINAPI vm_thread (LPVOID lpParameter) ;
/**
* \ingroup atomvm
* \b atomvmCtrlCreate
*
* This is an atomvm controll function used by a controlling thread.
*
* Initializes the virtual machine.
*
* @param[out] atomvm Handle to the virtual machine to create.
*
* @return Zero on failure.
*/
uint32_t
atomvmCtrlCreate (HATOMVM *atomvm)
{
PATOMVM patomvm = 0 ;
patomvm = (PATOMVM) malloc (sizeof(struct ATOMVM_S)) ;
if (patomvm) {
memset (patomvm, 0, sizeof(struct ATOMVM_S)) ;
patomvm->atomvm_id = InterlockedIncrement(&g_atomvm_id) - 1 ;
if (patomvm->atomvm_id == 0) {
g_atomvm_tls_idx = TlsAlloc () ;
}
patomvm->atomvm_call = CreateEvent (NULL, TRUE, FALSE, 0) ;
patomvm->atomvm_int = CreateEvent (NULL, TRUE, FALSE, 0) ;
patomvm->atomvm_int_complete = CreateEvent (NULL, FALSE, TRUE, 0) ;
patomvm->atomvm_close = CreateEvent (NULL, TRUE, FALSE, 0) ;
ATOMVM_ASSERT(patomvm->atomvm_call && patomvm->atomvm_int && patomvm->atomvm_int_complete &&
patomvm->atomvm_close, _T("ResumeThread failed")) ;
patomvm->vm_thread = CreateThread (NULL, 0, vm_thread, (void*)patomvm, CREATE_SUSPENDED, NULL) ;
ATOMVM_ASSERT(patomvm->vm_thread, _T("CreateThread failed")) ;
patomvm->atom_init_context.interrupt_mask = 1 ;
patomvm->current_context = &patomvm->atom_init_context ;
*atomvm = (HATOMVM)patomvm ;
}
return patomvm != 0 ;
}
/**
* \ingroup atomvm
* \b atomvmCtrlRun
*
* After a call to atomvmCtrlCreate this function start the atom virtual machine.
* The calling thread will be used to manage interrupts and service calls in
* the virtual machine. This function will not return untill atomvmCtrlClose
* is called.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlCreate.
* @param[in] flags not used.
*
* @return None
*/
void
atomvmCtrlRun (HATOMVM atomvm, uint32_t flags)
{
PATOMVM patomvm = (PATOMVM) atomvm ;
HANDLE wait[3] ;
uint32_t res ;
uint32_t wait_object ;
PATOMVM_CALLBACK service_call ;
#if defined DEBUG || defined _DEBUG
BOOL tls_res =
#endif
TlsSetValue (g_atomvm_tls_idx, (void*) atomvm) ;
ATOMVM_ASSERT(tls_res, _T("TlsSetValue failed")) ;
ResumeThread (patomvm->vm_thread) ;
wait[0] = patomvm->atomvm_call ;
wait[1] = patomvm->atomvm_int ;
wait[2] = patomvm->atomvm_close ;
for(;;) {
wait_object = WaitForMultipleObjects (3, wait,FALSE,INFINITE) ;
if (wait_object == WAIT_OBJECT_0) {
service_call = patomvm->service_call ;
while (!service_call->lock) {
SwitchToThread () ;
}
while ((res = SuspendThread (patomvm->vm_thread)) == (DWORD)-1) ;
ATOMVM_ASSERT(res == 0 , _T("SuspendThread failed")) ;
#if (_WIN32_WINNT >= 0x0600)
/*
This is used for multi processor machines to ensure the thread
is stopped before executing the next instruction. Set
_WIN32_WINNT < 0x0600 if you are running Windows XP */
FlushProcessWriteBuffers ();
#endif
InterlockedExchange (&service_call->result, service_call->callback (patomvm, service_call)) ;
InterlockedExchange (&service_call->lock, 0) ;
ResetEvent (patomvm->atomvm_call) ;
res = ResumeThread (patomvm->vm_thread) ;
ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ;
}
else if (wait_object == WAIT_OBJECT_0 + 1) {
if (patomvm->current_context->interrupt_mask == 0) {
while ((res = SuspendThread (patomvm->vm_thread)) == (DWORD)-1) ;
ATOMVM_ASSERT(res == 0 , _T("SuspendThread failed")) ;
#if (_WIN32_WINNT >= 0x0600)
/*
This is used for multi processor machines to ensure the thread
is stopped before executing the next instruction. Set
_WIN32_WINNT < 0x0600 if you are running Windows XP */
FlushProcessWriteBuffers ();
#endif
if (patomvm->current_context->interrupt_mask == 0) {
patomvm->status_isr++ ;
patomvm->isr () ;
patomvm->status_isr-- ;
res = ResumeThread (patomvm->vm_thread) ;
ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ;
ResetEvent (patomvm->atomvm_int) ;
InterlockedExchange ((volatile uint32_t*)&patomvm->isr, 0) ;
SetEvent (patomvm->atomvm_int_complete) ;
} else {
res = ResumeThread (patomvm->vm_thread) ;
ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ;
SwitchToThread () ;
}
} else {
SwitchToThread () ;
}
} else if (wait_object == WAIT_OBJECT_0 + 2) {
break ;
} else {
ATOMVM_ASSERT(res == 1 , _T("WaitForMultipleObjects failed")) ;
}
}
}
/**
* \ingroup atomvm
* \b atomvmCtrlClose
*
* This is an atomvm controll function used by a controlling thread
* and must not be called from the atom virtual machine.
*
* Closes the virtual machine and release all memory and handles created
* in atomvmCtrlCreate.
*
* ToDo: more testing.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlCreate.
*
* @return None
*/
void
atomvmCtrlClose (HATOMVM atomvm)
{
PATOMVM patomvm = (PATOMVM) atomvm ;
DWORD code ;
__atomvmClose () ;
SetEvent (patomvm->atomvm_close) ;
do {
SwitchToThread () ;
GetExitCodeThread (patomvm->vm_thread, &code) ;
} while (code == STILL_ACTIVE) ;
CloseHandle (patomvm->atomvm_call) ;
CloseHandle (patomvm->atomvm_int) ;
CloseHandle (patomvm->atomvm_int_complete) ;
CloseHandle (patomvm->atomvm_close) ;
CloseHandle (patomvm->vm_thread) ;
// TlsFree (g_atomvm_tls_idx) ;
free (atomvm) ;
}
/**
* \b invokeCallback
*
* Invokes callback functions in the context of the controll thread as
* requested from the virtual machine. In case this callback came from inside,
* an isr it is already in the conrtext of the controll thread and the callback
* routine is called directly.
*
* The atom virtual machine thread is suspended during the callback.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @param[in] callback Callback function.
* @param[in/out] context Context the function will operate on.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
invokeCallback (PATOMVM patomvm, ATOMVM_CALLBACK_F callback, PATOMVM_CALLBACK service_call)
{
uint32_t res ;
if (patomvm->status_isr == 0) {
service_call->lock = 0 ;
service_call->callback = callback ;
patomvm->service_call = service_call ;
SetEvent (patomvm->atomvm_call) ;
InterlockedIncrement (&service_call->lock) ;
while (service_call->lock != 0) ;
res = service_call->result ;
} else {
res = callback (patomvm, service_call) ;
}
return res ;
}
/*
* \b getAtomvm
*
* Get the atomvm instance for the calling thread
*
* @return atomvm instance
*/
__inline PATOMVM
getAtomvm (void)
{
PATOMVM patomvm = (PATOMVM) TlsGetValue (g_atomvm_tls_idx) ;
ATOMVM_ASSERT(patomvm , _T("TlsGetValue failed")) ;
return patomvm ;
}
/**
* \ingroup atomvm
* \b atomvmInterruptMask
*
* This function is to be used by the atom virtual machine.
*
* This function will mask interrupts for the current atomvm context.
*
* @param[in] mask zero enables interrupts any other value masks interrupts.
*
* @return Interrupt mask before the function call.
*/
int32_t
atomvmInterruptMask (uint32_t mask)
{
PATOMVM patomvm = getAtomvm () ;
int32_t interrupts = 0;
if (patomvm->status_isr == 0) {
interrupts = InterlockedExchange (&patomvm->current_context->interrupt_mask, mask) ;
}
return interrupts ;
}
/**
* \ingroup atomvm
* \b atomvmCtrlIntRequest
*
* This is an atomvm controll function used by external threads
* and must not be called from the atom virtual machine.
*
* This function requests an interrupt service routine to be called in the
* context of the atom virtual machine.
*
* The call will return immediately after the interrupt was scheduled.
* The call will block while a previously scheduled interrupt is in progress.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlCreate.
* @param[in] isr The address of the interrupt service routine.
*
* @return None
*/
void
atomvmCtrlIntRequest (HATOMVM atomvm, void (*isr) (void))
{
PATOMVM patomvm = (PATOMVM) atomvm ;
WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ;
while (InterlockedCompareExchange ((volatile uint32_t *)&patomvm->isr, (uint32_t)isr, 0) != 0) {
SwitchToThread() ;
}
SetEvent (patomvm->atomvm_int) ;
}
/**
* \b callbackContextCreate
*
* This function is invoked from the controll thread after a call to atomvmContextCreate.
*
* The atom virtual machine is suspended while this function is called.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @param[out] context Context to be initialized.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
callbackContextCreate (PATOMVM patomvm, PATOMVM_CALLBACK callback)
{
PATOMVM_CALLBACK_CONTEXT context_switch = (PATOMVM_CALLBACK_CONTEXT)callback;
CONTEXT * pcontext = &context_switch->pcontext->context ;
pcontext->ContextFlags = CONTEXT_VM ;
return GetThreadContext (patomvm->vm_thread, pcontext) ;
}
/**
* \ingroup atomvm
* \b atomvmContextCreate
*
* This function is to be used by the atom virtual machine.
*
* This function creates a atomvm thread context that can be scheduled
* by atomvmContextSwitch.
*
* @param[in] interrupt_mask initial interrupt mask of the thread.
*
* @return Handle to the context of the thread created.
*/
HATOMVM_CONTEXT
atomvmContextCreate (uint32_t interrupt_mask)
{
uint32_t res ;
PATOMVM patomvm = getAtomvm () ;
PATOMVM_CONTEXT new_context = (PATOMVM_CONTEXT)malloc (sizeof(ATOMVM_CONTEXT)) ;
CONTEXT* pcontext = &new_context->context ;
ATOMVM_CALLBACK_CONTEXT context_init ;
context_init.pcontext = new_context ;
new_context->interrupt_mask = interrupt_mask ;
new_context->thread_id = (uint32_t) -1 ;
res = invokeCallback (patomvm, callbackContextCreate, (PATOMVM_CALLBACK)&context_init) ;
if (res) {
return (HATOMVM_CONTEXT)new_context ;
} else {
free (new_context) ;
}
return 0 ;
}
/**
* \ingroup atomvm
* \b atomvmContextInit
*
* This function is to be used by the atom virtual machine.
*
* This function initialize a atomvm thread context that can be scheduled
* by atomvmContextSwitch.
*
* @param[out] context Handle to the context of the thread that are allocated
* by the caller.
* @param[in] stack Stack top.
* @param[in] entry Entry point of the thread.
* @param[in] arg argument passed on the stack as first parameter.
* @param[in] exit exit function to return to.
* @param[in] status status for exit function.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
atomvmContextInit (HATOMVM_CONTEXT context, uint32_t* stack, void (*entry)(uint32_t), uint32_t arg, void (*exit)(uint32_t))
{
uint32_t res = 0 ;
PATOMVM_CONTEXT new_context = (PATOMVM_CONTEXT)context ;
CONTEXT* pcontext = &new_context->context ;
*stack-- = arg;
*stack = (uint32_t)exit ;
pcontext->Ebp = (uint32_t)stack ;
pcontext->Esp = (uint32_t)stack ;
pcontext->Eip = (uint32_t)entry ;
return res ;
}
/**
* \b callbackContextSwitch
*
* This function is invoked from the controll thread after a call to atomvmContextSwitch.
*
* The atom virtual machine is suspended while this function is called.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @param[out] context Context to be scheduled.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
callbackContextSwitch (PATOMVM patomvm, PATOMVM_CALLBACK callback)
{
uint32_t res1 = 1 ;
uint32_t res2 ;
PATOMVM_CALLBACK_CONTEXT_SWITCH context_switch = (PATOMVM_CALLBACK_CONTEXT_SWITCH)callback ;
if (context_switch->p_old_context) {
res1 = GetThreadContext (patomvm->vm_thread, &context_switch->p_old_context->context) ;
ATOMVM_ASSERT(res1 , _T("GetThreadContext failed")) ;
}
patomvm->current_context = context_switch->p_new_context ;
res2 = SetThreadContext (patomvm->vm_thread, &context_switch->p_new_context->context) ;
ATOMVM_ASSERT(res2 , _T("SetThreadContext failed")) ;
return res1 & res2 ;
}
/**
* \ingroup atomvm
* \b atomvmContextSwitch
*
* This function is to be used by the atom virtual machine.
*
* This function schedules a thread for the context created by atomvmContextCreate.
*
* @param[in] new_context The context to schedule.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
atomvmContextSwitch (HATOMVM_CONTEXT old_context, HATOMVM_CONTEXT new_context)
{
PATOMVM patomvm = getAtomvm () ;
ATOMVM_CALLBACK_CONTEXT_SWITCH context_switch ;
context_switch.p_old_context = (PATOMVM_CONTEXT) old_context ;
context_switch.p_new_context = (PATOMVM_CONTEXT) new_context ;
return invokeCallback (patomvm, callbackContextSwitch, (PATOMVM_CALLBACK)&context_switch) ;
}
/**
* \ingroup atomvm
* \b atomvmContextDesrtroy
*
* This function is to be used by the atom virtual machine.
*
* This functiondestroyes a atomvm context created by atomvmContextCreate.
*
* @param[in] context The context to destroy.
*
* @return None
*/
void
atomvmContextDesrtroy (HATOMVM_CONTEXT context)
{
PATOMVM patomvm = getAtomvm () ;
ATOMVM_ASSERT(patomvm->current_context != (PATOMVM_CONTEXT)context,
_T("atomvmContextDesrtroy failed")) ;
free((void*)context) ;
}
/**
* \ingroup atomvm
* \b atomvmWriteThreadId
*
* Write a thread ID.
*
* Write a thread ID for the current context.
*
* @param[in] thread_id thread_id.
*
* @return None
*/
void
atomvmWriteThreadId (uint32_t thread_id)
{
PATOMVM patomvm = getAtomvm () ;
patomvm->current_context->thread_id = thread_id ;
}
/**
* \ingroup atomvm
* \b atomvmReadThreadId
*
* Write a thread ID.
*
* Read a thread ID for the current context.
*
* @return thread_id
*/
uint32_t
atomvmReadThreadId (void)
{
PATOMVM patomvm = getAtomvm () ;
return patomvm->current_context->thread_id ;
}
/**
* \ingroup atomvm
* \b atomvmGetVmId
*
* Returns an identifier for the virtual machine. This is zero for the first
* virtual machine created with atomvmCtrlCreate(), 1 for the second and so on.
*
* @return The atom vm ID
*/
uint32_t
atomvmGetVmId (void)
{
PATOMVM patomvm = getAtomvm () ;
return patomvm->atomvm_id ;
}
/**
* \b callbackInterruptWait
*
* This function is invoked from the controll thread after a call to atomvmInterruptWait().
*
* The atom virtual machine is suspended while this function is called.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @param[out] callback Callback parameter.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
callbackIntWait (PATOMVM patomvm, PATOMVM_CALLBACK callback)
{
WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ;
return WaitForSingleObject (patomvm->atomvm_int, INFINITE) == WAIT_OBJECT_0 ;
}
/**
* \ingroup atomvm
* \b atomvmInterruptWait
*
* This function is to be used by the atom virtual machine.
*
* This function if for synchronization between multiple
* atom vms.
*
*
* @return void.
*/
void
atomvmIntWait (void)
{
PATOMVM patomvm = getAtomvm () ;
ATOMVM_CALLBACK callback ;
invokeCallback (patomvm, callbackIntWait, (PATOMVM_CALLBACK)&callback) ;
}
/**
* \b callbackIntRequest
*
* This function is invoked from the controll thread after a call to atomvmIntRequest().
*
* The atom virtual machine is suspended while this function is called.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @param[in] callback Callback parameter.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
callbackIntRequest (PATOMVM patomvm, PATOMVM_CALLBACK callback)
{
PATOMVM_CALLBACK_INT_REQUEST int_request = (PATOMVM_CALLBACK_INT_REQUEST)callback ;
int_request->isr () ;
return 1 ;
}
/**
* \ingroup atomvm
* \b atomvmIntRequest
*
* This function is to be used by the atom virtual machine.
*
* @param[in] isr Function that will be called from the controll thread.
*
* @return void.
*/
void
atomvmIntRequest (void (*isr) (void))
{
PATOMVM patomvm = getAtomvm () ;
ATOMVM_CALLBACK_INT_REQUEST callback ;
callback.isr = isr ;
invokeCallback (patomvm, callbackIntRequest, (PATOMVM_CALLBACK)&callback) ;
}
/**
* \b vm_thread
*
* Windows thread in which the atom virtual machine will execute.
*
* __atomvmReset() runs the virtual machie and should only return after
* __atomvmClose() was called.
*
* @return None.
*/
DWORD WINAPI
vm_thread (LPVOID lpParameter)
{
BOOL res = TlsSetValue (g_atomvm_tls_idx, lpParameter) ;
ATOMVM_ASSERT(res, _T("TlsSetValue failed")) ;
__atomvmReset () ;
return 0 ;
}

View File

@@ -1,121 +0,0 @@
/*
* Copyright (c) 2010, 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.
*/
/** \mainpage \ref atomvm
* \defgroup atomvm Atomvm API
*
* @authors Natie van Rooyen
*
* @section intro Introduction
* Atomvm is a tiny virtual machine that runs on Windows and can be debugged
* from an IDE like Microsoft Visual C++ Express. The primary purpose of this
* virtual machine is for the evaluation of Real Time Operating Systems (like
* Atomthreads) and the development and testing of modules for this Real Time
* Operating System on a Windows machine.
*
* Atomvm makes use of the Windows API functions GetThreadContext() and
* SetThreadContext() to create multiple virtual contexts or threads inside a
* single Windows thread. Atomvm also simulates interrupts with an interrupt
* mask accessible from the Atomvm threads. External events can be queued as
* interrupts to Atomvm, for example a timer loop generating system timer tick
* interrupts for a Real Time Operating System ported to Atomvm.
*
* */
#ifndef __ATOMVM_H__
#define __ATOMVM_H__
#include <crtdbg.h>
#include "types.h"
#if defined _DEBUG || defined DEBUG
#define ATOMVM_ASSERT(x, msg) _ASSERT((x))
#else
#define ATOMVM_ASSERT(x, msg)
#endif
#define ATOMVM_MAX_VM 8
/* Forward declarations */
/* This is an opaque handle to an instance of an atomvm created
by a call to atomvmCtrlCreate() */
typedef struct ATOMVM* HATOMVM ;
/* This is an opaque handle to an atomvm context created
by a call to atomvmContextCreate() */
typedef struct ATOMVM_CONTEXT* HATOMVM_CONTEXT ;
/* Function prototypes used for controlling the atom virtual machine */
extern uint32_t atomvmCtrlCreate (HATOMVM* atomvm) ;
extern void atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) ;
extern void atomvmCtrlIntRequest (HATOMVM atomvm, void (*isr) (void)) ;
extern void atomvmCtrlClose (HATOMVM atomvm) ;
/* Function prototypes for use by the atom virtual machine from within the
call to __atomvmReset(). */
extern int32_t atomvmInterruptMask (uint32_t mask) ;
extern HATOMVM_CONTEXT atomvmContextCreate (uint32_t interrupt_mask) ;
extern uint32_t atomvmContextInit (HATOMVM_CONTEXT context, uint32_t* stack,
void (*entry)(uint32_t), uint32_t arg, void (*exit)(uint32_t)) ;
extern uint32_t atomvmContextSwitch (HATOMVM_CONTEXT old_context, HATOMVM_CONTEXT new_context) ;
extern void atomvmContextDesrtroy (HATOMVM_CONTEXT context) ;
extern void atomvmWriteThreadId (uint32_t thread_id) ;
extern uint32_t atomvmReadThreadId (void) ;
extern void atomvmIntWait (void) ;
extern void atomvmIntRequest (void (*isr) (void)) ;
extern uint32_t atomvmGetVmId (void) ;
/**
* \ingroup atomvm
* \b __atomvmReset
*
* Function prototype to be implemented as entry point for the atom virtual machine.
*
* @return void.
*/
extern void __atomvmReset (void) ;
/**
* \ingroup atomvm
* \b __atomvmClose
*
* Function prototype to be implemted in the atom virtual machine
*
* @return void.
*/
extern void __atomvmClose (void) ;
#endif /* __ATOMVM_H__ */

View File

@@ -1,270 +0,0 @@
#include <stdio.h>
#include <windows.h>
#include "atom.h"
#include "atomvm.h"
#include "atomport.h"
// #define UNIT_TESTS
#ifdef UNIT_TESTS
extern uint32_t test_start (void) ;
#endif
#define TEST_THREADS 47
#define TEST_STACK_BYTE_SIZE 0x10000
#define IDLE_STACK_BYTE_SIZE 0x10000
#define MONITOR_STACK_BYTE_SIZE 0x10000
static unsigned char idle_stack[IDLE_STACK_BYTE_SIZE] ;
static unsigned char monitor_stack[MONITOR_STACK_BYTE_SIZE] ;
static unsigned char test_stack[TEST_THREADS+1][TEST_STACK_BYTE_SIZE] ;
static unsigned int test_counter[TEST_THREADS+1] = {0} ;
static unsigned int test2_counter = 0 ;
static unsigned int test3_counter = 0 ;
static unsigned int test_isr_count = 0 ;
static unsigned char test2_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char test3_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char test_idle_stack[TEST_STACK_BYTE_SIZE] ;
static uint8_t test_prio[60] = {
001,010,100,200,250, 200,200,200,200,200,
150,150,150,150,150, 250,250,250,250,250,
101,102,103,104,105, 202,204,206,208,210,
150,150,150,150,150, 250,250,250,250,250,
121,122,123,124,125, 061,063,065,067,061,
150,150,150,150,150, 250,250,250,250,250
};
static uint32_t test_interv[60] = {
001,001,001,001,001, 002,003,004,005,006,
015,015,015,015,015, 025,024,023,022,021,
905,005,005,005,805, 050,051,052,053,054,
015,015,015,015,015, 025,024,023,022,021,
030,030,030,030,030, 070,071,072,073,474,
005,006,007,007,001, 001,001,003,003,005
};
ATOM_TCB test_tcb[TEST_THREADS+1] ;
ATOM_TCB monitor_tcb ;
ATOM_TCB test2_tcb ;
ATOM_TCB test3_tcb ;
ATOM_TCB test_idle_tcb ;
DWORD WINAPI isr_thread_proc (LPVOID lpParameter) ;
static HANDLE isr_thread_1 ;
static HANDLE isr_thread_2 ;
static HANDLE isr_thread_3 ;
static HANDLE isr_thread_4 ;
void
ipi_sr()
{
printf("ipi\r\n") ;
}
void
monitor_thread (uint32_t parm)
{
CRITICAL_STORE;
int i ;
int c = 0 ;
ATOM_TCB *tcb ;
static unsigned int idle_1 = 0, idle_2 = 0, int_count = 0 ;
unsigned int delta_idle_1 , delta_idle_2 , delta_int_count ;
tcb = atomCurrentContext() ;
for (;;)
{
CRITICAL_START();
printf("Monitor # %04d (%08d)\n", c++, atomTimeGet()) ;
printf("-------------------------\n") ;
for (i=0; i<TEST_THREADS/3; i++) {
printf("Thr %.2d cnt %08d\t",i,test_counter[i]);
printf("Thr %.2d cnt %08d\t",i+TEST_THREADS/3,test_counter[i+TEST_THREADS/3]);
printf("Thr %.2d cnt %08d\n",i+TEST_THREADS*2/3,test_counter[i+TEST_THREADS*2/3]);
}
delta_idle_1 = test2_counter - idle_1 ;
delta_idle_2 = test3_counter - idle_2 ;
delta_int_count = test_isr_count - int_count ;
printf("\nIdle Threadd 1 Counter = %d %d %d\nIdle Theadrd 2 Counter = %d %d %d\nInterrupt Counter = %d %d %d",
test2_counter, delta_idle_1, (unsigned int)(test2_counter / c),
test3_counter, delta_idle_2, (unsigned int)(test3_counter / c),
test_isr_count, delta_int_count, (unsigned int)(test_isr_count / c));
printf ("\n\n") ;
idle_1 = test2_counter ;
idle_2 = test3_counter ;
int_count = test_isr_count ;
CRITICAL_END();
//for (i=0; i<100;i++) {
// atomvmInterruptWait () ;
//}
atomTimerDelay (450) ;
//atomvmScheduleIpi (atomvmGetVmId(), (uint32_t) ipi_sr) ;
}
}
void
test_thread (uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
atomTimerDelay (test_interv[parm]) ;
CRITICAL_START();
test_counter[parm]++ ;
CRITICAL_END();
}
}
void
test2_thread (uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
CRITICAL_START();
test2_counter++ ;
CRITICAL_END();
}
}
void test3_thread(uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
CRITICAL_START();
test3_counter++ ;
CRITICAL_END();
}
}
#ifdef UNIT_TESTS
void unit_test_thread(uint32_t parm)
{
unsigned int failures ;
failures = test_start () ;
printf ("test_start %d failures\n", failures) ;
while(1) {
atomTimerDelay (100);
}
}
#endif
void
__atomvmReset ()
{
unsigned int i ;
atomOSInit(&idle_stack[0], IDLE_STACK_BYTE_SIZE, 1) ;
#ifndef UNIT_TESTS
for (i=0; i< TEST_THREADS;i++) {
atomThreadCreate ((ATOM_TCB *)&test_tcb[i], test_prio[i], test_thread, i, &test_stack[i][0], TEST_STACK_BYTE_SIZE, 1);
}
atomThreadCreate ((ATOM_TCB *)&monitor_tcb, 50, monitor_thread, 0, &monitor_stack[0], MONITOR_STACK_BYTE_SIZE, 1);
atomThreadCreate ((ATOM_TCB *)&test2_tcb, 253, test2_thread, 0, &test2_stack[0], TEST_STACK_BYTE_SIZE, 1);
atomThreadCreate ((ATOM_TCB *)&test3_tcb, 253, test3_thread, 0, &test3_stack[0], TEST_STACK_BYTE_SIZE, 1);
#else
atomThreadCreate ((ATOM_TCB *)&test2_tcb, 16, unit_test_thread, 0, &test2_stack[], TEST_STACK_BYTE_SIZE, 1);
#endif
atomOSStart() ;
}
void
__atomvmClose ()
{
}
void
test_isr (void)
{
static int i = 0 ;
test_isr_count++ ;
if (i++==25) {
//Sleep(3) ;
i = 0;
}
}
DWORD WINAPI
isr_thread_proc (LPVOID lpParameter)
{
int i = 0 ;
int x ;
int y = rand() % 100 ;
while (1) {
atomvmCtrlIntRequest (the_atomvm, test_isr) ;
if (i++==y) {
x = rand() % 50 ;
Sleep (x) ;
y = rand() % 100 ;
i = 0 ;
}
}
return 0 ;
}
void
main ()
{
atomvmRun () ;
#ifndef UNIT_TESTS
isr_thread_1 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_2 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_3 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_4 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
ResumeThread (isr_thread_1) ;
ResumeThread (isr_thread_2) ;
ResumeThread (isr_thread_3) ;
ResumeThread (isr_thread_4) ;
#endif
while (1) {
Sleep(1) ;
atomvmCtrlIntRequest (the_atomvm, archTimerTickIrqHandler) ;
}
}

View File

@@ -1,20 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C++ Express 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvc", "msvc.vcxproj", "{77095EB1-4988-4A04-8751-69C63C7C541B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{77095EB1-4988-4A04-8751-69C63C7C541B}.Debug|Win32.ActiveCfg = Debug|Win32
{77095EB1-4988-4A04-8751-69C63C7C541B}.Debug|Win32.Build.0 = Debug|Win32
{77095EB1-4988-4A04-8751-69C63C7C541B}.Release|Win32.ActiveCfg = Release|Win32
{77095EB1-4988-4A04-8751-69C63C7C541B}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -1,102 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{77095EB1-4988-4A04-8751-69C63C7C541B}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>msvc</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(MSBuildProjectDirectory)/../../../kernel;$(MSBuildProjectDirectory)/..;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(MSBuildProjectDirectory)/..;$(MSBuildProjectDirectory)/../../../kernel;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\..\kernel\atom.h" />
<ClInclude Include="..\..\..\kernel\atommutex.h" />
<ClInclude Include="..\..\..\kernel\atomqueue.h" />
<ClInclude Include="..\..\..\kernel\atomsem.h" />
<ClInclude Include="..\..\..\kernel\atomtimer.h" />
<ClInclude Include="..\atomport-tests.h" />
<ClInclude Include="..\atomport.h" />
<ClInclude Include="..\atomuser.h" />
<ClInclude Include="..\atomvm.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\kernel\atomkernel.c" />
<ClCompile Include="..\..\..\kernel\atommutex.c" />
<ClCompile Include="..\..\..\kernel\atomqueue.c" />
<ClCompile Include="..\..\..\kernel\atomsem.c" />
<ClCompile Include="..\..\..\kernel\atomtimer.c" />
<ClCompile Include="..\atomport.c" />
<ClCompile Include="..\atomvm.c" />
<ClCompile Include="main.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="atomthreads">
<UniqueIdentifier>{d05cbb5a-256f-4127-bd5b-c3bd69b3672c}</UniqueIdentifier>
</Filter>
<Filter Include="port">
<UniqueIdentifier>{f30700d8-652d-477c-a4f2-d23e7784de50}</UniqueIdentifier>
</Filter>
<Filter Include="atomvm">
<UniqueIdentifier>{a4f641bc-296d-4546-a831-2e1d0d7e9242}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\kernel\atom.h">
<Filter>atomthreads</Filter>
</ClInclude>
<ClInclude Include="..\..\..\kernel\atommutex.h">
<Filter>atomthreads</Filter>
</ClInclude>
<ClInclude Include="..\..\..\kernel\atomqueue.h">
<Filter>atomthreads</Filter>
</ClInclude>
<ClInclude Include="..\..\..\kernel\atomsem.h">
<Filter>atomthreads</Filter>
</ClInclude>
<ClInclude Include="..\..\..\kernel\atomtimer.h">
<Filter>atomthreads</Filter>
</ClInclude>
<ClInclude Include="..\atomport.h">
<Filter>port</Filter>
</ClInclude>
<ClInclude Include="..\atomport-tests.h">
<Filter>port</Filter>
</ClInclude>
<ClInclude Include="..\atomuser.h">
<Filter>port</Filter>
</ClInclude>
<ClInclude Include="..\atomvm.h">
<Filter>atomvm</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\kernel\atomkernel.c">
<Filter>atomthreads</Filter>
</ClCompile>
<ClCompile Include="..\..\..\kernel\atommutex.c">
<Filter>atomthreads</Filter>
</ClCompile>
<ClCompile Include="..\..\..\kernel\atomqueue.c">
<Filter>atomthreads</Filter>
</ClCompile>
<ClCompile Include="..\..\..\kernel\atomsem.c">
<Filter>atomthreads</Filter>
</ClCompile>
<ClCompile Include="..\..\..\kernel\atomtimer.c">
<Filter>atomthreads</Filter>
</ClCompile>
<ClCompile Include="..\atomport.c">
<Filter>port</Filter>
</ClCompile>
<ClCompile Include="main.c" />
<ClCompile Include="..\atomvm.c">
<Filter>atomvm</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -1,270 +0,0 @@
#include <stdio.h>
#include <windows.h>
#include "atom.h"
#include "atomvm.h"
#include "atomport.h"
// #define UNIT_TESTS
#ifdef UNIT_TESTS
extern uint32_t test_start (void) ;
#endif
#define TEST_THREADS 47
#define TEST_STACK_BYTE_SIZE 0x10000
#define IDLE_STACK_BYTE_SIZE 0x10000
#define MONITOR_STACK_BYTE_SIZE 0x10000
static unsigned char idle_stack[IDLE_STACK_BYTE_SIZE] ;
static unsigned char monitor_stack[MONITOR_STACK_BYTE_SIZE] ;
static unsigned char test_stack[TEST_THREADS+1][TEST_STACK_BYTE_SIZE] ;
static unsigned int test_counter[TEST_THREADS+1] = {0} ;
static unsigned int test2_counter = 0 ;
static unsigned int test3_counter = 0 ;
static unsigned int test_isr_count = 0 ;
static unsigned char test2_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char test3_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char test_idle_stack[TEST_STACK_BYTE_SIZE] ;
static uint8_t test_prio[60] = {
001,010,100,200,250, 200,200,200,200,200,
150,150,150,150,150, 250,250,250,250,250,
101,102,103,104,105, 202,204,206,208,210,
150,150,150,150,150, 250,250,250,250,250,
121,122,123,124,125, 061,063,065,067,061,
150,150,150,150,150, 250,250,250,250,250
};
static uint32_t test_interv[60] = {
001,001,001,001,001, 002,003,004,005,006,
015,015,015,015,015, 025,024,023,022,021,
905,005,005,005,805, 050,051,052,053,054,
015,015,015,015,015, 025,024,023,022,021,
030,030,030,030,030, 070,071,072,073,474,
005,006,007,007,001, 001,001,003,003,005
};
ATOM_TCB test_tcb[TEST_THREADS+1] ;
ATOM_TCB monitor_tcb ;
ATOM_TCB test2_tcb ;
ATOM_TCB test3_tcb ;
ATOM_TCB test_idle_tcb ;
DWORD WINAPI isr_thread_proc (LPVOID lpParameter) ;
static HANDLE isr_thread_1 ;
static HANDLE isr_thread_2 ;
static HANDLE isr_thread_3 ;
static HANDLE isr_thread_4 ;
void
ipi_sr()
{
printf("ipi\r\n") ;
}
void
monitor_thread (uint32_t parm)
{
CRITICAL_STORE;
int i ;
int c = 0 ;
ATOM_TCB *tcb ;
static unsigned int idle_1 = 0, idle_2 = 0, int_count = 0 ;
unsigned int delta_idle_1 , delta_idle_2 , delta_int_count ;
tcb = atomCurrentContext() ;
for (;;)
{
CRITICAL_START();
printf("Monitor # %04d (%08d)\n", c++, atomTimeGet()) ;
printf("-------------------------\n") ;
for (i=0; i<TEST_THREADS/3; i++) {
printf("Thr %.2d cnt %08d\t",i,test_counter[i]);
printf("Thr %.2d cnt %08d\t",i+TEST_THREADS/3,test_counter[i+TEST_THREADS/3]);
printf("Thr %.2d cnt %08d\n",i+TEST_THREADS*2/3,test_counter[i+TEST_THREADS*2/3]);
}
delta_idle_1 = test2_counter - idle_1 ;
delta_idle_2 = test3_counter - idle_2 ;
delta_int_count = test_isr_count - int_count ;
printf("\nIdle Threadd 1 Counter = %d %d %d\nIdle Theadrd 2 Counter = %d %d %d\nInterrupt Counter = %d %d %d",
test2_counter, delta_idle_1, (unsigned int)(test2_counter / c),
test3_counter, delta_idle_2, (unsigned int)(test3_counter / c),
test_isr_count, delta_int_count, (unsigned int)(test_isr_count / c));
printf ("\n\n") ;
idle_1 = test2_counter ;
idle_2 = test3_counter ;
int_count = test_isr_count ;
CRITICAL_END();
//for (i=0; i<100;i++) {
// atomvmInterruptWait () ;
//}
atomTimerDelay (150) ;
//atomvmScheduleIpi (atomvmGetVmId(), (uint32_t) ipi_sr) ;
}
}
void
test_thread (uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
atomTimerDelay (test_interv[parm]) ;
CRITICAL_START();
test_counter[parm]++ ;
CRITICAL_END();
}
}
void
test2_thread (uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
CRITICAL_START();
test2_counter++ ;
CRITICAL_END();
}
}
void test3_thread(uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
CRITICAL_START();
test3_counter++ ;
CRITICAL_END();
}
}
#ifdef UNIT_TESTS
void unit_test_thread(uint32_t parm)
{
unsigned int failures ;
failures = test_start () ;
printf ("test_start %d failures\n", failures) ;
while(1) {
atomTimerDelay (100);
}
}
#endif
void
__atomvmReset ()
{
unsigned int i ;
atomOSInit(&idle_stack[IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)], IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)) ;
#ifndef UNIT_TESTS
for (i=0; i< TEST_THREADS;i++) {
atomThreadCreate ((ATOM_TCB *)&test_tcb[i], test_prio[i], test_thread, i, &test_stack[i][TEST_STACK_BYTE_SIZE - sizeof(unsigned int)], TEST_STACK_BYTE_SIZE - sizeof(unsigned int));
}
atomThreadCreate ((ATOM_TCB *)&monitor_tcb, 50, monitor_thread, 0, &monitor_stack[(MONITOR_STACK_BYTE_SIZE) - sizeof(unsigned int)], MONITOR_STACK_BYTE_SIZE - sizeof(unsigned int));
atomThreadCreate ((ATOM_TCB *)&test2_tcb, 253, test2_thread, 0, &test2_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], (TEST_STACK_BYTE_SIZE) - sizeof(unsigned int));
atomThreadCreate ((ATOM_TCB *)&test3_tcb, 253, test3_thread, 0, &test3_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], (TEST_STACK_BYTE_SIZE) - sizeof(unsigned int));
#else
atomThreadCreate ((ATOM_TCB *)&test2_tcb, 16, unit_test_thread, 0, &test2_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], (TEST_STACK_BYTE_SIZE) - sizeof(unsigned int));
#endif
atomOSStart() ;
}
void
__atomvmClose ()
{
}
void
test_isr ()
{
static int i = 0 ;
test_isr_count++ ;
if (i++==25) {
//Sleep(3) ;
i = 0;
}
}
DWORD WINAPI
isr_thread_proc (LPVOID lpParameter)
{
int i = 0 ;
int x ;
int y = rand() % 100 ;
while (1) {
atomvmCtrlIntRequest (the_atomvm, (uintptr_t)test_isr) ;
if (i++==y) {
x = rand() % 50 ;
Sleep (x) ;
y = rand() % 100 ;
i = 0 ;
}
}
return 0 ;
}
void
main ()
{
atomvmRun () ;
#ifndef UNIT_TESTS
isr_thread_1 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_2 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_3 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_4 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
ResumeThread (isr_thread_1) ;
ResumeThread (isr_thread_2) ;
ResumeThread (isr_thread_3) ;
ResumeThread (isr_thread_4) ;
#endif
while (1) {
Sleep(1) ;
atomvmCtrlIntRequest (the_atomvm, (uintptr_t)archTimerTickIrqHandler) ;
}
}

View File

@@ -1,61 +0,0 @@
/*
* 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.
*/
#ifndef __ATOM_USER_H__
#define __ATOM_USER_H__
/* Portable uint8_t and friends not available from stdint.h on this platform */
#include <windows.h>
#define SYSTEM_MEMALIGN sizeof (unsigned int)
typedef unsigned int uintptr_t ;
typedef int intptr_t ;
typedef unsigned int uint32_t ;
typedef unsigned short uint16_t ;
typedef unsigned char uint8_t ;
typedef int int32_t ;
typedef short int16_t ;
typedef char int8_t ;
/**
* Architecture-specific types.
* Most of these are available from stdint.h on this platform, which is
* included above.
*/
#define POINTER void *
#define ATOM_TLS HATOMVM_CONTEXT context ;
#endif /* __ATOM_USER_H__ */

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

@@ -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

@@ -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

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
* 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
@@ -26,21 +26,12 @@
* 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 Stellaris LM3S6965 Microcontroller
*/
#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
#include "LPC17xx.h"
#include "drivers/lpc17xx_uart.h"
/* Function prototypes */
extern int low_level_init (void) ;
extern void dbg_format_msg (char *format, ...) ;
extern void dbg_fault_handler (unsigned int * hardfault_args) ;
#endif /* __MODULES_H__ */
#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

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
* 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
@@ -27,24 +27,21 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOMPORT_TEST_H__
#define __ATOMPORT_TEST_H__
#ifndef __ATOM_PORT_TESTS_H
#define __ATOM_PORT_TESTS_H
/* Include Atomthreads kernel API */
#include <stdio.h>
#include "atom.h"
extern void dbg_format_msg (char *format, ...) ;
/* 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 TEST_THREAD_STACK_SIZE 1024
#define ATOMLOG dbg_format_msg
#define _STR(x) x
#define ATOMLOG printf
#define _STR
#endif /* __ATOM_PORT_TESTS_H */
/* API for starting each test */
extern uint32_t test_start (void);
#endif /* __ATOMPORT_TEST_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

@@ -1,57 +1,100 @@
/*
* 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.
*/
#ifndef __ATOMPORT_TEST_H__
#define __ATOMPORT_TEST_H__
/* Include Atomthreads kernel API */
#include "atom.h"
/* Prerequisite include for ATOMLOG() macro (via printf) */
#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) */
#define TEST_THREAD_STACK_SIZE 0x4000
/* Uncomment to enable logging of stack usage to UART */
/* #define TESTS_LOG_STACK_USAGE */
#endif /* __ATOMPORT_TEST_H__ */
/*
* 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

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
* 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
@@ -26,63 +26,68 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "modules.h"
#include "atom.h"
#include "tests/atomtests.h"
#ifndef ATOMTHREADS_TEST
#define ATOMTHREADS_TEST "kern1"
#endif
#define TEST_STACK_BYTE_SIZE 1024
#define IDLE_STACK_BYTE_SIZE 512
static unsigned char test_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char idle_stack[IDLE_STACK_BYTE_SIZE] ;
ATOM_TCB test_tcb ;
#include <errno.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/lm4f/uart.h>
/**
* \b test_thread
*
* Function calling the test function of the Atomthreads test suite.
* _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
*/
void
test_thread (uint32_t param)
int _read(int fd, void *buf, size_t count)
{
uint32_t failures ;
CRITICAL_STORE ;
int rcvd;
char *ptr;
failures = test_start () ;
if(fd <= 2){
ptr = (char *) buf;
rcvd = 0;
atomTimerDelay (10) ;
CRITICAL_START() ;
printf ("%s %s\r\n", ATOMTHREADS_TEST, failures ? "FAIL" : "PASS") ;
exit (failures) ;
CRITICAL_END() ;
while(count > 0){
*ptr = uart_recv_blocking(STD_CON);
if(*ptr == '\r'){
*ptr = '\n';
}
++rcvd;
--count;
}
}else{
rcvd = -1;
errno = EIO;
}
return rcvd;
}
/**
* \b main
*
* Initialize atomthreads and start a test_thread to run the Atomthreads test suite.
*
*/
int
main (void)
int _write(int fd, const void *buf, size_t count)
{
int i = 0 ;
int sent;
char *ptr;
uint32_t failures ;
printf ("Atomthreads starting %s... \r\n", ATOMTHREADS_TEST) ;
if(fd <= 2){
sent = count;
ptr = (char *) buf;
atomOSInit(&idle_stack[0], IDLE_STACK_BYTE_SIZE, TRUE) ;
atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0, &test_stack[0], TEST_STACK_BYTE_SIZE, TRUE);
atomOSStart() ;
while(count > 0){
if(*ptr == '\n'){
uart_send_blocking(STD_CON, '\r');
}
uart_send_blocking(STD_CON, *ptr++);
return 0 ;
++sent;
--count;
}
}else{
errno = EIO;
sent = -1;
}
return sent;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
* 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
@@ -27,55 +27,66 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_PORT_H__
#define __ATOM_PORT_H__
#include <errno.h>
#include "types.h"
#define SYSTEM_TICKS_PER_SEC 100
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/stm32/usart.h>
/**
* Definition of NULL.
* If stddef.h is available on the platform it is simplest to include it
* from this header, otherwise define below.
*/
#ifndef NULL
#define NULL ((void *)(0))
#endif
/* Size of each stack entry / stack alignment size (e.g. 32 bits) */
#define STACK_ALIGN_SIZE sizeof(unsigned int)
/**
* Architecture-specific types.
* Most of these are available from types.h on this platform, which is
* included above.
*/
/**
* Architecture-specific types.
* Most of these are available from types.h on this platform, which is
* included above.
*/
#ifndef POINTER
#define POINTER void *
#endif
/* *
*
* Functions defined in atomport_arm.asm
* _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
*/
extern void contextInit (void) ;
extern uint32_t contextEnterCritical (void) ;
extern void contextExitCritical (uint32_t posture) ;
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;
}
/* Critical region protection */
#define CRITICAL_STORE uint32_t __atom_critical
#define CRITICAL_START() __atom_critical = contextEnterCritical()
#define CRITICAL_END() contextExitCritical(__atom_critical)
return rcvd;
}
#endif /* __ATOM_PORT_H__ */
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);
}
}

View File

@@ -1,19 +0,0 @@
ATOMTHREADS_PORT = $(ATOMTHREADS)/ports/cortex_m
ATOMTHREADS_KERNEL = $(ATOMTHREADS)/kernel
INCLUDES := $(INCLUDES) \
-I$(ATOMTHREADS_KERNEL) \
-I$(ATOMTHREADS_PORT)
SRCS := $(SRCS) \
$(ATOMTHREADS_KERNEL)/atomkernel.c \
$(ATOMTHREADS_KERNEL)/atommutex.c \
$(ATOMTHREADS_KERNEL)/atomqueue.c \
$(ATOMTHREADS_KERNEL)/atomsem.c \
$(ATOMTHREADS_KERNEL)/atomtimer.c \
$(ATOMTHREADS_PORT)/atomport.c
ASMS := $(ASMS) \
$(ATOMTHREADS_PORT)/atomport_s.S

Some files were not shown because too many files have changed in this diff Show More