1 /* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight
2 threads of different priorities, using a message queue, semaphore, mutex, event flags group,
3 byte pool, and block pool. */
4
5 #include "tx_api.h"
6
7 #define DEMO_STACK_SIZE 4096
8 #define DEMO_BYTE_POOL_SIZE 40000
9 #define DEMO_BLOCK_POOL_SIZE 100
10 #define DEMO_QUEUE_SIZE 100
11
12
13 /* Define MALTA constants for accessing the display. */
14
15 #define MALTA_ASCIIWORD 0xBF000410 /* ASCIIWORD bit 32:0 */
16 #define MALTA_ASCIIPOS0 0xBF000418 /* ASCIIPOS0 bit 7:0 */
17 #define MALTA_ASCIIPOS1 0xBF000420 /* ASCIIPOS1 bit 7:0 */
18 #define MALTA_ASCIIPOS2 0xBF000428 /* ASCIIPOS2 bit 7:0 */
19 #define MALTA_ASCIIPOS3 0xBF000430 /* ASCIIPOS3 bit 7:0 */
20 #define MALTA_ASCIIPOS4 0xBF000438 /* ASCIIPOS4 bit 7:0 */
21 #define MALTA_ASCIIPOS5 0xBF000440 /* ASCIIPOS5 bit 7:0 */
22 #define MALTA_ASCIIPOS6 0xBF000448 /* ASCIIPOS6 bit 7:0 */
23 #define MALTA_ASCIIPOS7 0xBF000450 /* ASCIIPOS7 bit 7:0 */
24
25
26 /* Define the ThreadX object control blocks... */
27
28 TX_THREAD thread_0;
29 TX_THREAD thread_1;
30 TX_THREAD thread_2;
31 TX_THREAD thread_3;
32 TX_THREAD thread_4;
33 TX_THREAD thread_5;
34 TX_THREAD thread_6;
35 TX_THREAD thread_7;
36 TX_THREAD lcd_thread;
37 TX_QUEUE queue_0;
38 TX_SEMAPHORE semaphore_0;
39 TX_MUTEX mutex_0;
40 TX_EVENT_FLAGS_GROUP event_flags_0;
41 TX_BYTE_POOL byte_pool_0;
42 TX_BLOCK_POOL block_pool_0;
43
44
45 /* Define the counters used in the demo application... */
46
47 ULONG thread_0_counter;
48 ULONG thread_1_counter;
49 ULONG thread_1_messages_sent;
50 ULONG thread_2_counter;
51 ULONG thread_2_messages_received;
52 ULONG thread_3_counter;
53 ULONG thread_4_counter;
54 ULONG thread_5_counter;
55 ULONG thread_6_counter;
56 ULONG thread_7_counter;
57 ULONG lcd_counter;
58
59
60 /* Define thread prototypes. */
61
62 void thread_0_entry(ULONG thread_input);
63 void thread_1_entry(ULONG thread_input);
64 void thread_2_entry(ULONG thread_input);
65 void thread_3_and_4_entry(ULONG thread_input);
66 void thread_5_entry(ULONG thread_input);
67 void thread_6_and_7_entry(ULONG thread_input);
68 void lcd_thread_entry(ULONG thread_input);
69
70 #ifdef TX_ENABLE_EVENT_TRACE
71
72 UCHAR event_buffer[64000];
73 #endif
74
75
76 /* Define main entry point. */
77
main()78 int main()
79 {
80
81 /* Indicate ThreadX is being entered. */
82 *((ULONG *) 0xBF000418) = 'T';
83 *((ULONG *) 0xBF000420) = 'X';
84 *((ULONG *) 0xBF000428) = ' ';
85 *((ULONG *) 0xBF000430) = 'E';
86 *((ULONG *) 0xBF000438) = 'N';
87 *((ULONG *) 0xBF000440) = 'T';
88 *((ULONG *) 0xBF000448) = 'E';
89 *((ULONG *) 0xBF000450) = 'R';
90
91 /* Enter the ThreadX kernel. */
92 tx_kernel_enter();
93 }
94
95
96 /* Define what the initial system looks like. */
97
tx_application_define(void * first_unused_memory)98 void tx_application_define(void *first_unused_memory)
99 {
100
101 CHAR *pointer;
102
103
104 #ifdef TX_ENABLE_EVENT_TRACE
105
106 tx_trace_enable(event_buffer, sizeof(event_buffer), 32);
107 #endif
108
109 /* Create a byte memory pool from which to allocate the thread stacks. */
110 tx_byte_pool_create(&byte_pool_0, "byte pool 0", first_unused_memory, DEMO_BYTE_POOL_SIZE);
111
112 /* Put system definition stuff in here, e.g. thread creates and other assorted
113 create information. */
114
115 /* Allocate the stack for thread 0. */
116 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
117
118 /* Create the main thread. */
119 tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
120 pointer, DEMO_STACK_SIZE,
121 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
122
123 /* Allocate the stack for LCD thread. */
124 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
125
126 /* Create the lcd thread. */
127 tx_thread_create(&lcd_thread, "lcd thread", lcd_thread_entry, 0,
128 pointer, DEMO_STACK_SIZE,
129 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
130
131 /* Allocate the stack for thread 1. */
132 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
133
134 /* Create threads 1 and 2. These threads pass information through a ThreadX
135 message queue. It is also interesting to note that these threads have a time
136 slice. */
137 tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
138 pointer, DEMO_STACK_SIZE,
139 16, 16, 4, TX_AUTO_START);
140
141 /* Allocate the stack for thread 2. */
142 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
143
144 tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,
145 pointer, DEMO_STACK_SIZE,
146 16, 16, 4, TX_AUTO_START);
147
148 /* Allocate the stack for thread 3. */
149 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
150
151 /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore.
152 An interesting thing here is that both threads share the same instruction area. */
153 tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3,
154 pointer, DEMO_STACK_SIZE,
155 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
156
157 /* Allocate the stack for thread 4. */
158 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
159
160 tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4,
161 pointer, DEMO_STACK_SIZE,
162 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
163
164 /* Allocate the stack for thread 5. */
165 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
166
167 /* Create thread 5. This thread simply pends on an event flag which will be set
168 by thread_0. */
169 tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5,
170 pointer, DEMO_STACK_SIZE,
171 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
172
173 /* Allocate the stack for thread 6. */
174 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
175
176 /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */
177 tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6,
178 pointer, DEMO_STACK_SIZE,
179 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
180
181 /* Allocate the stack for thread 7. */
182 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
183
184 tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7,
185 pointer, DEMO_STACK_SIZE,
186 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
187
188 /* Allocate the message queue. */
189 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT);
190
191 /* Create the message queue shared by threads 1 and 2. */
192 tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG));
193
194 /* Create the semaphore used by threads 3 and 4. */
195 tx_semaphore_create(&semaphore_0, "semaphore 0", 1);
196
197 /* Create the event flags group used by threads 1 and 5. */
198 tx_event_flags_create(&event_flags_0, "event flags 0");
199
200 /* Create the mutex used by thread 6 and 7 without priority inheritance. */
201 tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT);
202
203 /* Allocate the memory for a small block pool. */
204 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT);
205
206 /* Create a block memory pool to allocate a message buffer from. */
207 tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE);
208
209 /* Allocate a block and release the block memory. */
210 tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT);
211
212 /* Release the block back to the pool. */
213 tx_block_release(pointer);
214
215 /* Indicate that we are ready to start scheduling, which will happen after
216 this rountine returns. */
217 *((ULONG *) 0xBF000418) = 'T';
218 *((ULONG *) 0xBF000420) = 'X';
219 *((ULONG *) 0xBF000428) = ' ';
220 *((ULONG *) 0xBF000430) = 'G';
221 *((ULONG *) 0xBF000438) = 'O';
222 *((ULONG *) 0xBF000440) = '!';
223 *((ULONG *) 0xBF000448) = ' ';
224 *((ULONG *) 0xBF000450) = ' ';
225 }
226
227
228
229 /* Define the test threads. */
230
thread_0_entry(ULONG thread_input)231 void thread_0_entry(ULONG thread_input)
232 {
233
234 UINT status;
235
236 /* This thread simply sits in while-forever-sleep loop. */
237 while(1)
238 {
239
240 /* Increment the thread counter. */
241 thread_0_counter++;
242
243 /* Sleep for 10 ticks. */
244 tx_thread_sleep(10);
245
246 /* Set event flag 0 to wakeup thread 5. */
247 status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR);
248
249 /* Check status. */
250 if (status != TX_SUCCESS)
251 break;
252 }
253 }
254
255
thread_1_entry(ULONG thread_input)256 void thread_1_entry(ULONG thread_input)
257 {
258
259 UINT status;
260
261
262 /* This thread simply sends messages to a queue shared by thread 2. */
263 while(1)
264 {
265
266 /* Increment the thread counter. */
267 thread_1_counter++;
268
269 /* Send message to queue 0. */
270 status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER);
271
272 /* Check completion status. */
273 if (status != TX_SUCCESS)
274 break;
275
276 /* Increment the message sent. */
277 thread_1_messages_sent++;
278 }
279 }
280
281
thread_2_entry(ULONG thread_input)282 void thread_2_entry(ULONG thread_input)
283 {
284
285 ULONG received_message;
286 UINT status;
287
288
289 /* This thread retrieves messages placed on the queue by thread 1. */
290 while(1)
291 {
292
293 /* Increment the thread counter. */
294 thread_2_counter++;
295
296 /* Retrieve a message from the queue. */
297 status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER);
298
299 /* Check completion status and make sure the message is what we
300 expected. */
301 if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received))
302 break;
303
304 /* Otherwise, all is okay. Increment the received message count. */
305 thread_2_messages_received++;
306 }
307 }
308
309
thread_3_and_4_entry(ULONG thread_input)310 void thread_3_and_4_entry(ULONG thread_input)
311 {
312
313 UINT status;
314
315
316 /* This function is executed from thread 3 and thread 4. As the loop
317 below shows, these function compete for ownership of semaphore_0. */
318 while(1)
319 {
320
321 /* Increment the thread counter. */
322 if (thread_input == 3)
323 thread_3_counter++;
324 else
325 thread_4_counter++;
326
327 /* Get the semaphore with suspension. */
328 status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER);
329
330 /* Check status. */
331 if (status != TX_SUCCESS)
332 break;
333
334 /* Sleep for 2 ticks to hold the semaphore. */
335 tx_thread_sleep(2);
336
337 /* Release the semaphore. */
338 status = tx_semaphore_put(&semaphore_0);
339
340 /* Check status. */
341 if (status != TX_SUCCESS)
342 break;
343 }
344 }
345
346
thread_5_entry(ULONG thread_input)347 void thread_5_entry(ULONG thread_input)
348 {
349
350 UINT status;
351 ULONG actual_flags;
352
353
354 /* This thread simply waits for an event in a forever loop. */
355 while(1)
356 {
357
358 /* Increment the thread counter. */
359 thread_5_counter++;
360
361 /* Wait for event flag 0. */
362 status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR,
363 &actual_flags, TX_WAIT_FOREVER);
364
365 /* Check status. */
366 if ((status != TX_SUCCESS) || (actual_flags != 0x1))
367 break;
368 }
369 }
370
371
thread_6_and_7_entry(ULONG thread_input)372 void thread_6_and_7_entry(ULONG thread_input)
373 {
374
375 UINT status;
376
377
378 /* This function is executed from thread 6 and thread 7. As the loop
379 below shows, these function compete for ownership of mutex_0. */
380 while(1)
381 {
382
383 /* Increment the thread counter. */
384 if (thread_input == 6)
385 thread_6_counter++;
386 else
387 thread_7_counter++;
388
389 /* Get the mutex with suspension. */
390 status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
391
392 /* Check status. */
393 if (status != TX_SUCCESS)
394 break;
395
396 /* Get the mutex again with suspension. This shows
397 that an owning thread may retrieve the mutex it
398 owns multiple times. */
399 status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
400
401 /* Check status. */
402 if (status != TX_SUCCESS)
403 break;
404
405 /* Sleep for 2 ticks to hold the mutex. */
406 tx_thread_sleep(2);
407
408 /* Release the mutex. */
409 status = tx_mutex_put(&mutex_0);
410
411 /* Check status. */
412 if (status != TX_SUCCESS)
413 break;
414
415 /* Release the mutex again. This will actually
416 release ownership since it was obtained twice. */
417 status = tx_mutex_put(&mutex_0);
418
419 /* Check status. */
420 if (status != TX_SUCCESS)
421 break;
422 }
423 }
424
425
lcd_thread_entry(ULONG thread_input)426 void lcd_thread_entry(ULONG thread_input)
427 {
428
429 UINT state = 0;
430
431
432 /* Loop to continue displaying info on the LCD. */
433 while(1)
434 {
435
436 /* Sleep for a bit... */
437 tx_thread_sleep(100);
438
439 lcd_counter++;
440
441 switch (state)
442 {
443
444 case 0:
445
446 *((ULONG *) MALTA_ASCIIPOS0) = 'T';
447 *((ULONG *) MALTA_ASCIIPOS1) = 'H';
448 *((ULONG *) MALTA_ASCIIPOS2) = 'R';
449 *((ULONG *) MALTA_ASCIIPOS3) = 'E';
450 *((ULONG *) MALTA_ASCIIPOS4) = 'A';
451 *((ULONG *) MALTA_ASCIIPOS5) = 'D';
452 *((ULONG *) MALTA_ASCIIPOS6) = 'X';
453 *((ULONG *) MALTA_ASCIIPOS7) = ' ';
454 break;
455
456 case 1:
457
458 *((ULONG *) MALTA_ASCIIPOS0) = 'D';
459 *((ULONG *) MALTA_ASCIIPOS1) = 'e';
460 *((ULONG *) MALTA_ASCIIPOS2) = 'm';
461 *((ULONG *) MALTA_ASCIIPOS3) = 'o';
462 *((ULONG *) MALTA_ASCIIPOS4) = ' ';
463 *((ULONG *) MALTA_ASCIIPOS5) = 'F';
464 *((ULONG *) MALTA_ASCIIPOS6) = 'o';
465 *((ULONG *) MALTA_ASCIIPOS7) = 'r';
466 break;
467
468 case 2:
469
470 *((ULONG *) MALTA_ASCIIPOS0) = 'M';
471 *((ULONG *) MALTA_ASCIIPOS1) = 'I';
472 *((ULONG *) MALTA_ASCIIPOS2) = 'P';
473 *((ULONG *) MALTA_ASCIIPOS3) = 'S';
474 *((ULONG *) MALTA_ASCIIPOS4) = ' ';
475 *((ULONG *) MALTA_ASCIIPOS5) = ' ';
476 *((ULONG *) MALTA_ASCIIPOS6) = ' ';
477 *((ULONG *) MALTA_ASCIIPOS7) = ' ';
478 break;
479
480 case 3:
481
482 *((ULONG *) MALTA_ASCIIPOS0) = 'i';
483 *((ULONG *) MALTA_ASCIIPOS1) = 'n';
484 *((ULONG *) MALTA_ASCIIPOS2) = 't';
485 *((ULONG *) MALTA_ASCIIPOS3) = 'A';
486 *((ULONG *) MALTA_ASCIIPOS4) = 'p';
487 *((ULONG *) MALTA_ASCIIPOS5) = 't';
488 *((ULONG *) MALTA_ASCIIPOS6) = 'i';
489 *((ULONG *) MALTA_ASCIIPOS7) = 'v';
490 break;
491
492 case 7:
493
494 *((ULONG *) MALTA_ASCIIPOS0) = 'E';
495 *((ULONG *) MALTA_ASCIIPOS1) = 'R';
496 *((ULONG *) MALTA_ASCIIPOS2) = 'R';
497 *((ULONG *) MALTA_ASCIIPOS3) = 'O';
498 *((ULONG *) MALTA_ASCIIPOS4) = 'R';
499 *((ULONG *) MALTA_ASCIIPOS5) = ' ';
500 *((ULONG *) MALTA_ASCIIPOS6) = ' ';
501 *((ULONG *) MALTA_ASCIIPOS7) = ' ';
502 break;
503
504 default:
505 break;
506 }
507
508 /* Change state for new print! */
509 state++;
510 if (state > 3)
511 state = 0;
512 }
513 }
514
515