请选择 进入手机版 | 继续访问电脑版

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

【NUCLEO-L476RG开发】LPUART唤醒停止模式STOP Mode 2  

[复制链接]
风子 提问时间:2015-11-8 14:49 /
本帖最后由 风子 于 2015-11-8 16:16 编辑

LPUART 即 LOW POWER UART,是STM32L4系列专为低功耗设计的低功耗外设之一,既然玩低功耗的板子,当然不能少了捣鼓低功耗功能,这次就玩玩LPUART。
同时,在上一篇帖子【NUCLEO-L476RG LL库开发】STM32【LL库】开发使用指南中初步介绍了 STM32 LL库以及它的独立使用方法,这个帖子顺便演示一下可能是更通用(实用)的使用方法:LL库和HAL库混合使用。毕竟HAL库使用CUBEMX,非常方便,而独立使用LL库还需要自己建立工程,况且LL库本来就是和HAL库集成在一起的,相互配合,优势互补,最大限度的兼顾用户编程使用方便和MCU性能功耗,我想这才是ST设计这个库的初衷。不过这不是这个帖子的重点,不讲,只在代码中演示。
实验目的是测试LPUART的唤醒Stop mode 2功能,要做的工作如下:
1.硬件,nucleo的虚拟串口默认接的是USART2,要使用LPUART,需要重新接线
2.软件,配置好LPUART,并且重定向printf函数,便于输出需要的信息
3.配置进入Stop mode 2的准备工作
4.进入Stop mode 2
5.使用LPUART唤醒MCU
6.输出一些过程中观察需要的调试信息
大概就有这么些内容,这个实验是参考了STM32L4Cube里面的一个例子,由于水平有限,这也只是个人实验笔记,可能有些地方写得不好,大家自己去看官方库里面的例程,位于STM32Cube_FW_L4_V1.1.0\Projects\STM32L476RG-Nucleo\Examples_LL\LPUART\LPUART_WakeUpFromStop2文件夹中。下面是具体操作:
1.板载ST-LINK有虚拟串口功能,并且引出了TX,RX引脚,只需要把他们和LPUART1的RX,TX引脚连起来即可,注意板子上的TX,RX是针对ST-LINK端说的,所以连接时和LPUART的TX,RX反过来连接,如图

QQ截图20151108134437.png

注意RX,TX上连了其他USART的时候千万不要同时使用USART2,本来使用其他串口的时候应该断开板子上SB13,SB14,闲麻烦就不断开了,别使用USART2就好。
2.1配置LPUART1,这个使用Cubemx来完成,比较简单

QQ截图20151108134929.png

打开LPUART1,配置PC0,PC1为LPUART1_RX,LPUART1_TX,打开RCC 外部低速时钟LSE

QQ截图20151108135045.png

系统时钟选HSI经PLL倍频,80M,LPUART时钟选择LSE,这里不能使用PCLK,因为进入stop mode 2后PLL,系统时钟会被关闭,相应外设不能工作,所以此处只能选择HSI或者LSE,如果用HSI,上一步可以不必打开LSE。

QQ截图20151108135103.png

LPUART1参数:波特率9600,使用LSE时钟波特率最高只能9600,其他默认。

QQ截图20151108135124.png

打开LPUART的中断。
配置好后就可以直接生成工程了,我使用的是MDK5.16a,生成MDKv5工程。
2.2,重定向printf到串口LPUART1
printf函数非常方便,所以用它来输出调试信息,打开上一步生成的工程,在合适的地方加入代码:

  1. #ifdef  __GNUC__
  2. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
  3. #else
  4. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
  5. #endif
  6. PUTCHAR_PROTOTYPE
  7. {
  8. HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);
  9. return ch;
  10. }
复制代码
  1. //main中
  2.         printf("This is a test!\n");
复制代码

最后一句是放在主函数中,用来测试下printf函数能不能正常输出信息

QQ截图20151108141120.png

