我正在使用STM32F427,我想得到最后一次重置的原因.有RCC时钟控制和状态寄存器RCC_CSR有许多复位标志,但我无法获得任何有意义的值.
通过读取该寄存器的值,我只获得0x03,这意味着LSI就绪并且LSI为ON,但是如果我尝试上电,软件复位,低电压等,则不会设置有关复位的标志.我找到了用于获取复位标志的代码片段如下所示,但所有标志仍为0.
if (RCC_GetFlagStatus(RCC_FLAG_SFTRST)) ...
您有什么建议如何获得更好的结果?在读取这些重置标志之前是否需要一些配置?
谢谢
@floppes建议:
启动任何其他外围设备之前,请在启动后尽快读取RCC_CSR。首先初始化系统时钟是安全的(如果使用ST的库,则在SystemInit()中完成)。
现在,要确定确切的重置原因,以下是一项完整的功能可以为您提供帮助。
请注意,所有复位标志都可以在微控制器的“复位和时钟控制器”(RCC)头文件中找到。
例如:“ STM32Cube_FW_F2_V1.7.0 / Drivers / STM32F2xx_HAL_Driver / Inc / stm32f2xx_hal_rcc.h”。
这是__HAL_RCC_GET_FLAG()
从“ stm32f2xx_hal_rcc.h”复制并粘贴的宏及其输入的示例说明。以下功能中使用的所有复位标志均来自此列表:
/ ** @brief检查是否设置了RCC标志。
* @param FLAG指定要检查的标志。
*此参数可以是下列值之一:
* @arg RCC_FLAG_HSIRDY:HSI振荡器时钟准备就绪。
* @arg RCC_FLAG_HSERDY:HSE振荡器时钟准备就绪。
* @arg RCC_FLAG_PLLRDY:主PLL时钟就绪。
* @arg RCC_FLAG_PLLI2SRDY:PLLI2S时钟准备就绪。
* @arg RCC_FLAG_LSERDY:LSE振荡器时钟准备就绪。
* @arg RCC_FLAG_LSIRDY:LSI振荡器时钟准备就绪。
* @arg RCC_FLAG_BORRST:POR / PDR或BOR复位。
* @arg RCC_FLAG_PINRST:引脚复位。
* @arg RCC_FLAG_PORRST:POR / PDR复位。
* @arg RCC_FLAG_SFTRST:软件重置。
* @arg RCC_FLAG_IWDGRST:独立的看门狗复位。
* @arg RCC_FLAG_WWDGRST:窗口看门狗重置。
* @arg RCC_FLAG_LPWRRST:低功耗复位。
* @retval FLAG的新状态(TRUE或FALSE)。
* /
#define RCC_FLAG_MASK ((uint8_t)0x1FU)
#define __HAL_RCC_GET_FLAG(__FLAG__) (((((((__FLAG__) >> 5U) == 1U)? RCC->CR :((((__FLAG__) >> 5U) == 2U) ? RCC->BDCR :((((__FLAG__) >> 5U) == 3U)? RCC->CSR :RCC->CIR))) & ((uint32_t)1U << ((__FLAG__) & RCC_FLAG_MASK)))!= 0U)? 1U : 0U)
/// @brief Possible STM32 system reset causes typedef enum reset_cause_e { RESET_CAUSE_UNKNOWN = 0, RESET_CAUSE_LOW_POWER_RESET, RESET_CAUSE_WINDOW_WATCHDOG_RESET, RESET_CAUSE_INDEPENDENT_WATCHDOG_RESET, RESET_CAUSE_SOFTWARE_RESET, RESET_CAUSE_POWER_ON_POWER_DOWN_RESET, RESET_CAUSE_EXTERNAL_RESET_PIN_RESET, RESET_CAUSE_BROWNOUT_RESET, } reset_cause_t; /// @brief Obtain the STM32 system reset cause /// @param None /// @return The system reset cause reset_cause_t reset_cause_get(void) { reset_cause_t reset_cause; if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST)) { reset_cause = RESET_CAUSE_LOW_POWER_RESET; } else if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST)) { reset_cause = RESET_CAUSE_WINDOW_WATCHDOG_RESET; } else if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) { reset_cause = RESET_CAUSE_INDEPENDENT_WATCHDOG_RESET; } else if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)) { reset_cause = RESET_CAUSE_SOFTWARE_RESET; // This reset is induced by calling the ARM CMSIS `NVIC_SystemReset()` function! } else if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)) { reset_cause = RESET_CAUSE_POWER_ON_POWER_DOWN_RESET; } else if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)) { reset_cause = RESET_CAUSE_EXTERNAL_RESET_PIN_RESET; } // Needs to come *after* checking the `RCC_FLAG_PORRST` flag in order to ensure first that the reset cause is // NOT a POR/PDR reset. See note below. else if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) { reset_cause = RESET_CAUSE_BROWNOUT_RESET; } else { reset_cause = RESET_CAUSE_UNKNOWN; } // Clear all the reset flags or else they will remain set during future resets until system power is fully removed. __HAL_RCC_CLEAR_RESET_FLAGS(); return reset_cause; } // Note: any of the STM32 Hardware Abstraction Layer (HAL) Reset and Clock Controller (RCC) header // files, such as "STM32Cube_FW_F7_V1.12.0/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_rcc.h", // "STM32Cube_FW_F2_V1.7.0/Drivers/STM32F2xx_HAL_Driver/Inc/stm32f2xx_hal_rcc.h", etc., indicate that the // brownout flag, `RCC_FLAG_BORRST`, will be set in the event of a "POR/PDR or BOR reset". This means that a // Power-On Reset (POR), Power-Down Reset (PDR), OR Brownout Reset (BOR) will trip this flag. See the // doxygen just above their definition for the `__HAL_RCC_GET_FLAG()` macro to see this: // "@arg RCC_FLAG_BORRST: POR/PDR or BOR reset." <== indicates the Brownout Reset flag will *also* be set in // the event of a POR/PDR. // Therefore, you must check the Brownout Reset flag, `RCC_FLAG_BORRST`, *after* first checking the // `RCC_FLAG_PORRST` flag in order to ensure first that the reset cause is NOT a POR/PDR reset. /// @brief Obtain the system reset cause as an ASCII-printable name string from a reset cause type /// @param[in] reset_cause The previously-obtained system reset cause /// @return A null-terminated ASCII name string describing the system reset cause const char * reset_cause_get_name(reset_cause_t reset_cause) { const char * reset_cause_name = "TBD"; switch (reset_cause) { case RESET_CAUSE_UNKNOWN: reset_cause_name = "UNKNOWN"; break; case RESET_CAUSE_LOW_POWER_RESET: reset_cause_name = "LOW_POWER_RESET"; break; case RESET_CAUSE_WINDOW_WATCHDOG_RESET: reset_cause_name = "WINDOW_WATCHDOG_RESET"; break; case RESET_CAUSE_INDEPENDENT_WATCHDOG_RESET: reset_cause_name = "INDEPENDENT_WATCHDOG_RESET"; break; case RESET_CAUSE_SOFTWARE_RESET: reset_cause_name = "SOFTWARE_RESET"; break; case RESET_CAUSE_POWER_ON_POWER_DOWN_RESET: reset_cause_name = "POWER-ON_RESET (POR) / POWER-DOWN_RESET (PDR)"; break; case RESET_CAUSE_EXTERNAL_RESET_PIN_RESET: reset_cause_name = "EXTERNAL_RESET_PIN_RESET"; break; case RESET_CAUSE_BROWNOUT_RESET: reset_cause_name = "BROWNOUT_RESET (BOR)"; break; } return reset_cause_name; }
reset_cause_t reset_cause = reset_cause_get(); printf("The system reset cause is \"%s\"\n", reset_cause_get_name(reset_cause));
输出:
系统重置原因为“ INDEPENDENT_WATCHDOG_RESET”
当然,如果您打算不仅仅打印输出,还可以将上述函数的返回值转换为枚举而不是C字符串。
编辑2019年10月26日:刚刚添加了枚举和单独的函数以从重置类型获取可打印的字符串!现在,如果只需要枚举重置类型而不必打印名称,则不必在程序空间中存储所有这些重置字符串名称,从而节省了大量闪存空间!我还为函数添加了doxygen标头,因为看到基本代码文档的好示例总是很高兴。