IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32F103 DMA快速写片外flash 解决没有双缓存的两种方案 -> 正文阅读

[嵌入式]STM32F103 DMA快速写片外flash 解决没有双缓存的两种方案

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

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-30 12:54:10  更:2021-07-30 12:55:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 10:10:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计