在上一讲中,我们对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);
}
全部0条评论
快来发表一下你的评论吧 !