This video presentation is the fifteenth installment of the Essentials of MQX RTOS Application Development training course. In this session, you will be introduced to Time Services.
This training was created by Embedded Access Inc., a Freescale sponsored training provider and proven partner.
|Session 15 Course Line||Lab Outline|
First, watch the video for Session 15: Time Services.
Then, follow through with the interactive lab assignment below.
SESSION 15: LAB ASSIGNMENT
This lab has two parts. In the first part we will update the application to fetch the current time and store it in each health record when it is logged. Since the application does not automatically know the absolute current time it will represent the running time until it is updated. Two new shell commands will be added then, one to update the current date and the other to update the current time. The logs will then contain the absolute current time.The second part of the lab demonstrates how to measure a time interval. In this case we'll measure the time it takes to run the ISR associated with switch 1 and print it out.
The objective of this lab is to 1) learn how time is used and can be updated to represent the absolute time and 2) to learn how the time functions can be used to measure an interval such as the execution of a section of code.
ADDING A TIME STAMP TO THE HEALTH LOGS
- In order to add a time stamp to the Health Logs this data structure will have to be updated. In main.h, add the variable 'TIME' of type TIME_STRUCT to the HEALTH_RECORD data structure.
- We will need the current time when the health records are added to the queue (using the _queue_enqueue() function ). This is done in the Health Task when a LOG_TICK_MESSAGE has been received. Use the _time_get() function to fetch the current time and to store it in the TIME variable of the current health record.
- Since the current time is being logged in each record, the UI Task can now print this out by the Shell_log() function so it appears at the beginning of each record beside the record number.
- Compile and run your code and ensure that the log time is currently being printed out. Note that the time will start at 00:00:00.
SETTING THE DATE AND TIME
- It would be helpful to be able to set the date and time so the health logs have a more meaningful time entry. This is best accomplished by enhancing the shell that we just implemented in the lab for the previous session. Start by adding two new function prototypes for shell functions in UiTask.c: Shell_set_date() and Shell_set_time().
- Add two commands, 'date' and 'time' to the list of shell commands that are listed at the top of UiTask.c.
- Create the Shell_set_date() function. You might want to copy the Shell_log() function and make the appropriate changes instead of starting from scratch. The command for setting the date will be 'date YYYY/MM/DD', so a total of two arguments will be required. The sscanf() function can be used in a similar way to how it was used in the Shell_can() function to get the number of CAN tasks to create, however in this case you will be expecting 3 arguments to be processed, which will each be copied into a uint32_t. Note that updating the date is a bit more involved than you'd think at first. Remember that the absolute time is the Offset Time (time from Jan 1, 1970 to boot up time) + the Running Time. A change to the current date means that the offset needs to be adjusted which is done for you when you use the _time_set() function. So you will have to first get the current time, convert it to the DATE_STRUCT format, update the date, convert it back to the TIME_STRUCT and then set the current time based on this new value. The Whiteboard popup below gives you some additional info.
- Copy the Shell_set_date() function to create a Shell_set_time() function. The format to change the time will be 'time HH:MM:SS' but otherwise there is very little to change. Remember that you'll still have to get the current time (in TIME_STRUCT which is the seconds and milliseconds from Jan 1, 1970), convert it to the date format (which includes the hours, minutes, seconds), update the time, convert it back and save it.
UPDATING THE SHELL_LOG() FUNCTION
- Since the user can now update the absolute date and time, it makes sense to update the printing of the logged records that is done by the Shell_log() function accordingly. Add a new printf statement in Shell_log() that will print out the absolute date and time based on the TIME saved in the record. The TIME in the record will have to be converted to the DATE_STRUCT with the time_to_date() function first in order to determine the YYYY/MM/DD and HH:MM:SS that the logged time equates to.
- Compile and run your code to ensure that everything is working.
MEASURING AN ISR'S EXECUTION TIME
- The second part of the lab involves the measurement of time. One of the switch ISRs will be used, and these are located in InputTask.c. Getting the current time at the beginning of the ISR and then again at the end of the ISR code and subtracting the two is not truly representative of the time to execute the ISR because it includes the overhead associated with getting the current time. So first we should measure what this overhead time is and then subtract it when we calculate the ISR execution time later.
- When determining an overhead it's a good idea to take several measurements and average them to get a more accurate number. Create a for loop in the initialization section of the Input Task that will loop for something like 16 times. Call the _time_get_ticks() function twice in a row in the for loop. Subtracting the two times will give the overhead associated with calling this function once. Use _time_diff_nanoseconds() function to calculate the difference and add it to an 'overhead' variable to calculate a running total of the measured overheads. You will need to declare a Boolean for an 'overflow' variable that the time diff function requires, and you will also need to declare two variables ('isr_start' and 'isr_end'), both of type MQX_TICK_STRUCT, for the _time_get_ticks() function to write to.
- After the for loop divide the total overhead by the number of times through the for loop to determine the average overhead.
- In the sw1_isr() function at the top of InputTask.c use the _time_get_ticks() function at the beginning of the ISR to save the current time into 'isr_start' and use the _time_get_ticks() function again at the end of the ISR to save the current time into 'isr_end'.
- Subtract these two times to get the ISR execution time and save it to a global variable.
- In the while(1) loop of the Input Task print out the execution time whenever the switch 1 event bit has been set. Remember that the exeution time will be the time measured in the ISR less the average overhead time calculated in step 13.
- Compile and run your code. Verify that the switch 1 ISR execution time is calculated and printed out.
Need more help? The full source code for this lab can be found in the 'Lab Source Code' folder here.