你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32L151 stop模式 rtc 闹钟唤醒不稳定

[复制链接]
firstwangjin 提问时间:2018-5-22 20:47 /
本帖最后由 firstwangjin 于 2018-5-24 11:26 编辑

1.芯片 stm32l151CBT6

2.使用 cubemx 生成的框架代码。

芯片工作一会儿进入 stop模式,到某个时刻点闹钟唤醒。发现经常有设备到闹钟点没有醒来。


//时钟B 延时minutes后唤醒
void setMinuteDelayAlarmB(RTC_TimeTypeDef sTime,uint8_t minutes)
{   
  ...
  if(HAL_RTC_SetAlarm_IT(&hrtc,&sAlarm,RTC_FORMAT_BIN) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }   
  HAL_NVIC_SetPriority(RTC_Alarm_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
}


//rtc 中断许可

  HAL_NVIC_SetPriority(RTC_Alarm_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);



上面是我写的alarm 设置唤醒,关于alarm 事件的配置省略了。

HAL_RTC_SetAlarm_IT 是库函数,

就可以完成 ALARM 对STOP模式的唤醒。

目前的问题是,有时候alarm 唤醒会失效


详细如下
1.Rtc 使用外部时钟

void SystemClock_Config(void)
{

RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInit;


   __HAL_RCC_PWR_CLK_ENABLE();
    /**Configure the main internal regulator output voltage
    */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);


    /**Initializes the CPU, AHB and APB busses clocks
    */
//RCC_OSCILLATORTYPE_HSI 是為了ADC 使用
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = 0;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_5;

RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
    _Error_Handler(__FILE__, __LINE__);
}


    /**Initializes the CPU, AHB and APB busses clocks
    */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;


if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
    _Error_Handler(__FILE__, __LINE__);
}


PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
    _Error_Handler(__FILE__, __LINE__);
}


    /**Configure the Systick interrupt time
    */
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);


    /**Configure the Systick
    */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);


/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}



* RTC init function */
static void MX_RTC_Init(void)
{
__HAL_RCC_PWR_CLK_ENABLE();

RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
RTC_AlarmTypeDef sAlarm;


    /**Initialize RTC Only
    */
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
    _Error_Handler(__FILE__, __LINE__);
}

    /**Initialize RTC and set the Time and Date
    */
if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0) != 0x32F2)
{
sTime.Hours = 19;
sTime.Minutes = 34;
sTime.Seconds = 30;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
{
    _Error_Handler(__FILE__, __LINE__);
}


sDate.WeekDay = 1;
sDate.Month = 4;
sDate.Date = 25;
sDate.Year = 18;


if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
{
    _Error_Handler(__FILE__, __LINE__);
}


    HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,0x32F2);
}

/**Enable the WakeUp
    */
if (HAL_RTCEx_SetWakeUpTimer(&hrtc, 0, RTC_WAKEUPCLOCK_RTCCLK_DIV16) != HAL_OK)
{
    _Error_Handler(__FILE__, __LINE__);
}

}


2.每隔3分钟调用下面函数,设定新的timer Wakeup 用来切换工作

