multitask.c


1
/*
2
  Copyright 2014 Marc Prager
3
4
  Multithreading example.
5
 */
6
7
#include <armv6-m/tl.h>    // context switcher for Cortex-M0
8
9
#include <lpc8/syscon.h>
10
#include <lpc8/swm.h>
11
#include <lpc8/usart.h>
12
#include <lpc8/systickTimer.h>
13
14
#include <print.h>
15
#include <fixedPoint.h>
16
17
enum {
18
  PCLK  = 12*MEGA,
19
  BAUD  = 115200,
20
};
21
22
void handlerDefault(void) {
23
  printString("CRASHED!! - STOP.");
24
  while(true);
25
}
26
27
void sleepMs(TlContext *ctx, int ms) {
28
  int timeoutMs = systickTimerMs + ms;
29
  while (timeoutMs-systickTimerMs > 0) tlYield(ctx);
30
}
31
32
__attribute__((naked)) Uint32 getSp(void) {
33
  asm("mov r0,sp");  // AAPCS: r0 = function return
34
  asm("bx lr");
35
}
36
37
#define TOP_OF_STACK(s) (&s[sizeof s/sizeof s[0]])
38
39
// prototypes: signature enforcement
40
TlLoop
41
  threadA,  // printing 'A' every 500ms
42
  threadB,  // printing 'B<num>' every 2s, num counting up
43
  threadT,  // complex thread, calling 2 child threads every second
44
  threadT1,  // printing 'T1', then yield
45
  threadT2;  // printing 'T2', then yield
46
47
void threadA(TlContext *ctx) {
48
  tlYield(ctx);
49
  while(true) {
50
    printChar('A');
51
    sleepMs(ctx,500);
52
  }
53
}
54
55
void threadB(TlContext *ctx) {
56
  tlYield(ctx);
57
  for (int i=0; ; i++) {
58
    printChar('B'); printUDec32(i); printChar(' ');
59
    sleepMs(ctx,2000);
60
  }
61
}
62
63
64
void threadT(TlContext *ctx) {
65
  Uint32  stackT1[64], stackT2[64];  // complex task, needs more threads
66
  // these stacks reside on the local stack of 'T'
67
68
  TlContext
69
    ctxT1 = { TOP_OF_STACK(stackT1) },
70
    ctxT2 = { TOP_OF_STACK(stackT2) };
71
72
  tlCreate(&ctxT1,threadT1);
73
  tlCreate(&ctxT2,threadT2);
74
75
76
  printString("SP in T="); printHex32(getSp()); printLn();
77
78
  tlYield(ctx);
79
  while (true) {
80
    tlCall(&ctxT1);
81
    tlCall(&ctxT2);
82
    sleepMs(ctx,1000);
83
  }
84
}
85
86
void threadT1(TlContext *ctx) {
87
  while (true) {
88
    tlYield(ctx);
89
    printString("T1");
90
  }
91
}
92
93
void threadT2(TlContext *ctx) {
94
  while (true) {
95
    tlYield(ctx);
96
    printString("T2");
97
  }
98
}
99
100
void runThreads(void);
101
102
void main(void) {
103
  systickTimerInit(PCLK / 100/*Hz*/, 10/*ms*/ );
104
105
  SYSCON
106
  .ahbClkCtrl  |= 1<<_SYSCON_AHBCLKCTRL_SWM
107
      | 1<<_SYSCON_AHBCLKCTRL_USART0
108
      ;
109
110
  swmPin(SWM_FUNCTION_U0_RXD,0);
111
  swmPin(SWM_FUNCTION_U0_TXD,4);
112
113
  usart0InitFrom12Mhz (1);
114
  print (usart0BlockingWriteChar);
115
116
  printString("Running.\n");
117
  printString("SP before="); printHex32(getSp()); printLn();
118
119
  runThreads();
120
121
  printString("\nSP after="); printHex32(getSp()); printLn();
122
123
  // all threads and their stacks gone by at this point...
124
  printString("Terminated.\n");
125
}
126
127
void runThreads(void) {
128
  Uint32  stackA[64];
129
  Uint32  stackB[64];
130
  Uint32  stackT[3*64];
131
132
  TlContext
133
    ctxA = { TOP_OF_STACK(stackA) },
134
    ctxB = { TOP_OF_STACK(stackB) },
135
    ctxT = { TOP_OF_STACK(stackT) };
136
137
  tlCreate(&ctxA,threadA);
138
  tlCreate(&ctxB,threadB);
139
  tlCreate(&ctxT,threadT);
140
141
  printString("SP in scheduler="); printHex32(getSp()); printLn();
142
143
  // Round robin scheduler, 10 seconds lifetime.
144
  for (int tMs=systickTimerMs+10*1000; tMs-systickTimerMs>=0; ) {
145
    tlCall(&ctxA);
146
    tlCall(&ctxB);
147
    tlCall(&ctxT);
148
  }
149
}