谷动谷力

 找回密码
 立即注册
查看: 1462|回复: 0
打印 上一主题 下一主题
收起左侧

灵动微|基于MM32L0130的LPUART应用(2)

[复制链接]
跳转到指定楼层
楼主
发表于 2022-11-24 22:49:30 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
灵动微|基于MM32L0130的LPUART应用(2)

LPUART(Low power universal asynchronous receiver transmitter,低功耗通用异步收发器),相比标准的UART,其功耗极低,支持在低功耗模式下运行,并且可以将MCU从低功耗模式唤醒。
上期介绍了MM32全新低功耗系列MM32L0130的LPUART外设,并实现了基本UART收发通信和使用LPUART唤醒MCU。本期介绍LPUART的高级应用,实现DMA收发实验、使用数据匹配寄存器匹配到指定字符后唤醒MCU。

1
LPUART使用DMA
LPUART可以使用DMA来搬运数据,实现无需CPU参与的快速自动数据传输。硬件发出DMA请求与对应的DMA通道直连,也可以通过软件配置寄存器的方式触发DMA通道请求。LPUART的控制寄存器有对应的DMA使能位,如下图所示:

1.1  DMA中断
DMA的每个通道都有三种中断事件标志:DMA半传输、DMA传输完成和DMA传输出错。各通道单独的中断请求由这3种事件标志逻辑或起来。可以配置寄存器的对应位来使能这些中断:

1.2  LPUART使用DMA的配置步骤
1
根据基本UART配置步骤配置LPUART
2
使能LPUEN的DMAR与DMAT位激活DMA模式
3
使能DMA时钟
4
发送需要配置DMA的源地址(存储器地址)和目的地址(LPUTXD),传输的数据量以及DMA通道
5
配置完发送后,只要TXFIFO为空,就会请求DMA发送
6
接收需要配置DMA的源地址(LPURXD)和目的地址(存储器地址),传输的数据量以及DMA通道
7
配置完接收后,只要RXFIFO有数据,即不为空,就会请求DMA接收

1.3  功能代码实现
下面例程实现了使用DMA发送和接收LPUART数据,发送和接收完成后进入中断,例程在基本UART收发实验的基础上完成。
a.
申请例程所用到的TX和RX缓存、TX和RX完成标志:
uint8_t TX_Buffer[16], RX_Buffer[16];
uint8_t TX_Complete = 0, RX_Complete = 0;

b.
配置NVIC:
NVIC_InitTypeDef  NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel2_3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);

c.
配置DMA通道2为LPUART_TX:
void LPUART_DMA_TX_Init(void)
{
    DMA_InitTypeDef DMA_InitStruct;

    RCC_DMA_ClockCmd(DMA1, ENABLE);
    DMA_DeInit(DMA1_Channel2);
    DMA_StructInit(&DMA_InitStruct);
    //DMA transfer peripheral address
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&LPUART1->LPUTXD;
    //DMA transfer memory address
    DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)TX_Buffer;
    //DMA transfer direction from peripheral to memory
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
    //DMA cache size
    DMA_InitStruct.DMA_BufferSize = 16;
    //The peripheral address is forbidden to move backward
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    //The memory address is shifted backward
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    //Define the peripheral data width to 8 bits
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
    //M2M mode is disabled
    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
    DMA_InitStruct.DMA_Auto_reload = DMA_Auto_Reload_Disable;
    DMA_Init(DMA1_Channel2, &DMA_InitStruct);
    DMA_SetChannelMuxSource(DMA1_Channel2, DMA1_MUX_LPUART1_TX);
    //Enable LPUART_DMA1_Channel Transfer complete interrupt
    DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
    LPUART_TX_DMACmd(LPUART1, ENABLE);
    while((LPUART1->LPUEN & LPUART_LPUEN_DMAT) == 0);
    //LPUART_DMA1_Channel enable
    DMA_Cmd(DMA1_Channel2, ENABLE);
}

d.
配置DMA通道3为LPUART_RX:
void LPUART_DMA_RX_Init(void)
{
    DMA_InitTypeDef DMA_InitStruct;

    RCC_DMA_ClockCmd(DMA1, ENABLE);

    DMA_DeInit(DMA1_Channel3);
    DMA_StructInit(&DMA_InitStruct);
    //DMA transfer peripheral address
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&LPUART1->LPURXD;
    //DMA transfer memory address
    DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)RX_Buffer;
    //DMA transfer direction from peripheral to memory
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
    //DMA cache size
    DMA_InitStruct.DMA_BufferSize = 16;
    //The peripheral address is forbidden to move backward
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    //The memory address is shifted backward
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    //Define the peripheral data width to 8 bits
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
    //M2M mode is disabled
    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
    DMA_InitStruct.DMA_Auto_reload = DMA_Auto_Reload_Disable;
    DMA_Init(DMA1_Channel3, &DMA_InitStruct);
    DMA_SetChannelMuxSource(DMA1_Channel3, DMA1_MUX_LPUART1_RX);
    //Enable LPUART_DMA1_Channel Transfer complete interrupt
    DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);
    LPUART_RX_DMACmd(LPUART1, ENABLE);
    while((LPUART1->LPUEN & LPUART_LPUEN_DMAR) == 0);
    //LPUART_DMA1_Channel enable
    DMA_Cmd(DMA1_Channel3, ENABLE);
}

