执行 pow(2, ((m - 69.0f) / 12.0f)) 时出现 DeepSleepLo​​ck 下溢错误 - MBed OS

DeepSleepLock underflow error when doing pow(2, ((m - 69.0f) / 12.0f)) - MBed OS

我在 NUCLEO_L432KC 上使用 MBed OS 和 MBed CLI 来编译、刷新和测试。使用 OpenOCD 和 gdb 进行调试。 MBed 有自己的 GreenTea 测试自动化工具,用于对嵌入式硬件进行单元测试,它使用了 utest 和 Unity 测试框架。

当我使用 GreenTea 对这个函数进行单元测试时:

float Piano::midiNumToFrequency(uint8_t m)
{
    float exp = (m - 69.0f) / 12.0f;
    return pow(2, exp);
}

我收到 DeepSleepLo​​ck 下溢错误:

[1589410046.26][CONN][RXD] ++ MbedOS Error Info ++ [1589410046.30][CONN][RXD] Error Status: 0x80040124 Code: 292 Module: 4 [1589410046.35][CONN][RXD] Error Message: DeepSleepLock underflow (< 0) [1589410046.37][CONN][RXD] Location: 0x8003B09 [1589410046.40][CONN][RXD] File: mbed_power_mgmt.c+197 [1589410046.43][CONN][RXD] Error Value: 0xFFFF [1589410046.53][CONN][RXD] Current Thread: main Id: 0x20001200 Entry: 0x80044A7 StackSize: 0x1000 StackMem: 0x20001C18 SP: 0x2000FF04 [1589410046.62][CONN][RXD] For more info, visit: https://mbed.com/s/error?error=0x80040124&tgt=NUCLEO_L432KC [1589410046.64][CONN][RXD] – MbedOS Error Info –

然而,当我将函数更改为:

float Piano::midiNumToFrequency(uint8_t m)
{
    float exp = (m - 69.0f);
    return pow(2, exp);
}

它可以正常工作并测试。

MBed 有一个错误状态解码器 here

Use the "Location" reported to figure out the address of the location which caused the error or try building a non-release version with MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED configuration enabled to capture the filename and line number where this error originates from.

当我启用 MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED 时,它说位置在 mbed_power_mgmt.c 第 197 行,这是函数:

/** Send the microcontroller to sleep
 *
 * @note This function can be a noop if not implemented by the platform.
 * @note This function will be a noop in debug mode (debug build profile when MBED_DEBUG is defined).
 * @note This function will be a noop if the following conditions are met:
 *   - The RTOS is present
 *   - The processor turn off the Systick clock during sleep
 *   - The target does not implement tickless mode
 *
 * The processor is setup ready for sleep, and sent to sleep using __WFI(). In this mode, the
 * system clock to the core is stopped until a reset or an interrupt occurs. This eliminates
 * dynamic power used by the processor, memory systems and buses. The processor, peripheral and
 * memory state are maintained, and the peripherals continue to work and can generate interrupts.
 *
 * The processor can be woken up by any internal peripheral interrupt or external pin interrupt.
 *
 * @note
 *  The mbed interface semihosting is disconnected as part of going to sleep, and can not be restored.
 * Flash re-programming and the USB serial port will remain active, but the mbed program will no longer be
 * able to access the LocalFileSystem
 */
static inline void sleep(void)
{
#if DEVICE_SLEEP
#if (MBED_CONF_RTOS_PRESENT == 0) || (DEVICE_SYSTICK_CLK_OFF_DURING_SLEEP == 0) || defined(MBED_TICKLESS)
    sleep_manager_sleep_auto();
#endif /* (MBED_CONF_RTOS_PRESENT == 0) || (DEVICE_SYSTICK_CLK_OFF_DURING_SLEEP == 0) || defined(MBED_TICKLESS) */
#endif /* DEVICE_SLEEP */
}

知道为什么会发生这种情况或如何进一步排除故障吗?

这部分:

StackSize: 0x1000 
StackMem: 0x20001C18 
SP: 0x2000FF04

建议堆栈指针不再在任务自己的堆栈中。

仅从发布的代码无法真正确定原因,但报告的位置无关紧要;当函数从损坏的堆栈中弹出 return 地址或使用损坏的堆栈指针时,程序计数器可能会在任何地方或任何地方结束。

例如,您的测试线程可能没有足够的堆栈分配,并且溢出已经损坏了其他线程的堆栈或 TCB,然后崩溃。这种行为可能会导致您看到的错误类型,其中指示的代码与错误源无关。然而,这纯粹是推测,还有其他错误机制,例如缓冲区溢出,可能会导致类似的非确定性行为。

需要理解的关键是,仅仅因为修改这个函数似乎影响了结果并不意味着这个函数本身就有问题。