SamD20 SysTick & sleep

Go To Last Post
10 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello. I have an ATSAMD20J18 cpu.

Is the SysTick interrupt operating when I enter into a Sleep mode?

 

system_set_sleepmode(SYSTEM_SLEEPMODE_IDLE_0);

system_sleep();

 

Having the ICE debugger on the board, it seems like operating fine but when I disconnect the debugger, the cpu goes totally on sleep and I don't see the SysTick interrupt to be triggering somehow.

 

What is the correct way to wake the cpu after a tick?

 

The Idea behind the problem:

I am having FreeRTOS running on the cpu. In order to minimize battery consumption, on my idle hook I try to enter sleep mode like bellow:

 

void vApplicationIdleHook( void ) {
	vTaskSuspendAll();

	////system_set_sleepmode(SYSTEM_SLEEPMODE_STANDBY);
	system_set_sleepmode(SYSTEM_SLEEPMODE_IDLE_0);
	system_sleep();

	xTaskResumeAll();
}

 

Obviously, the above hook is going to be called when all tasks are somehow suspended (either waiting for a semaphore or doing vTaskDelay).

But... I want my vTaskDelay to continue after the delay has passed. Unfortunately, it is not happening because the cpu enters a sleep mode and it does not seem to be waken up by the SysTick interrupt.

 

Is the SysTick really pausing?

If yes, should I wake the cpu by using a timer event?

 

Thank you very much.

This topic has a solution.
Last Edited: Mon. Jun 11, 2018 - 03:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Similar issue here

https://community.atmel.com/foru...

/Lars

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SysTick does not run in sleep modes since it requires the CPU clock. Other things can still wake up the CPU, such as external interrupts, but the systick will have been stopped an thus freeRTOS will not have accurate knowledge of how much time has passed.

 

You will need to re-implement the FreeRTOS systick using either TC4 (the only counter that runs in low power modes) or the RTC counter if you want an accurate systick. It is not as bad as it seems, you just need to set up the timer interrupt you want to use as a tick, and then use the callback to invoke the freeRTOS systick handler. You will also need to modify the FreeRTOS code in FreeRTOS/Source/portable/GCC/ARM_CM0/port.c to allow you to re-implement the timer setup.

 

For my system I chose the RTC since I wanted a faily slow tick and I was already using it. The downside of the RTC is that you are limited to the periodic interrupts (RTC GCLK divided by 3, 4, 5, 6, 7, 8, 9, or 10) and Atmesl START doesn't support the periodic interrupts so you are left to implement that yourself.

 

TC4 is a bit easier since you can use the START/ASK code to set it up and your tick can be an arbitrary speed, within the capabilities of the timer.

 

I roughly followed this blog, which shows the changes you need to make to port.c and how to set up TC4. (They talk a lot about tickless idle but you can ignore that part unless you want to do that too):

Changing port.c: https://yurovsky.github.io/2015/04/03/freertos-tickless-low-power-m0.html

Setting up TC4: https://yurovsky.github.io/2015/04/09/freertos-low-power-samd20.html

My repo if you want to see it in a project, or want to see how to use the RTC: https://github.com/SealHAT/SealHAT

 

One last tip, I would enable the tick hook and throw an LED or Pin toggle in it for debugging. You can then probe it with a scope and make sure it is going at the frequency you set and doesn't pause during sleep.

 

EDIT: also just noticed your idle hook. You shouldn't be calling vTaskSuspendAll() in there. That will disable the scheduler, and then you sleep. You do want a working tick to wake you up again. This does mean that your system will have to wake up every tick to see if any tasks can run. If that is a problem then you either need to implement tickless idle or slow down your tick rate.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you very much for your detailed answer. It answers all my questions!

 

I use the RTC in calendar mode but I am having a feeling that I can still use the internal 32.768Khz oscillator (the one I use in RTC) in order to have my ticks. Having a prescaler of 32 in that I think that I am going to have a good millisecond accuracy. I am actually using an IMU (Inertial Measurement Unit) in order to get acceleration and gyroscope measurements and I get them from the FIFO buffer of it almost once every second. As such I will have to sleep for a whole second and for that reason I will try to implement the tickles idle as you stated on the bottom of your post.

My biggest problem was that the SPI communication with the sensor interface was requiring a small amount of delays for the communication (a couple of milliseconds) and because of that when I was calling the vTaskDelay, my processor was going instantly to deep sleep without waking up at all. Obviously, based on the solution you have given me, I will not need to use at all both the tick (and of course) the idle hook.

 

Thank you very much again for your help!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is there a reason you need ms ticks? if you are looking for low power then there is no real reason to make your tick rate so high. The system I am making (and linked to my github repo in the last post) is a logger with IMU, light, and temperature sensors and the microcontroller uses an average current of 100uA when sampling at 50Hz. Our tick rate is only 16Hz.

 

