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