如何使用DMA进行USART不定长度接收

描述

在上一讲中,我们对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);

}

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表德赢Vwin官网 网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分