void setMinuteAlarmA(RTC_TimeTypeDef sTime,uint8_t minuteInterval)
{
    /**Enable the Alarm A
*/

RTC_AlarmTypeDef sAlarm;
sAlarm.AlarmTime = sTime;
sAlarm.AlarmTime.Seconds = 10;


uint8_t minuteMaxBit = (60/minuteInterval) - 1;
//设置分钟
uint8_t minuteBit = sAlarm.AlarmTime.Minutes/minuteInterval;
if(minuteBit == minuteMaxBit)
{
    sAlarm.AlarmTime.Minutes = 0;
   
    //考虑小时位升级
    if(sAlarm.AlarmTime.Hours ==23) //23点后是0点
    {
      sAlarm.AlarmTime.Hours = 0;
    }
    else//否则小时位进1
    {
       sAlarm.AlarmTime.Hours++;
    }
}
else
{
    minuteBit++;
    sAlarm.AlarmTime.Minutes = minuteBit*minuteInterval;
}


sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_WEEKDAY;
sAlarm.AlarmDateWeekDay = 1;
sAlarm.Alarm = RTC_ALARM_A;
if(HAL_RTC_SetAlarm_IT(&hrtc,&sAlarm,RTC_FORMAT_BIN) != HAL_OK)
{
    /* Initialization Error */
    Error_Handler();
}

HAL_NVIC_SetPriority(RTC_Alarm_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
}


void enterSotpMode()
{
  GPIO_InitTypeDef GPIO_InitStruct;
  
  __HAL_RCC_PWR_CLK_ENABLE();    /* Enable Power Control clock */
  HAL_PWREx_EnableUltraLowPower();  /* Enable Ultra low power mode */
  HAL_PWREx_EnableFastWakeUp(); /* Enable the fast wake up from Ultra low power mode */   
  
  SX1278LoRaSetOpMode( RFLR_OPMODE_SLEEP );
  
  GPIO_InitStruct.Pin = 0xF9ff;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);  

  GPIO_InitStruct.Pin = GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);  
  
  //d
  GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_8;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  //  
  //GPIO_InitStruct.Pin = 0xFfFf;
  GPIO_InitStruct.Pin = 0xFf3f;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  //PBOOT0 低电平
  GPIO_InitStruct.Pin = GPIO_PIN_4;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  

  GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


  GPIO_InitStruct.Pin = GPIO_PIN_All;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
  
  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
  
  
  
  //20180515
    /*Configure GPIO pin : PA8 */
  GPIO_InitStruct.Pin = GPIO_PIN_8;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF0_MCO;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  
  //__HAL_RCC_GPIOA_CLK_DISABLE();
  __HAL_RCC_GPIOB_CLK_DISABLE();  
  //__HAL_RCC_GPIOC_CLK_DISABLE();  
  __HAL_RCC_GPIOH_CLK_DISABLE();
  

  HAL_PWREx_EnableUltraLowPower();
  HAL_PWREx_EnableFastWakeUp();
  HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
  
  SystemClock_Config();
  MX_GPIO_Init();
  HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
  SX1278LoraInit();  
  
}



收藏 评论22 发布时间:2018-5-22 20:47

举报

22个回答
firstwangjin 回答时间:2018-5-31 10:39:58
xmshao 发表于 2018-5-28 17:35
你说的有时唤不醒是所有板都 这样吗? 另外,所谓不唤醒发生后,后续是否一直不再唤醒? 如果说只是偶尔不 ...

你好! 唤醒失败的板子,后续一直睡眠,除非用外部中断触发。 这种现象的板子,具有随机和普遍性。
我采用喂狗后,唤不醒就重启了。这是个问题啊
下面是昨天运行的一段日志:

time now :19时43分04秒  HAL_IWDG_Refresh !      //喂狗时刻
Rset B :Send data DelayTimeout Time:19时43分24秒 // 设置alarmB 用来唤醒喂狗,设置完成后立即进入stop模式


Client Mode VERSION 1.30..  //设备又一次重启,重启后立即喂狗 ,查看下面的时刻是 19时43分31秒,alarmB并没有醒来喂狗,导致超时
time now :19时43分31秒  HAL_IWDG_Refresh !
time now :19时43分31秒  ThreadClientOnlineRequest delaytime .... randDelay = 939 sum =21
Rset B :Send data DelayTimeout Time:19时43分52秒
firstwangjin 回答时间:2018-6-1 10:25:06
ALL: 昨天我把唤醒改成wakeup唤醒,目前的话一切正常。 由于唤醒的时间间隔大,顾只能选用1hz的clock。
HAL_RTCEx_SetWakeUpTimer_IT 函数直接设定:
该函数下有 IS_RTC_WAKEUP_COUNTER(COUNTER)  ((COUNTER) <= 0xFFFF) ,虽然counter 值是uint32_t,但是不能超过65535,刚开始我 使用RTC_WAKEUPCLOCK_RTCCLK_DIV16 . CLOCK 为 32.768k 16分频,这样的话 2048 个计数值才代表1s,计数器范围不够使用。后来只能用1hz 时钟。
不知道1hz 时钟的精度如何?    RTC_WAKEUPCLOCK_CK_SPRE_17BITS 这个值的真正含义又是什么,和RTC_WAKEUPCLOCK_CK_SPRE_16BITS (1hz)相比,使用起来又有和区别?
firstwangjin 回答时间:2018-5-23 15:32:26
安 发表于 2018-5-23 14:21
可能是因为你算法的问题,楼主计算完时间后,最好打印一下,是否是得到的时间。下面这句话我不是很理解:
u ...

