Implementing tickless idle on Cortex M4.

rtel wrote on Tuesday, September 16, 2014:

Please try the following, then report back:

  1. Find the function prvEnableAST() in SAM4L_low_power_tick_management().

  2. Add the following line to the top of the function: “ast_write_counter_value( AST, 0 );”

Regards.

rtel wrote on Tuesday, September 16, 2014:

Actually - instead try the attached. Only one line different from the current release.

hilt0n wrote on Tuesday, September 16, 2014:

Ok thank you, I have found the same solution than you (reset the AST counter when the uC is awakened by external interrupt) however, I have sometimes some problems with timing and fall into the assert of the function vTaskStepTick because the actual time is bigger than the next unblock time.

Have you an idea, a direction to find the problem ?

Best regards

jpt106 wrote on Thursday, September 18, 2014:

I believe I found the issue. The AST counter was not being reset and updated correctly. I was able to reliable reproduce the problem and the attached file fixes the issue on my system.

rtel wrote on Friday, September 19, 2014:

Are you saying the fix I already posted did not fix your problem?

Regards.

jpt106 wrote on Monday, September 22, 2014:

Sorry I was not clear. Yes the fix posted made the problem happen less often but I was to reproduce the issue still. I am using tickless configuration in my system. There is a task that runs periodically every 8 ticks (62.5 milliseconds). There is CLI interface through a UART. From the CLI I run different commands that cause other tasks to run processing the request for the CLI command. For testing, I have a script that continuously runs different CLI commands. This causes the other tasks to randomly run and generate other interrupts beside the AST interrupt.

Without your fix posted, running the test script my system fails the assert “configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime )” within a minute. With the posted fix, it takes about 10 minutes running the test script.

Originally I found when the system was failing it was calculating a negative alarm value and programming that negative value into the alarm for the AST. The code I posted tried to prevent the negative alarm value issue. After further investigation, I found the root cause of the issue. The AST clear counter on alarm does not clear the counter on the same AST clock cycle as when the counter equals the alarm. The counter gets reset to one on the next clock cycle when the counter exceeds the alarm value. This caused a race condition where during the time of single AST clock cycle (61 microseconds) the counter equals the alarm value. I saw during debugging in the code “if( ulTickFlag != pdFALSE)”
where ast_read_counter_value( AST ) returned the same value as the alarm value. This caused a negative value to be calculated for ulAlarmValue.

The newly posted code fixes the root cause directly by detected when the race condition happens and taking action.

1 Like

hilt0n wrote on Monday, September 29, 2014:

Thanks Joe for your big work, I didn’t yet tested completely your solution but that sound promising.
On my side, I have simply took the tickless implementation of the STM32L, it’s very similar to the SAM4L but there is 3 missing asynchronous counter clear on the SAM4L. I actually wonder why this porting difference…

Hello Joe. I read that you posted fix for “negative value of Alarm 0” but unfortunately didn’t found where is particular. Would you help me to see that? Thank you!

You are replying to an 8-year old post. Can you describe the issue you are having? Have you tried the latest code?

I modifiting now a project of 2014 year basis on GCC - Freertos 8.1.2 - ATSAM4LS and have a problem with LOW POWER DEMO(TICKLESS IDLE). I can see problem existed before and previous engineer make modification of “tick_mangmet.c”, this reduce frequency of problem but not fixed compleat. After ~30 minutes in RUN OS will supress ticks for almost maximum period of counter (68174084 ticks * 3.85mS), however one of the my task should to be done regularly and has only 100mS delay. Next - no one task go to running. Also after interrupt on push button (GPIO) system wake up but no one task RUN, only interupts works. So, I have two points:

  1. My application has not problem when LOW POWER DEMO is disable
  2. I took only “tick_mangmet.c” file from newest freertos version and replaced with them file in my project with the same name. But problem not disappear and looks simillar.

Would you suggest what is best thing of this situation?
I compare my version of FreeRTOS and last. A lot of code different at “port.c” file. System Core is changed.

Is it possible to replace only one file “tick_mangmet.c”, or is it necessary to update all files of the operating system to completely solve the problem with the tick suppression mode?

Thank you!

I am not familiar with this specific file but I’d suggest to update all the files as that is tested and known to work. Is it possible for you to update all the files?

Updating all files of the operating system is of course possible, but time-consuming, because I need to compare all the configuration settings. And another important point: in the latest version of FreeRTOS in the demo project to suppress ticks ATSAM4L, the AST(asynchronous timer) is clocked from an external crystal oscillator at 32 kHz, but in old version FreeRTOS - from the internal RC at the same frequency. Do you think this is an important difference or not?

The external crystal is probably more accurate.

I updated OS files and I was surprised that for my ATSAM4L (CortexM4 with MPU) should take port.c and other files from “ARM_CM3” directory, but NOT from “ARM_CM4_MPU”!

  1. What is the reason for this file location?

