方案一:设置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都不会丢失数据。
|