打印
[产品介绍及宣传专区]

CW32 UART低功耗模式介绍

[复制链接]
1302|22
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
芯源新闻官|  楼主 | 2023-5-22 16:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在嵌入式系统的设计中,低功耗设计(Low-Power Design)是许多设计人员必须面对的问题,其原因在于嵌入式系统被广泛应用于便携式和移动性较强的产品中去,而这些产品不是一直都有充足的电源供应,往往是靠电池来供电,所以设计人员从每一个细节来考虑降低功率消耗,从而尽可能地延长电池使用时间。因此,大部分芯片都会有低功耗模式,以CW32L083为例,它就是一个32位低功耗微控制器。

一、芯片模式介绍
1.CW32L083工作模式
CW32L083 支持三种工作模式,由内嵌的电源管理模块自动完成电源的统一管理。三种工作模式是:
• 运行模式(Active mode)
• 休眠模式(Sleep mode)
• 深度休眠模式(DeepSleep mode)
电源上电后,系统自动进入运行模式。用户可通过软件程序,进入休眠或深度休眠两种低功耗运行状态;在低功耗运行状态时,可通过硬件中断触发唤醒机制,使系统返回到运行模式。

2.进入休眠模式或深度休眠模式
使用 M0+ 内核的 ARM 等待中断专用指令,WFI(Wait for Interrupt),配合 M0+ 内核的系统控制寄存器(SCR, System Control Register)的 SLEEPONEXIT 和 SLEEPDEEP 位域,可实现立即进入或退出(中断服务程序)时进 入休眠模式或深度休眠模式。
• 立即进入
执行 WFI 指令,MCU 将立即进入休眠模式(SLEEPDEEP 为 0 时)或深度休眠模式(SLEEPDEEP 为 1 时)
• 退出时进入
将 SLEEPONEXIT 位置 1,当退出最低优先级的中断服务程序后,MCU 会进入休眠模式(SLEEPDEEP 为 0 时) 或深度休眠模式(SLEEPDEEP 为 1 时),而不需执行 WFI 指令 。

在深度休眠模式下,系统将自动关闭高速时钟。如用户需要在深度休眠模式下使部分外设仍保持运行,则须在进入深度休眠模式前,启动相应的低速时钟并将该外设时钟设置为此低速时钟。

3.退出休眠模式或深度休眠模式
在休眠模式或深度休眠模式下,均可通过中断来唤醒 CPU,返回到运行模式。但是,值得注意的是,如果用户在中断服务程序中执行 WFI 命令进入休眠(包括深度休眠),则需要比此中断更高优先级的中断才能唤醒 CPU,因此,我们强烈建议用户在准备进入休眠前,应先处理完所有中断服务程序,并且清除所有中断请求和中断标志。
使用中断退出休眠模式,用户必须在进入休眠(包括深度休眠)前使能此中断的允许位。
中断唤醒退出深度休眠模式时,CPU 运行状态与退出休眠模式相同。

4.UART控制深度休眠模式
UART控制器工作在双时钟域下,支持在深度休眠模式下进行正常的数据收发,并通过接收完成中断唤醒 MCU回到运行模式。
如果设置了传输时钟 UCLK来源为低速时钟,当系统进入深度休眠模式后,高速时钟将停止,低速时钟保持运行,UART仍可以进行正常的数据收发(波特率仅支持 2400 bps、4800 bps 和 9600 bps)。 要实现深度休眠模式下使用 UART 唤醒功能,需在进入深度休眠模式之前使能 UART 接收完成中断(即设置 UARTx_IER.RC 为 1),数据接收完成时,接收完成中断将唤醒MCU恢复到运行模式。
如果设置了传输时钟 UCLK 来源为高速时钟,当系统进入深度休眠模式后,高速时钟会停止运行,UAR不会接收数据。此时,仍可通过GPIO中断唤醒 MCU,实现在深度休眠模式下接收数据,参考配置步骤如下:
步骤 1:使能 UARTx_RXD 对应引脚的 GPIO 下降沿中断;
步骤 2:设置 UARTx_CR1.START 为 1,选择 RXD 信号起始位判定方式为低电平;
步骤 3:使能 UART 接收(即设置 UARTx_CR1.RXEN 为 1);
步骤 4:进入深度休眠模式;
步骤 5:等待主机发送数据,产生 GPIO 下降沿中断,唤醒 MCU;
步骤 6:关闭 RXD 对应引脚的 GPIO 中断功能,等待 RXD 接收完成。

