在上一講中,我們對USART進行了簡單介紹,并講解了如何在不使用DMA的情況下進行不定長度數據接收,本講將著重講解如何使用DMA進行USART不定長度接收。
USART可以利用DMA連續通信。Rx緩沖器和Tx緩沖器的DMA請求是分別產生的。參考產品技術說明以確定是否可用DMA控制器。如果所用產品無DMA功能,發送器或接收器里所描述的方法使用USART。在USART2_SR寄存器里,可以清零TXE/RXNE標志來實現連續通信。
利用DMA發送
使用DMA進行發送,可以通過設置USART_CR3寄存器上的DMAT位激活。當TXE位被置為’1’時,DMA就從指定的SRAM區傳送數據到USART_DR寄存器。為USART的發送分配一個DMA通道的步驟如下(x表示通道號):
在DMA控制寄存器上將USART_DR寄存器地址配置成DMA傳輸的目的地址。在每個TXE事件后,數據將被傳送到這個地址;
在DMA控制寄存器上將存儲器地址配置成DMA傳輸的源地址。在每個TXE事件后,將從此存儲器區讀出數據并傳送到USART_DR寄存器;
在DMA控制寄存器中配置要傳輸的總的字節數;
在DMA寄存器上配置通道優先級;
根據應用程序的要求,配置在傳輸完成一半還是全部完成時產生DMA中斷;
在DMA寄存器上激活該通道。
當傳輸完成DMA控制器指定的數據量時,DMA控制器在該DMA通道的中斷向量上產生一中斷。在發送模式下,當DMA傳輸完所有要發送的數據時,DMA控制器設置DMA_ISR寄存器的TCIF標志;監視USART_SR寄存器的TC標志可以確認USART通信是否結束,這樣可以在關閉USART或進入停機模式之前避免破壞最后一次傳輸的數據;軟件需要先等待TXE=1,再等待TC=1。
圖1 利用DMA發送
利用DMA接收
可以通過設置USART_CR3寄存器的DMAR位激活使用DMA進行接收,每次接收到一個字節,DMA控制器就就把數據從USART_DR寄存器傳送到指定的SRAM區(參考DMA相關說明)。
為USART的接收分配一個DMA通道的步驟如下(x表示通道號):
通過DMA控制寄存器把USART_DR寄存器地址配置成傳輸的源地址。在每個RXNE事件后,將從此地址讀出數據并傳輸到存儲器;
通過DMA控制寄存器把存儲器地址配置成傳輸的目的地址。在每個RXNE事件后,數據將從USART_DR傳輸到此存儲器區;
在DMA控制寄存器中配置要傳輸的總的字節數;
在DMA寄存器上配置通道優先級;
根據應用程序的要求配置在傳輸完成一半還是全部完成時產生DMA中斷;
在DMA控制寄存器上激活該通道。
當接收完成DMA控制器指定的傳輸量時,DMA控制器在該DMA通道的中斷矢量上產生一中斷。
圖2 利用DMA接收
DMA通道
在CKS32F107xx DMA章節中,我們對DMA進行了基本介紹,根據各通道DMA請求表可以發現,USART1需要使用的DMA通道為DMA1的第4和第5通道。
圖3 USART1 DMA通道
USART初始化程序
在該例程中,我們使用USART1,利用DMA接收并發送不定長度數據。
開啟GPIO、USART1、DMA1時鐘;
對USART引腳進行配置,PA9映射TX,PA10映射RX;
初始化DMA1相關參數;
對USART參數進行配置,此例程使用USART的IDLE中斷對不定長度數據接收完成進行判斷;
對中斷參數進行配置;
/*******************************************************************************
* Function Name : USART_Configuration
* Description : Configure USART1
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
void CKS_USART_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/*USART1_TX -> PA9 , USART1_RX -> PA10*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* DMA configuration ----------------------------------------------*/
/* USART1_RX DMA Init */
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)CKS_Uart_Rx;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = CKS_UART_TX_RX_BUFF;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel5, ENABLE);
/* USART1_TX DMA Init */
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)CKS_Uart_Tx;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel4, DISABLE);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
/* USART1 interrupt configuration ----------------------------------------------*/
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
USART_Cmd(USART1, ENABLE);
}
USART_IRQHandler函數
我們利用USART的IDLE進行不定長度數據接收完成判斷,當USART被IDLE中斷觸發后,即標志著本次數據流已完成傳輸。
/*******************************************************************************
* Function Name : USART1_IRQHandler
* Description : This function handles USART1 global interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void USART1_IRQHandler(void)
{
if(USART_GetFlagStatus(USART1, USART_FLAG_IDLE) != RESET)
{
DMA_Cmd(DMA1_Channel5, DISABLE);
uint8_t i = USART1->SR;
i = USART1->DR;
CKS_Uart_Rx_Data_Lenth = CKS_UART_TX_RX_BUFF - DMA_GetCurrDataCounter(DMA1_Channel5);
DMA1_Channel5->CNDTR = CKS_UART_TX_RX_BUFF;
CKS_Uart_Tx_Data_Lenth = CKS_Uart_Rx_Data_Lenth;
memcpy(CKS_Uart_Tx, CKS_Uart_Rx, CKS_Uart_Rx_Data_Lenth);
memset(CKS_Uart_Rx, 0x00, sizeof(CKS_Uart_Rx));
DMA_Cmd(DMA1_Channel5, ENABLE);
CKS_Uart_Transmite_With_DMA(CKS_Uart_Tx_Data_Lenth);
}
USART_ClearFlag(USART1, USART_IT_RXNE);
}
USART發送程序
發送程序通過DMA發送長度為lenth的CKS_Uart_Tx數組。
/*******************************************************************************
* Function Name : CKS_Uart_Transmite_With_DMA
* Description : transmite data.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CKS_Uart_Transmite_With_DMA(uint32_t lenth)
{
DMA1_Channel4->CNDTR = lenth;
DMA_Cmd(DMA1_Channel4, ENABLE);
while(!DMA_GetFlagStatus(DMA1_FLAG_TC4)){}
DMA_ClearFlag(DMA1_FLAG_TC4);
memset(CKS_Uart_Tx, 0x00, sizeof(CKS_Uart_Tx));
CKS_Uart_Tx_Data_Lenth = 0x00;
DMA_Cmd(DMA1_Channel4, DISABLE);
}
-
控制器
+關注
關注
113文章
16505瀏覽量
179925 -
寄存器
+關注
關注
31文章
5386瀏覽量
121459 -
dma
+關注
關注
3文章
568瀏覽量
101186 -
USART
+關注
關注
1文章
198瀏覽量
31035
原文標題:MCU微課堂|CKS32F107xx USART(二)
文章出處:【微信號:中科芯MCU,微信公眾號:中科芯MCU】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
STM32之串口DMA接收不定長數據
stm32串口是如何實現接收不定長度數據的呢
基于DMA接收利用空閑模式接收不定長數據
STM32F072使用DMA+IDLE進行串口接收不定長數據有問題,改為DMA+RTO接收正常。

stm32 串口接收不定長度數據及黏包處理 + 串口DMA接收

STM32F429 標準庫 串口完成中斷+DMA 接收不定長數據

評論