Friday, February 17, 2012

Notes about timer configuration

To test how the timer works, we design a task with period of 50ms and execution time of 20.5ms.
First let's see two screen shots from the scope. The orange line indicates the execution time. The green line indicates the sleep time. And the purple line indicates the task scheduler is called.
Fig. 1 unexpected result

Fig. 2 expected result
From these two figures, we can conclude that task is not activated in time in the figure 1 and it seems that task is overdue the first wake-up time and the OS timer  wraps back to the wake-up point. (timer counts to 255, back to 0 and then to the wake-up time)

Then let's look at the code. The first figure is using code as following,
Code segment:      _nrk_os_timer_set(24);
                               nrk_wait_until_next_period();
And the second figure is using code as following,
Code segment:      _nrk_os_timer_set(24);
                               do {
                                    NOP();
                               } while (--timeout); // timeout is initialized as 200

                               nrk_wait_until_next_period();
We can see the only difference between these two segments is the delay used by the second one which gives us the expected result. How does this happen? We have to look up what the data sheet says about the timer.

Firstly, the timer is working under the CTC mode. In CTC mode the counter is cleared to zero when
the counter value (TCNTn) matches either the OCRnA. In nano-rk, _nrk_set_next_wakeup() is used for setting OCRnA and  _nrk_set_os_timer() is used for setting TCNTn. So the OS timer starts from 0 and an interrupt happens once it reaches the value of OCRnA. What if the OS timer is manually set to a value that may be larger than OCRnA? 

The data sheet says: "Writing to the TCNTn Register blocks (removes) the Compare Match on the following timer clock. Modifying the counter (TCNTn) while the counter is running, introduces a risk of missing a Compare Match between TCNTn and the OCRnA Registers." (Page 121) Once a match is missing, the counter would wrap back to the match which means unexpected 255ms may be introduced just as Fig 1 shows.

Then the question is why the code works fine when a loop is introduced? The data sheet says: "When writing to one of the registers TCNTn, OCRnX, or TCCRnX, the value is transferred to a temporary register, and latched after two positive edges on TOSC1." So when _nrk_os_timer_set(24) is called, the value of timer is not immediately set to 24 (which is verified by observing the minicom). However, in nrk_wait_until_next_period() the first wake-up time is set to 2ms after current timer value. Therefore, the next wake-up time is unfortunately set to 22ms which is in advance of 24ms. A match is missed and thus figure 1 is the output which is undesired.

No comments:

Post a Comment