Skip to content
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

Merged
merged 27 commits into from
Apr 11, 2016

Conversation

neelnatu
Copy link
Contributor

@neelnatu neelnatu commented Apr 7, 2016

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:

  • os_tick_init() is used to initialize the periodic timer.
  • os_tick_idle() is used to enter tickless mode and halt the CPU when idle.

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

…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;
Copy link
Contributor

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.

Copy link
Contributor

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.

@asfgit asfgit merged commit dda6cb4 into apache:develop Apr 11, 2016
asfgit pushed a commit that referenced this pull request Apr 11, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants