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".

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" ); // <---------------------------------

        __asm volatile("mov %0, r7" : "=r" (test5258));
        
...

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:

          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]
08000f96:   dsb     sy
08000f9a:   isb     sy
 68         wdt_trigger(wdt_idle_reference);
08000f9e:   ldr     r3, [pc, #556]  ; (0x80011cc <prvIdleTask.lto_priv.54+596>)
08000fa0:   ldrb    r0, [r3, #0]
08000fa2:   bl      0x8000f68 <wdt_trigger>
202         wdt_states[reference] = WDT_STATE_ALIVE;
08000fa6:   bl      0x80002c8 <prvGetExpectedIdleTime>
5912                  if( xExpectedIdleTime >= ( TickType_t ) configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
08000faa:   cmp     r0, #1
08000fac:   bls.n   0x8000f7e <prvIdleTask.lto_priv.54+6>
5920                          test3261 = xTickCount;
08000fae:   ldr     r7, [pc, #544]  ; (0x80011d0 <prvIdleTask.lto_priv.54+600>)
5914                      vTaskSuspendAll();
08000fb0:   bl      0x8000bd4 <vTaskSuspendAll>
5920                          test3261 = xTickCount;
08000fb4:   ldr     r3, [pc, #540]  ; (0x80011d4 <prvIdleTask.lto_priv.54+604>)
08000fb6:   ldr     r2, [r7, #0]
5923                          configASSERT( xNextTaskUnblockTime >= test3261 );
08000fb8:   ldr     r1, [pc, #540]  ; (0x80011d8 <prvIdleTask.lto_priv.54+608>)
5920                          test3261 = xTickCount;
08000fba:   str     r2, [r3, #0]
08000fbc:   ldr     r2, [r1, #0]
08000fbe:   ldr     r3, [r3, #0]
08000fc0:   cmp     r2, r3
08000fc2:   bcs.n   0x800100e <prvIdleTask.lto_priv.54+150>
217           __asm volatile
08000fc4:   mov.w   r3, #80 ; 0x50
08000fc8:   msr     BASEPRI, r3
08000fcc:   isb     sy
08000fd0:   dsb     sy
08000fd4:   b.n     0x8000fd4 <prvIdleTask.lto_priv.54+92>
6146                      taskENTER_CRITICAL();
08000fd6:   bl      0x80013e8 <vPortEnterCritical>
6152                              pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
08000fda:   ldr     r3, [r6, #12]
08000fdc:   ldr     r4, [r3, #12]
6153                              ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
08000fde:   adds    r0, r4, #4
08000fe0:   bl      0x80023ac <uxListRemove>
6154                              --uxCurrentNumberOfTasks;
08000fe4:   ldr.w   r3, [r8]
08000fe8:   subs    r3, #1
08000fea:   str.w   r3, [r8]
6158                              --uxDeletedTasksWaitingCleanUp;
08000fee:   ldr     r3, [r7, #0]
08000ff0:   subs    r3, #1
08000ff2:   str     r3, [r7, #0]
6163                      taskEXIT_CRITICAL();
08000ff4:   bl      0x80013c0 <vPortExitCritical>
6506                  configDEINIT_TLS_BLOCK( pxTCB->xTLSBlock );
08000ff8:   add.w   r0, r4, #72     ; 0x48
08000ffc:   bl      0x8002760 <_reclaim_reent>
6514                  vPortFreeStack( pxTCB->pxStack );
08001000:   ldr     r0, [r4, #48]   ; 0x30
08001002:   bl      0x8001338 <vPortFree>
6515                  vPortFree( pxTCB );
08001006:   mov     r0, r4
08001008:   bl      0x8001338 <vPortFree>
0800100c:   b.n     0x8000f84 <prvIdleTask.lto_priv.54+12>
5927                          xExpectedIdleTime = prvGetExpectedIdleTime();
0800100e:   bl      0x80002c8 <prvGetExpectedIdleTime>
5934                          if( xExpectedIdleTime >= ( TickType_t ) configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
08001012:   cmp     r0, #1
08001014:   bls.w   0x80011b6 <prvIdleTask.lto_priv.54+574>
......... ...
08001019:   ldr     r3, [pc, #448]  ; (0x80011dc <prvIdleTask.lto_priv.54+612>)
0800101b:   ldr     r3, [r3, #0]
0800101d:   cpsid   i
0800101f:   dsb     sy
.........   isb     sy
5986              if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0U )
08001026:   ldr     r2, [pc, #440]  ; (0x80011e0 <prvIdleTask.lto_priv.54+616>)
08001028:   ldr     r2, [r2, #0]
0800102a:   cmp     r2, #0
0800102c:   bne.w   0x80011b4 <prvIdleTask.lto_priv.54+572>
5991              else if( xYieldPendings[ portGET_CORE_ID() ] != pdFALSE )
08001030:   ldr     r2, [pc, #432]  ; (0x80011e4 <prvIdleTask.lto_priv.54+620>)
08001032:   ldr     r2, [r2, #0]
08001034:   cmp     r2, #0
08001036:   bne.w   0x80011b4 <prvIdleTask.lto_priv.54+572>
5996              else if( xPendedTicks != 0U )
0800103a:   ldr.w   r8, [pc, #464]  ; 0x800120c <prvIdleTask.lto_priv.54+660>
0800103e:   ldr.w   r2, [r8]
08001042:   cmp     r2, #0
08001044:   bne.w   0x80011b4 <prvIdleTask.lto_priv.54+572>
6004                  else if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
08001048:   ldr     r2, [pc, #412]  ; (0x80011e8 <prvIdleTask.lto_priv.54+624>)
0800104a:   ldr.w   lr, [pc, #452]  ; 0x8001210 <prvIdleTask.lto_priv.54+664>
0800104e:   ldr     r2, [r2, #0]
08001050:   ldr     r2, [pc, #408]  ; (0x80011ec <prvIdleTask.lto_priv.54+628>)
08001052:   ldr     r2, [r2, #0]
629                   portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT );
08001054:   ldr     r2, [pc, #408]  ; (0x80011f0 <prvIdleTask.lto_priv.54+632>)
08001056:   movs    r4, #6
08001058:   str     r4, [r2, #0]
636                   ulSysTickDecrementsLeft = portNVIC_SYSTICK_CURRENT_VALUE_REG;
0800105a:   adds    r2, #8
0800105c:   ldr     r2, [r2, #0]
638                   if( ulSysTickDecrementsLeft == 0 )
0800105e:   cbnz    r2, 0x8001064 <prvIdleTask.lto_priv.54+236>
640                       ulSysTickDecrementsLeft = ulTimerCountsForOneTick;
08001060:   ldr.w   r2, [lr]
08001064:   cmp     r0, r3
08001066:   it      cs
08001068:   movcs   r0, r3
649                   ulReloadValue = ulSysTickDecrementsLeft + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
0800106a:   ldr.w   r3, [lr]
0800106e:   subs    r4, r0, #1
08001070:   mla     r12, r3, r4, r2
651                   if( ( portNVIC_INT_CTRL_REG & portNVIC_PEND_SYSTICK_SET_BIT ) != 0 )
08001074:   ldr     r3, [r5, #0]
08001076:   lsls    r3, r3, #5
653                       portNVIC_INT_CTRL_REG = portNVIC_PEND_SYSTICK_CLEAR_BIT;
08001078:   itttt   mi
0800107a:   movmi.w r3, #33554432   ; 0x2000000
0800107e:   strmi   r3, [r5, #0]
654                       ulReloadValue -= ulTimerCountsForOneTick;
08001080:   ldrmi.w r2, [lr]
08001084:   submi.w r12, r12, r2
657                   if( ulReloadValue > ulStoppedTimerCompensation )
08001088:   ldr     r2, [pc, #360]  ; (0x80011f4 <prvIdleTask.lto_priv.54+636>)
0800108a:   ldr     r3, [r2, #0]
0800108c:   cmp     r3, r12
659                       ulReloadValue -= ulStoppedTimerCompensation;
0800108e:   it      cc
08001090:   subcc.w r12, r12, r3
663                   portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
08001094:   ldr     r3, [pc, #352]  ; (0x80011f8 <prvIdleTask.lto_priv.54+640>)
667                   portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
08001096:   mov.w   r9, #0
663                   portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
0800109a:   str.w   r12, [r3]
667                   portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
0800109e:   str.w   r9, [r3, #4]
670                   portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
080010a2:   ldr.w   r9, [pc, #332]  ; 0x80011f0 <prvIdleTask.lto_priv.54+632>
080010a6:   ldr.w   r3, [r9]
080010aa:   orr.w   r3, r3, #1
080010ae:   str.w   r3, [r9]
680                   __asm volatile("mov %0, r7" : "=r" (test5257));
080010b2:   mov     r3, r7
080010b4:   ldr.w   r9, [pc, #348]  ; 0x8001214 <prvIdleTask.lto_priv.54+668>
080010b8:   str.w   r3, [r9]
681                   if( xModifiableIdleTime > 0 )
080010bc:   cbz     r0, 0x80010c8 <prvIdleTask.lto_priv.54+336>
683                       __asm volatile ( "dsb" ::: "memory" );
080010be:   dsb     sy
684                       __asm volatile ( "wfi" );
080010c2:   wfi     
685                       __asm volatile ( "isb" );
080010c4:   isb     sy
695                   __asm volatile ("nop" ::: "memory");
080010c8:   nop     
696                   __asm volatile ( "dsb" );

---------------->

080010ca:   dsb     sy
705                   __asm volatile ( "isb" );
080010ce:   isb     sy
715                   __asm volatile("mov %0, r7" : "=r" (test5258));

<----------------

080010d2:   mov     r3, r7
080010d4:   ldr.w   r9, [pc, #320]  ; 0x8001218 <prvIdleTask.lto_priv.54+672>
080010d8:   str.w   r3, [r9]
722                   __asm volatile ( "cpsid i" ::: "memory" );
080010dc:   cpsid   i
723                   __asm volatile ( "dsb" );
080010de:   dsb     sy
724                   __asm volatile ( "isb" );
080010e2:   isb     sy
733                   portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT );
080010e6:   ldr     r3, [pc, #264]  ; (0x80011f0 <prvIdleTask.lto_priv.54+632>)
080010e8:   mov.w   r9, #6
080010ec:   str.w   r9, [r3]
736                   if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
080010f0:   ldr     r3, [r3, #0]
080010f2:   tst.w   r3, #65536      ; 0x10000
080010f6:   ldr     r3, [pc, #260]  ; (0x80011fc <prvIdleTask.lto_priv.54+644>)
080010f8:   beq.n   0x8001152 <prvIdleTask.lto_priv.54+474>
743                       ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
080010fa:   ldr.w   r0, [lr]
080010fe:   ldr     r3, [r3, #0]
749                       if( ( ulCalculatedLoadValue <= ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
08001100:   ldr     r2, [r2, #0]
743                       ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
08001102:   add     r3, r0
08001104:   subs    r3, #1
08001106:   sub.w   r3, r3, r12
749                       if( ( ulCalculatedLoadValue <= ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
0800110a:   cmp     r3, r2
0800110c:   bls.n   0x8001112 <prvIdleTask.lto_priv.54+410>
0800110e:   cmp     r0, r3
08001110:   bcs.n   0x8001114 <prvIdleTask.lto_priv.54+412>
751                           ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
08001112:   subs    r3, r0, #1
794                       portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
08001114:   ldr     r2, [pc, #224]  ; (0x80011f8 <prvIdleTask.lto_priv.54+640>)
08001116:   str     r3, [r2, #0]
804                   portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
08001118:   ldr     r3, [pc, #224]  ; (0x80011fc <prvIdleTask.lto_priv.54+644>)
0800111a:   movs    r2, #0
0800111c:   str     r2, [r3, #0]
805                   portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
0800111e:   movs    r2, #7
08001120:   str.w   r2, [r3, #-8]
808                       portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
08001124:   ldr.w   r3, [lr]
08001128:   ldr     r2, [pc, #204]  ; (0x80011f8 <prvIdleTask.lto_priv.54+640>)
0800112a:   subs    r3, #1
0800112c:   str     r3, [r2, #0]
4583              xUpdatedTickCount = test3257 + test3258;
0800112e:   ldr     r3, [pc, #208]  ; (0x8001200 <prvIdleTask.lto_priv.54+648>)
08001130:   ldr     r3, [r3, #0]
08001132:   ldr     r3, [pc, #208]  ; (0x8001204 <prvIdleTask.lto_priv.54+652>)
08001134:   ldr     r3, [r3, #0]
4584              xUpdatedTickCount = xTickCount + xTicksToJump;
08001136:   ldr     r3, [r7, #0]
4588              configASSERT( xUpdatedTickCount <= xNextTaskUnblockTime );
08001138:   ldr     r2, [r1, #0]
4584              xUpdatedTickCount = xTickCount + xTicksToJump;
0800113a:   add     r3, r4
4588              configASSERT( xUpdatedTickCount <= xNextTaskUnblockTime );
0800113c:   cmp     r3, r2
0800113e:   bls.n   0x8001168 <prvIdleTask.lto_priv.54+496>
08001140:   mov.w   r3, #80 ; 0x50
08001144:   msr     BASEPRI, r3
08001148:   isb     sy
0800114c:   dsb     sy
08001150:   b.n     0x8001150 <prvIdleTask.lto_priv.54+472>
08001152:   ldr     r2, [r3, #0]
08001154:   ldr.w   r3, [lr]
08001158:   muls    r0, r3
0800115a:   subs    r0, r0, r2
0800115c:   udiv    r4, r0, r3
08001160:   mla     r3, r4, r3, r3
08001164:   subs    r3, r3, r0
08001166:   b.n     0x8001114 <prvIdleTask.lto_priv.54+412>
08001168:   ldr     r2, [r1, #0]
0800116a:   cmp     r3, r2
0800116c:   bne.n   0x80011ae <prvIdleTask.lto_priv.54+566>
0800116e:   ldr     r3, [pc, #152]  ; (0x8001208 <prvIdleTask.lto_priv.54+656>)
08001170:   ldr     r3, [r3, #0]
08001172:   cbnz    r3, 0x8001186 <prvIdleTask.lto_priv.54+526>
08001174:   mov.w   r3, #80 ; 0x50
08001178:   msr     BASEPRI, r3
0800117c:   isb     sy
08001180:   dsb     sy
08001184:   b.n     0x8001184 <prvIdleTask.lto_priv.54+524>
4596                  configASSERT( xTicksToJump != ( TickType_t ) 0 );
08001186:   cbnz    r4, 0x800119a <prvIdleTask.lto_priv.54+546>
08001188:   mov.w   r3, #80 ; 0x50
0800118c:   msr     BASEPRI, r3
08001190:   isb     sy
08001194:   dsb     sy
08001198:   b.n     0x8001198 <prvIdleTask.lto_priv.54+544>
0800119a:   bl      0x80013e8 <vPortEnterCritical>
4601                      xPendedTicks++;
0800119e:   ldr.w   r3, [r8]
080011a2:   adds    r3, #1
080011a4:   str.w   r3, [r8]
4603                  taskEXIT_CRITICAL();
080011a8:   bl      0x80013c0 <vPortExitCritical>
4604                  xTicksToJump--;
080011ac:   subs    r4, #1
4614              xTickCount += xTicksToJump;
080011ae:   ldr     r3, [r7, #0]
080011b0:   add     r4, r3
080011b2:   str     r4, [r7, #0]
832                   __asm volatile ( "cpsie i" ::: "memory" );
080011b4:   cpsie   i
5945                      ( void ) xTaskResumeAll();
080011b6:   bl      0x8000a90 <xTaskResumeAll>
080011ba:   b.n     0x8000f7e <prvIdleTask.lto_priv.54+6>
080011bc:   lsls    r4, r1, #5
080011be:   movs    r0, #0
080011c0:   stc     0, cr14, [r4, #-0]
080011c4:   lsls    r0, r0, #3
080011c6:   movs    r0, #0
080011c8:   lsls    r0, r7, #6
080011ca:   movs    r0, #0
080011cc:   lsls    r0, r7, #5
080011ce:   movs    r0, #0
080011d0:   lsls    r4, r2, #12
080011d2:   movs    r0, #0
080011d4:   movs    r4, r2
080011d6:   movs    r0, #0
080011d8:   lsls    r4, r2, #6
080011da:   movs    r0, #0
080011dc:   lsls    r0, r2, #6
080011de:   movs    r0, #0
080011e0:   lsls    r4, r4, #4
080011e2:   movs    r0, #0
080011e4:   lsls    r0, r3, #12
080011e6:   movs    r0, #0
080011e8:   lsls    r0, r7, #4
080011ea:   movs    r0, #0
080011ec:   lsls    r0, r6, #12
080011ee:   movs    r0, #0
080011f0:   b.n     0x8001214 <prvIdleTask.lto_priv.54+668>
080011f2:   b.n     0x80011f6 <prvIdleTask.lto_priv.54+638>
080011f4:   lsls    r0, r6, #5
080011f6:   movs    r0, #0
080011f8:   b.n     0x8001224 <PendSV_Handler+4>
080011fa:   b.n     0x80011fe <prvIdleTask.lto_priv.54+646>
080011fc:   b.n     0x8001230 <PendSV_Handler+16>
080011fe:   b.n     0x8001202 <prvIdleTask.lto_priv.54+650>
08001200:   movs    r4, r1
08001202:   movs    r0, #0
08001204:   movs    r0, r2
08001206:   movs    r0, #0
08001208:   lsls    r4, r0, #3
0800120a:   movs    r0, #0
0800120c:   lsls    r0, r4, #4
0800120e:   movs    r0, #0
08001210:   lsls    r4, r6, #5
08001212:   movs    r0, #0
08001214:   movs    r0, r3
08001216:   movs    r0, #0
08001218:   movs    r4, r3
0800121a:   movs    r0, #0
0800121c:   movs    r0, r0
0800121e:   movs    r0, r0