e.
编写中断服务函数:
void DMA1_Channel2_3_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_IT_TC2))
    {
        DMA_ClearITPendingBit(DMA1_IT_TC2);
        TX_Complete = 1;
    }
    if(DMA_GetITStatus(DMA1_IT_TC3))
    {
        DMA_ClearITPendingBit(DMA1_IT_TC3);
        RX_Complete = 1;
    }
}

f.
编写实验样例:
void LPUART_RxTx_DMA_Test(void)
{
    uint8_t i;

    for(i = 0; i < 16; i++)
    {
        TX_Buffer = i;
    }
    LPUART_DMA_TX_Init();
    LPUART_DMA_RX_Init();

    while(1)
    {
        if(TX_Complete == 1)
        {
            TX_Complete = 0;
            DMA1_Channel3->CMAR = (uint32_t)RX_Buffer;
            DMA1_Channel3->CNDTR = 16;
            DMA_Cmd(DMA1_Channel3, ENABLE);
        }
        if(RX_Complete == 1)
        {
            RX_Complete = 0;
            memcpy((void *)TX_Buffer, (void *)RX_Buffer, 16);
            DMA1_Channel2->CMAR = (uint32_t)TX_Buffer;
            DMA1_Channel2->CNDTR = 16;
            DMA_Cmd(DMA1_Channel2, ENABLE);
        }
    }
}

g.
在main函数中配置好LPUART和DMA后,调用实验函数LPUART_RxTx_DMA_Test,可以得到如下结果:

2
使用数据匹配寄存器匹配到指定字符后唤醒MCU
为进一步降低系统功耗,MM32L0130系列的LPUART提供了一种接收到指定字符才能唤醒低功耗状态的MCU的功能。用于唤醒的指定字符,由数据匹配寄存器确定:

2.1  接收中断配置寄存器
可以通过LPUART的LPUCON.RXEV寄存器配置唤醒事件为START位、一帧接收完成、一帧数据匹配或者RXD下降沿唤醒。

2.2  功能代码实现
匹配指定字符唤醒MCU功能,需要在上期讲解的LPUART唤醒低功耗模式中的MCU基础上修改中断事件配置、指定唤醒字符,具体代码如下:
a.
配置LPUART接收中断事件为接收数据匹配成功:
LPUART_InitTypeDef init_struct;

init_struct.LPUART_Clock_Source = 0;
init_struct.LPUART_BaudRate = LPUART_Baudrate_9600;
init_struct.LPUART_WordLength = LPUART_WordLength_8b;
init_struct.LPUART_StopBits = LPUART_StopBits_1;
init_struct.LPUART_Parity = LPUART_Parity_No;
init_struct.LPUART_MDU_Value = 0x952;
init_struct.LPUART_NEDET_Source = LPUART_NegativeDectect_Source2;
init_struct.LPUART_RecvEventCfg = LPUART_RecvEvent_RecvData_Mactched;
LPUART_Init(LPUART1, &init_struct);

b.
配置特定的唤醒字符:
LPUART_SetMatchData(LPUART1, ‘5’); //指定字符’5’为唤醒字符

c.
编写中断服务程序,判断接收匹配事件并清除标志:
void LPUART1_IRQHandler()
{
    if(LPUART_GetFlagStatus(LPUART1, LPUART_LPUSTA_START))
    {
        LPUART_ClearFlagStatus(LPUART1, LPUART_LPUSTA_START);
    }
    if(LPUART_GetFlagStatus(LPUART1, LPUART_LPUSTA_MATCH))
    {//判断接收中断匹配事件
        LPUART_ClearFlagStatus(LPUART1, LPUART_LPUSTA_MATCH);

    }
    if(LPUART_GetITStatus(LPUART1, LPUART_LPUIF_RXIF) == SET) {
        LPUART_ClearITPendingBit(LPUART1, LPUART_LPUIF_RXIF);
        rxDataBuf[cnt] = LPUART_ReceiveData(LPUART1);
        if(++cnt >= 10)
            cnt_flag = 1;
    }
    EXTI_ClearITPendingBit(EXTI_Line22);
}

d.
编写试验样例:
void LPUART_Wakeup_Test(void)
{
    uint8_t temp, i;
    char string1[] = "LPUART wakeup mcu test!\r\n";
    char string2[] = "mcu stop!\r\n";
    char string3[] = "mcu wakeup!\r\n";

    for(i = 0; i < strlen(string1); i++)
    {
        Output_Byte(LPUART1, string1);
    }
    DELAY_Ms(20);
    for(i = 0; i < strlen(string2); i++)
    {
        Output_Byte(LPUART1, string2);
    }
    PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);//休眠
    for(i = 0; i < strlen(string3); i++)
    {
        Output_Byte(LPUART1, string3);
    }

    while(1)
    {

    }
}

e.
在main函数配置好LPUART后,调用实验函数LPUART_Wakeup_Test,可以得到如下结果:


+10
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-6-14 16:56 , Processed in 0.086130 second(s), 42 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表