看起来一切正常,可以下一步了。
2.3先来输出一些信息,供后面比较,输出系统时钟信息:
在前面配置中,我们使用了PLL倍频,得到80M的系统时钟,而在进入stop mode 2后PLL会被关闭,重新唤醒之后只能使用HSI或者MSI作为系统时钟,PLL需要重新使能才能使用,就像系统刚复位的时候一样,所以进入停止模式之前,应该先设置好唤醒之后的系统时钟,这是准备工作之一,
下面的函数用于获取当前系统时钟设置:

  1. void HAL_RCC_GetClockConfig(RCC_ClkInitTypeDef  *RCC_ClkInitStruct, uint32_t *pFLatency)
复制代码

获得时钟信息后用printf函数输出:

QQ截图20151108141959.png

现在的时钟是PLL,和之前的配置相符。
3.进入停止模式2之前准备工作
为了使MCU能正常进入停止模式,且能正常被唤醒,有些工作必须做好,不然就睡死过去醒不来了。

3.1打开PWR时钟,设置系统唤醒后时钟为MSI

  1.   LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
  2.   LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_MSI);
复制代码

3.2开中断,在HAL_UART_MspInit中加入代码:

  1.   /* USER CODE BEGIN LPUART1_MspInit 1 */
  2. LL_LPUART_SetWKUPType(LPUART1, LL_LPUART_WAKEUP_ON_RXNE);//设置唤醒方式为RXNE
  3. LL_LPUART_EnableIT_RXNE(LPUART1);//打开RXNE中断
  4. LL_LPUART_EnableIT_WKUP(LPUART1);//打开wakeup中断

  5. /* USER CODE END LPUART1_MspInit 1 */
复制代码

3.3检查LPUART的一些状态位,这个我就直接复制了例程中的一个函数,稍加修改

  1. __STATIC_INLINE void PrepareLPUARTToStopMode(void)
  2. {
  3.   /* Empty RX Fifo before entering Stop Mode 2 (Otherwise, characters already present in FIFO
  4.      will lead to immediate wake up */
  5.   while (LL_LPUART_IsActiveFlag_RXNE(LPUART1))
  6.   {
  7.     /* Read Received character. RXNE flag is cleared by reading of RDR register */
  8.     ubReceivedChar=LL_LPUART_ReceiveData8(LPUART1);
  9.   }

  10.   /* Clear OVERRUN flag */
  11.   LL_LPUART_ClearFlag_ORE(LPUART1);

  12.   /* Make sure that no LPUART transfer is on-going */
  13.   while(LL_LPUART_IsActiveFlag_BUSY(LPUART1) == 1)
  14.   {
  15.   }
  16.   /* Make sure that LPUART is ready to receive */   
  17.   while(LL_LPUART_IsActiveFlag_REACK(LPUART1) == 0)
  18.   {
  19.   }

  20.   /* About to enter stop mode: switch off LED */
  21.   LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_5);

  22.   /* Configure LPUART1 transfer interrupts : */
  23.   /* Clear WUF flag and enable the UART Wake Up from stop mode Interrupt */
  24.   LL_LPUART_ClearFlag_WKUP(LPUART1);
  25.   LL_LPUART_EnableIT_WKUP(LPUART1);

  26.   /* Enable Wake Up From Stop */
  27.   LL_LPUART_EnableInStopMode(LPUART1);
  28. }
复制代码

分析一下这个函数都干了些什么(其实代码里有注释):

a.不断读取接收数据,知道RXNE为0,确保已经没有数据发进来

b.清除OVERRUN标志,确保所有当前工作完成,进入可以接收的状态

c.清除WUF标志位,开WKUP中断(上一步自己做了),使能wakeup功能

4.一切准备工作就绪,MCU可以进入停止模式了,

  1. PrepareLPUARTToStopMode();

  2.   HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
复制代码

不过还有一个问题,还没写中断函数呢,MCU醒来后不知道干什么啊,人早上醒来知道洗脸刷牙,机器可不知道,所以得告诉它,写中断服务函数。


剩下的更新在一楼,完整工程见附件:

STM32L476_HAL LL_LPUART.rar (2.88 MB, 下载次数: 636)

评分

参与人数 1 ST金币 +49 收起 理由
沐紫 + 49 赞一个!

查看全部评分

1 收藏 4 评论30 发布时间:2015-11-8 14:49

举报

30个回答
风子 回答时间:2015-11-8 14:49:41
本帖最后由 风子 于 2015-11-8 15:31 编辑

