This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Cotex M4 + FreeRTOS -- CPU register cleared after wfi/sleep mode

Hello,

We're currently facing a weird problem with our project and FreeRTOS. I've asked in the FreeRTOS forum (see FreeRTOS Forum post), but within the investigation it seems to me that the problem might be not directly linked with FreeRTOS itself. Please be aware that I'm not an expert in assembly language.

The original problem manifests itself in the program hanging in one of the RTOS asserts on system power up. After some forward and backward (see other thread), my conclusion is that, at boot, when the RTOS uses the sleep function for the first time, one of the CPU registers is cleared without any obvious reason. This leads to the assert further down the chain.
This is the sleep function: (sleep function source code).  This is called in the idle task: idle task source. This is the assert: Tick plausability.
The assert fails because the value of xTickCount is invalid. I've analysed the assembly to the point that at the beginning of the function, CPU reg R7 is set as pointer to xTickCount. This register is then de-referenced later again, to get the tick for the assert. At this point, however, the register contains the value "0", leading to another value being loaded. I've narrowed it down to a few lines after the call to "wfi".

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
volatile uint32_t test5257;
volatile uint32_t test5258;
...
vPortSuppressTicksAndSleep()
...
__asm volatile("mov %0, r7" : "=r" (test5257));
if( xModifiableIdleTime > 0 )
{
__asm volatile ( "dsb" ::: "memory" );
__asm volatile ( "wfi" );
__asm volatile ( "isb" );
}
configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
//don't enable interrupt processing here, just to be sure...
//__asm volatile ( "cpsie i" ::: "memory" ); <-----------------
__asm volatile ("nop" ::: "memory");
__asm volatile ( "dsb" );
__asm volatile ( "isb" ); // <---------------------------------
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

when I pause the target with the debugger and read the values of the variables, "test5257" contains a pointer to xTickCount and "test5258" contains "0". When i patch the second "isb" directly in the binary to a 4 byte "nop", the pointer remains valid and the assertion is gone. I can't see any reason why the value of the register should change as a result of the "isb" instruction.

  • The error occurs only after power-up, not on reset.
  • Adding/removing a line of code in the right spot removes the problem. I haven't found any logic to this. This might be why we haven't seen this problem before now.
  • placing a breakpoint and then starting the target also removes the problem.

I would appreciate any help on understanding what causes this behaviour. As adding/removing code sometimes "fixes" the error, I have no idea how I can check if a change actually fixed the underlying problem...

regards,
Martin

Details for our system:

  • CPU is a Cortex M4F STM32F302CCT
  • FreeRTOS Code base V11.0.1 (FreeRTOS)
  • Custom board
  • custom drivers, not STM Cube
  • toolchain "arm-freertos-eabi-gcc (GNU Tools for ARM Embedded Processors 6-2017-q3-update)" (standard toolchain modified to have thread-save malloc/newlib)
  • optimization "-Os" + link time

This is the full assembly for the function above:

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
prvIdleTask.lto_priv.54:
08000f78: push {r7, lr}
6152 pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
08000f7a: ldr r6, [pc, #576] ; (0x80011bc <prvIdleTask.lto_priv.54+580>)
5881 taskYIELD();
08000f7c: ldr r5, [pc, #576] ; (0x80011c0 <prvIdleTask.lto_priv.54+584>)
6142 while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
08000f7e: ldr r7, [pc, #580] ; (0x80011c4 <prvIdleTask.lto_priv.54+588>)
6154 --uxCurrentNumberOfTasks;
08000f80: ldr.w r8, [pc, #616] ; 0x80011ec <prvIdleTask.lto_priv.54+628>
6142 while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
08000f84: ldr r3, [r7, #0]
08000f86: cbnz r3, 0x8000fd6 <prvIdleTask.lto_priv.54+94>
5879 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) configNUMBER_OF_CORES )
08000f88: ldr r3, [pc, #572] ; (0x80011c8 <prvIdleTask.lto_priv.54+592>)
08000f8a: ldr r3, [r3, #0]
08000f8c: cmp r3, #1
08000f8e: bls.n 0x8000f9e <prvIdleTask.lto_priv.54+38>
5881 taskYIELD();
08000f90: mov.w r3, #268435456 ; 0x10000000
08000f94: str r3, [r5, #0]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

0