以前在使用stm32F103系列单片机时,若要将串口配置成DMA发送,只需要正确配置DMA通道,然后发送数据时候,给DMA通道的CNDTR寄存器赋以发送长度,再使能DMA即可。
如下代码所示:F103版本
while (DMA_GetCurrDataCounter(DMA1_Channel7));// 检查DMA发送通道内是否还有数据 memcpy(DMASendBuf, Buffer, (ucSend_num > 1024 ? 1024 : ucSend_num)); //DMA发送数据-要先关 设置发送长度 开启DMA DMA_Cmd(DMA1_Channel7, DISABLE); DMA1_Channel7->CNDTR = ucSend_num;// 设置发送长度 DMA_Cmd(DMA1_Channel7, ENABLE); // 启动DMA发送
这次在F407上使用,发现像上面一样设置并不能用,DMA只能发送一次,后面直接不发送了。
如下代码所示:F407 错误配置DMA
while (DMA_GetCurrDataCounter(DEBUG_USART_DMA_STREAM));// 检查DMA发送通道内是否还有数据 memcpy((uint8_t *)SendBuff, Buf,(Len > 1024 ? 1024 : Len)); DMA_Cmd(DEBUG_USART_DMA_STREAM, DISABLE); // 关闭DMA发送 DEBUG_USART_DMA_STREAM->NDTR = Len; DMA_Cmd(DEBUG_USART_DMA_STREAM, ENABLE); // 启动DMA发送
后来查阅手册,发现串口使用DMA通信的话,官方要求使能DMA发送完成中断,并在中断中清除TC标志位。
如下代码所示:官方手册中要求的DMA发送过程
NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); DMA_ITConfig(DMA2_Stream7,DMA_IT_TC,ENABLE); void DMA2_Stream7_IRQHandler(void) if(DMA_GetFlagStatus(DMA2_Stream7,DMA_FLAG_TCIF7)!=RESET)//等待DMA2_Steam7传输完成 DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_TCIF7);//清除DMA2_Steam7传输完成标志 void Send_Data(u8 *Buf, uint16_t Len) while (DMA_GetCurrDataCounter(DMA2_Stream7));// 检查DMA发送通道内是否还有数据 memcpy((uint8_t *)SendBuff, Buf,(Len > 1024 ? 1024 : Len)); DMA_Cmd(DMA2_Stream7, DISABLE); // 关闭DMA发送 DMA2_Stream7->NDTR = Len; DMA_Cmd(DMA2_Stream7, ENABLE); // 启动DMA发送
我认为此举没有必要,便关闭了DMA TC中断,再每次发送前清除TC标志位即可。
如下代码所示:在之前代码基础上增加一条清除DMA TC标志位的指令。
while (DMA_GetCurrDataCounter(DMA2_Stream7));// 检查DMA发送通道内是否还有数据 while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) /*确保发送结束*/ DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7); memcpy((uint8_t *)Rs485No1DmaSendBuf, Buf,(Len > 1024 ? 1024 : Len)); DMA_Cmd(DMA2_Stream7, DISABLE); // 关闭DMA发送 while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE){} //确保DMA可以被设置 DMA_SetCurrDataCounter(DMA2_Stream7, Len);// 设置发送长度 DMA_Cmd(DMA2_Stream7, ENABLE); // 启动DMA发送
但是发现一个问题,如果不使用DMA TC中断,在DMA在初始化配置时,缓存区大小不能设置为0,即:
DMA_Initstructure1.DMA_BufferSize = 1; //此值随便赋,但是不能为0。
我猜测这可能是芯片的一个BUG,着实有点坑。
以下是Stm32F1手册中关于串口DMA发送的介绍
以下是Stm32F4手册中关于串口DMA发送的介绍
QQ扫一扫,加入答疑群聊
|