Using the IMU FIFO is important, are you getting an interrupt when the FIFO is ready (watermark)? The interrupt code will execute and in that ISR you should set a semaphore, or use a direct to task notification. Then you just call portYEILD_FROM_ISR() and the scheduler will run any tasks that were unblocked by the interrupt. See the example here for doing this with a direct to task notification. If you care to look this is what we did in our IMU_task.c. Using this technique it does not matter how slow your ticks are because the ISR will always invoke the scheduler to see if something needs to run. In fact, since all the sensors on my system have a data ready interrupt we had the same bug you are dealing with for about a week before we noticed. Data was being gathered fine, since the interrupts would start the scheduler, but all our timestamps were off since the tick wasn't running during sleep!

 

Just things to consider, since the tickless sleep is not very easy to implement, and you can get very good results by just using a slower tick rate and properly setting up interrupts and priorities.

 

The RTC interrupts are actually from the pre-scaler, but come from the upper 8 bits so you can't really get milliseconds. The interrupt frequency when the RTC is in calendar mode is given by f=1024/(2^n) where n=3, 4, .... , 10. so basically 128Hz, 64Hz, 32Hz, .... , 1Hz.

See section 25.6.8.1 in the datasheet (Periodic Intervals in the RTC section, I'm using the L variant so my pages may be different).

Last Edited: Mon. Jun 11, 2018 - 05:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, yes! I am using the watermark of both the accelerator and the gyro sensors. They both trigger an interrupt callback from which they call xSemaphoreGiveFromISR(IMU::tsInterruptSemaphore, NULL). Then the task is waken up by this semaphore and starts getting the data from the FIFOs.

The only reason I am using so high tick rate is because I am using the BMF055 from Bosch which is an Atmel SAMD20J18 with an accelerometer, a gyro and a magnetometer (all 4 chips in one). A totally bad choice as it consumes 10mA in full operation sad. There, in their routines they use delays like the following:

p_bma2x2->delay_msec(BMA2x2_INTERFACE_IDLE_TIME_DELAY);

'delay_msec' is actually a callback function in which I can create my own delay (either timer or vTaskDelay or anything else delay based on what I choose) like bellow.

void bma_delay_msec(u32 msec)
{
	vTaskDelay(msec / portTICK_PERIOD_MS);
//	tc4_wait_for_msec(msec);
}

I guess that if I choose a 16Hz tick some operations that use such delays (eg. power on), will take longer but it shouldn't be problem as they occur only once (in the startup of the program). Also because they need sometimes a minimun 450usec delay for the SPI communication with the sensors, the sensor sdk uses a minimum msec delay (which is totally awkward).

 

Well, my 32Khz clock is defined like that:

/* SYSTEM_CLOCK_SOURCE_OSC32K configuration - Internal 32KHz oscillator */
#  define CONF_CLOCK_OSC32K_ENABLE                true
#  define CONF_CLOCK_OSC32K_STARTUP_TIME          SYSTEM_OSC32K_STARTUP_130
#  define CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT    true
#  define CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT   true
#  define CONF_CLOCK_OSC32K_ON_DEMAND             false
#  define CONF_CLOCK_OSC32K_RUN_IN_STANDBY        true

and the RTC generator contains:

/* Configure GCLK generator 2 (RTC) */
#  define CONF_CLOCK_GCLK_2_ENABLE                true
#  define CONF_CLOCK_GCLK_2_RUN_IN_STANDBY        true
#  define CONF_CLOCK_GCLK_2_CLOCK_SOURCE          SYSTEM_CLOCK_SOURCE_XOSC32K
#  define CONF_CLOCK_GCLK_2_PRESCALER             32
#  define CONF_CLOCK_GCLK_2_OUTPUT_ENABLE         false

I am not quite sure why it points to the external oscillator that it doesn't exist angrybut it seems like counting normally every 1 sec.surprise

I am guessing that when setting up the RTC callendar it switches automatically to the internal one? Super strange... as the init is using the GCLK2 inside the ASF call!!!: 

gclk_chan_conf.source_generator = GCLK_GENERATOR_2;

I guess I will never understand totally how Atmel ASF internally works and how it always succeed operating even with wrong parameters!

 

Anyway, why can't I use a timer that uses the OSC32K to an other GCLK (eg. 4) in order to count 32KHz ticks per second? Also, PER0 can generate events every 8 ticks.  Shouldn't it be f=32768/(2^(n+3)) where n is the PERn number and as such for PER0, f=4096?

 

Thank you very much.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SysTick does not run in sleep modes since it requires the CPU clock.

 This is apparently "implementation dependent", somehow.  In another thread, someone found systick to be unexpected RUNNING during sleep (on SAM3X)

http://forum.arduino.cc/index.ph...

And: https://community.arm.com/proces...

 

Last Edited: Tue. Jun 12, 2018 - 08:59 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

SysTick does not run in sleep modes since it requires the CPU clock.

 This is apparently "implementation dependent", somehow.  In another thread, someone found systick to be unexpected RUNNING during sleep (on SAM3X)

http://forum.arduino.cc/index.ph...

And: https://community.arm.com/proces...

 

 

Yes, it seems like they should list the implementation decision in the datasheet. In section 12.1.1 There is a while table of ARM M0+ options and which one they decided to use. All it says is that it can be present or absent, and then goes on to say in the next subsection "The System Timer is a 24-bit timer clocked by CLK_CPU that extends the functionality of both the processor and the NVIC. Refer to the Cortex-M0+ Technical Reference Manual for details"

If you go to the Cortex-M0+ TRM it says implementation dependent. frown

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ekalyvio wrote:

Well, yes! I am using the watermark of both the accelerator and the gyro sensors. They both trigger an interrupt callback from which they call xSemaphoreGiveFromISR(IMU::tsInterruptSemaphore, NULL). Then the task is waken up by this semaphore and starts getting the data from the FIFOs.

The only reason I am using so high tick rate is because I am using the BMF055 from Bosch which is an Atmel SAMD20J18 with an accelerometer, a gyro and a magnetometer (all 4 chips in one). A totally bad choice as it consumes 10mA in full operation sad. There, in their routines they use delays like the following:

 

Are you using portYEILD_FROM_ISR() at the end of your ISR? (like in the example on the xSemaphoreGiveFromISR() documentation). If so your tick rate can be as slow as you want, but the ISR will always run and then if that ISR wakes a task the scheduler will send the CPU directly to that task after the ISR. This is what hid the tick problem on my system, since everything was driven by ISRs there was no data loss and everyhting was working as expected. It was once we added timestamps and a watchdog timer that everything fell apart since the ticks weren't happening in sleep.

 

ekalyvio wrote:

p_bma2x2->delay_msec(BMA2x2_INTERFACE_IDLE_TIME_DELAY);

'delay_msec' is actually a callback function in which I can create my own delay (either timer or vTaskDelay or anything else delay based on what I choose) like bellow.

void bma_delay_msec(u32 msec)
{
	vTaskDelay(msec / portTICK_PERIOD_MS);
//	tc4_wait_for_msec(msec);
}

I guess that if I choose a 16Hz tick some operations that use such delays (eg. power on), will take longer but it shouldn't be problem as they occur only once (in the startup of the program). Also because they need sometimes a minimun 450usec delay for the SPI communication with the sensors, the sensor sdk uses a minimum msec delay (which is totally awkward).

 

That is an interesting design problem. If it were only happening at startup I would maybe try to use regular old blocking waits and do it before the scheduler starts? Something I have yet to figure out but want to look into after this project is how the freeRTOS delays work if the delay is shorter than, or not a multiple of, the tick period. sorry I don't really know and it wasn't an issue for us.

 

ekalyvio wrote:

I guess I will never understand totally how Atmel ASF internally works and how it always succeed operating even with wrong parameters!

 

We've been using Atmel START for this project. It was very nice in the beginning.... less nice as our project matured :) So sorry I haven't used ASF in a while but I am sure it has it's own quirks.  Hopefully it doesn't try to overwrite all your files every time you make a change to the config??? haha smiley

 

ekalyvio wrote:

Anyway, why can't I use a timer that uses the OSC32K to an other GCLK (eg. 4) in order to count 32KHz ticks per second? Also, PER0 can generate events every 8 ticks.  Shouldn't it be f=32768/(2^(n+3)) where n is the PERn number and as such for PER0, f=4096?

The trick is that PER0-PER7 operate from the prescaler, and if your RTC is in calendar mode and counting seconds then the actual clock input is 1024Hz. Honestly if you aren't using TC4 you should just use that. It was easier to set up (just use ASF and follow that example I linked), it can do any frequency you want, and operates in sleep. The only reason I didn't use it is because I am still trying to use it as a millisecond counter.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

 

SysTick does not run in sleep modes since it requires the CPU clock.

 This is apparently "implementation dependent",

Probably more to the point, different implementations have different sets of "low power" modes available.

 

Names are not consistent - the mode called "Sleep" in one chip will not necessarily be related to the mode called "Sleep" in another.

 

 

Yes, it seems like they should list the implementation decision in the datasheet.

What is enabled/disabled it each of the available low-power modes is usually documented in the low-power modes section of the datasheet.

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...