For background, in order to support the Signpost use case, we want Tock go into a deep sleep state (~5μA on the SAM4L) whenever possible.
Our initial goal is to support the common case of applications with some duty cycle that do nothing between active states. For those cases, we basically only need the AST (asynchronous timer) and TWIS (I2C device) controllers to be able to wake up the CPU and for the OSC32 clock to run the AST.
I have an initial attempt in progress which basically relies on the SAM4L’s power manager clock mask registers to tell us whether we can drop into a deep sleep state. The hypothesis is that we can tweak the low-level drivers (potentially with minor changes to the drivers that live above the HIL) to just mask off their clocks when they are not needed (e.g. not waiting on any incoming transfers to USART3? turn off the USART3 clock!).
If that’s successful, we can check the mask registers in the PM against a known bit-mask that we know is fine for deep sleep right before the WFI instruction.
I’ve managed to get this working for a basic example that uses the AST and USART. It prints out a string every 5 seconds, which requires the CPU to sleep both in and out of deep sleep and different times (out of deep sleep when the DMA is driving the USART for printf). This seems to work with fairly minimal changes to the USART. The most notable one was adding a state to wait for the TXEMPTY interrupt (the TX buffer is empty), which we were intentionally ignoring.
Some issues I’m anticipating, though:
The GPIO clock is on by default, and we do nothing to manage it at the moment. This isn’t an issue for GPIO outputs, but the clock is off during deep sleep and must be on for GPIO interrupts (the EIC controller is actually used for this case). The way our GPIO system call interface is written, I believe the way our GPIO system call driver is written, we lazily disable interrupts, which means we may get into a state where no processes are waiting on a GPIO interrupt but we don’t go into deep sleep for an unbounded amount of time. I think this is fixable though, and I don’t believe it’s an issue for signpost.
It’s not clear to me yet how exactly we setup the TWIS to operate as expected during deep sleep. E.g. Can we still rely on the DMA or do we have to set it up again after wakeup?
I don’t totally understand how the flashcalw’s pico-cache, which we currently turn on by default, interacts with deep sleep. For example, if there is an ongoing transaction to flush the page buffer to flash, and the pico-cache is active, does that halt if we go into deep sleep (which disables the flash’s pico-cache RAM clock)?