LPUART(Low power universal asynchronous receiver transmitter,低功耗通用異步收發(fā)器),相比標(biāo)準(zhǔn)的UART,其功耗極低,支持在低功耗模式下運行,并且可以將MCU從低功耗模式喚醒。
上期介紹了MM32全新低功耗系列MM32L0130的LPUART外設(shè),并實現(xiàn)了基本UART收發(fā)通信和使用LPUART喚醒MCU。本期介紹LPUART的高級應(yīng)用,實現(xiàn)DMA收發(fā)實驗、使用數(shù)據(jù)匹配寄存器匹配到指定字符后喚醒MCU。
1 LPUART使用DMA
LPUART可以使用DMA來搬運數(shù)據(jù),實現(xiàn)無需CPU參與的快速自動數(shù)據(jù)傳輸。硬件發(fā)出DMA請求與對應(yīng)的DMA通道直連,也可以通過軟件配置寄存器的方式觸發(fā)DMA通道請求。LPUART的控制寄存器有對應(yīng)的DMA使能位,如下圖所示:
1.1 DMA中斷
DMA的每個通道都有三種中斷事件標(biāo)志:DMA半傳輸、DMA傳輸完成和DMA傳輸出錯。各通道單獨的中斷請求由這3種事件標(biāo)志邏輯或起來??梢耘渲眉拇嫫鞯膶?yīng)位來使能這些中斷:
1.2 LPUART使用DMA的配置步驟
- 根據(jù)基本UART配置步驟配置LPUART
- 使能LPUEN的DMAR與DMAT位激活DMA模式
- 使能DMA時鐘
- 發(fā)送需要配置DMA的源地址(存儲器地址)和目的地址(LPUTXD),傳輸?shù)臄?shù)據(jù)量以及DMA通道
- 配置完發(fā)送后,只要TXFIFO為空,就會請求DMA發(fā)送
- 接收需要配置DMA的源地址(LPURXD)和目的地址(存儲器地址),傳輸?shù)臄?shù)據(jù)量以及DMA通道
- 配置完接收后,只要RXFIFO有數(shù)據(jù),即不為空,就會請求DMA接收
1.3 功能代碼實現(xiàn)
下面例程實現(xiàn)了使用DMA發(fā)送和接收LPUART數(shù)據(jù),發(fā)送和接收完成后進(jìn)入中斷,例程在基本UART收發(fā)實驗的基礎(chǔ)上完成。
a.
申請例程所用到的TX和RX緩存、TX和RX完成標(biāo)志:
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.
編寫中斷服務(wù)函數(shù):
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] = 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函數(shù)中配置好LPUART和DMA后,調(diào)用實驗函數(shù)LPUART_RxTx_DMA_Test,可以得到如下結(jié)果:
2 使用數(shù)據(jù)匹配寄存器匹配到指定字符后喚醒MCU
為進(jìn)一步降低系統(tǒng)功耗,MM32L0130系列的LPUART提供了一種接收到指定字符才能喚醒低功耗狀態(tài)的MCU的功能。用于喚醒的指定字符,由數(shù)據(jù)匹配寄存器確定:
2.1 接收中斷配置寄存器
可以通過LPUART的LPUCON.RXEV寄存器配置喚醒事件為START位、一幀接收完成、一幀數(shù)據(jù)匹配或者RXD下降沿喚醒。
2.2 功能代碼實現(xiàn)
匹配指定字符喚醒MCU功能,需要在上期講解的LPUART喚醒低功耗模式中的MCU基礎(chǔ)上修改中斷事件配置、指定喚醒字符,具體代碼如下:
a.
配置LPUART接收中斷事件為接收數(shù)據(jù)匹配成功:
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.
編寫中斷服務(wù)程序,判斷接收匹配事件并清除標(biāo)志:
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[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函數(shù)配置好LPUART后,調(diào)用實驗函數(shù)LPUART_Wakeup_Test,可以得到如下結(jié)果:
-
寄存器
+關(guān)注
關(guān)注
31文章
5290瀏覽量
119787 -
異步收發(fā)器
+關(guān)注
關(guān)注
0文章
36瀏覽量
10834 -
FIFO存儲
+關(guān)注
關(guān)注
0文章
103瀏覽量
5955 -
串口中斷
+關(guān)注
關(guān)注
0文章
64瀏覽量
13845 -
MCU芯片
+關(guān)注
關(guān)注
3文章
246瀏覽量
11348
發(fā)布評論請先 登錄
相關(guān)推薦
評論