解释一下:
1.设置时间的格式 我选择的是RTC_FORMAT_BIN ,所以分钟和秒数 值范围 0-59 ,小时数是 0-23
2.现在假设我需要每隔 minuteInterval(假设是10) 时刻进行唤醒,  比如现在时刻是 15:13分,按此间隔,我需要在 15:20 15:30 ....16:00 ....这些时刻唤醒。
按10分钟间隔算,一小时有 6次,比如15:00 ,15:10 , 15:20,15:30,15:40,15:50   (次数可以看成是 0-5,最大数是5),这里的minuteMaxBit 就是最大次数,到了最大次数,下一次唤醒 分钟位就设为0,时钟位需要进位了
feixiang20 回答时间:2018-5-23 00:56:57
可能是PWR之WakeUp的问题,可参考代码资料【使用RTC闹钟,从待机模式唤醒的问题】

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

firstwangjin 回答时间:2018-5-23 10:06:54
feixiang20 发表于 2018-5-23 00:56
可能是PWR之WakeUp的问题,可参考代码资料【使用RTC闹钟,从待机模式唤醒的问题】 ...

感谢你的回复。 我看了你说的帖子,我的问题与帖子中的有差别。我这边 stop 模式用的是 rtc 闹钟唤醒。
通过HAL_RTC_SetAlarm_IT 函数设定醒来的时刻,并没有使用wakeup 。目前就是有时候醒不来
废鱼 回答时间:2018-5-23 10:35:27
楼主,建议加个可以通过外部唤醒的,如果唤醒不的情况下,外部唤醒后,看一下时钟是否已经停止,看一下真实的时钟。

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

firstwangjin 回答时间:2018-5-23 11:10:22
安 发表于 2018-5-23 10:35
楼主,建议加个可以通过外部唤醒的,如果唤醒不的情况下,外部唤醒后,看一下时钟是否已经停止,看一下真实 ...

感谢回复。
1.我配置了RCC_MCO引脚,针对无法唤醒的板子,查看时钟,发现时钟正常
2.和你说的一样,用外部中断触发一下,发现程序可以触发醒来,且逻辑正确。
废鱼 回答时间:2018-5-23 11:42:22
如果时钟正常,那就看一下时钟alarm寄存器是否是正确的。是否因为设置错误导致未唤醒。
firstwangjin 回答时间:2018-5-23 12:33:50
配置好 rtc后,alarm通过库函数 HAL_RTC_SetAlarm_IT 设定,寄存器操作由库函数替代了
废鱼 回答时间:2018-5-23 14:21:44
可能是因为你算法的问题,楼主计算完时间后,最好打印一下,是否是得到的时间。下面这句话我不是很理解:
uint8_t minuteMaxBit = (60/minuteInterval) - 1;
废鱼 回答时间:2018-5-23 17:14:09
嗯。怀疑还是算法算错时间的问题,楼主可以加个打印,打印一下每次得到的唤醒时间,看一下每次不能唤醒的时候,alarm设置的时刻。

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

firstwangjin 回答时间:2018-5-24 09:58:07
本帖最后由 firstwangjin 于 2018-5-24 10:20 编辑
安 发表于 2018-5-23 17:14
嗯。怀疑还是算法算错时间的问题,楼主可以加个打印,打印一下每次得到的唤醒时间,看一下每次不能唤醒的时 ...

你好,下面log是昨天追了一天后未唤醒的信息。
time now :20时50分36秒  ThreadSendSensorData Client has send sensor data Success!!!
Rset B :Next turn time 2018年05月23日20时55分05秒
time now :20时50分36秒  ThreadSendSensorData Reset AlarmB to make sure can Wake UP...

时刻是 20:50:36 alarmB 设定的唤醒时间是 20:55:05 ,但是最终程序并没有唤醒
可以加微信请教啊 15601756551
废鱼 回答时间:2018-5-24 10:35:01
楼主,下面这几句话是不是可以只保留开启中断的就可以了?
if (HAL_RTC_SetAlarm(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
{
    _Error_Handler(__FILE__, __LINE__);
}

if(HAL_RTC_SetAlarm_IT(&hrtc,&sAlarm,RTC_FORMAT_BIN) != HAL_OK)
{
    /* Initialization Error */
    Error_Handler();
}

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

firstwangjin 回答时间:2018-5-24 11:26:09
安 发表于 2018-5-24 10:35
楼主,下面这几句话是不是可以只保留开启中断的就可以了?
if (HAL_RTC_SetAlarm(&hrtc, &sAlarm, RTC_FORM ...

是的目前的程序里只保留了HAL_RTC_SetAlarm_IT 这一个函数
废鱼 回答时间:2018-5-24 14:00:34
这个问题,我感觉还是得冲RTCalarm设置以后,是否成功找了。
firstwangjin 回答时间:2018-5-28 09:14:57
目前还没有找到真正的问题,先用一个IWDG定期唤醒。测了几天,到是没有死机。但是耗电会增加
12下一页
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版