STM32 RTC 初始化期间超时
STM32 RTC Timeout during initialization
我正在尝试在 STM32F469I-DISCO 板上初始化 RTC。由于我仍在学习,所以我尝试使用 HAL API 来完成一些项目,直到有一天我对这个微控制器有足够的了解,可以直接使用寄存器。
无论如何,我的代码使用 CubeF4 的 STM32F469I-DISCO 模板,允许直接加载 HAL 层和系统时钟(通过 8 MHz HSE 振荡器为 180 MHz)。
为了初始化 RTC,我按照 UM1725 : Description of STM32F4 HAL and LL drivers 中给出的说明进行操作。第 715 页,第 55.2.4 节,您有使用 HAL_RTC API.
的说明
而第一点说有必要启用"RTC Domain Access"。这一点在上一节(55.2.3,同一页)中有解释。
然后我按照要求做了。这是我的代码(经过简化,我只让 RTC Init 部分和系统时钟配置):
#include "main.h"
RTC_HandleTypeDef rtcHandle;
RTC_InitTypeDef rtcInit;
RTC_TimeTypeDef rtcTime;
RTC_DateTypeDef rtcDate;
static void SystemClock_Config(void);
static void Error_Handler(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
////////////////// RTC
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE);
__HAL_RCC_RTC_ENABLE();
rtcInit.HourFormat = RTC_HOURFORMAT_24;
rtcInit.AsynchPrediv = 0x7F;
rtcInit.SynchPrediv = 0xFF;
rtcInit.OutPut = RTC_OUTPUT_DISABLE;
rtcInit.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
rtcInit.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
rtcHandle.Instance = RTC;
rtcHandle.Init = rtcInit;
HAL_RTC_Init(&rtcHandle);
rtcTime.Hours = 12;
rtcTime.Minutes = 30;
rtcTime.Seconds = 40;
rtcDate.WeekDay = RTC_WEEKDAY_WEDNESDAY;
rtcDate.Month = RTC_MONTH_APRIL;
rtcDate.Date = 4;
rtcDate.Year= 17;
HAL_RTC_SetTime(&rtcHandle, &rtcTime, RTC_FORMAT_BCD);
while (1)
{
}
}
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
#if defined(USE_STM32469I_DISCO_REVA)
RCC_OscInitStruct.PLL.PLLM = 25;
#else
RCC_OscInitStruct.PLL.PLLM = 8;
#endif /* USE_STM32469I_DISCO_REVA */
RCC_OscInitStruct.PLL.PLLN = 360;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
RCC_OscInitStruct.PLL.PLLR = 6;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Enable the OverDrive to reach the 180 Mhz Frequency */
if(HAL_PWREx_EnableOverDrive() != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
static void Error_Handler(void)
{
/* User may add here some code to deal with this error */
while(1)
{
}
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
而且它不起作用。在深入研究最低层之后,我设法找到了它不起作用的地方。只是不知道为什么。
HAL_RTC_Init() 调用 returns 一个 HAL_ERROR 状态。此 HAL_ERROR 出现是因为 HAL_RTC_Init() 调用 RTC_EnterInitMode() 并且它 returns 一个 HAL_TIMEOUT 状态,因为在预期时间内未达到条件。以下是功能:
HAL_StatusTypeDef HAL_RTC_Init(RTC_HandleTypeDef *hrtc)
{
/* Check the RTC peripheral state */
if(hrtc == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_RTC_HOUR_FORMAT(hrtc->Init.HourFormat));
assert_param(IS_RTC_ASYNCH_PREDIV(hrtc->Init.AsynchPrediv));
assert_param(IS_RTC_SYNCH_PREDIV(hrtc->Init.SynchPrediv));
assert_param (IS_RTC_OUTPUT(hrtc->Init.OutPut));
assert_param (IS_RTC_OUTPUT_POL(hrtc->Init.OutPutPolarity));
assert_param(IS_RTC_OUTPUT_TYPE(hrtc->Init.OutPutType));
if(hrtc->State == HAL_RTC_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hrtc->Lock = HAL_UNLOCKED;
/* Initialize RTC MSP */
HAL_RTC_MspInit(hrtc);
}
/* Set RTC state */
hrtc->State = HAL_RTC_STATE_BUSY;
/* Disable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);
/* Set Initialization mode */
if(RTC_EnterInitMode(hrtc) != HAL_OK)
{
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
/* Set RTC state */
hrtc->State = HAL_RTC_STATE_ERROR;
return HAL_ERROR;
}
else
{
/* Clear RTC_CR FMT, OSEL and POL Bits */
hrtc->Instance->CR &= ((uint32_t)~(RTC_CR_FMT | RTC_CR_OSEL | RTC_CR_POL));
/* Set RTC_CR register */
hrtc->Instance->CR |= (uint32_t)(hrtc->Init.HourFormat | hrtc->Init.OutPut | hrtc->Init.OutPutPolarity);
/* Configure the RTC PRER */
hrtc->Instance->PRER = (uint32_t)(hrtc->Init.SynchPrediv);
hrtc->Instance->PRER |= (uint32_t)(hrtc->Init.AsynchPrediv << 16U);
/* Exit Initialization mode */
hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT;
hrtc->Instance->TAFCR &= (uint32_t)~RTC_TAFCR_ALARMOUTTYPE;
hrtc->Instance->TAFCR |= (uint32_t)(hrtc->Init.OutPutType);
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
/* Set RTC state */
hrtc->State = HAL_RTC_STATE_READY;
return HAL_OK;
}
}
和:
HAL_StatusTypeDef RTC_EnterInitMode(RTC_HandleTypeDef* hrtc)
{
uint32_t tickstart = 0U;
/* Check if the Initialization mode is set */
if((hrtc->Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
{
/* Set the Initialization mode */
hrtc->Instance->ISR = (uint32_t)RTC_INIT_MASK;
/* Get tick */
tickstart = HAL_GetTick();
/* Wait till RTC is in INIT state and if Time out is reached exit */
while((hrtc->Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
{
if((HAL_GetTick() - tickstart ) > RTC_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
return HAL_OK;
}
所以,如果我仔细调查,问题是条件:
hrtc->Instance->ISR & RTC_ISR_INITF == (uint32_t)RESET 为真
一直(自超时条件出现以来)。我不明白的是根据上面的函数(EnterInitMode),RTC_ISR_INITF和ISR变量似乎定义明确,因此,按位运算值不是0(RESET)。
函数中直接定义了"ISR",即RTC_INIT_MASK(#define with 0xFFFFFFFF value in stm32f4xx_hal_rtc.h)
"RTC_ISR_INITF" 是一个宏:(0x1U << RTC_ISR_INITF_Pos) 其中 RTC_ISR_INITF_Pos 是在 stm32f469xx.h[=14= 中定义的 6U (#define) ]
我说“&”运算不为0是不是错了?
你知道我为什么会出现这个 TIMEOUT 条件吗?
提前致谢!
晚安后我的问题解决了。我忘记在 SystemClock_Config() 例程中初始化 LSE 时钟...我只是在 SystemClock_Config().
中添加以下代码
RCC_OscInitTypeDef RCC_OscInitLSE;
RCC_OscInitLSE.OscillatorType = RCC_OSCILLATORTYPE_LSE;
RCC_OscInitLSE.LSEState = RCC_LSE_ON;
if(HAL_RCC_OscConfig(&RCC_OscInitLSE) != HAL_OK){
Error_Handler();
}
之后我使用 STM Studio 进行了测试,以可视化变量的演变。而且效果很好(以前没有)。
对于给您带来的不便,我们深表歉意。
我正在尝试在 STM32F469I-DISCO 板上初始化 RTC。由于我仍在学习,所以我尝试使用 HAL API 来完成一些项目,直到有一天我对这个微控制器有足够的了解,可以直接使用寄存器。
无论如何,我的代码使用 CubeF4 的 STM32F469I-DISCO 模板,允许直接加载 HAL 层和系统时钟(通过 8 MHz HSE 振荡器为 180 MHz)。
为了初始化 RTC,我按照 UM1725 : Description of STM32F4 HAL and LL drivers 中给出的说明进行操作。第 715 页,第 55.2.4 节,您有使用 HAL_RTC API.
的说明而第一点说有必要启用"RTC Domain Access"。这一点在上一节(55.2.3,同一页)中有解释。
然后我按照要求做了。这是我的代码(经过简化,我只让 RTC Init 部分和系统时钟配置):
#include "main.h"
RTC_HandleTypeDef rtcHandle;
RTC_InitTypeDef rtcInit;
RTC_TimeTypeDef rtcTime;
RTC_DateTypeDef rtcDate;
static void SystemClock_Config(void);
static void Error_Handler(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
////////////////// RTC
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE);
__HAL_RCC_RTC_ENABLE();
rtcInit.HourFormat = RTC_HOURFORMAT_24;
rtcInit.AsynchPrediv = 0x7F;
rtcInit.SynchPrediv = 0xFF;
rtcInit.OutPut = RTC_OUTPUT_DISABLE;
rtcInit.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
rtcInit.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
rtcHandle.Instance = RTC;
rtcHandle.Init = rtcInit;
HAL_RTC_Init(&rtcHandle);
rtcTime.Hours = 12;
rtcTime.Minutes = 30;
rtcTime.Seconds = 40;
rtcDate.WeekDay = RTC_WEEKDAY_WEDNESDAY;
rtcDate.Month = RTC_MONTH_APRIL;
rtcDate.Date = 4;
rtcDate.Year= 17;
HAL_RTC_SetTime(&rtcHandle, &rtcTime, RTC_FORMAT_BCD);
while (1)
{
}
}
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
#if defined(USE_STM32469I_DISCO_REVA)
RCC_OscInitStruct.PLL.PLLM = 25;
#else
RCC_OscInitStruct.PLL.PLLM = 8;
#endif /* USE_STM32469I_DISCO_REVA */
RCC_OscInitStruct.PLL.PLLN = 360;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
RCC_OscInitStruct.PLL.PLLR = 6;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Enable the OverDrive to reach the 180 Mhz Frequency */
if(HAL_PWREx_EnableOverDrive() != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
static void Error_Handler(void)
{
/* User may add here some code to deal with this error */
while(1)
{
}
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
而且它不起作用。在深入研究最低层之后,我设法找到了它不起作用的地方。只是不知道为什么。
HAL_RTC_Init() 调用 returns 一个 HAL_ERROR 状态。此 HAL_ERROR 出现是因为 HAL_RTC_Init() 调用 RTC_EnterInitMode() 并且它 returns 一个 HAL_TIMEOUT 状态,因为在预期时间内未达到条件。以下是功能:
HAL_StatusTypeDef HAL_RTC_Init(RTC_HandleTypeDef *hrtc)
{
/* Check the RTC peripheral state */
if(hrtc == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_RTC_HOUR_FORMAT(hrtc->Init.HourFormat));
assert_param(IS_RTC_ASYNCH_PREDIV(hrtc->Init.AsynchPrediv));
assert_param(IS_RTC_SYNCH_PREDIV(hrtc->Init.SynchPrediv));
assert_param (IS_RTC_OUTPUT(hrtc->Init.OutPut));
assert_param (IS_RTC_OUTPUT_POL(hrtc->Init.OutPutPolarity));
assert_param(IS_RTC_OUTPUT_TYPE(hrtc->Init.OutPutType));
if(hrtc->State == HAL_RTC_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hrtc->Lock = HAL_UNLOCKED;
/* Initialize RTC MSP */
HAL_RTC_MspInit(hrtc);
}
/* Set RTC state */
hrtc->State = HAL_RTC_STATE_BUSY;
/* Disable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);
/* Set Initialization mode */
if(RTC_EnterInitMode(hrtc) != HAL_OK)
{
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
/* Set RTC state */
hrtc->State = HAL_RTC_STATE_ERROR;
return HAL_ERROR;
}
else
{
/* Clear RTC_CR FMT, OSEL and POL Bits */
hrtc->Instance->CR &= ((uint32_t)~(RTC_CR_FMT | RTC_CR_OSEL | RTC_CR_POL));
/* Set RTC_CR register */
hrtc->Instance->CR |= (uint32_t)(hrtc->Init.HourFormat | hrtc->Init.OutPut | hrtc->Init.OutPutPolarity);
/* Configure the RTC PRER */
hrtc->Instance->PRER = (uint32_t)(hrtc->Init.SynchPrediv);
hrtc->Instance->PRER |= (uint32_t)(hrtc->Init.AsynchPrediv << 16U);
/* Exit Initialization mode */
hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT;
hrtc->Instance->TAFCR &= (uint32_t)~RTC_TAFCR_ALARMOUTTYPE;
hrtc->Instance->TAFCR |= (uint32_t)(hrtc->Init.OutPutType);
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
/* Set RTC state */
hrtc->State = HAL_RTC_STATE_READY;
return HAL_OK;
}
}
和:
HAL_StatusTypeDef RTC_EnterInitMode(RTC_HandleTypeDef* hrtc)
{
uint32_t tickstart = 0U;
/* Check if the Initialization mode is set */
if((hrtc->Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
{
/* Set the Initialization mode */
hrtc->Instance->ISR = (uint32_t)RTC_INIT_MASK;
/* Get tick */
tickstart = HAL_GetTick();
/* Wait till RTC is in INIT state and if Time out is reached exit */
while((hrtc->Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
{
if((HAL_GetTick() - tickstart ) > RTC_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
return HAL_OK;
}
所以,如果我仔细调查,问题是条件: hrtc->Instance->ISR & RTC_ISR_INITF == (uint32_t)RESET 为真 一直(自超时条件出现以来)。我不明白的是根据上面的函数(EnterInitMode),RTC_ISR_INITF和ISR变量似乎定义明确,因此,按位运算值不是0(RESET)。
函数中直接定义了"ISR",即RTC_INIT_MASK(#define with 0xFFFFFFFF value in stm32f4xx_hal_rtc.h)
"RTC_ISR_INITF" 是一个宏:(0x1U << RTC_ISR_INITF_Pos) 其中 RTC_ISR_INITF_Pos 是在 stm32f469xx.h[=14= 中定义的 6U (#define) ]
我说“&”运算不为0是不是错了?
你知道我为什么会出现这个 TIMEOUT 条件吗?
提前致谢!
晚安后我的问题解决了。我忘记在 SystemClock_Config() 例程中初始化 LSE 时钟...我只是在 SystemClock_Config().
中添加以下代码RCC_OscInitTypeDef RCC_OscInitLSE;
RCC_OscInitLSE.OscillatorType = RCC_OSCILLATORTYPE_LSE;
RCC_OscInitLSE.LSEState = RCC_LSE_ON;
if(HAL_RCC_OscConfig(&RCC_OscInitLSE) != HAL_OK){
Error_Handler();
}
之后我使用 STM Studio 进行了测试,以可视化变量的演变。而且效果很好(以前没有)。
对于给您带来的不便,我们深表歉意。