继续更新:
为方便观察,进入停止模式之前先让LED闪烁3秒钟,同时输出一些信息。接着写中断函数


  1. void LPUART1_IRQHandler(void)
  2. {
  3.   /* USER CODE BEGIN LPUART1_IRQn 0 */
  4.   if(LL_LPUART_IsActiveFlag_WKUP(LPUART1) && LL_LPUART_IsEnabledIT_WKUP(LPUART1))
  5.   {
  6.     /* Configure LPUART1 transfer interrupts : */
  7.     /* Disable the UART Wake UP from stop mode Interrupt */
  8.     LL_LPUART_DisableIT_WKUP(LPUART1);

  9.     /* WUF flag clearing */
  10.     LL_LPUART_ClearFlag_WKUP(LPUART1);
  11.         
  12.     ubReceivedChar=LL_LPUART_ReceiveData8(LPUART1);
  13.   }

  14.   /* USER CODE END LPUART1_IRQn 0 */
  15.   HAL_UART_IRQHandler(&hlpuart1);
  16.   /* USER CODE BEGIN LPUART1_IRQn 1 */

  17.   /* USER CODE END LPUART1_IRQn 1 */
  18. }
复制代码

当有中断发生,先检查中断源是不是WKUP中断,并且是否使能该中断,如果不是,则忽略掉。



      检查确定是WKUP中断,则关闭WKUP中断,清除相应标志位,避免重复进中断,最后将接收到的数据读出来存放,以便后用。
中断结束,MCU已经被唤醒,会回到进入停止模式的地方继续执行后面的代码,后面也不用做什么事,就是把收到的字符发送回串口助手,这样我们就可以知道MCU已经成功被唤醒了,当然,唤醒后直接把LED打开,观察更方便代码也更简单。同时发送系统时钟的信息和进入停止模式之前的信息做个比较,








QQ截图20151108151534.png

可以清楚的看到,我们发送到MCU的字符'a'成功发送回来,进入停止模式前系统时钟是PLL,而唤醒之后变成了MSI,如果要继续使用PLL,需要重新配置使能,如果不影响其他地方,可以简单的再调用一次cube生成的时钟配置函数:


  1. printf("System clock reconfiguration\n\r");
  2.         SystemClock_Config();
  3.   displayclkinfo();
复制代码
QQ截图20151108153625.png

最后,把唤醒后的时钟改为HSI,测试一下效果:


  1. LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI);
复制代码
QQ截图20151108153258.png

此时唤醒后系统时钟就是HSI。


风子 回答时间:2017-7-6 09:23:21
ataudio 发表于 2017-6-28 10:23
楼主,请教一下。@风子

“注意RX,TX上连了其他USART的时候千万不要同时使用USART2”,同时开启USART2,会 ...

那样做结果是把两个串口链接在同一根线上,通信会相互干扰,你看原理图就懂了
风子 回答时间:2015-11-8 14:50:00
再占板凳
aabird 回答时间:2015-11-8 15:36:28
还行吧。挺好的。我都不知道该如何表达了
风子 回答时间:2015-11-8 15:39:07
aabird 发表于 2015-11-8 15:36
还行吧。挺好的。我都不知道该如何表达了

呵呵
埃斯提爱慕 回答时间:2015-11-8 17:35:06
提示: 作者被禁止或删除 内容自动屏蔽
Paderboy 回答时间:2015-11-8 19:05:46
多谢分享。。。
陈金华 回答时间:2015-11-8 20:30:57
帮顶              
kingsings 回答时间:2015-11-8 22:57:18
写的很详细
风子 回答时间:2015-11-9 08:58:30

谢谢支持
奋斗逼 回答时间:2015-11-9 09:04:20

多谢分享。。。
埃斯提爱慕 回答时间:2015-11-9 21:27:55
提示: 作者被禁止或删除 内容自动屏蔽
风子 回答时间:2015-11-9 21:31:14
dsjsjf 发表于 2015-11-9 21:27
这一个加分,换板了的50金币就到手了

好像挺划算的,哈哈
ataudio 回答时间:2015-11-20 16:59:26
以后跟着楼主混了。
风子 回答时间:2015-11-20 22:04:27
ataudio 发表于 2015-11-20 16:59
以后跟着楼主混了。

  
123下一页

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版