方案一:设置DMA为DMA_Mode_Normal模式,开启DMA DMA_IT_TC接收完成中断,初始化两个接收buffer,接收中断触发以后,关闭DMA接收,切换接收buffe1r到buffer2,重置传输值,开启DMA接收。处理接收buffer1.
/***********************************************
** Function name:
** Descriptions: 串口DMA中断
** input parameters: 无
** output parameters: 无
** Returned value: 无
*************************************************/
void Usart_DMA_IRQHandler(USART_TypeDef* com)
{
u8 com_id = 0;
for(u8 i = 0; i < COMn; i++)
{
if(EVAL_USART[i] == com)
{
com_id = i;
}
}
if(com_id >= COMn)
{
return;
}
if((DMA_GetFlagStatus(EVAL_COM_DMA_IT_TC[com_id]) != RESET) ||
(strlen((char *)DownBuf[(DmaUseNum) % 2])))
{
/*清除全部中断标志*/
DMA_ClearFlag(EVAL_COM_DMA_IT_TC[com_id]);
DmaUseNum = (DmaUseNum + 1) % 2;
DMA_Cmd(EVAL_COM_DMA_CHANNEL[com_id], DISABLE);
memset((u8 *)DownBuf[DmaUseNum], 0, DOWNLOAD_SIZE);
/*设置DMA的传输值*/
EVAL_COM_DMA_CHANNEL[com_id] -> CNDTR = (DOWNLOAD_SIZE - 32);
/*设置传输地址*/
EVAL_COM_DMA_CHANNEL[com_id] -> CMAR = (u32)DownBuf[DmaUseNum];
/*打开DMA*/
DMA_Cmd(EVAL_COM_DMA_CHANNEL[com_id], ENABLE);
DownloadWriteFlash((char *)DownBuf[(DmaUseNum + 1) % 2], (u32 *)&DownOffset);
Dmastartdown = 1;
DownBuf_Time_Update();
}
}
void usart_dma_config(USART_TypeDef* com, u8 DMAFlag)
{
u8 com_id = 0;
/* DMA1通道5配置 */
DMA_InitTypeDef DMA_InitStructure;
/*DMA 内存申请和释放*/
Request_DownBuf(DMAFlag);
for(u8 i = 0; i < COMn; i++)
{
if(EVAL_USART[i] == com)
{
com_id = i;
}
}
if(com_id >= COMn)
{
return;
}
RCC_AHBPeriphClockCmd(COM_DMA_CLK[com_id], ENABLE);
/* 关DMA通道 */
DMA_Cmd(EVAL_COM_DMA_CHANNEL[com_id], DISABLE);
/* 恢复缺省值 */
DMA_DeInit(EVAL_COM_DMA_CHANNEL[com_id]);
/* DMA外设地址 */
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
/* DMA 存储器0地址 */
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DownBuf[DmaUseNum];
/* 外设到存储器模式 */
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
/* 数据传输量 */
DMA_InitStructure.DMA_BufferSize = (DOWNLOAD_SIZE - 32);
/* 外设非增量模式 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
/* 存储器增量模式 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/* 外设数据长度:8位 */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
/* 存储器数据长度:8位 */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
/* 使用普通模式 */
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
/* 中等优先级 */
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
/* 设置DMA的2个memory中的变量互相访问*/
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
/* 初始化DMA Stream */
DMA_Init(EVAL_COM_DMA_CHANNEL[com_id], &DMA_InitStructure);
/* 配置DMA发送完成后产生中断 */
DMA_ITConfig(EVAL_COM_DMA_CHANNEL[com_id], DMA_IT_TC, ENABLE);
/* 使能通道 */
DMA_Cmd(EVAL_COM_DMA_CHANNEL[com_id], ENABLE);
/*采用DMA方式接收*/
if(DMAFlag == 1)
{
/*开启串口的 DMA 接受功能*/
USART_DMACmd(com, USART_DMAReq_Rx, ENABLE);
/*关闭串口接收中断*/
USART_ITConfig(com, USART_IT_RXNE, DISABLE);
/*关闭串口发送中断*/
//USART_ITConfig(WIFI_USARTx, USART_IT_TC, DISABLE);
/*使能串口空闲中断*/
//USART_ITConfig(WIFI_USARTx, USART_IT_IDLE, ENABLE);
memory_down_mode = 1;
}
else
{
USART_DMACmd(com, USART_DMAReq_Rx, DISABLE);
USART_ITConfig(com, USART_IT_RXNE, ENABLE);
/*开启串口发送中断*/
//USART_ITConfig(WIFI_USARTx, USART_IT_TC, ENABLE);
//USART_ITConfig(WIFI_USARTx, USART_IT_IDLE, DISABLE);
memory_down_mode = 0;
}
Dmastartdown = 0;
}
方案二:设置DMA为DMA_Mode_Circular模式,开启DMA DMA_IT_TC接收完成中断和DMA_IT_HT接收过半中断,初始化1个接收buffer,接收到过半中断后处理上一半接收buffer,接收到接收完成中断后处理下一半接收buffer。
/***********************************************
** Function name:
** Descriptions: 串口DMA中断
** input parameters: 无
** output parameters: 无
** Returned value: 无
*************************************************/
void Usart_DMA_IRQHandler(USART_TypeDef* com)
{
u8 com_id = 0;
u32 test_ms;
u32 len;
u32 addr;
for(u8 i = 0; i < COMn; i++)
{
if(EVAL_USART[i] == com)
{
com_id = i;
}
}
if(com_id >= COMn)
{
return;
}
if((DMA_GetFlagStatus(EVAL_COM_DMA_IT_TC[com_id]) != RESET) ||
(strlen((char *)DownBuf[(DmaUseNum) % 2])))
{
/*清除全部中断标志*/
DMA_ClearFlag(EVAL_COM_DMA_IT_TC[com_id]);
DmaUseNum = (DmaUseNum + 1) % 2;
DMA_Cmd(EVAL_COM_DMA_CHANNEL[com_id], DISABLE);
// memset((u8 *)DownBuf[DmaUseNum], 0, DOWNLOAD_SIZE);
/*设置DMA的传输值*/
EVAL_COM_DMA_CHANNEL[com_id] -> CNDTR = (DOWNLOAD_SIZE - 32);
/*设置传输地址*/
EVAL_COM_DMA_CHANNEL[com_id] -> CMAR = (u32)DownBuf[DmaUseNum];
/*打开DMA*/
DMA_Cmd(EVAL_COM_DMA_CHANNEL[com_id], ENABLE);
dma_full = 1;
down_buff_nub = (DmaUseNum + 1) % 2;
// printf("%s", (char *)DownBuf[(DmaUseNum + 1) % 2]);
// test_ms = (RTC_GetCounter()%1000) * 1000 + ((32767 - RTC_GetDivider()) * 1000 / 32767);
// printf("d_s:%d\r\n", test_ms);
// DownloadWriteFlash((char *)DownBuf[(DmaUseNum + 1) % 2], (u32 *)&DownOffset);
// test_ms = (RTC_GetCounter()%1000) * 1000 + ((32767 - RTC_GetDivider()) * 1000 / 32767);
// len = strlen((char *)DownBuf[(DmaUseNum + 1) % 2]);
// addr = HEX_START_ADDR + DownOffset;
// SPI_FLASH_BufferWrite(0,(u8*)DownBuf[(DmaUseNum + 1) % 2], addr, len);
// DownOffset = DownOffset + len;
// printf("dma:%d\r\n",down_buff_nub);
}
}
void usart_dma_config(USART_TypeDef* com, u8 DMAFlag)
{
u8 com_id = 0;
/* DMA1通道5配置 */
DMA_InitTypeDef DMA_InitStructure;
/*DMA 内存申请和释放*/
Request_DownBuf(DMAFlag);
for(u8 i = 0; i < COMn; i++)
{
if(EVAL_USART[i] == com)
{
com_id = i;
}
}
if(com_id >= COMn)
{
return;
}
RCC_AHBPeriphClockCmd(COM_DMA_CLK[com_id], ENABLE);
/* 关DMA通道 */
DMA_Cmd(EVAL_COM_DMA_CHANNEL[com_id], DISABLE);
/* 恢复缺省值 */
DMA_DeInit(EVAL_COM_DMA_CHANNEL[com_id]);
/* DMA外设地址 */
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
/* DMA 存储器0地址 */
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DownBuf[DmaUseNum];
/* 外设到存储器模式 */
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
/* 数据传输量 */
DMA_InitStructure.DMA_BufferSize = (DOWNLOAD_SIZE - 32);
/* 外设非增量模式 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
/* 存储器增量模式 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/* 外设数据长度:8位 */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
/* 存储器数据长度:8位 */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
/* 使用普通模式 */
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
/* 中等优先级 */
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
/* 设置DMA的2个memory中的变量互相访问*/
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
/* 初始化DMA Stream */
DMA_Init(EVAL_COM_DMA_CHANNEL[com_id], &DMA_InitStructure);
/* 配置DMA发送完成后产生中断 */
DMA_ITConfig(EVAL_COM_DMA_CHANNEL[com_id], DMA_IT_TC, ENABLE);
/* 使能通道 */
DMA_Cmd(EVAL_COM_DMA_CHANNEL[com_id], ENABLE);
/*采用DMA方式接收*/
if(DMAFlag == 1)
{
/*开启串口的 DMA 接受功能*/
USART_DMACmd(com, USART_DMAReq_Rx, ENABLE);
/*关闭串口接收中断*/
USART_ITConfig(com, USART_IT_RXNE, DISABLE);
/*关闭串口发送中断*/
//USART_ITConfig(WIFI_USARTx, USART_IT_TC, DISABLE);
/*使能串口空闲中断*/
//USART_ITConfig(WIFI_USARTx, USART_IT_IDLE, ENABLE);
memory_down_mode = 1;
}
else
{
USART_DMACmd(com, USART_DMAReq_Rx, DISABLE);
USART_ITConfig(com, USART_IT_RXNE, ENABLE);
/*开启串口发送中断*/
//USART_ITConfig(WIFI_USARTx, USART_IT_TC, ENABLE);
//USART_ITConfig(WIFI_USARTx, USART_IT_IDLE, DISABLE);
memory_down_mode = 0;
}
Dmastartdown = 0;
}
说明:
方案二的处理方式比方案一效果更好,特别是当接收的数据速度比较快的时候,方案一关闭再重置DMA的过程有可能导致数据丢失。方案二是循环接收,没有关闭DMA就不存在这个问题,但是两种方案都要注意尽量不在接收中断中处理接收数据。经过测试方案二通过串口接收大量数据的波特率最大调整到921600 然后通过spi写片外flash都不会丢失数据。