|
//========================= Copyright (c) 2016 Tony Philipsson ======================= |
|
// main.c - tiny msp430 preemptive multitasking system |
|
// |
|
// See: |
|
// http://forum.43oh.com/topic/9450-tiny-msp430-preemptive-multitasking-system/?p=71458 |
|
// |
|
// Changes: |
|
// 2016/03/18 Rick Kimball port to msp430-gcc MSP430G2553 and MSP430FR5969 |
|
// 2016/03/20 Rick Kimball version specific for FR5969 using FRAM as stack |
|
// |
|
|
|
#include <stdint.h> |
|
#include "common.h" |
|
|
|
#define SAVED_STACK_WORDS 11 |
|
#define MIN_STACK_WORDS (SAVED_STACK_WORDS+1+1) |
|
#define tasks (sizeof(taskpnt)/sizeof(taskpnt[0])) |
|
|
|
static taskptr const taskpnt[] = { |
|
task1, task2, task3, task4 |
|
}; |
|
|
|
|
|
#define STACK_WORD_SIZE (1024+128+256+64) |
|
static const unsigned stacksize[tasks] = { |
|
1024, 128, 256, 64 |
|
}; |
|
|
|
static unsigned taskstackpnt[tasks]; |
|
|
|
unsigned *alt_stack_space; |
|
volatile systick_t systick; |
|
register unsigned *taskrun asm(FIXED_REG); |
|
|
|
//========================================================================= |
|
|
|
void main( void ) |
|
{ |
|
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer |
|
|
|
PM5CTL0 &= ~LOCKLPM5; // Unlock Pin Registers |
|
CSCTL0_H = CSKEY >> 8; // Unlock CS registers |
|
CSCTL1 = DCOFSEL_6; // Set DCO to 8MHz |
|
CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK; // SMCLK/MCLK DCO and VLO |
|
CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; // Set all dividers to 1 |
|
CSCTL0_H = 0; // Lock CS registers |
|
|
|
P3DIR |= BIT0; P3OUT &= ~BIT0; |
|
|
|
taskrun = taskstackpnt; |
|
alt_stack_space = (unsigned *) 0xff00-(STACK_WORD_SIZE); |
|
|
|
register unsigned *multistack = &alt_stack_space[STACK_WORD_SIZE]; |
|
register unsigned *p = multistack; |
|
register unsigned i=0; |
|
|
|
while( i < tasks-1 ) { |
|
multistack -= stacksize[i]; // adjust stack to accomodate n stack words |
|
*(multistack) = (unsigned)taskpnt[++i]; // prefill in PC |
|
*(multistack-1) = GIE; // prefill in SR |
|
taskstackpnt[i] = (unsigned) |
|
(multistack-((MIN_STACK_WORDS)-1)); // point at dummy stack words |
|
} |
|
|
|
//WDTCTL = WDT_MDLY_32; // 4ms tick using MCLK |
|
//WDTCTL = WDT_MDLY_8;; // 1ms tick using MCLK |
|
WDTCTL = WDT_MDLY_0_5; // 1/16ms tick using MCLK |
|
|
|
SFRIE1 |= WDTIE; |
|
|
|
#if 1 |
|
__enable_interrupt(); |
|
#else |
|
__asm__ volatile (" eint\n nop\n"); |
|
#endif |
|
|
|
__asm__ volatile ( |
|
" mov %1, r1\n" // set stack pointer to fram |
|
" br 0(%0)\n" // indirect jmp to first task |
|
:: |
|
"r" (taskpnt) |
|
,"r" (p) |
|
); |
|
} |
|
|
|
//============= TASK SWITCHER ISR ============= |
|
|
|
__attribute__((interrupt(WDT_VECTOR), naked, used)) |
|
void taskswitcher(void); |
|
|
|
void taskswitcher(void) |
|
{ |
|
__asm__ volatile ("xor.b #1,%0" :: "m" (P3OUT) ); // measure overhead |
|
|
|
// push r15-r5 |
|
__asm__ volatile ("pushm %0, r15" :: "i" (SAVED_STACK_WORDS)); |
|
|
|
#if 0 |
|
++systick; |
|
#else |
|
__asm__ volatile (" inc %A0\n" :: "m" (systick)); |
|
__asm__ volatile (" adc %B0\n" :: "m" (systick)); |
|
#endif |
|
|
|
__asm__ volatile ( |
|
" mov r1, 0(%2)\n" |
|
" incd %2\n" |
|
" cmp %0, %2\n" |
|
" jnz 1f\n" |
|
" mov %1, %2\n" |
|
"1:\n" |
|
" mov 0(%2), r1\n" |
|
::"i" (taskstackpnt+tasks) |
|
,"i" (taskstackpnt) |
|
,"r" (taskrun) |
|
); |
|
|
|
// pop r5-r15 |
|
__asm__ volatile ("popm %0, r15" :: "i" (SAVED_STACK_WORDS)); |
|
__asm__ volatile ("xor.b #1,%0" :: "m" (P3OUT) ); |
|
__asm__ volatile ("reti\n"); |
|
} |
|
|