[riot-notifications] [RIOT-OS/RIOT] cpu/stm32f1: CPU hangs after wake-up from STOP power mode (#13918)

Juergen Fitschen notifications at github.com
Fri May 8 11:11:18 CEST 2020


> But in case it does: @jue89, could you post the dissassembly of `cortexm_sleep()` in the three cases? This might be just the crucial information needed to understand the issue if it will pop up in the future again.

Sure. `cortexm_sleep()` was in-lined into `pm_set()`. I'm posting this assembly.

<details>
<summary>pm_set() on current master (8ffd34d) still hangs</summary>

```
08000670 <pm_set>:
#define PWR_CR_REG     PWR->CR
#define PWR_WUP_REG    PWR->CSR
#endif

void pm_set(unsigned mode)
{
 8000670:       b510            push    {r4, lr}
    int deep;

    switch (mode) {
 8000672:       b198            cbz     r0, 800069c <pm_set+0x2c>
 8000674:       2801            cmp     r0, #1
 8000676:       d023            beq.n   80006c0 <pm_set+0x50>
            /* Set SLEEPDEEP bit of system control block */
            deep = 1;
            break;
#endif
        default:
            deep = 0;
 8000678:       2400            movs    r4, #0
{
    if (deep) {
        SCB->SCR |=  (SCB_SCR_SLEEPDEEP_Msk);
    }
    else {
        SCB->SCR &= ~(SCB_SCR_SLEEPDEEP_Msk);
 800067a:       4a17            ldr     r2, [pc, #92]   ; (80006d8 <pm_set+0x68>)
 800067c:       6913            ldr     r3, [r2, #16]
 800067e:       f023 0304       bic.w   r3, r3, #4
 8000682:       6113            str     r3, [r2, #16]
    }

    /* ensure that all memory accesses have completed and trigger sleeping */
    unsigned state = irq_disable();
 8000684:       f7ff ffc6       bl      8000614 <irq_disable>
  \details Acts as a special kind of Data Memory Barrier.
           It completes when all explicit memory accesses before this instruction complete.
 */
__STATIC_FORCEINLINE void __DSB(void)
{
  __ASM volatile ("dsb 0xF":::"memory");
 8000688:       f3bf 8f4f       dsb     sy
    __DSB();
    __WFI();
 800068c:       bf30            wfi
#if defined(CPU_MODEL_STM32L152RE)
    /* STM32L152RE crashes if branching to irq_restore(state). See #11830. */
    __set_PRIMASK(state);
#else
    irq_restore(state);
 800068e:       f7ff ffc9       bl      8000624 <irq_restore>
            break;
    }

    cortexm_sleep(deep);

    if (deep) {
 8000692:       b1fc            cbz     r4, 80006d4 <pm_set+0x64>
        /* Re-init clock after STOP */
        stmclk_init_sysclk();
    }
}
 8000694:       e8bd 4010       ldmia.w sp!, {r4, lr}
        stmclk_init_sysclk();
 8000698:       f000 bb6a       b.w     8000d70 <stmclk_init_sysclk>
            PWR_CR_REG &= ~(PM_STOP_CONFIG | PM_STANDBY_CONFIG);
 800069c:       4b0f            ldr     r3, [pc, #60]   ; (80006dc <pm_set+0x6c>)
 800069e:       681a            ldr     r2, [r3, #0]
 80006a0:       f022 020f       bic.w   r2, r2, #15
 80006a4:       601a            str     r2, [r3, #0]
            PWR_CR_REG |= PM_STANDBY_CONFIG;
 80006a6:       681a            ldr     r2, [r3, #0]
 80006a8:       f042 020e       orr.w   r2, r2, #14
 80006ac:       601a            str     r2, [r3, #0]
            PWR_WUP_REG |= PM_EWUP_CONFIG;
 80006ae:       685a            ldr     r2, [r3, #4]
 80006b0:       605a            str     r2, [r3, #4]
        SCB->SCR |=  (SCB_SCR_SLEEPDEEP_Msk);
 80006b2:       4a09            ldr     r2, [pc, #36]   ; (80006d8 <pm_set+0x68>)
 80006b4:       2401            movs    r4, #1
 80006b6:       6913            ldr     r3, [r2, #16]
 80006b8:       f043 0304       orr.w   r3, r3, #4
 80006bc:       6113            str     r3, [r2, #16]
 80006be:       e7e1            b.n     8000684 <pm_set+0x14>
            PWR_CR_REG &= ~(PM_STOP_CONFIG | PM_STANDBY_CONFIG);
 80006c0:       4b06            ldr     r3, [pc, #24]   ; (80006dc <pm_set+0x6c>)
 80006c2:       681a            ldr     r2, [r3, #0]
 80006c4:       f022 020f       bic.w   r2, r2, #15
 80006c8:       601a            str     r2, [r3, #0]
            PWR_CR_REG |= PM_STOP_CONFIG;
 80006ca:       681a            ldr     r2, [r3, #0]
 80006cc:       f042 0201       orr.w   r2, r2, #1
 80006d0:       601a            str     r2, [r3, #0]
    if (deep) {
 80006d2:       e7ee            b.n     80006b2 <pm_set+0x42>
}
 80006d4:       bd10            pop     {r4, pc}
 80006d6:       bf00            nop
 80006d8:       e000ed00        and     lr, r0, r0, lsl #26
 80006dc:       40007000        andmi   r7, r0, r0
```

And `irq_restore()`:
```
08000624 <irq_restore>:
  \details Assigns the given value to the Priority Mask Register.
  \param [in]    priMask  Priority Mask
 */
__STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask)
{
  __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory");
 8000624:       f380 8810       msr     PRIMASK, r0
 * @brief Restore the state of the IRQ flags
 */
void irq_restore(unsigned int state)
{
    __set_PRIMASK(state);
}
 8000628:       4770            bx      lr
```

</details>

<details>
<summary>pm_set() with the modified #ifdef for the in-lined irq_restore() hardfaults</summary>

```
08000670 <pm_set>:
#define PWR_CR_REG     PWR->CR
#define PWR_WUP_REG    PWR->CSR
#endif

void pm_set(unsigned mode)
{
 8000670:       b510            push    {r4, lr}
    int deep;

    switch (mode) {
 8000672:       b198            cbz     r0, 800069c <pm_set+0x2c>
 8000674:       2801            cmp     r0, #1
 8000676:       d023            beq.n   80006c0 <pm_set+0x50>
            /* Set SLEEPDEEP bit of system control block */
            deep = 1;
            break;
#endif
        default:
            deep = 0;
 8000678:       2400            movs    r4, #0
{
    if (deep) {
        SCB->SCR |=  (SCB_SCR_SLEEPDEEP_Msk);
    }
    else {
        SCB->SCR &= ~(SCB_SCR_SLEEPDEEP_Msk);
 800067a:       4a17            ldr     r2, [pc, #92]   ; (80006d8 <pm_set+0x68>)
 800067c:       6913            ldr     r3, [r2, #16]
 800067e:       f023 0304       bic.w   r3, r3, #4
 8000682:       6113            str     r3, [r2, #16]
    }

    /* ensure that all memory accesses have completed and trigger sleeping */
    unsigned state = irq_disable();
 8000684:       f7ff ffc6       bl      8000614 <irq_disable>
  \details Acts as a special kind of Data Memory Barrier.
           It completes when all explicit memory accesses before this instruction complete.
 */
__STATIC_FORCEINLINE void __DSB(void)
{
  __ASM volatile ("dsb 0xF":::"memory");
 8000688:       f3bf 8f4f       dsb     sy
    __DSB();
    __WFI();
 800068c:       bf30            wfi
  __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory");
 800068e:       f380 8810       msr     PRIMASK, r0
            break;
    }

    cortexm_sleep(deep);

    if (deep) {
 8000692:       b1fc            cbz     r4, 80006d4 <pm_set+0x64>
        /* Re-init clock after STOP */
        stmclk_init_sysclk();
    }
}
8000694:       e8bd 4010       ldmia.w sp!, {r4, lr}
        stmclk_init_sysclk();
 8000698:       f000 bb6a       b.w     8000d70 <stmclk_init_sysclk>
            PWR_CR_REG &= ~(PM_STOP_CONFIG | PM_STANDBY_CONFIG);
 800069c:       4b0f            ldr     r3, [pc, #60]   ; (80006dc <pm_set+0x6c>)
 800069e:       681a            ldr     r2, [r3, #0]
 80006a0:       f022 020f       bic.w   r2, r2, #15
 80006a4:       601a            str     r2, [r3, #0]
            PWR_CR_REG |= PM_STANDBY_CONFIG;
 80006a6:       681a            ldr     r2, [r3, #0]
 80006a8:       f042 020e       orr.w   r2, r2, #14
 80006ac:       601a            str     r2, [r3, #0]
            PWR_WUP_REG |= PM_EWUP_CONFIG;
 80006ae:       685a            ldr     r2, [r3, #4]
 80006b0:       605a            str     r2, [r3, #4]
        SCB->SCR |=  (SCB_SCR_SLEEPDEEP_Msk);
 80006b2:       4a09            ldr     r2, [pc, #36]   ; (80006d8 <pm_set+0x68>)
 80006b4:       2401            movs    r4, #1
 80006b6:       6913            ldr     r3, [r2, #16]
 80006b8:       f043 0304       orr.w   r3, r3, #4
 80006bc:       6113            str     r3, [r2, #16]
 80006be:       e7e1            b.n     8000684 <pm_set+0x14>
            PWR_CR_REG &= ~(PM_STOP_CONFIG | PM_STANDBY_CONFIG);
 80006c0:       4b06            ldr     r3, [pc, #24]   ; (80006dc <pm_set+0x6c>)
 80006c2:       681a            ldr     r2, [r3, #0]
 80006c4:       f022 020f       bic.w   r2, r2, #15
 80006c8:       601a            str     r2, [r3, #0]
            PWR_CR_REG |= PM_STOP_CONFIG;
 80006ca:       681a            ldr     r2, [r3, #0]
 80006cc:       f042 0201       orr.w   r2, r2, #1
 80006d0:       601a            str     r2, [r3, #0]
    if (deep) {
 80006d2:       e7ee            b.n     80006b2 <pm_set+0x42>
}
 80006d4:       bd10            pop     {r4, pc}
 80006d6:       bf00            nop
 80006d8:       e000ed00        and     lr, r0, r0, lsl #26
 80006dc:       40007000        andmi   r7, r0, r0
```

</details>

Both differ only at the in-linded `irq_restore()`:

![diff](https://user-images.githubusercontent.com/6105784/81389981-fee7c200-911a-11ea-974b-577bace43a93.png)

<details>
<summary>pm_set() from #13999 still works (HEAD: 9012c6c)</summary>

```
 8000658 <pm_set>:

void pm_set(unsigned mode)
{
    int deep;

    switch (mode) {
 8000658:       b190            cbz     r0, 8000680 <pm_set+0x28>
 800065a:       2801            cmp     r0, #1
 800065c:       d022            beq.n   80006a4 <pm_set+0x4c>
{
    if (deep) {
        SCB->SCR |=  (SCB_SCR_SLEEPDEEP_Msk);
    }
    else {
        SCB->SCR &= ~(SCB_SCR_SLEEPDEEP_Msk);
 800065e:       4a17            ldr     r2, [pc, #92]   ; (80006bc <pm_set+0x64>)
 8000660:       6913            ldr     r3, [r2, #16]
 8000662:       f023 0304       bic.w   r3, r3, #4
 8000666:       6113            str     r3, [r2, #16]
            /* Set SLEEPDEEP bit of system control block */
            deep = 1;
            break;
#endif
        default:
            deep = 0;
 8000668:       2300            movs    r3, #0
  __ASM volatile ("MRS %0, primask" : "=r" (result) :: "memory");
 800066a:       f3ef 8210       mrs     r2, PRIMASK
  __ASM volatile ("cpsid i" : : : "memory");
 800066e:       b672            cpsid   i
  \details Acts as a special kind of Data Memory Barrier.
           It completes when all explicit memory accesses before this instruction complete.
 */
__STATIC_FORCEINLINE void __DSB(void)
{
  __ASM volatile ("dsb 0xF":::"memory");
 8000670:       f3bf 8f4f       dsb     sy
    }

    /* ensure that all memory accesses have completed and trigger sleeping */
    unsigned state = irq_disable();
    __DSB();
    __WFI();
 8000674:       bf30            wfi
  __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory");
 8000676:       f382 8810       msr     PRIMASK, r2
            break;
    }

    cortexm_sleep(deep);

    if (deep) {
 800067a:       b1eb            cbz     r3, 80006b8 <pm_set+0x60>
        /* Re-init clock after STOP */
        stmclk_init_sysclk();
 800067c:       f000 bb60       b.w     8000d40 <stmclk_init_sysclk>
            PWR_CR_REG &= ~(PM_STOP_CONFIG | PM_STANDBY_CONFIG);
 8000680:       4b0f            ldr     r3, [pc, #60]   ; (80006c0 <pm_set+0x68>)
 8000682:       681a            ldr     r2, [r3, #0]
 8000684:       f022 020f       bic.w   r2, r2, #15
 8000688:       601a            str     r2, [r3, #0]
            PWR_CR_REG |= PM_STANDBY_CONFIG;
 800068a:       681a            ldr     r2, [r3, #0]
 800068c:       f042 020e       orr.w   r2, r2, #14
 8000690:       601a            str     r2, [r3, #0]
            PWR_WUP_REG |= PM_EWUP_CONFIG;
 8000692:       685a            ldr     r2, [r3, #4]
 8000694:       605a            str     r2, [r3, #4]
        SCB->SCR |=  (SCB_SCR_SLEEPDEEP_Msk);
 8000696:       4a09            ldr     r2, [pc, #36]   ; (80006bc <pm_set+0x64>)
 8000698:       6913            ldr     r3, [r2, #16]
 800069a:       f043 0304       orr.w   r3, r3, #4
 800069e:       6113            str     r3, [r2, #16]
 80006a0:       2301            movs    r3, #1
 80006a2:       e7e2            b.n     800066a <pm_set+0x12>
            PWR_CR_REG &= ~(PM_STOP_CONFIG | PM_STANDBY_CONFIG);
 80006a4:       4b06            ldr     r3, [pc, #24]   ; (80006c0 <pm_set+0x68>)
 80006a6:       681a            ldr     r2, [r3, #0]
 80006a8:       f022 020f       bic.w   r2, r2, #15
 80006ac:       601a            str     r2, [r3, #0]
            PWR_CR_REG |= PM_STOP_CONFIG;
 80006ae:       681a            ldr     r2, [r3, #0]
 80006b0:       f042 0201       orr.w   r2, r2, #1
 80006b4:       601a            str     r2, [r3, #0]
    if (deep) {
 80006b6:       e7ee            b.n     8000696 <pm_set+0x3e>
    }
}
 80006b8:       4770            bx      lr
 80006ba:       bf00            nop
 80006bc:       e000ed00        and     lr, r0, r0, lsl #26
 80006c0:       40007000        andmi   r7, r0, r0
```

</details>

I hope I caught everything interesting!

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/RIOT-OS/RIOT/issues/13918#issuecomment-625721036
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.riot-os.org/pipermail/notifications/attachments/20200508/04696c6e/attachment-0001.htm>


More information about the notifications mailing list