[Tinyos-devel] TinyOS on Cortex M3?
Paul Kimelman
paul at nikoosha.com
Thu Mar 13 09:32:55 PDT 2008
To do justice to a port, it should be done taking advantage of the many
specialized capabilities of Cortex-M3. It is important to note that CM3 is very
much an interrupt-driven processor. The interrupt controller is integrated in,
and provides 8 levels (minimum) priorities for all ISRs, including all processor
faults (bus fault (both I and D), invalid instruction, divide-by-0, etc). It
takes a max 12 cycles from pre-emption to 1st instruction of actual code (the HW
pushes the scratch registers for you, so this is entry to a normal C function)
and is designed to have a max of 2 cycles latency, even for load/store multiple
(but some chips like the STM32 have multiple cycle stalls on memory/peripheals,
so the worst case single stall must be considered).
It has multiple features to avoid use of interrupt-disable (critical sections).
More importantly, it provides integrated sleep and integrated tasking models.
The integrated sleep allows for both SLEEP and DEEPSLEEP as builtin concepts to
the processor (DEEPSLEEP is presumed to take more cycles to awaken in exchange
for using less power, but it is up to the system design to determine what it
does). SLEEP/DEEPSLEEP can be activated from use of an instruction (WFI
normally) or by return from last exception (if selected). Return from last
exception means that if no task is ready to run, you can skip idling code and
the HW will just sleep (with faster wakeup on next interrupt). There is a
built-in timer (SYSTICK) which ensures the OS port works the same on all CM3
chips. The tasking model is normally supported by PendSV. PendSV is a bit in the
interrupt controller. It allows an ISR to set that bit so that upon return from
all active interrupts, the task scheduler will be woken. By making the task
scheduler (PendSV) the lowest priority interrupt, it then runs only when there
is something to do. Note that PendSV is reentrant safe and also atomicity safe.
So, if about to return from PendSV (nothing to do) and an interrupt comes in and
the ISR sets PendSV again, PendSV ISR will exit and re-enter immediately (even
faster than 12 cycles, basically jumps back to itself).
Critical sections can be avoided in three ways: BASEPRI, exclusives, bit-band.
BASEPRI allows masking all interrupts of a specified priority and below (0 is
highest, so BASEPRI=5 masks 5, 6, and 7). For example, if the top 4 priority
interrupts (0-3) do not use memory objects, then the critical section on memory
object manipulation would mask off only the next 4 priorities by writing a 4. To
make BASEPRI even easier, a register called BASEPRI_MAX is written to - this
only raises the priority mask and does not lower. So, you do not have to use "if
(critsect_pri < BASEPRI) BASEPRI = critsect_pri;". Instead, you just set
BASEPRI_MAX and it will only set if a lower number (you restore by writing the
saved value to BASEPRI). Additionally, you can avoid use of critical sections
using Exclusives. This is LDREX and STREX. This makes it possible to read a
value from memory (byte, half, word, or bit), modify it, and then write it back;
if another task or an ISR has written it between the load and store, the store
will not happen and you will be told that via a register. So, you use a
spin-lock model with no extra test-and-set location. Exclusives can be used for
FIFOs (e.g. from ISR to tasks or tasks to ISRs) as non-locking and non-blocking
models, as well as for many other shared resources. Finally the bit-band can be
used. Bit-band maps 1MB of SRAM and 1MB of peripheral into 32MB of addressable
bits (each). So, for each word in the SRAM, you have 32 words in the bit-band
space; these each access 1 bit of the word (you can also access by byte or half,
but since a 32-bit register model, access by word is convenient). The bit band
not only allows for memory savings (when you use boolean data), but can be used
for critical data as well. Writes to the bit-band area are atomic in HW
(implicit RMW of word cannot be split by an ISR). So, bits can be used for
population and claim bits as well as requests. For example, ISRs can not only
set PendSV, but also set tasks-to-wake via bit band. Then, the PendSV handler
can read by word (or DWORD) to see if any tasks are waiting to be woken (or have
work to do). To find the 1st task to run, you can use the CLZ instruction; this
is count-leading-zeros. So, it will return the MSb which is 1. If you need the
LSb, you use RBIT and then CLZ.
Hope this helps.
Regards, Paul
John Regehr wrote:
> I'm just curious-- has anyone looked into porting TinyOS to Cortex M3
> chips? These represent ARM's attempt to woo developers away from 8 and
> 16 bit MCUs. Based on a quick look, the STM32 product line from ST has
> power numbers roughly in the ballpark for a mote-class device.
>
> http://www.st.com/mcu/inchtml.php?fdir=pages&fnam=stm32
> http://www.st.com/mcu/files/mcu/1190813173.pdf
>
> John Regehr
> _______________________________________________
> Tinyos-devel mailing list
> Tinyos-devel at millennium.berkeley.edu
> https://www.millennium.berkeley.edu/cgi-bin/mailman/listinfo/tinyos-devel
>
--
Paul Kimelman Personal email
Home: 925.256.4048 Mobile: 510.882.6495
More information about the Tinyos-devel
mailing list