mirror of
https://github.com/kelvinlawson/atomthreads.git
synced 2026-01-11 18:33:16 +01:00
STM8 port: Add RTOS port for IAR EWSTM8 compiler.
* Split assembler routines into -cosmic.s and -iar.s. * Split Cosmic and IAR specific code using __CSMC__ and __IAR_SYSTEMS_ICC__. * Context-switch virtual registers on IAR. * Add detailed description of IAR context-switch scheme. * Add sample IAR project. * Add support for IAR to STM8S peripheral driver modules. * Fix EWSTM8 compiler warnings.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Atomthreads Project. All rights reserved.
|
||||
* Copyright (c) 2010, Atomthreads Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
||||
@@ -24,7 +24,7 @@ BUILD_DIR=build
|
||||
|
||||
# Port/application object files
|
||||
APP_OBJECTS = atomport.o tests-main.o stm8_interrupt_vector.o uart.o
|
||||
APP_ASM_OBJECTS = atomport-asm.o
|
||||
APP_ASM_OBJECTS = atomport-asm-cosmic.o
|
||||
|
||||
# STM8S Peripheral driver object files
|
||||
PERIPH_OBJECTS = stm8s_gpio.o stm8s_tim1.o stm8s_clk.o stm8s_uart2.o
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
;
|
||||
; Copyright (c) 2005, Atomthreads Project. All rights reserved.
|
||||
; Copyright (c) 2010, Atomthreads Project. All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; Modification, are permitted provided that the following conditions
|
||||
@@ -28,6 +28,9 @@
|
||||
;
|
||||
|
||||
|
||||
; Cosmic assembler routines
|
||||
|
||||
|
||||
; Export functions to other modules
|
||||
xdef _archContextSwitch, _archFirstThreadRestore
|
||||
|
||||
@@ -49,7 +52,7 @@ xdef _archContextSwitch, _archFirstThreadRestore
|
||||
; void archContextSwitch (ATOM_TCB *old_tcb_ptr, ATOM_TCB *new_tcb_ptr)
|
||||
_archContextSwitch:
|
||||
|
||||
; Parameter locations:
|
||||
; Parameter locations (Cosmic calling convention):
|
||||
; old_tcb_ptr = X register (word-width)
|
||||
; new_tcb_ptr = stack (word-width)
|
||||
|
||||
391
ports/stm8/atomport-asm-iar.s
Normal file
391
ports/stm8/atomport-asm-iar.s
Normal file
@@ -0,0 +1,391 @@
|
||||
;
|
||||
; Copyright (c) 2010, Atomthreads Project. All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; Modification, are permitted provided that the following conditions
|
||||
; are met:
|
||||
;
|
||||
; 1. Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; 2. Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; 3. No personal names or organizations' names associated with the
|
||||
; Atomthreads project may be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
|
||||
; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
; TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
|
||||
; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
; POSSIBILITY OF SUCH DAMAGE.
|
||||
;
|
||||
|
||||
|
||||
; IAR assembler routines
|
||||
|
||||
|
||||
NAME ATOMPORTASM
|
||||
SECTION .text:code
|
||||
|
||||
; Get definitions for virtual registers used by the compiler
|
||||
#include "vregs.inc"
|
||||
|
||||
|
||||
; \b archContextSwitch
|
||||
;
|
||||
; Architecture-specific context switch routine.
|
||||
;
|
||||
; Note that interrupts are always locked out when this routine is
|
||||
; called. For cooperative switches, the scheduler will have entered
|
||||
; a critical region. For preemptions (called from an ISR), the
|
||||
; ISR will have disabled interrupts on entry.
|
||||
;
|
||||
; @param[in] old_tcb_ptr Pointer to the thread being scheduled out
|
||||
; @param[in] new_tcb_ptr Pointer to the thread being scheduled in
|
||||
;
|
||||
; @return None
|
||||
;
|
||||
; void archContextSwitch (ATOM_TCB *old_tcb_ptr, ATOM_TCB *new_tcb_ptr)
|
||||
PUBLIC archContextSwitch
|
||||
archContextSwitch:
|
||||
|
||||
; Parameter locations (IAR calling convention):
|
||||
; old_tcb_ptr = X register (word-width)
|
||||
; new_tcb_ptr = Y register (word-width)
|
||||
|
||||
; STM8 CPU Registers:
|
||||
;
|
||||
; A, X, Y: Standard working registers
|
||||
; SP: Stack pointer
|
||||
; PC: Program counter
|
||||
; CC: Code condition register
|
||||
;
|
||||
; IAR compiler virtual registers
|
||||
;
|
||||
; ?b0 - ?b7: Scratch registers
|
||||
; ?b8 - ?b15: Preserved registers
|
||||
;
|
||||
; The basic scheme is that some registers will already be saved
|
||||
; onto the stack if the caller wishes them not to be clobbered.
|
||||
; We only need to context-switch additional registers which the
|
||||
; caller does not expect to be modified in a subroutine.
|
||||
;
|
||||
; If this is a cooperative context switch (a thread has called us
|
||||
; to schedule itself out), the IAR compiler will have saved any
|
||||
; of the registers which it does not want us to clobber. For IAR
|
||||
; only virtual registers ?b8 to ?b15 are expected to retain their
|
||||
; value across a function call, hence for cooperative context
|
||||
; switches with this compiler we only need to save ?b8 to ?b15.
|
||||
;
|
||||
; If we were called from an interrupt routine (because a thread
|
||||
; is being preemptively scheduled out), the situation is exactly
|
||||
; the same. Any ISR which calls out to a subroutine will have
|
||||
; similarly saved all registers which it needs us not to clobber,
|
||||
; leaving only ?b8 to ?b15 which must be saved.
|
||||
;
|
||||
; The Cosmic compiler version of this context switch routine
|
||||
; does not require any registers to be saved/restored, whereas
|
||||
; this IAR equivalent reqires that 8 of the virtual registers
|
||||
; are.
|
||||
|
||||
; We also have to do a little more work in here: we need to store
|
||||
; the current stack pointer to the current thread's TCB, and
|
||||
; switch in the new thread by taking the stack pointer from
|
||||
; the new thread's TCB and making that our new stack pointer.
|
||||
|
||||
; (IAR) Compiler will have already saved any scratch registers
|
||||
; (A, X, Y, CC, and ?b0 to ?b7) which it needs before calling here
|
||||
; for cooperative switches. So these will already be on the stack
|
||||
; and do not need to be context-switched. This assumes that
|
||||
; __interrupt funcs (although EWSTM8 docs say they don't save
|
||||
; vregs) do actually save ?b0 to ?b7 if they call out to another
|
||||
; function. Can't verify this with Kickstart edition. If this
|
||||
; assumption is incorrect then we actually need to save all vregs
|
||||
; here, and this would be inefficient if called for a cooperative
|
||||
; switch where we know ?b0 to ?b7 do not need to be saved.
|
||||
PUSH ?b8
|
||||
PUSH ?b9
|
||||
PUSH ?b10
|
||||
PUSH ?b11
|
||||
PUSH ?b12
|
||||
PUSH ?b13
|
||||
PUSH ?b14
|
||||
PUSH ?b15
|
||||
|
||||
; The parameter pointing to the the old TCB (a word-width
|
||||
; pointer) is still untouched in the X register.
|
||||
|
||||
; (IAR) Take a copy of the new_tcb_ptr parameter from Y-reg in
|
||||
; a temporary (?b0) register. We need to use Y briefly for SP
|
||||
; access.
|
||||
ldw ?b0, Y
|
||||
|
||||
; Store current stack pointer as first entry in old_tcb_ptr
|
||||
ldw Y, SP ; Move current stack pointer into Y register
|
||||
ldw (X), Y ; Store current stack pointer at first offset in TCB
|
||||
|
||||
|
||||
; At this point, all of the current thread's context has been saved
|
||||
; so we no longer care about keeping the contents of any registers
|
||||
; except ?b0 which contains our passed new_tcb_ptr parameter (a
|
||||
; pointer to the TCB of the thread which we wish to switch in).
|
||||
;
|
||||
; Our stack frame now contains all registers which need to be
|
||||
; preserved or context-switched. It also contains the return address
|
||||
; which will be either a function called via an ISR (for preemptive
|
||||
; switches) or a function called from thread context (for cooperative
|
||||
; switches).
|
||||
;
|
||||
; In addition, the thread's stack pointer (after context-save) is
|
||||
; stored in the thread's TCB.
|
||||
|
||||
; We are now ready to restore the new thread's context. We switch
|
||||
; our stack pointer to the new thread's stack pointer, and pop its
|
||||
; context off the stack, before returning to the caller (the
|
||||
; original caller when the new thread was last scheduled out).
|
||||
|
||||
; Get the new thread's stack pointer off the TCB (new_tcb_ptr).
|
||||
; We kept a copy of new_tcb_ptr earlier in ?b0, copy it into X.
|
||||
ldw X,?b0
|
||||
|
||||
; Pull the first entry out of new_tcb_ptr (the new thread's
|
||||
; stack pointer) into X register.
|
||||
ldw X,(X)
|
||||
|
||||
; Switch our current stack pointer to that of the new thread.
|
||||
ldw SP,X
|
||||
|
||||
; (IAR) We only save/restore ?b8 to ?b15
|
||||
POP ?b15
|
||||
POP ?b14
|
||||
POP ?b13
|
||||
POP ?b12
|
||||
POP ?b11
|
||||
POP ?b10
|
||||
POP ?b9
|
||||
POP ?b8
|
||||
|
||||
; The return address on the stack will now be the new thread's return
|
||||
; address - i.e. although we just entered this function from a
|
||||
; function called by the old thread, now that we have restored the new
|
||||
; thread's stack, we actually return from this function to wherever
|
||||
; the new thread was when it was previously scheduled out. This could
|
||||
; be either a regular C routine if the new thread previously scheduled
|
||||
; itself out cooperatively, or it could be an ISR if this new thread was
|
||||
; previously preempted (on exiting the ISR, execution will return to
|
||||
; wherever the new thread was originally interrupted).
|
||||
|
||||
; Return to the caller. Note that we always use a regular RET here
|
||||
; because this is a subroutine regardless of whether we were called
|
||||
; during an ISR or by a thread cooperatively switching out. The
|
||||
; difference between RET and IRET on the STM8 architecture is that
|
||||
; RET only pops the return address off the stack, while IRET also
|
||||
; pops from the stack all of the CPU registers saved when the ISR
|
||||
; started, including restoring the interrupt-enable bits from the CC
|
||||
; register.
|
||||
;
|
||||
; It is important that whenever we call this function (whether from
|
||||
; an ISR for preemptive switches or from thread context for
|
||||
; cooperative switches) interrupts are always disabled. This means
|
||||
; that whichever method by which we leave this routine we always
|
||||
; have to reenable interrupts, so we can use the same context-switch
|
||||
; routine for preemptive and cooperative switches.
|
||||
;
|
||||
; The possible call/return paths are as follows:
|
||||
;
|
||||
; Scenario 1 (cooperative -> cooperative):
|
||||
; Thread A: cooperatively switches out
|
||||
; * Thread A relinquishes control / cooperatively switches out
|
||||
; * Interrupts already disabled by kernel for cooperative reschedules
|
||||
; * Partial register context saved by calling function
|
||||
; * Call here at thread context
|
||||
; * Switch to Thread B
|
||||
; Thread B (was previously cooperatively switched out):
|
||||
; * Stack context for Thread B contains its return address
|
||||
; * Return to function which was called at thread context
|
||||
; * Interrupts are reenabled by CRITICAL_END() call in kernel
|
||||
; * Return to Thread B application code
|
||||
;
|
||||
; Scenario 2 (preemptive -> preemptive):
|
||||
; Thread A: preemptively switches out
|
||||
; * ISR occurs
|
||||
; * Interrupts disabled by CPU at ISR entry (assume no nesting allowed)
|
||||
; * Full register context saved by CPU at ISR entry
|
||||
; * Call here at ISR context
|
||||
; * Switch to Thread B
|
||||
; Thread B (was previously preemptively switched out):
|
||||
; * Stack context for Thread B contains its return address
|
||||
; and all context saved by the CPU on ISR entry
|
||||
; * Return to function which was called at ISR context
|
||||
; * Eventually returns to calling ISR which calls IRET
|
||||
; * IRET performs full register context restore
|
||||
; * IRET reenables interrupts
|
||||
; * Return to Thread B application code
|
||||
;
|
||||
; Scenario 3 (cooperative -> preemptive):
|
||||
; Thread A: cooperatively switches out
|
||||
; * Thread A relinquishes control / cooperatively switches out
|
||||
; * Interrupts already disabled by kernel for cooperative reschedules
|
||||
; * Partial register context saved by calling function
|
||||
; * Call here at thread context
|
||||
; * Switch to Thread B
|
||||
; Thread B (was previously preemptively switched out):
|
||||
; * Stack context for Thread B contains its return address
|
||||
; and all context saved by the CPU on ISR entry
|
||||
; * Return to function which was called at ISR context
|
||||
; * Eventually returns to calling ISR which calls IRET
|
||||
; * IRET performs full register context restore
|
||||
; * IRET reenables interrupts
|
||||
; * Return to Thread B application code
|
||||
;
|
||||
; Scenario 4 (preemptive -> cooperative):
|
||||
; Thread A: preemptively switches out
|
||||
; * ISR occurs
|
||||
; * Interrupts disabled by CPU at ISR entry (assume no nesting allowed)
|
||||
; * Full register context saved by CPU at ISR entry
|
||||
; * Call here at ISR context
|
||||
; * Switch to Thread B
|
||||
; Thread B (was previously cooperatively switched out):
|
||||
; * Stack context for Thread B contains its return address
|
||||
; * Return to function which was called at thread context
|
||||
; * Interrupts are reenabled by CRITICAL_END() call in kernel
|
||||
; * Return to Thread B application code
|
||||
;
|
||||
; The above shows that it does not matter whether we are rescheduling
|
||||
; from/to thread context or ISR context. It is perfectly valid to
|
||||
; enter here at ISR context but leave via a thread which previously
|
||||
; cooperatively switched out because:
|
||||
; 1. Although the CPU handles ISRs differently by automatically
|
||||
; stacking all 6 CPU registers, and restoring them on an IRET,
|
||||
; we handle this because we switch the stack pointer to a
|
||||
; different thread's stack. Because the stack pointer is
|
||||
; switched, it does not matter that on entry via ISRs more
|
||||
; registers are saved on the original thread's stack than entries
|
||||
; via non-ISRs. Those extra registers will be restored properly
|
||||
; by an IRET when the thread is eventually scheduled back in
|
||||
; (which could be a long way off). This assumes that the CPU does
|
||||
; not have hidden behaviour that occurs on interrupts, and we can
|
||||
; in fact trick it into leaving via another thread's call stack,
|
||||
; and performing the IRET much later.
|
||||
; 2. Although the CPU handles ISRs differently by setting the CC
|
||||
; register interrupt-enable bits on entry/exit, we handle this
|
||||
; anyway by always assuming interrupts are disabled on entry
|
||||
; and exit regardless of the call path.
|
||||
|
||||
; Return from subroutine
|
||||
ret
|
||||
|
||||
|
||||
; \b archFirstThreadRestore
|
||||
;
|
||||
; Architecture-specific function to restore and start the first thread.
|
||||
; This is called by atomOSStart() when the OS is starting. Its job is to
|
||||
; restore the context for the first thread and start running at its
|
||||
; entry point.
|
||||
;
|
||||
; All new threads have a stack context pre-initialised with suitable
|
||||
; data for being restored by either this function or the normal
|
||||
; function used for scheduling threads in, archContextSwitch(). Only
|
||||
; the first thread run by the system is launched via this function,
|
||||
; after which all other new threads will first be run by
|
||||
; archContextSwitch().
|
||||
;
|
||||
; Typically ports will implement something similar here to the
|
||||
; latter half of archContextSwitch(). In this port the context
|
||||
; switch does not restore many registers, and instead relies on the
|
||||
; fact that returning from any function which called
|
||||
; archContextSwitch() will restore any of the necessary registers.
|
||||
; For new threads which have never been run there is no calling
|
||||
; function which will restore context on return, therefore we
|
||||
; do not restore many register values here. It is not necessary
|
||||
; for the new threads to have initialised values for the scratch
|
||||
; registers A, X and Y or the code condition register CC which
|
||||
; leaves SP and PC. SP is restored because this is always needed to
|
||||
; switch to a new thread's stack context. It is not necessary to
|
||||
; restore PC, because the thread's entry point is in the stack
|
||||
; context (when this function returns using RET the PC is
|
||||
; automatically changed to the thread's entry point because the
|
||||
; entry point is stored in the preinitialised stack).
|
||||
;
|
||||
; When new threads are started interrupts must be enabled, so there
|
||||
; is some scope for enabling interrupts in the CC here. It must be
|
||||
; done for all new threads, however, not just the first thread, so
|
||||
; we use a different system. We instead use a thread shell routine
|
||||
; which all functions run when they are first started, and
|
||||
; interrupts are enabled in there. This allows us to avoid having
|
||||
; to enable interrupts both in here and in the normal context
|
||||
; switch routine (archContextSwitch()). For the normal context
|
||||
; switch routine we would otherwise need to pass in notification of
|
||||
; and implement special handling for the first time a thread is
|
||||
; restored.
|
||||
;
|
||||
; In summary, first threads do not require a set of CPU registers
|
||||
; to be initialised to known values, so we only set SP to the new
|
||||
; thread's stack pointer. PC is restored for free because the RET
|
||||
; call at the end of this function pops the return address off the
|
||||
; stack.
|
||||
;
|
||||
; Note that you can create more than one thread before starting
|
||||
; the OS - only one thread is restored using this function, so
|
||||
; all other threads are actually restored by archContextSwitch().
|
||||
; This is another reminder that the initial context set up by
|
||||
; archThreadContextInit() must look the same whether restored by
|
||||
; archFirstThreadRestore() or archContextSwitch().
|
||||
;
|
||||
; @param[in] new_tcb_ptr Pointer to the thread being scheduled in
|
||||
;
|
||||
; @return None
|
||||
;
|
||||
; void archFirstThreadRestore (ATOM_TCB *new_tcb_ptr)
|
||||
PUBLIC archFirstThreadRestore
|
||||
archFirstThreadRestore:
|
||||
; Parameter locations:
|
||||
; new_tcb_ptr = X register (word-width)
|
||||
|
||||
; As described above, first thread restores in this port do not
|
||||
; expect any initial register context to be pre-initialised in
|
||||
; the thread's stack area. The thread's initial stack need only
|
||||
; contain the thread's initial entry point, and we do not even
|
||||
; "restore" that within this function. We leave the thread's entry
|
||||
; point in the stack, and RET at the end of the function pops it
|
||||
; off and "returns" to the entry point as if we were called from
|
||||
; there.
|
||||
;
|
||||
; The one thing we do need to set in here, though, is the thread's
|
||||
; stack pointer. This is available from the passed thread TCB
|
||||
; structure.
|
||||
|
||||
; Get the new thread's stack pointer off the TCB (new_tcb_ptr).
|
||||
; new_tcb_ptr is stored in the parameter register X. The stack
|
||||
; pointer it conveniently located at the top of the TCB so no
|
||||
; indexing is required to pull it out.
|
||||
ldw X,(X)
|
||||
|
||||
; Switch our current stack pointer to that of the new thread.
|
||||
ldw SP,X
|
||||
|
||||
; (IAR) We only context switch ?b8 to ?b15
|
||||
POP ?b15
|
||||
POP ?b14
|
||||
POP ?b13
|
||||
POP ?b12
|
||||
POP ?b11
|
||||
POP ?b10
|
||||
POP ?b9
|
||||
POP ?b8
|
||||
|
||||
; The "return address" left on the stack now will be the new
|
||||
; thread's entry point. RET will take us there as if we had
|
||||
; actually been there before calling this subroutine, whereas
|
||||
; the return address was actually set up by archThreadContextInit().
|
||||
ret
|
||||
|
||||
|
||||
end
|
||||
@@ -33,7 +33,10 @@
|
||||
|
||||
/* Function prototypes */
|
||||
void archInitSystemTickTimer (void);
|
||||
@far @interrupt void TIM1_SystemTickISR (void);
|
||||
|
||||
#ifdef __CSMC__
|
||||
@far @interrupt void TIM1_SystemTickISR (void);
|
||||
#elif __IAR_SYSTEMS_ICC__
|
||||
__interrupt void TIM1_SystemTickISR (void);
|
||||
#endif
|
||||
|
||||
#endif /* __ATOM_PORT_PRIVATE_H */
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
#define TEST_THREAD_STACK_SIZE 128
|
||||
|
||||
/* Uncomment to enable logging of stack usage to UART */
|
||||
/* #define TESTS_LOG_STACK_USAGE */
|
||||
#define TESTS_LOG_STACK_USAGE
|
||||
|
||||
|
||||
#endif /* __ATOM_PORT_TESTS_H */
|
||||
|
||||
@@ -79,7 +79,11 @@ static void thread_shell (void)
|
||||
* Enable interrupts - these will not be enabled when a thread
|
||||
* is first restored.
|
||||
*/
|
||||
#if defined(__CSMC__)
|
||||
_asm("rim");
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
rim();
|
||||
#endif
|
||||
|
||||
/* Call the thread entry point */
|
||||
if (curr_tcb && curr_tcb->entry_point)
|
||||
@@ -101,19 +105,30 @@ static void thread_shell (void)
|
||||
* and running the thread via archFirstThreadRestore() or
|
||||
* archContextSwitch().
|
||||
*
|
||||
* On this port we take advantage of the fact that when the context
|
||||
* switch routine is called the compiler will automatically stack
|
||||
* all registers which should not be clobbered. This means that the
|
||||
* context switch need only save and restore the stack pointer,
|
||||
* which is stored in the thread's TCB. Because of this, it is not
|
||||
* necessary to prefill a new thread's stack with any register
|
||||
* values here. The only entry we need to make in the stack is the
|
||||
* thread's entry point - this is not exactly restored when the
|
||||
* (COSMIC) On this port we take advantage of the fact that when
|
||||
* the context switch routine is called the compiler will
|
||||
* automatically stack all registers which should not be clobbered.
|
||||
* This means that the context switch need only save and restore the
|
||||
* stack pointer, which is stored in the thread's TCB. Because of
|
||||
* this, it is not necessary to prefill a new thread's stack with any
|
||||
* register values here. The only entry we need to make in the stack
|
||||
* is the thread's entry point - this is not exactly restored when
|
||||
* the thread is context switched in, but rather is popped off the
|
||||
* stack by the context switch routine's RET call. That is used to
|
||||
* direct the program counter to our thread's entry point - we are
|
||||
* faking a return to a caller which never actually existed.
|
||||
*
|
||||
* (IAR) The IAR compiler works around the lack of CPU registers on
|
||||
* STM8 by allocating some space in low SRAM which is used for
|
||||
* "virtual" registers. The compiler uses these like normal CPU
|
||||
* registers, and hence their values must be preserved when
|
||||
* context-switching between threads. Some of these (?b8 to ?b15)
|
||||
* are expected to be preserved by called functions, and hence we
|
||||
* actually need to save/restore those registers (unlike the rest
|
||||
* of the virtual registers and the standard CPU registers). We
|
||||
* therefore must prefill the stack with values for ?b8 to ?b15
|
||||
* here.
|
||||
*
|
||||
* We could pre-initialise the stack so that the RET call goes
|
||||
* directly to the thread entry point, with the thread entry
|
||||
* parameter filled in. On this architecture, however, we use an
|
||||
@@ -172,11 +187,28 @@ void archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_poi
|
||||
*/
|
||||
|
||||
/**
|
||||
* In this port we do not initialise any registers via the initial
|
||||
* stack context at all. All thread context has now been
|
||||
* initialised. All that is left is to save the current stack
|
||||
* pointer to the thread's TCB so that it knows where to start
|
||||
* looking when the thread is started.
|
||||
* (IAR) Set up initial values for ?b8 to ?b15.
|
||||
*/
|
||||
#if defined(__IAR_SYSTEMS_ICC__)
|
||||
*stack_ptr-- = 0; // ?b8
|
||||
*stack_ptr-- = 0; // ?b9
|
||||
*stack_ptr-- = 0; // ?b10
|
||||
*stack_ptr-- = 0; // ?b11
|
||||
*stack_ptr-- = 0; // ?b12
|
||||
*stack_ptr-- = 0; // ?b13
|
||||
*stack_ptr-- = 0; // ?b14
|
||||
*stack_ptr-- = 0; // ?b15
|
||||
#endif
|
||||
|
||||
/**
|
||||
* (COSMIC) We do not initialise any registers via the initial
|
||||
* stack context at all.
|
||||
*/
|
||||
|
||||
/**
|
||||
* All thread context has now been initialised. All that is left
|
||||
* is to save the current stack pointer to the thread's TCB so
|
||||
* that it knows where to start looking when the thread is started.
|
||||
*/
|
||||
tcb_ptr->sp_save_ptr = stack_ptr;
|
||||
|
||||
@@ -192,16 +224,16 @@ void archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_poi
|
||||
*/
|
||||
void archInitSystemTickTimer ( void )
|
||||
{
|
||||
/* Reset TIM1 */
|
||||
/* Reset TIM1 */
|
||||
TIM1_DeInit();
|
||||
|
||||
/* Configure a 10ms tick */
|
||||
|
||||
/* Configure a 10ms tick */
|
||||
TIM1_TimeBaseInit(10000, TIM1_COUNTERMODE_UP, 1, 0);
|
||||
|
||||
/* Generate an interrupt on timer count overflow */
|
||||
|
||||
/* Generate an interrupt on timer count overflow */
|
||||
TIM1_ITConfig(TIM1_IT_UPDATE, ENABLE);
|
||||
|
||||
/* Enable TIM1 */
|
||||
|
||||
/* Enable TIM1 */
|
||||
TIM1_Cmd(ENABLE);
|
||||
|
||||
}
|
||||
@@ -243,7 +275,11 @@ void archInitSystemTickTimer ( void )
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void TIM1_SystemTickISR (void)
|
||||
#if defined(__IAR_SYSTEMS_ICC__)
|
||||
#pragma vector = 13
|
||||
__interrupt
|
||||
#endif
|
||||
void TIM1_SystemTickISR (void)
|
||||
{
|
||||
/* Call the interrupt entry routine */
|
||||
atomIntEnter();
|
||||
@@ -252,7 +288,7 @@ void TIM1_SystemTickISR (void)
|
||||
atomTimerTick();
|
||||
|
||||
/* Ack the interrupt (Clear TIM1:SR1 register bit 0) */
|
||||
TIM1->SR1 = (uint8_t)(~(uint8_t)TIM1_IT_UPDATE);
|
||||
TIM1->SR1 = (uint8_t)(~(uint8_t)TIM1_IT_UPDATE);
|
||||
|
||||
/* Call the interrupt exit routine */
|
||||
atomIntExit(TRUE);
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
|
||||
#include "stm8s_type.h"
|
||||
|
||||
#if defined(__IAR_SYSTEMS_ICC__)
|
||||
#include "intrinsics.h"
|
||||
#endif
|
||||
|
||||
|
||||
/* Required number of system ticks per second (normally 100 for 10ms tick) */
|
||||
#define SYSTEM_TICKS_PER_SEC 100
|
||||
@@ -51,10 +55,19 @@
|
||||
|
||||
|
||||
/* Critical region protection */
|
||||
|
||||
/* COSMIC: Use inline assembler */
|
||||
#if defined(__CSMC__)
|
||||
#define CRITICAL_STORE uint8_t ccr
|
||||
#define CRITICAL_START() _asm ("push CC\npop a\nld (X),A\nsim", &ccr)
|
||||
#define CRITICAL_END() _asm ("ld A,(X)\npush A\npop CC", &ccr)
|
||||
|
||||
/* IAR: Use intrinsics */
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
#define CRITICAL_STORE __istate_t _istate
|
||||
#define CRITICAL_START() _istate = __get_interrupt_state(); __disable_interrupt()
|
||||
#define CRITICAL_END() __set_interrupt_state(_istate)
|
||||
#endif
|
||||
|
||||
/* Uncomment to enable stack-checking */
|
||||
/* #define ATOM_STACK_CHECKING */
|
||||
|
||||
1917
ports/stm8/atomthreads-sample-iar.dep
Normal file
1917
ports/stm8/atomthreads-sample-iar.dep
Normal file
File diff suppressed because it is too large
Load Diff
369
ports/stm8/atomthreads-sample-iar.ewd
Normal file
369
ports/stm8/atomthreads-sample-iar.ewd
Normal file
@@ -0,0 +1,369 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
|
||||
<project>
|
||||
<fileVersion>2</fileVersion>
|
||||
<configuration>
|
||||
<name>Debug</name>
|
||||
<toolchain>
|
||||
<name>STM8</name>
|
||||
</toolchain>
|
||||
<debug>1</debug>
|
||||
<settings>
|
||||
<name>C-SPY</name>
|
||||
<archiveVersion>1</archiveVersion>
|
||||
<data>
|
||||
<version>0</version>
|
||||
<wantNonLocal>1</wantNonLocal>
|
||||
<debug>1</debug>
|
||||
<option>
|
||||
<name>CSpyMandatory</name>
|
||||
<state>1</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyInput</name>
|
||||
<state>1</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyRunToEnable</name>
|
||||
<state>1</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyRunToName</name>
|
||||
<state>main</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyMacOverride</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyMacFile</name>
|
||||
<state></state>
|
||||
</option>
|
||||
<option>
|
||||
<name>DynDriver</name>
|
||||
<state>STLINK_STM8</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyDDFOverride</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyDDFFile</name>
|
||||
<state>$TOOLKIT_DIR$\config\ddf\iostm8s105c6.ddf</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyEnableExtraOptions</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyExtraOptions</name>
|
||||
<state></state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyImagesSuppressCheck1</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyImagesPath1</name>
|
||||
<state></state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyImagesSuppressCheck2</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyImagesPath2</name>
|
||||
<state></state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyImagesSuppressCheck3</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyImagesPath3</name>
|
||||
<state></state>
|
||||
</option>
|
||||
</data>
|
||||
</settings>
|
||||
<settings>
|
||||
<name>SIMULATOR_STM8</name>
|
||||
<archiveVersion>1</archiveVersion>
|
||||
<data>
|
||||
<version>0</version>
|
||||
<wantNonLocal>1</wantNonLocal>
|
||||
<debug>1</debug>
|
||||
<option>
|
||||
<name>SimMandatory</name>
|
||||
<state>1</state>
|
||||
</option>
|
||||
</data>
|
||||
</settings>
|
||||
<settings>
|
||||
<name>STICE_STM8</name>
|
||||
<archiveVersion>1</archiveVersion>
|
||||
<data>
|
||||
<version>0</version>
|
||||
<wantNonLocal>1</wantNonLocal>
|
||||
<debug>1</debug>
|
||||
<option>
|
||||
<name>STiceMandatory</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STiceSuppressLoad</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STiceVerifyLoad</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STiceLogFileOver</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STiceLogFile</name>
|
||||
<state>$PROJ_DIR$\cspycomm.log</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STiceUseSwim</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
</data>
|
||||
</settings>
|
||||
<settings>
|
||||
<name>STLINK_STM8</name>
|
||||
<archiveVersion>1</archiveVersion>
|
||||
<data>
|
||||
<version>0</version>
|
||||
<wantNonLocal>1</wantNonLocal>
|
||||
<debug>1</debug>
|
||||
<option>
|
||||
<name>STlinkMandatory</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STlinkSuppressLoad</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STlinkVerifyLoad</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STlinkLogFileOver</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STlinkLogFile</name>
|
||||
<state>$PROJ_DIR$\cspycomm.log</state>
|
||||
</option>
|
||||
</data>
|
||||
</settings>
|
||||
<debuggerPlugins>
|
||||
<plugin>
|
||||
<file>$EW_DIR$\common\plugins\CodeCoverage\CodeCoverage.ENU.ewplugin</file>
|
||||
<loadFlag>1</loadFlag>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<file>$EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin</file>
|
||||
<loadFlag>0</loadFlag>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<file>$EW_DIR$\common\plugins\Profiling\Profiling.ENU.ewplugin</file>
|
||||
<loadFlag>1</loadFlag>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<file>$EW_DIR$\common\plugins\Stack\Stack.ENU.ewplugin</file>
|
||||
<loadFlag>1</loadFlag>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<file>$EW_DIR$\common\plugins\SymList\SymList.ENU.ewplugin</file>
|
||||
<loadFlag>1</loadFlag>
|
||||
</plugin>
|
||||
</debuggerPlugins>
|
||||
</configuration>
|
||||
<configuration>
|
||||
<name>Release</name>
|
||||
<toolchain>
|
||||
<name>STM8</name>
|
||||
</toolchain>
|
||||
<debug>0</debug>
|
||||
<settings>
|
||||
<name>C-SPY</name>
|
||||
<archiveVersion>1</archiveVersion>
|
||||
<data>
|
||||
<version>0</version>
|
||||
<wantNonLocal>1</wantNonLocal>
|
||||
<debug>0</debug>
|
||||
<option>
|
||||
<name>CSpyMandatory</name>
|
||||
<state>1</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyInput</name>
|
||||
<state>1</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyRunToEnable</name>
|
||||
<state>1</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyRunToName</name>
|
||||
<state>main</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyMacOverride</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyMacFile</name>
|
||||
<state></state>
|
||||
</option>
|
||||
<option>
|
||||
<name>DynDriver</name>
|
||||
<state>STLINK_STM8</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyDDFOverride</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyDDFFile</name>
|
||||
<state>$TOOLKIT_DIR$\config\ddf\iostm8s105c6.ddf</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyEnableExtraOptions</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyExtraOptions</name>
|
||||
<state></state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyImagesSuppressCheck1</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyImagesPath1</name>
|
||||
<state></state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyImagesSuppressCheck2</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyImagesPath2</name>
|
||||
<state></state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyImagesSuppressCheck3</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>CSpyImagesPath3</name>
|
||||
<state></state>
|
||||
</option>
|
||||
</data>
|
||||
</settings>
|
||||
<settings>
|
||||
<name>SIMULATOR_STM8</name>
|
||||
<archiveVersion>1</archiveVersion>
|
||||
<data>
|
||||
<version>0</version>
|
||||
<wantNonLocal>1</wantNonLocal>
|
||||
<debug>0</debug>
|
||||
<option>
|
||||
<name>SimMandatory</name>
|
||||
<state>1</state>
|
||||
</option>
|
||||
</data>
|
||||
</settings>
|
||||
<settings>
|
||||
<name>STICE_STM8</name>
|
||||
<archiveVersion>1</archiveVersion>
|
||||
<data>
|
||||
<version>0</version>
|
||||
<wantNonLocal>1</wantNonLocal>
|
||||
<debug>0</debug>
|
||||
<option>
|
||||
<name>STiceMandatory</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STiceSuppressLoad</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STiceVerifyLoad</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STiceLogFileOver</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STiceLogFile</name>
|
||||
<state>$PROJ_DIR$\cspycomm.log</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STiceUseSwim</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
</data>
|
||||
</settings>
|
||||
<settings>
|
||||
<name>STLINK_STM8</name>
|
||||
<archiveVersion>1</archiveVersion>
|
||||
<data>
|
||||
<version>0</version>
|
||||
<wantNonLocal>1</wantNonLocal>
|
||||
<debug>0</debug>
|
||||
<option>
|
||||
<name>STlinkMandatory</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STlinkSuppressLoad</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STlinkVerifyLoad</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STlinkLogFileOver</name>
|
||||
<state>0</state>
|
||||
</option>
|
||||
<option>
|
||||
<name>STlinkLogFile</name>
|
||||
<state>$PROJ_DIR$\cspycomm.log</state>
|
||||
</option>
|
||||
</data>
|
||||
</settings>
|
||||
<debuggerPlugins>
|
||||
<plugin>
|
||||
<file>$EW_DIR$\common\plugins\CodeCoverage\CodeCoverage.ENU.ewplugin</file>
|
||||
<loadFlag>1</loadFlag>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<file>$EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin</file>
|
||||
<loadFlag>0</loadFlag>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<file>$EW_DIR$\common\plugins\Profiling\Profiling.ENU.ewplugin</file>
|
||||
<loadFlag>1</loadFlag>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<file>$EW_DIR$\common\plugins\Stack\Stack.ENU.ewplugin</file>
|
||||
<loadFlag>1</loadFlag>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<file>$EW_DIR$\common\plugins\SymList\SymList.ENU.ewplugin</file>
|
||||
<loadFlag>1</loadFlag>
|
||||
</plugin>
|
||||
</debuggerPlugins>
|
||||
</configuration>
|
||||
</project>
|
||||
|
||||
|
||||
3132
ports/stm8/atomthreads-sample-iar.ewp
Normal file
3132
ports/stm8/atomthreads-sample-iar.ewp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -580,13 +580,13 @@ Next=Root.Port.atomport.c
|
||||
[Root.Port.atomport.c]
|
||||
ElemType=File
|
||||
PathName=atomport.c
|
||||
Next=Root.Port.atomport-asm.s
|
||||
Next=Root.Port.atomport-asm-cosmic.s
|
||||
|
||||
[Root.Port.atomport-asm.s]
|
||||
[Root.Port.atomport-asm-cosmic.s]
|
||||
ElemType=File
|
||||
PathName=atomport-asm.s
|
||||
PathName=atomport-asm-cosmic.s
|
||||
Next=Root.Port.stm8_interrupt_vector.c
|
||||
|
||||
[Root.Port.stm8_interrupt_vector.c]
|
||||
ElemType=File
|
||||
PathName=stm8_interrupt_vector.c
|
||||
PathName=stm8_interrupt_vector.c
|
||||
|
||||
@@ -38,7 +38,7 @@ build\stm8s_uart2.o
|
||||
build\tests-main.o
|
||||
build\atomport.o
|
||||
build\uart.o
|
||||
build\atomport-asm.o
|
||||
build\atomport-asm-cosmic.o
|
||||
# Caller passes in test application object name as param1
|
||||
@1
|
||||
#<END OBJECT_FILES>
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
*/
|
||||
|
||||
|
||||
/* COSMIC: Requires interrupt vector table */
|
||||
#if defined(__CSMC__)
|
||||
|
||||
/* Import Atomthreads system tick ISR prototype */
|
||||
#include "atomport-private.h"
|
||||
|
||||
@@ -58,3 +61,5 @@ struct interrupt_vector const _vectab[] = {
|
||||
{0x82, NonHandledInterrupt}, /* irq28 */
|
||||
{0x82, NonHandledInterrupt}, /* irq29 */
|
||||
};
|
||||
|
||||
#endif /* __CSMC__ */
|
||||
|
||||
@@ -29,10 +29,16 @@
|
||||
/* Check the used compiler */
|
||||
#if defined(__CSMC__)
|
||||
#undef _RAISONANCE_
|
||||
#undef _IAR_SYSTEMS_
|
||||
#define _COSMIC_
|
||||
#elif defined(__RCST7__)
|
||||
#undef _COSMIC_
|
||||
#undef _IAR_SYSTEMS_
|
||||
#define _RAISONANCE_
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
#undef _COSMIC_
|
||||
#undef _RAISONANCE_
|
||||
#define _IAR_SYSTEMS_
|
||||
#else
|
||||
#error "Unsupported Compiler!" /* Compiler defines not found */
|
||||
#endif
|
||||
@@ -42,7 +48,8 @@
|
||||
Tip: To avoid modifying this file each time you need to switch between these
|
||||
devices, you can define the device in your toolchain compiler preprocessor. */
|
||||
#if !defined (STM8S208) && !defined (STM8S207) && !defined (STM8S105) && !defined (STM8S103) && !defined (STM8S903)
|
||||
#define STM8S208
|
||||
# error "STM8S device not specified"
|
||||
/* #define STM8S208 */
|
||||
/* #define STM8S207 */
|
||||
/* #define STM8S105 */
|
||||
/* #define STM8S103 */
|
||||
@@ -67,12 +74,21 @@
|
||||
#define NEAR @near
|
||||
#define TINY @tiny
|
||||
#define __CONST const
|
||||
#else /* __RCST7__ */
|
||||
#endif
|
||||
|
||||
#ifdef _RAISONANCE_
|
||||
#define FAR far
|
||||
#define NEAR data
|
||||
#define TINY page0
|
||||
#define __CONST code
|
||||
#endif /* __CSMC__ */
|
||||
#endif
|
||||
|
||||
#ifdef _IAR_SYSTEMS_
|
||||
#define FAR __far
|
||||
#define NEAR __near
|
||||
#define TINY __tiny
|
||||
#define __CONST const
|
||||
#endif
|
||||
|
||||
#ifdef PointerAttr_Far
|
||||
#define PointerAttr FAR
|
||||
@@ -2495,7 +2511,9 @@ CFG_TypeDef;
|
||||
#define trap() _trap_() /* Trap (soft IT) */
|
||||
#define wfi() _wfi_() /* Wait For Interrupt */
|
||||
#define halt() _halt_() /* Halt */
|
||||
#else /* COSMIC */
|
||||
#endif
|
||||
|
||||
#ifdef _COSMIC_
|
||||
#define enableInterrupts() {_asm("rim\n");} /* enable interrupts */
|
||||
#define disableInterrupts() {_asm("sim\n");} /* disable interrupts */
|
||||
#define rim() {_asm("rim\n");} /* enable interrupts */
|
||||
@@ -2506,6 +2524,18 @@ CFG_TypeDef;
|
||||
#define halt() {_asm("halt\n");} /* Halt */
|
||||
#endif
|
||||
|
||||
#ifdef _IAR_SYSTEMS_
|
||||
#include <intrinsics.h>
|
||||
#define enableInterrupts() __enable_interrupt() /* enable interrupts */
|
||||
#define disableInterrupts() __disable_interrupt() /* disable interrupts */
|
||||
#define rim() __enable_interrupt() /* enable interrupts */
|
||||
#define sim() __disable_interrupt() /* disable interrupts */
|
||||
#define nop() __no_operation() /* No Operation */
|
||||
#define trap() __trap_() /* Trap (soft IT) */
|
||||
#define wfi() __wait_for_interrupt() /* Wait For Interrupt */
|
||||
#define halt() __halt_() /* Halt */
|
||||
#endif
|
||||
|
||||
/*============================== Handling bits ====================================*/
|
||||
/*-----------------------------------------------------------------------------
|
||||
Method : I
|
||||
|
||||
@@ -117,47 +117,6 @@ void GPIO_Init(GPIO_TypeDef* GPIOx,
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes data to the specified GPIO data port.
|
||||
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
|
||||
* @param[in] PortVal : Specifies the value to be written to the port output.
|
||||
* data register.
|
||||
* @retval None
|
||||
* @par Required preconditions:
|
||||
* The port must be configured in output mode.
|
||||
*/
|
||||
void GPIO_Write(GPIO_TypeDef* GPIOx, u8 PortVal)
|
||||
{
|
||||
GPIOx->ODR = PortVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes high level to the specified GPIO pins.
|
||||
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
|
||||
* @param[in] PortPins : Specifies the pins to be turned high to the port output.
|
||||
* data register.
|
||||
* @retval None
|
||||
* @par Required preconditions:
|
||||
* The port must be configured in output mode.
|
||||
*/
|
||||
void GPIO_WriteHigh(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins)
|
||||
{
|
||||
GPIOx->ODR |= (u8)PortPins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes low level to the specified GPIO pins.
|
||||
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
|
||||
* @param[in] PortPins : Specifies the pins to be turned low to the port output.
|
||||
* data register.
|
||||
* @retval None
|
||||
* @par Required preconditions:
|
||||
* The port must be configured in output mode.
|
||||
*/
|
||||
void GPIO_WriteLow(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins)
|
||||
{
|
||||
GPIOx->ODR &= (u8)(~PortPins);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes reverse level to the specified GPIO pins.
|
||||
@@ -173,67 +132,6 @@ void GPIO_WriteReverse(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins)
|
||||
GPIOx->ODR ^= (u8)PortPins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads the specified GPIO output data port.
|
||||
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
|
||||
* @retval u8 : GPIO output data port value.
|
||||
* @par Required preconditions:
|
||||
* The port must be configured in input mode.
|
||||
*/
|
||||
u8 GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)
|
||||
{
|
||||
return ((u8)GPIOx->ODR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads the specified GPIO input data port.
|
||||
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
|
||||
* @retval u8 : GPIO input data port value.
|
||||
* @par Required preconditions:
|
||||
* The port must be configured in input mode.
|
||||
*/
|
||||
u8 GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
|
||||
{
|
||||
return ((u8)GPIOx->IDR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads the specified GPIO input data pin.
|
||||
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
|
||||
* @param[in] GPIO_Pin : This parameter contains the pin number, it can be one member
|
||||
* of the @ref GPIO_Pin_TypeDef enumeration.
|
||||
* @retval BitStatus : GPIO input pin status.
|
||||
* This parameter can be any of the @ref BitStatus enumeration.
|
||||
* @par Required preconditions:
|
||||
* The port must be configured in input mode.
|
||||
*/
|
||||
BitStatus GPIO_ReadInputPin(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin)
|
||||
{
|
||||
return ((BitStatus)(GPIOx->IDR & (vu8)GPIO_Pin));
|
||||
}
|
||||
/**
|
||||
* @brief Configures the external pull-up on GPIOx pins.
|
||||
* @param[in] GPIOx : Select the GPIO peripheral number (x = A to I).
|
||||
* @param[in] GPIO_Pin : This parameter contains the pin number, it can be one or many members
|
||||
* of the @ref GPIO_Pin_TypeDef enumeration.
|
||||
* @param[in] NewState : The new state of the pull up pin.
|
||||
* This parameter can be any of the @ref FunctionalState enumeration.
|
||||
* @retval None
|
||||
*/
|
||||
void GPIO_ExternalPullUpConfig(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, FunctionalState NewState)
|
||||
{
|
||||
/* Check the parameters */
|
||||
assert_param(IS_GPIO_PIN_OK(GPIO_Pin));
|
||||
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
|
||||
|
||||
if (NewState != DISABLE) /* External Pull-Up Set*/
|
||||
{
|
||||
GPIOx->CR1 |= (u8)GPIO_Pin;
|
||||
} else /* External Pull-Up Reset*/
|
||||
{
|
||||
GPIOx->CR1 &= (u8)(~(GPIO_Pin));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
@@ -47,18 +47,18 @@
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GPIO_MODE_IN_FL_NO_IT = (u8)0b00000000, /*!< Input floating, no external interrupt */
|
||||
GPIO_MODE_IN_PU_NO_IT = (u8)0b01000000, /*!< Input pull-up, no external interrupt */
|
||||
GPIO_MODE_IN_FL_IT = (u8)0b00100000, /*!< Input floating, external interrupt */
|
||||
GPIO_MODE_IN_PU_IT = (u8)0b01100000, /*!< Input pull-up, external interrupt */
|
||||
GPIO_MODE_OUT_OD_LOW_FAST = (u8)0b10100000, /*!< Output open-drain, low level, 10MHz */
|
||||
GPIO_MODE_OUT_PP_LOW_FAST = (u8)0b11100000, /*!< Output push-pull, low level, 10MHz */
|
||||
GPIO_MODE_OUT_OD_LOW_SLOW = (u8)0b10000000, /*!< Output open-drain, low level, 2MHz */
|
||||
GPIO_MODE_OUT_PP_LOW_SLOW = (u8)0b11000000, /*!< Output push-pull, low level, 2MHz */
|
||||
GPIO_MODE_OUT_OD_HIZ_FAST = (u8)0b10110000, /*!< Output open-drain, high-impedance level,10MHz */
|
||||
GPIO_MODE_OUT_PP_HIGH_FAST = (u8)0b11110000, /*!< Output push-pull, high level, 10MHz */
|
||||
GPIO_MODE_OUT_OD_HIZ_SLOW = (u8)0b10010000, /*!< Output open-drain, high-impedance level, 2MHz */
|
||||
GPIO_MODE_OUT_PP_HIGH_SLOW = (u8)0b11010000 /*!< Output push-pull, high level, 2MHz */
|
||||
GPIO_MODE_IN_FL_NO_IT = (u8)0x00, // 0b00000000, /*!< Input floating, no external interrupt */
|
||||
GPIO_MODE_IN_PU_NO_IT = (u8)0x40, // 0b01000000, /*!< Input pull-up, no external interrupt */
|
||||
GPIO_MODE_IN_FL_IT = (u8)0x20, // 0b00100000, /*!< Input floating, external interrupt */
|
||||
GPIO_MODE_IN_PU_IT = (u8)0x60, // 0b01100000, /*!< Input pull-up, external interrupt */
|
||||
GPIO_MODE_OUT_OD_LOW_FAST = (u8)0xA0, // 0b10100000, /*!< Output open-drain, low level, 10MHz */
|
||||
GPIO_MODE_OUT_PP_LOW_FAST = (u8)0xE0, // 0b11100000, /*!< Output push-pull, low level, 10MHz */
|
||||
GPIO_MODE_OUT_OD_LOW_SLOW = (u8)0x80, // 0b10000000, /*!< Output open-drain, low level, 2MHz */
|
||||
GPIO_MODE_OUT_PP_LOW_SLOW = (u8)0xC0, // 0b11000000, /*!< Output push-pull, low level, 2MHz */
|
||||
GPIO_MODE_OUT_OD_HIZ_FAST = (u8)0xB0, // 0b10110000, /*!< Output open-drain, high-impedance level,10MHz */
|
||||
GPIO_MODE_OUT_PP_HIGH_FAST = (u8)0xF0, // 0b11110000, /*!< Output push-pull, high level, 10MHz */
|
||||
GPIO_MODE_OUT_OD_HIZ_SLOW = (u8)0x90, // 0b10010000, /*!< Output open-drain, high-impedance level, 2MHz */
|
||||
GPIO_MODE_OUT_PP_HIGH_SLOW = (u8)0xD0 // 0b11010000 /*!< Output push-pull, high level, 2MHz */
|
||||
}GPIO_Mode_TypeDef;
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,9 +45,16 @@ u8 ITC_GetCPUCC(void)
|
||||
_asm("push cc");
|
||||
_asm("pop a");
|
||||
return; /* Ignore compiler warning, the returned value is in A register */
|
||||
#else /* _RAISONANCE_ */
|
||||
#endif
|
||||
|
||||
#ifdef _RAISONANCE_
|
||||
return _getCC_();
|
||||
#endif /* _COSMIC_*/
|
||||
#endif
|
||||
|
||||
#ifdef _IAR_SYSTEMS_
|
||||
__asm("push cc");
|
||||
__asm("pop a");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,6 +31,14 @@
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
/* Public functions ----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* IAR EWSTM8: Ignore unused variable warning on dummy variable.
|
||||
*/
|
||||
#ifdef __IAR_SYSTEMS_ICC__
|
||||
#pragma diag_suppress=Pe550
|
||||
#endif
|
||||
|
||||
|
||||
/** @}
|
||||
* @addtogroup UART2_Public_Functions
|
||||
* @{
|
||||
@@ -149,7 +157,7 @@ void UART2_Init(u32 BaudRate, UART2_WordLength_TypeDef WordLength, UART2_StopBit
|
||||
UART2->CR3 |= (u8)((u8)SyncMode & UART2_CR3_CKEN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns the most recent received data by the UART2 peripheral.
|
||||
@@ -179,7 +187,7 @@ void UART2_SendData8(u8 Data)
|
||||
/* Transmit Data */
|
||||
UART2->DR = Data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks whether the specified UART2 flag is set or not.
|
||||
@@ -253,8 +261,8 @@ FlagStatus UART2_GetFlagStatus(UART2_Flag_TypeDef UART2_FLAG)
|
||||
|
||||
/* Return the UART2_FLAG status*/
|
||||
return status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "atom.h"
|
||||
#include "atomport-private.h"
|
||||
#include "atomport-tests.h"
|
||||
#include "atomtests.h"
|
||||
#include "atomtimer.h"
|
||||
#include "uart.h"
|
||||
@@ -104,10 +105,10 @@ extern int _stack;
|
||||
static ATOM_TCB main_tcb;
|
||||
|
||||
/* Main thread's stack area (large so place outside of the small page0 area on STM8) */
|
||||
@near static uint8_t main_thread_stack[MAIN_STACK_SIZE_BYTES];
|
||||
NEAR static uint8_t main_thread_stack[MAIN_STACK_SIZE_BYTES];
|
||||
|
||||
/* Idle thread's stack area (large so place outside of the small page0 area on STM8) */
|
||||
@near static uint8_t idle_thread_stack[IDLE_STACK_SIZE_BYTES];
|
||||
NEAR static uint8_t idle_thread_stack[IDLE_STACK_SIZE_BYTES];
|
||||
|
||||
|
||||
/* Forward declarations */
|
||||
@@ -162,9 +163,6 @@ void main ( void )
|
||||
}
|
||||
}
|
||||
|
||||
while (1)
|
||||
;
|
||||
|
||||
/* There was an error starting the OS if we reach here */
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,78 +1,138 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "stm8s.h"
|
||||
|
||||
#include "atom.h"
|
||||
#include "atommutex.h"
|
||||
#include "uart.h"
|
||||
|
||||
|
||||
/*
|
||||
* Semaphore for single-threaded access to UART device
|
||||
*/
|
||||
static ATOM_MUTEX uart_mutex;
|
||||
|
||||
|
||||
/*
|
||||
* Initialize the UART to requested baudrate, tx/rx, 8N1.
|
||||
*/
|
||||
int uart_init(uint32_t baudrate)
|
||||
{
|
||||
int status;
|
||||
|
||||
/**
|
||||
* Set up UART2 for putting out debug messages.
|
||||
* This the UART used on STM8S Discovery, change if required.
|
||||
*/
|
||||
UART2_DeInit();
|
||||
UART2_Init (baudrate, UART2_WORDLENGTH_8D, UART2_STOPBITS_1, UART2_PARITY_NO,
|
||||
UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);
|
||||
|
||||
/* Create a mutex for single-threaded putchar() access */
|
||||
if (atomMutexCreate (&uart_mutex) != ATOM_OK)
|
||||
{
|
||||
status = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = 0;
|
||||
}
|
||||
|
||||
/* Finished */
|
||||
return (status);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \b putchar
|
||||
*
|
||||
* Retarget putchar() to use UART2
|
||||
*
|
||||
* @param[in] c Character to send
|
||||
*
|
||||
* @return Character sent
|
||||
*/
|
||||
char putchar (char c)
|
||||
{
|
||||
/* Block on private access to the UART */
|
||||
if (atomMutexGet(&uart_mutex, 0) == ATOM_OK)
|
||||
{
|
||||
/* Convert \n to \r\n */
|
||||
if (c == '\n')
|
||||
putchar('\r');
|
||||
|
||||
/* Write a character to the UART2 */
|
||||
UART2_SendData8(c);
|
||||
|
||||
/* Loop until the end of transmission */
|
||||
while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)
|
||||
;
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "stm8s.h"
|
||||
|
||||
#include "atom.h"
|
||||
#include "atommutex.h"
|
||||
#include "uart.h"
|
||||
|
||||
|
||||
/*
|
||||
* Semaphore for single-threaded access to UART device
|
||||
*/
|
||||
static ATOM_MUTEX uart_mutex;
|
||||
|
||||
|
||||
/*
|
||||
* Initialize the UART to requested baudrate, tx/rx, 8N1.
|
||||
*/
|
||||
int uart_init(uint32_t baudrate)
|
||||
{
|
||||
int status;
|
||||
|
||||
/**
|
||||
* Set up UART2 for putting out debug messages.
|
||||
* This the UART used on STM8S Discovery, change if required.
|
||||
*/
|
||||
UART2_DeInit();
|
||||
UART2_Init (baudrate, UART2_WORDLENGTH_8D, UART2_STOPBITS_1, UART2_PARITY_NO,
|
||||
UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);
|
||||
|
||||
/* Create a mutex for single-threaded putchar() access */
|
||||
if (atomMutexCreate (&uart_mutex) != ATOM_OK)
|
||||
{
|
||||
status = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = 0;
|
||||
}
|
||||
|
||||
/* Finished */
|
||||
return (status);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \b uart_putchar
|
||||
*
|
||||
* Write a char out via UART2
|
||||
*
|
||||
* @param[in] c Character to send
|
||||
*
|
||||
* @return Character sent
|
||||
*/
|
||||
char uart_putchar (char c)
|
||||
{
|
||||
/* Block on private access to the UART */
|
||||
if (atomMutexGet(&uart_mutex, 0) == ATOM_OK)
|
||||
{
|
||||
/* Convert \n to \r\n */
|
||||
if (c == '\n')
|
||||
putchar('\r');
|
||||
|
||||
/* Write a character to the UART2 */
|
||||
UART2_SendData8(c);
|
||||
|
||||
/* Loop until the end of transmission */
|
||||
while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)
|
||||
;
|
||||
|
||||
/* Return mutex access */
|
||||
atomMutexPut(&uart_mutex);
|
||||
|
||||
}
|
||||
|
||||
return (c);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (c);
|
||||
}
|
||||
|
||||
|
||||
/* COSMIC: Requires putchar() routine to override stdio */
|
||||
#if defined(__CSMC__)
|
||||
/**
|
||||
* \b putchar
|
||||
*
|
||||
* Retarget putchar() to use UART2
|
||||
*
|
||||
* @param[in] c Character to send
|
||||
*
|
||||
* @return Character sent
|
||||
*/
|
||||
char putchar (char c)
|
||||
{
|
||||
return (uart_putchar(c));
|
||||
}
|
||||
#endif /* __CSMC__ */
|
||||
|
||||
|
||||
/* IAR: Requires __write() routine to override stdio */
|
||||
#if defined(__IAR_SYSTEMS_ICC__)
|
||||
/**
|
||||
* \b __write
|
||||
*
|
||||
* Override for IAR stream output
|
||||
*
|
||||
* @param[in] handle Stdio handle. -1 to flush.
|
||||
* @param[in] buf Pointer to buffer to be written
|
||||
* @param[in] bufSize Number of characters to be written
|
||||
*
|
||||
* @return Number of characters sent
|
||||
*/
|
||||
size_t __write(int handle, const unsigned char *buf, size_t bufSize)
|
||||
{
|
||||
size_t chars_written = 0;
|
||||
|
||||
/* Ignore flushes */
|
||||
if (handle == -1)
|
||||
{
|
||||
chars_written = (size_t)0;
|
||||
}
|
||||
/* Only allow stdout/stderr output */
|
||||
else if ((handle != 1) && (handle != 2))
|
||||
{
|
||||
chars_written = (size_t)-1;
|
||||
}
|
||||
/* Parameters OK, call the low-level character output routine */
|
||||
else
|
||||
{
|
||||
while (chars_written < bufSize)
|
||||
{
|
||||
uart_putchar (buf[chars_written]);
|
||||
chars_written++;
|
||||
}
|
||||
}
|
||||
|
||||
return (chars_written);
|
||||
}
|
||||
#endif /* __IAR_SYSTEMS_ICC__ */
|
||||
|
||||
@@ -139,7 +139,7 @@ uint32_t test_start (void)
|
||||
/* Check that time has advanced by exactly 1 tick */
|
||||
if ((end_time - start_time) != 1)
|
||||
{
|
||||
ATOMLOG (_STR("Tick1:%d\n"), (end_time-start_time));
|
||||
ATOMLOG (_STR("Tick1:%d\n"), (int)(end_time-start_time));
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
@@ -175,7 +175,7 @@ uint32_t test_start (void)
|
||||
/* Check that time has advanced by exactly 2 ticks */
|
||||
if ((end_time - start_time) != 2)
|
||||
{
|
||||
ATOMLOG (_STR("Tick2:%d\n"), (end_time-start_time));
|
||||
ATOMLOG (_STR("Tick2:%d\n"), (int)(end_time-start_time));
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
@@ -211,7 +211,7 @@ uint32_t test_start (void)
|
||||
/* Check that time has advanced by exactly 500 ticks */
|
||||
if ((end_time - start_time) != 500)
|
||||
{
|
||||
ATOMLOG (_STR("Tick500:%d\n"), (end_time-start_time));
|
||||
ATOMLOG (_STR("Tick500:%d\n"), (int)(end_time-start_time));
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ uint32_t test_start (void)
|
||||
{
|
||||
if (cb_order[i] != i)
|
||||
{
|
||||
ATOMLOG (_STR("T%d=%d\n"), i, cb_order[i]);
|
||||
ATOMLOG (_STR("T%d=%d\n"), i, (int)cb_order[i]);
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user