To further illustrate how to use the features of CMSIS-RTOS that we've introduced in this chapter, we'll return to the Pong program that we first introduced in Chapter 2, C Language Programming. We'll call this recipe: RTOS_Pong_v8v0
. Due to space limitations, we're only showing those parts of the code that are relevant to the RTOS implementation. Refer to Chapter 2, C Language Programming for details of helper functions defined in the pong_utils.c
file.
To create a multithreaded pong game, follow the steps given:
RTOS_Pong
. Set the RTE to include board support for the ADC and GLCD. Include CMSIS-RTOS.RTOS_Pong.c
and add a task to handle the GLCD:void taskGLCD (void const *argument) { BallInfo init_pstn = thisGame.ball; for (;;) { osEvent evt = osMailGet(mail_box, osWaitForever); if (evt.status == osEventMail) { mail_t *mail = (mail_t*)evt.value.p; thisGame.p1.y = mail->pdl; osMailFree(mail_box, mail); osMutexWait(mut_GLCD, osWaitForever); update_player(); if (thisGame.ball.x<BAR_W) { /* reset pstn */ osDelay(T_LONG); erase_ball(); thisGame.ball = init_pstn; } draw_ball(); osMutexRelease(mut_GLCD); osDelay(T_SHORT); osSignalSet(tid_taskBall, 0x0001); } } }
void taskBall (void const *argument) { for (;;) { osSignalWait(0x0001, osWaitForever); update_ball(); check_collision(); osSignalSet(tid_taskGLCD, 0x0001); } }
void taskADC (void const *argument) { uint32_t adcValue; for (;;) { mail_t *mail = (mail_t*)osMailAlloc(mail_box, osWaitForever); ADC_StartConversion(); adcValue = ADC_GetValue (); mail->pdl = (adcValue >> 4) * (HEIGHT-BAR_H)/256; osMailPut(mail_box, mail); osDelay(T_SHORT); } }
main()
, save RTOS_Pong.c
, and add the file to the project:int main (void) { HAL_Init ( ); SystemClock_Config ( ); game_Initialize(); ADC_Initialize(); GLCD_Initialize (); GLCD_Clear (White); /* Clear the GLCD */ GLCD_SetBackColor (White); /* Set the Back Color */ GLCD_SetTextColor (Blue); /* Set the Text Color */ mail_box = osMailCreate(osMailQ(mail_box), NULL); mut_GLCD = osMutexCreate(osMutex(mut_GLCD)); tid_taskGLCD = osThreadCreate(osThread(taskGLCD), NULL); tid_taskBall = osThreadCreate(osThread(taskBall), NULL); tid_taskADC = osThreadCreate(osThread(taskADC), NULL); osDelay(osWaitForever); while(1) ; }
RTOS_Pong.h
:#ifndef _RTOS_PONG_H #define _RTOS_PONG_H #include "cmsis_os.h" #define __FI 1 /* Font index 16x24 */ /* Mailbox */ typedef struct { uint32_t pdl; /* paddle position */ } mail_t; osMailQDef(mail_box, 1, mail_t); osMailQId mail_box; /* Mutex */ osMutexDef(mut_GLCD); osMutexId mut_GLCD; /* Mutex to control GLCD access */ /* Function Prototypes for Tasks */ void taskGLCD (void const *argument); void taskBall (void const *argument); void taskADC (void const *argument); /* Declare Task IDs */ osThreadId tid_taskGLCD; /* id of thread: taskGLCD */ osThreadId tid_taskBall; /* id of thread: taskGreq */ osThreadId tid_taskADC; /* id of thread: taskMotor */ /* Define Threads */ osThreadDef(taskGLCD, osPriorityNormal, __FI, 0); osThreadDef(taskBall, osPriorityNormal, __FI, 0); osThreadDef(taskADC, osPriorityNormal, __FI, 0); #endif /* _RTOS_PONG_H */
pong_utils.c
and pong_utils.h
files (refer to Chapter 2, C Language Programming.) and add these to the project.The tasks named taskGLCD( )
and taskBall( )
are synchronized using a flag so the ball position is updated every time the screen is refreshed. The task named taskADC( )
sends the position of the paddle to a mailbox; taskGLCD( )
receives this value and uses it to render the paddle. The tasks are illustrated in the following diagram:
The tasks are loosely coupled and can be independently tested. For example, during debuging, the taskADC( )
function and statements within taskGLCD( )
, which read the mailbox and render the paddle, can be "commented out," leaving a simpler program that just moves the ball around the screen. The mailbox has only one slot. This is a key design decision that ensures that the paddle is rendered each time the ADC is read, so everything is synchronized to taskADC()
.
3.144.9.124