DMA使用流程:
1. 配置
外设端:
- 串口引脚GPIO配置
- 串口功能参数配置(数据位格式,波特率等),此处还需要**配置对应的DMA请求允许**。
- 如果有中断,还需要配置中断优先级
DMA端:
- DMA功能配置
- 初始化DMA通道DMA_Init(DMA1_Channel4,&DMA_InitStructure);
。 DMA源(Memory)/目的(外设)地址
。 DMA的传输方向
。 DMA的buffer size
。 DMA外设(DISABLE)/Memory(ENABLE)地址自增使能配置
。 DMA传输字节格式(支持byte,half-word,word)
。 DMA传输方式(Normal和Circle)
。 DMA传输优先级(共有四种,)
。 DMA m2m使能/失能配置(此处不是用于m2m所以配置为DISABLE)
- 清除中断标志位
- 此处应DISABLE DMA通道,否则配置完成即会产生DMA数据传输(非期望数据)
- 使能DMA发送完成中断
- DMA中断服务函数
发送数据完成后,即关闭DMA通道,发送信号量到应用程序
参考代码:实现stm32f103 uart1 dma发送和接收
//#define DMA_USART1_DR_Base (USART1_BASE + 0x4) //0x40013804
#define DMA_USART1_DR_Base 0x40013804
//1. 串口1端口配置
void uart1_gpio_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//DBTX PA9 uart1_tx
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//DBRX PA10 uart1_rx
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
//2. 串口功能配置
void uart1_param_config(void)
{
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
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_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1,&USART_InitStructure);
//config uart DMA request
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);//enable usart1 dma send request
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //enable usart1 dma recieve request
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //enable usart1 idle interrupt
USART_Cmd(USART1,ENABLE);
}
//
void uart1_nvic_config(void){
NVIC_InitTypeDef NVIC_InitStructure;
//uart1 interrupt
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//dma interrupt
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn; //
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//DMA config/
//1. uart dma configs
void uart1_dma_init(void){
DMA_InitTypeDef DMA_InitStructure;
//Tx DMA CONFIG
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //enable DMA1 clock
DMA_Cmd(DMA1_Channel4,DISABLE); //close DMA Channel
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = DMA_USART1_DR_Base; //(uint32_t)(&USART1->DR)
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart1TxBuf;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = USART1_TX_BUFF_SIZE;
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_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4,&DMA_InitStructure);
DMA_ClearFlag(DMA1_FLAG_GL4); // clear all DMA flags
//DMA_Cmd(DMA1_Channel4,ENABLE); // close DMA Channel
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE); //open DMA send inttrupt
//Rx DMA CONFIG
DMA_Cmd(DMA1_Channel5, DISABLE); //
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart1RxBuf;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = USART1_RX_BUFF_SIZE;
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_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
DMA_ClearFlag(DMA1_FLAG_GL5);
DMA_Cmd(DMA1_Channel5, ENABLE);
}
///uart dma send//
void DMA1_Channel4_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_FLAG_TC4)==SET)
{
DMA_ClearFlag(DMA1_FLAG_GL4);
DMA_Cmd(DMA1_Channel4, DISABLE);
OSMboxPost(UartSndMBox, (void*)1);
}
}
void uart_dma_send_enable(uint16_t size)
{
DMA1_Channel4->CNDTR = (uint16_t)size;
DMA_Cmd(DMA1_Channel4, ENABLE);
}
///uart dma recv//
void uart1_dma_recv_data(void)
{
//INT8U err;
DMA_Cmd(DMA1_Channel5, DISABLE);
DMA_ClearFlag(DMA1_FLAG_GL5);
//index = USART1_RX_BUFF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);
DMA1_Channel5->CNDTR = USART1_RX_BUFF_SIZE;
DMA_Cmd(DMA1_Channel5, ENABLE);
OSMboxPost(UartRevMBox,(void*)1);
}
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
{
Uart1RevLen = USART1_RX_BUFF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5); //获得接收到的字节数
memcpy(Uart1RxBufCpy,Uart1RxBuf,Uart1RevLen);
uart1_dma_recv_data();
/*
* Clear IDLE interrupt flag bit
* 1. read USART_SR
* 2. read USART_DR
*/
USART_ReceiveData( USART1 ); // Clear IDLE interrupt flag bit
}
}
//3. 串口初始化
void uart1_init(void)
{
uart1_gpio_config();
uart1_param_config();
uart1_nvic_config();
uart1_dma_init();
}
INT16U uart1_send_data( INT8U *pbuff, INT16U size )
{
INT8U err;
if((NULL == pbuff) || (0==size) )
{
return 0;
}
if(size > USART1_TX_BUFF_SIZE)
{
size = USART1_TX_BUFF_SIZE;
}
memcpy(Uart1TxBuf,pbuff,size);
uart_dma_send_enable(size);
OSMboxPend(UartSndMBox, 3000, &err);
if(OS_ERR_NONE != err)
{
size = 0;
}
return size;
}
INT16U uart1_rev_data( INT8U *pbuff, INT16U size,INT16U TimeOutMs)
{
INT8U err;
if((NULL == pbuff) || (0==size) )
{
return 0;
}
if(size > USART1_RX_BUFF_SIZE)
{
size = USART1_RX_BUFF_SIZE;
}
memset(pbuff,0,size);
OSMboxPend(UartRevMBox, TimeOutMs, &err);
if(OS_ERR_NONE != err)
{
size = 0;
}
else
{
if(Uart1RevLen < size)
{
size = Uart1RevLen;
}
memcpy(pbuff,Uart1RxBufCpy,size);
}
return size;
}
void BSP_Init(void)
{
UartSndMBox = OSMboxCreate ((void*)0);
UartRevMBox = OSMboxCreate ((void*)0);
uart1_init();
}