-
Notifications
You must be signed in to change notification settings - Fork 364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement tickless mode during idle for nRF51 and nRF52 microcontrollers #34
Conversation
…y asking the callout and sched subsystems for the number of ticks until they need to perform some work. 'os_arch_idle()' then sets up the interval timer to wake it up after the specified number of ticks and then calls 'sigsuspend()' to the halt the process.
…ecific timer ISR to advance the os time. The OS might preempt the interrupted task if a higher priority task is now runnable (unless the 'resched' parameter is false).
…lace OS_ASSERT_CRITICAL() with a OS_ENTER_CRITICAL/OS_EXIT_CRITICAL in os_time_tick().
…clude the drift of the underlying physical clock source as well as the "drift" due to the finite granularity of each tick.
instead of hardcoding it in the BSP. Configure TIMER1 to run at a frequency of 1MHz and generate a periodic timer interrupt to drive the OS tick.
interrupt. This is in preparation for doing long sleeps when cpu is idle.
…_tick()' calls it implicitly via 'os_eventq_put()'.
'os_arch_idle(ticks)' now takes an argument to indicate how long before the OS has anything useful to schedule. The architecture specific function is allowed to suspend execution for up to those many ticks. Note that this function may return earlier if another interrupt wakes up the CPU. Note that 'ticks' may be zero in which case the CPU stays in the periodic timer regime. The idle stack size needed a bump to account for the increase in stack depth.
…ncy of the timer used to generate periodic interrupts. For example, it is important to choose a value for OS_TICKS_PER_SEC that divides cleanly into the underlying timer frequency to avoid a systemic time drift. MCU Timer Frequency OS_TICKS_PER_SEC nrf52 TIMER1 1000000 1000 nrf51 RTC 32768 1024 Move the definition of OS_TICKS_PER_SEC in the mcu-specific header file.
…ctly from the idle task. This was motivated by the fact that on most platforms the OS tick will be generated by a MCU-specific timer which implies that the idle function will also be MCU-specific.
It is not required that the periodic timer be based on the ARM's systick.
…er than the tick feature. This is in preparation for tickless support when idle.
Prior to the change context switching in sim happened "inline" as opposed to on hardware where it would trigger a special interrupt and the context switching happened in context of the interrupt handler. This causes subtle differences in how tasks are scheduled inside sim. For e.g. 'os_callout_tick()' is called from the timer handler with interrupts disabled. If a callout fires this function will post to an eventq and if a task is sleeping on it then it will be made runnable. On 'sim' the context switch happened immediately (i.e. from the timer handler context to the task that became runnable) whereas on real hardware all it would do is trigger the special interrupt. Note that the interrupt will not be recognized until the timer handler re-enables interrupts. The context switching behavior is now done similarly on sim by posting a signal to ourselves. The signal used is SIGURG because gdb treats this signal specially and forwards it to the process without any additional configuration (as opposed to gdb's treatment of SIGUSR1 which stops the process).
* worth of time has elapsed. | ||
*/ | ||
it.it_value.tv_sec = ticks / OS_TICKS_PER_SEC; | ||
it.it_value.tv_usec = (ticks % OS_TICKS_PER_SEC) * OS_USEC_PER_TICK; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would do this (ticks * OS_USEC_PER_TICK) % OS_TICKS_PER_SEC. But this change is not a must.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, misread that code. I was reading % as /. Ignore my previous comment.
Merge branch 'tickless' of https://github.com/neelnatu/incubator-mynewt-larva into develop
Implement tickless mode during idle for nRF51 and nRF52 microcontrollers.
When the idle task executes it gets from the OS the number of ticks until
there is useful work to be done (e.g. a callout handler needs to execute).
It then calls 'os_ticks_idle(idleticks)' which in turn idles the CPU for a
duration that does not exceed 'idleticks'.
'os_ticks_idle()' disables the periodic timer interrupt to enter the
tickless mode during idle. It sets up a one-shot timer to wake up the
CPU after a duration equivalent to 'idleticks' has elapsed. Finally,
it enters the low power idle state using a CPU-specific mechanism.
For e.g. ARM processors use the 'WFI' instruction for this purpose.
Add HAL APIs for the periodic OS timer:
A related change is to define 'OS_TICKS_PER_SEC' in MCU-specific header file.
This is needed because the capabilities of the underlying periodic timer
dictate the appropriate timer frequency.
Increase the idle task's stack size to account for the increase in function
call depth due to os_tick_idle().
Add APIs 'os_callout_wakeup_ticks()' and 'os_sched_wakeup_ticks()' that
return the number of ticks until which the callout and sched subsystems
do not have useful work. In other words these APIs indicate for how long
the OS can safely idle.
Implement context switching in 'sim' in a similar manner to how it is done
on ARM Cortex processors. More information in commit http://bit.ly/1MWxuuG