After update OS to last version I have the same wrong behaviour of my application in TICKLESS_MODE if “configTICK_RATE_HZ = 256”, BUT my application works stable ( means OS does not sleep for a wrong long time = 72 hours ) if “configTICK_RATE_HZ = 128” ( exectly like at DEMO project orginal).

  1. Could you tell me - for the stable operation of the system in the “tickless mode”, how important is this time interval exactly equals 128 and not equaling 256 for “configTICK_RATE_HZ” parameter?

If you aren’t using the MPU, then using the non-MPU version will be smaller and a bit faster. The M3 and the M4 as far as the software is concerned are the same, the M4 just has options for an FPU and an MPU, so if not using them you just use the M3 port.

As Richard mentioned, if you are not using MPU, you should use ARM_CM4F. If you are not using FPU also, you can use ARM_CM3.

I believe you are not using SysTick for tick interrupt - can you check how configTICK_RATE_HZ is used in your ISR configuration and if that can have any impact?

Dear Guarav,
I don’t use SystemTimer and SysTickInterrupt for context switch, but I use Asynchronous Timer of ATSAM4L which clocking from an external 32 kHz generator (AST) and its exeption “Alarm0” for set bit “portNVIC_PENDSVSET_BIT” and hence to calling “PortPendSVHandler” for context switch.

My settings the absolutely the same like on DEMO project:
#define configCREATE_LOW_POWER_DEMO 1

#if configCREATE_LOW_POWER_DEMO == 1
#define configCPU_CLOCK_HZ 16384
#define configSYSTICK_CLOCK_HZ 16384
#define configUSE_TICKLESS_IDLE 1
#define configTICK_RATE_HZ ((os_tick_type_t)128)

/* Calculate how many clock increments make up a single tick period. */
static const uint32_t ulAlarmValueForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );

BUT if I customise #define configTICK_RATE_HZ ((os_tick_type_t)256)
I have the same problem like description in this chat by Richard Barry/jabad06/hilt0n/YanikL
with “negative time” calculation for tickless idle task.

Remark:

  1. I updated and now use the last version FREERTOS
  2. I have not problem with my application when [ use SystemTimer and SysTickInterrupt (#define configCREATE_LOW_POWER_DEMO = 0) ] OR [ #define configCREATE_LOW_POWER_DEMO=1 + configTICK_RATE_HZ = 128) ]
  3. I have to make a reliable and at the same time energy-saving device

As a result I would to know is it strict value configTICK_RATE_HZ =128 setting for LOW_POWER_DEMO or I need looking for error in my application which appears only when configTICK_RATE_HZ = 256.

Thank you!

I do not think that tick frequency should cause this impact. Can you step through the vPortSuppressTicksAndSleep function in both the cases and try to see the difference?

Are you using SAM4L_low_power_tick_management.c? If so, it seems the issue identified above has not been addressed.

Can you try this experiment?

EXISTING CODE:

if( ulTickFlag != pdFALSE )
{
    /* The tick interrupt has already executed, although because this
    function is called with the scheduler suspended the actual tick
    processing will not occur until after this function has exited.
    Reset the alarm value with whatever remains of this tick period. */
    ulAlarmValue = ulAlarmValueForOneTick - ast_read_counter_value( AST );
    ast_write_alarm0_value( AST, ulAlarmValue );

PROPOSED EXPERIMENTAL CODE:

if( ulTickFlag != pdFALSE )
{
    /* The tick interrupt has already executed, although because this
    function is called with the scheduler suspended the actual tick
    processing will not occur until after this function has exited.
    Reset the alarm value with whatever remains of this tick period. */
    ulAlarmValue = ulAlarmValueForOneTick - ast_read_counter_value( AST );
    if( ulAlarmValue > ulAlarmValueForOneTick )   /* LINE ADDED */
    {                                             /* LINE ADDED */
        ulAlarmValue = ulAlarmValueForOneTick;    /* LINE ADDED */
    }                                             /* LINE ADDED */
    ast_write_alarm0_value( AST, ulAlarmValue );

Hello, Jeff! Yes I am using “SAM4L_low_power_tick_management.c”.
And I understood when I had settings #define configTICK_RATE_HZ ((os_tick_type_t)128 ) system never went to sleep because vTaskDelay=10mS for one of my task less then 2 ticks.
As a result I had not problem when system not go to tickless sleep mode :slight_smile:
So I disabled this frequently running task and go into the same problem as before when configTICK_RATE_HZ was 256 - this configASSERT:

    /* Correct the tick count value after a period during which the tick
     * was suppressed.  Note this does *not* call the tick hook function for
     * each stepped tick. */
    configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );

Thank you for your suggest to use PROPOSED EXPERIMENTAL CODE. I will test this and report here about result.

So I use PROPOSED EXPERIMENTAL CODE I have configASSERT like on the picture below.
Is the code demanding on execution time and does not accept additional instructions?