This video presentation is the eigth installment of the Essentials of MQX RTOS Application Development training course. In this session, you will be introduced to light weight timers, timer queues, and the timer task.
This training was created by Embedded Access Inc., a Freescale sponsored training provider and proven partner.
|Session 8 Course Line||Lab Outline|
First, watch the video for Session 8: Light Weight Timers.
Then, follow through with the interactive lab assignment below.
SESSION 8: LAB ASSIGNMENT
Though timers can be used in a great variety of ways, in this lab we'll implement a fairly straight forward, but typical, use case for a timer. A light weight timer will be used to periodically inform the Input Task of when to read the ADC and send a message to the Health Task. In keeping with our philosophy of keeping ISRs short, the timer ISR we implement will leverage the event group that was implemented in the lab for the previous session.
The objective of this lab is to learn about lwtimers by having the input task respond to an event that is periodically generated by a lwtimer.This objective will be accomplished by:
- In the input task, creating a lw timer period and a lwtimer timer
- Creating the timer function wheich generates an event
- Modifying the input task to handle the new event.
New functions/structures you will use:
LWTIMER_PERIOD_STRUCT, LWTIMER_STRUCT, _lwtimer_create_periodic_queue, _lwtimer_add_timer_to_queue
CREATING THE TIMER
- LW Timers is an optional component so lwtimer.h must be included for any file that will be accessing this feature. This is most conveniently added to main.h that all files have included.
- Prior to creating a timer queue and a timer to put in that queue we need two structures, one of type LWTIMER_PERIOD_STRUCT and one of type LWTIMER_STRUCT. These don't need to be global and can be declared at the top of the Input Task.
- The lwtimer periodic queue needs to be created which can be done with the _lwtimer_create_periodic_queue() function. It would make sense to create this in the Input Task just after the lwevent group is created. The periodic queue should have a period of 10 Hz, however the period needs to be expressed in system ticks so this number will have to be converted. The number of ticks / second for the system is defined in the board specific header file of our BSP, in this case twrK70f120m.h. In there you will see a define for BSP_ALARM_FREQUENCY which is set to 200. For a period of 10 Hz then our timer should be expiring then every 1/10th of a second, or every 20 ticks. To write code that is easier to follow and more transportable it is better to define the period in your function call as 'BSP_ALARM_FREQUENCY/10'. In our case there is no point to have a delay before the timer queue starts so this can be left at 0 in the _lwtimer_create_periodic_queue() function call.
- Now that the timer queue has been created you can add a timer to that queue using the _lwtimer_add_timer_to_queue() function. Reference the structure of type LWTIMER_STRUCT that you already declared and select an offset of 0 ticks. A timer ISR function to be called when the timer expires is required so you can select a function name now for this ISR (eg: 'adc_timer_isr') and we'll write this ISR shortly. We won't need a parameter to be passed to our ISR so you can set this parameter to 'NULL'.
CREATING THE TIMER ISR
- Add a new ISR to InputTask.c using the name you defined when the timer was created in the previous step. This ISR will be called when the timer expires every 1/10th of a second.
- Like the switch ISRs the timer ISR will set an event bit to indicate that the timer expired. Add a new define that specifies which bit in the event group will be used for this indication, which of course should be a different bit than the two used for the switches (eg 0x00000004). This define can be placed just below the define for the switches in InputTask.c
- Like the switch ISRs the timer ISR should use the _lwevent_set() function to set the bit reserved for the ADC Timer and that's all we'll use the timer ISR for. Don't over think it, it's a one line function.
UPDATING THE INPUT TASK
- In the next lab we'll set up the Input Task to read the ADC value when the timer expires. But since the ADC interface hasn't been covered in the course material yet we'll skip that step and simply send a message to the Health Task to indicate that the timer has gone off. The Input Task will need to unblock when timer expires so the _lwevent_wait_ticks() function should be updated accordingly.
- Since we will be adding a new message type for indicating that the ADC timer has expired our list of available message types will have to be updated. In main.h locate the APPLICATION_MESSAGE_TYPE_T enum and add a new type called ADC_READ_MESSAGE.
- The handling of the ADC timer expired bit needs to be added to the Input Task. You can copy the message passing code from the switch handling section and paste it in a new section that will handle the ADC timer expiry. Be sure to update the message type to ADC_READ_MESSAGE. You can leave the data field set to 0.
UPDATING THE DISPLAY TASK
- The Health Task passes all messages on to the Display Task and we should update the display task to indicate that the timer is working. For now we'll toggle the state of the blue LED (which is LED). Add the handling of an ADC_READ_MESSAGE in the Display Task. When this message is received, use the _lwgpio_toggle_value() function to change the state of the blue LED.
TESTING YOUR CHANGES
- Compile and run your code. You should see the blue LED changing state rapidly, ie every 1/10th of a second so it will flash on 5 times per second. The Timer Expired message should be seen continuously printing as well.
Need more help? The full source code for this lab can be found in the 'Lab Source Code' folder here.