二、实例演示:UART深度休眠模式示例(传输时钟为LSI)
程序运行一段时间后进入深度休眠模式,PC发送数据可唤醒MCU,唤醒后UART轮询接收数据,并存储到TxRxBuffer缓冲区,UART接收到'\n'后不再接收数据,然后将TxRxBuffer缓冲区中的数据回传至PC。传输结束后,LED1闪烁5s,并再次进入深度休眠模式。
1.外设时钟使能
void RCC_Configuration(void)
{
    InitTick(8000000); //复位后延时
    SysTickDelay(1000);
    RCC_HSI_Enable(RCC_HSIOSC_DIV6); //SYSCLK = HSI = 8MHz = HCLK = PCLK
    RCC_LSI_Enable();
    RCC_AHBPeriphClk_Enable(DEBUG_UART_GPIO_CLK | RCC_AHB_PERIPH_GPIOC, ENABLE);
    DEBUG_UART_APBClkENx(DEBUG_UART_CLK, ENABLE); //外设时钟使能
}
2.配置GPIO
void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    DEBUG_UART_AFTX; //UART TX RX 复用
    DEBUG_UART_AFRX;
    GPIO_InitStructure.Pins = DEBUG_UART_TX_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init(DEBUG_UART_TX_GPIO_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.Pins = DEBUG_UART_RX_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
    GPIO_Init(DEBUG_UART_RX_GPIO_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.Pins = GPIO_PIN_3; //PC3 LED1
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init(CW_GPIOC, &GPIO_InitStructure);
    PC03_SETLOW();
}
3.配置UART
void UART_Configuration(void)
{
    UART_InitTypeDef UART_InitStructure = {0};

    UART_InitStructure.UART_BaudRate = UARTyz_BaudRate; // 波特率
    UART_InitStructure.UART_Over = UART_Over_sp; // 专用采样
    UART_InitStructure.UART_Source = UART_Source_LSI; // 传输时钟源LSI
    UART_InitStructure.UART_UclkFreq = UARTyz_UclkFreq; // 传输时钟UCLK频率
    UART_InitStructure.UART_StartBit = UART_StartBit_FE; // 起始位判定方式
    UART_InitStructure.UART_StopBits = UART_StopBits_1; // 停止位长度
    UART_InitStructure.UART_Parity = UART_Parity_No ; // 校验方式
    UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
    UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx; // 发送/接收使能
UART_Init(DEBUG_UARTx, &UART_InitStructure);
}
4.配置低功耗模式
void PWR_Configuration(void)
{
    PWR_InitTypeDef PWR_InitStructure = {0};//低功耗模式配置结构体指针
    PWR_InitStructure.PWR_Sevonpend = PWR_Sevonpend_Disable;
    PWR_InitStructure.PWR_SleepDeep = PWR_SleepDeep_Enable; //Deep Sleep使能
    PWR_InitStructure.PWR_SleepOnExit = PWR_SleepOnExit_Disable;
    PWR_Config(&PWR_InitStructure);// 低功耗模式配置
}
void PWR_GotoLpmMode(void)//进入睡眠模式
{
    __WFI();
}
5.配置NVIC中断
void NVIC_Configuration(void)
{
    NVIC_SetPriority(DEBUG_UART_IRQ, 0); //优先级,无优先级分组
    NVIC_EnableIRQ(DEBUG_UART_IRQ); //UARTx中断使能
}
void UART2_UART5_IRQHandler(void)
{
if(UART_GetITStatus(CW_UART5, UART_IT_RC) != RESET)
    {
        UART_ClearITPendingBit(CW_UART5, UART_IT_RC);
}
}
6.发送8位数组
void UART_SendBuf_Polling(UART_TypeDef* UARTx, uint8_t *TxBuf, uint8_t TxCnt)
{
    while(TxCnt)
    {
        UART_SendData_8bit(UARTx, *TxBuf);
        while(UART_GetFlagStatus(UARTx, UART_FLAG_TXE) == RESET);
        TxBuf++;
        TxCnt--;
    }
    while(UART_GetFlagStatus(UARTx, UART_FLAG_TXBUSY) == SET);
}
7.接收8位数组
uint8_t UART_RecvBuf_Polling(UART_TypeDef* UARTx, uint8_t *RxBuf)
{
    uint8_t RxCnt = 0;
    RxBuf[RxCnt] = UART_ReceiveData_8bit(UARTx);
    RxCnt++;
    do
    {
        while(UART_GetFlagStatus(UARTx, UART_FLAG_RC) == RESET); //等待RC
        UART_ClearFlag(UARTx, UART_FLAG_RC); //清RC
        if(UART_GetFlagStatus(UARTx, UART_FLAG_PE|UART_FLAG_FE)) //ERROR: PE or FE
        {
            UART_ClearFlag(UARTx, UART_FLAG_PE|UART_FLAG_FE);
            RxCnt = 0x00;
        }
        else
        {
            RxBuf[RxCnt] = UART_ReceiveData_8bit(UARTx);
            RxCnt++;
        }
    }
    while(RxBuf[RxCnt-1] != '\n');
    return RxCnt;
}
8.主程序
int32_t main(void)
{
    RCC_Configuration();//配置RCC
    GPIO_Configuration();//配置GPIO
    UART_Configuration();//配置UART
    PWR_Configuration();//配置低功耗模式
    NVIC_Configuration();//配置NVIC
    InitTick(HCLKFREQ); //初始化SysTick
    RCC_WAKEUPCLK_Config(RCC_SYSCTRL_WAKEUPCLKDIS); //DeepSleep唤醒时,保持原系统时钟来源

    UART_SendString(DEBUG_UARTx, "\r\nCW32L083 UART DeepSleep mode LSE/LSI\r\n");
    while(1)
    {
        //进入深度休眠模式
        UART_SendString(DEBUG_UARTx, "\r\nEnter DeepSleep mode\r\n");
        UART_SendString(DEBUG_UARTx, "\r\nPC send data to wake up MCU\r\n");
        UART_ITConfig(DEBUG_UARTx, UART_IT_RC, ENABLE); //使能UARTx RC中断
        PWR_GotoLpmMode();
        UART_ITConfig(CW_UART5, UART_IT_RC, DISABLE); //失能UARTx RC中断
        //唤醒后轮询收发
        TxRxBufferSize = UART_RecvBuf_Polling(DEBUG_UARTx, TxRxBuffer);
        UART_SendBuf_Polling(DEBUG_UARTx, TxRxBuffer, TxRxBufferSize);
        for(int i = 0; i<10; i++)  //闪灯
        {
            PC03_TOG();
            SysTickDelay(500);
        }
    }
}
9.测试结果
结果显示,通过PC发送123456后唤醒MCU, 唤醒后UART轮询接收数据,并存储到TxRxBuffer缓冲区,UART接收到'\n'后不再接收数据,然后将TxRxBuffer缓冲区中的数据回传至PC收到123456。传输结束后,LED1闪烁5s,并再次进入深度休眠模式。

使用特权

评论回复
沙发
huangcunxiake| | 2023-5-23 15:04 | 只看该作者
发现高手们都喜欢用do while.

使用特权

评论回复
板凳
七毛钱| | 2023-5-23 16:14 | 只看该作者
高手与高手之间是心灵相通的吧,哈哈

使用特权

评论回复
地板
gaoyang9992006| | 2023-5-26 09:45 | 只看该作者
这个功能好,串口唤醒MCU。

使用特权

评论回复
5
duo点| | 2023-6-5 11:42 | 只看该作者
这功能强悍

使用特权

评论回复
6
jackcat| | 2023-7-5 10:07 | 只看该作者
降低电压可以减少电路中的能量消耗

使用特权

评论回复
7
wwppd| | 2023-7-5 10:17 | 只看该作者
使用UART通信时,可以利用中断功能来减少CPU的功耗。

使用特权

评论回复
8
youtome| | 2023-7-5 10:38 | 只看该作者
通过减小波特率,可以降低数据传输时钟的频率,从而减少电路中的功耗。

使用特权

评论回复
9
pentruman| | 2023-7-5 10:50 | 只看该作者
能在低功耗模式下使用CW32 的串口吗

使用特权

评论回复
10
xiaoyaodz| | 2023-7-5 10:59 | 只看该作者
可以增加UART通信的空闲时间,即在数据传输之间添加额外的延迟。

使用特权

评论回复
11
lzmm| | 2023-7-5 11:14 | 只看该作者
需要通信时,可以通过唤醒中断或其他触发机制将UART模块重新唤醒。

使用特权

评论回复
12
sdCAD| | 2023-7-5 11:34 | 只看该作者
降低UART的传输速率可以减少功耗。

使用特权

评论回复
13
primojones| | 2023-7-5 11:51 | 只看该作者
可以让UART在空闲状态下更长时间进入低功耗模式

使用特权

评论回复
14
minzisc| | 2023-7-5 12:18 | 只看该作者
将不需要进行通信的UART模块置于睡眠状态可以节省能量。

使用特权

评论回复
15
timfordlare| | 2023-7-5 12:31 | 只看该作者
当UART不需要传输数据时,可以通过关闭发送和接收功能来降低功耗。

使用特权

评论回复
16
jackcat| | 2023-7-5 13:28 | 只看该作者
可以降低数据传输时钟的频率,从而减少电路中的功耗。  

使用特权

评论回复
17
benjaminka| | 2023-7-5 13:51 | 只看该作者
低功耗实现方法取决于所使用的UART芯片或模块的规格和特性

使用特权

评论回复
18
deliahouse887| | 2023-7-5 14:08 | 只看该作者
在传输数据时根据接收端的缓冲区状态来控制数据流量。这可以有效地减少数据丢失和冗余传输

使用特权

评论回复
19
pssyx| | 2023-8-16 09:54 | 只看该作者
yszong 发表于 2023-8-15 21:27
进入深度休眠模式后UAR不会接收数据

UART可以接收数据的。因为UART工作时钟为LSI,CW32进入DeepSleep之后,LSI正常工作。如果PC端发送数据,UART的RX中断将唤醒MCU,从而进入UART的RX ISR,正常接收数据。

使用特权

评论回复
20
XIOAWEIYAOMB| | 2023-9-18 12:06 | 只看该作者
1111

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

36

主题

36

帖子

0

粉丝