灵动微课堂 (第237讲)|基于MM32L0130的LPUART应用(2)
来源:灵动MM32MCU发布时间:2022-11-24299浏览
询问 AILPUART(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_tTX_Buffer[16],RX_Buffer[16];
uint8_tTX_Complete=0,RX_Complete=0;
b.
配置NVIC:
NVIC_InitTypeDefNVIC_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:
voidLPUART_DMA_TX_Init(void)
{
DMA_InitTypeDefDMA_InitStruct;
RCC_DMA_ClockCmd(DMA1,ENABLE);
DMA_DeInit(DMA1_Channel2);
DMA_StructInit(DMA_InitStruct);
//DMAtransferperipheraladdress
DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t)LPUART1->LPUTXD;
//DMAtransfermemoryaddress
DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)TX_Buffer;
//DMAtransferdirectionfromperipheraltomemory
DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralDST;
//DMAcachesize
DMA_InitStruct.DMA_BufferSize=16;
//Theperipheraladdressisforbiddentomovebackward
DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
//Thememoryaddressisshiftedbackward
DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
//Definetheperipheraldatawidthto8bits
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;
//M2Mmodeisdisabled
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);
//EnableLPUART_DMA1_ChannelTransfercompleteinterrupt
DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);
LPUART_TX_DMACmd(LPUART1,ENABLE);
while((LPUART1->LPUENLPUART_LPUEN_DMAT)==0);
//LPUART_DMA1_Channelenable
DMA_Cmd(DMA1_Channel2,ENABLE);
}
d.
配置DMA通道3为LPUART_RX:
voidLPUART_DMA_RX_Init(void)
{
DMA_InitTypeDefDMA_InitStruct;
RCC_DMA_ClockCmd(DMA1,ENABLE);
DMA_DeInit(DMA1_Channel3);
DMA_StructInit(DMA_InitStruct);
//DMAtransferperipheraladdress
DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t)LPUART1->LPURXD;
//DMAtransfermemoryaddress
DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)RX_Buffer;
//DMAtransferdirectionfromperipheraltomemory
DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;
//DMAcachesize
DMA_InitStruct.DMA_BufferSize=16;
//Theperipheraladdressisforbiddentomovebackward
DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
//Thememoryaddressisshiftedbackward
DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
//Definetheperipheraldatawidthto8bits
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;
//M2Mmodeisdisabled
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);
//EnableLPUART_DMA1_ChannelTransfercompleteinterrupt
DMA_ITConfig(DMA1_Channel3,DMA_IT_TC,ENABLE);
LPUART_RX_DMACmd(LPUART1,ENABLE);
while((LPUART1->LPUENLPUART_LPUEN_DMAR)==0);
//LPUART_DMA1_Channelenable
DMA_Cmd(DMA1_Channel3,ENABLE);
}
e.
编写中断服务函数:
voidDMA1_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.
编写实验样例:
voidLPUART_RxTx_DMA_Test(void)
{
uint8_ti;
for(i=0;i<16;i++)
{
TX_Buffer[i]=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_InitTypeDefinit_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.
编写中断服务程序,判断接收匹配事件并清除标志:
voidLPUART1_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.
编写试验样例:
voidLPUART_Wakeup_Test(void)
{
uint8_ttemp,i;
charstring1[]="LPUARTwakeupmcutest!\r\n";
charstring2[]="mcustop!\r\n";
charstring3[]="mcuwakeup!\r\n";
for(i=0;i<strlen(string1);i++)
{
Output_Byte(LPUART1,string1[i]);
}
DELAY_Ms(20);
for(i=0;i<strlen(string2);i++)
{
Output_Byte(LPUART1,string2[i]);
}
PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);//休眠
for(i=0;i<strlen(string3);i++)
{
Output_Byte(LPUART1,string3[i]);
}
while(1)
{
}
}
e.
在main函数配置好LPUART后,调用实验函数LPUART_Wakeup_Test,可以得到如下结果:

往期精彩
第232讲 | 使用MM32L0130 SLCD驱动LCD显示
第229讲 | 基于MM32F0140的UDS Bootloader学习笔记
第224讲 | MM32F0140 FlexCAN一致性测试 (2)
第223讲 | MM32F0140 FlexCAN一致性测试 (1)
第222讲 | MM32F0140学习笔记——独立看门狗(IWDG)
第221讲 | 使用MM32F3270基于Azure RTOS抢占任务的应用
第220讲 | 使用MM32F3270基于Azure RTOS事件标志组的应用
第219讲 | 使用MM32F3270基于Azure RTOS消息队列的应用
第218讲 | 使用MM32F3270基于Azure RTOS (ThreadX)的多任务调度
第217讲 | 使用MM32F3270基于Azure RTOS (ThreadX) 的移植
第215讲 | MM32F0140学习笔记——窗口看门狗(WWDG)
第213讲 | MM32F0140学习笔记——FlexCAN 控制器局域网
第212讲 | 工程师笔记——MM32F0040使用总结 (2)
第211讲 | 工程师笔记——MM32F0040使用总结 (1)
第207讲 | MM32F0140学习笔记——时钟系统RCC
第200讲 | 使用MM32F0270 定时器DMA方式输出PWM
关于灵动
上海灵动微电子股份有限公司成立于 2011 年,是中国本土领先的通用 32 位 MCU 产品及解决方案供应商。公司基于 Arm Cortex-M 系列内核开发的 MM32 MCU 产品拥有 F/L/A/SPIN/W 五大系列,目前已量产 200多款型号,累计交付超3亿颗,每年都有近亿台配备了灵动 MM32MCU 的优秀产品交付到客户手中,在本土通用 32 位 MCU 公司中位居前列。

灵动客户涵盖智能工业、汽车电子、通信基建、医疗健康、智慧家电、物联网、个人设备、手机和电脑等应用领域。灵动是中国为数不多的同时获得了 Arm-KEIL、IAR、SEGGER 官方支持的本土 MCU 公司,并建立了独立、完整的通用 MCU 生态体系。灵动始终秉承着“诚信、承诺、创新、合作”的精神,为客户提供从硬件芯片到软件算法、从参考方案到系统设计的全方位支持。

灵动股份
微信号:MindMotion-MMCU


长按识别二维码关注我们

MORE
官网:www.mm32mcu.com
微信公众号:灵动MM32MCU
灵动MM32MCU技术论坛:
bbs.21ic.com/iclist-696-1.html
新闻来源:灵动MM32MCU,文中所述为作者独立观点,不代表icspec立场。更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj。


