DMA发送全部历史记录数据到串口

背景

博主参与的项目中,有个读取全部历史记录的功能,如果下位机在主程序中将全部历史记录单纯地通过串口传输会比较占用cpu资源,影响主程序中别的功能。最后商量得出以下实现方案:

定义两个发送缓冲区DMATxbuf1和DMATxbuf2,以及这两个发送缓冲区的标志DMATxbuf1Flag和DMATxbuf2Flag,发送缓冲区的标志取值有三种:可搬运、可发送和发送中。主main中负责搬运数据到这两个发送缓冲区中以及如果存在可发送的缓冲区且不存在发送中的缓冲区,那么主main开启一下这个DMA的通道使能。在DMA传输完成中断中,需要更新刚刚发送缓冲区的标志即可。

相关代码

初始化串口和DMA

void InitDebug_Sub(void)
{
//  stc_gpio_cfg_t stcGpioCfg;
//  stc_uart_cfg_t    stcCfg;/***********************RAM口初始化******************************************/Rxput_232 = 0;Rxget_232 = 0;Txput_232 = 0;Txget_232 = 0;TXing_232 = 0;/***********************GPIO口初始化**********************************************/      stc_gpio_cfg_t stcGpioCfg;DDL_ZERO_STRUCT(stcGpioCfg);Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE);/***********TX************/stcGpioCfg.enDir =  GpioDirOut;Gpio_Init(GpioPortA,GpioPin0,&stcGpioCfg);Gpio_SetAfMode(GpioPortA,GpioPin0,GpioAf2); //配置PC10为LPUART1_TX/**********RX**************/stcGpioCfg.enDir =  GpioDirIn;Gpio_Init(GpioPortA,GpioPin1,&stcGpioCfg);Gpio_SetAfMode(GpioPortA,GpioPin1,GpioAf2); //配置PC11为LPUART1_RX/***********************串口初始化**********************************************/    stc_lpuart_cfg_t  stcCfg;DDL_ZERO_STRUCT(stcCfg);Sysctrl_SetPeripheralGate(SysctrlPeripheralLpUart1,TRUE);  //<外设模块时钟使能  stcCfg.enStopBit = LPUart1bit;                   ///<1停止位    stcCfg.enMmdorCk = LPUartEven;                   ///<偶校验stcCfg.stcBaud.enSclkSel = LPUartMskPclk;        ///<传输时钟源stcCfg.stcBaud.u32Sclk = Sysctrl_GetPClkFreq();  ///<PCLK获取stcCfg.stcBaud.enSclkDiv = LPUartMsk4Or8Div;     ///<采样分频stcCfg.stcBaud.u32Baud = 38400;                   ///<波特率stcCfg.enRunMode = LPUartMskMode1;               ///<工作模式1,异步模式全双工LPUart_Init(M0P_LPUART1, &stcCfg);/***********************DMA初始化**********************************************/    Sysctrl_SetPeripheralGate(SysctrlPeripheralDma,TRUE); //开启DMA外设时钟stc_dma_cfg_t dmaCfg;//CONFB配置dmaCfg.enMode = DmaMskBlock;  //Block传输dmaCfg.enTransferWidth = DmaMsk8Bit; // 传输宽度 8bit(适用于 UART)dmaCfg.enSrcAddrMode = DmaMskSrcAddrInc;  // 源地址递增dmaCfg.enDstAddrMode = DmaMskDstAddrFix;  // 目标地址固定dmaCfg.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable;//使能源地址重载dmaCfg.enDestAddrReloadCtl = DmaMskDstAddrReloadEnable;//使能目标地址重载dmaCfg.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable; //使能BC/TC重载dmaCfg.enTransferMode = DmaMskOneTransfer;  // 单次传输模式//CONFA配置dmaCfg.u16BlockSize = 1;  // 每次传输 1 字节dmaCfg.u16TransferCnt = 131;  //实际传输的时候会设置长度dmaCfg.enRequestNum = DmaLpUart1TxTrig;                //触发源配置:LPUART1 SBUF为空dmaCfg.u32SrcAddress = (uint32_t)&DMATxbuf1.DATA[0];      // 源地址:发送缓冲区dmaCfg.u32DstAddress = (uint32_t)&M0P_LPUART1->SBUF; // 目标地址:LPUART1 发送寄存器dmaCfg.enPriority = DmaMskPriorityFix;  // 固定优先级Dma_InitChannel(DmaCh1, &dmaCfg);     //初始化DMA通道Dma_EnableChannelIrq(DmaCh1); //使能DMA传输完成中断NVIC_EnableIRQ(DMAC_IRQn);    //使能NVIC DMA中断sendingHistoryRemaingTime = 0; //初始化发送历史记录剩余时间为0carryHistoryFinishFlag = 1;   //初始化不需要搬运历史记录DMATxbuf1Flag = 1;            //初始化DMA缓冲区1可搬运DMATxbuf2Flag = 1;            //初始化DMA缓冲区2可搬运/**********************LPUART 中断使能*********************************/LPUart_ClrStatus(M0P_LPUART1,LPUartRC);          //<清接收中断请求LPUart_ClrStatus(M0P_LPUART1,LPUartTC);          //<清发送中断请求LPUart_EnableIrq(M0P_LPUART1,LPUartRxIrq);       //<使能接收中断LPUart_DisableIrq(M0P_LPUART1,LPUartTxIrq);      //发送完成之后关闭发送中断//  LPUart_EnableIrq(M0P_LPUART1,LPUartTxIrq);       //<不使能发送中断,EnableNvic(LPUART1_IRQn,IrqLevel3,TRUE);         //<系统中断使能LPUart_EnableFunc(M0P_LPUART1,LPUartDmaTxFunc);  //DMA发送LPUART使能P_RD_DBG = 0;//初始化调试口485方向为接收

收到获取全部指令时

  case 12:      //读取全部历史记录sendingHistoryRemaingTime = 2000; //设置发送超时时间,同时也标记着此时在传输历史及记录FlashReadSP = W25QX_RECSTART_ADDR; //初始化历史记录读取地址为开始地址//重置两个缓冲区状态为可搬运DMATxbuf1Flag = 1;DMATxbuf2Flag = 1;carryHistoryFinishFlag = 0;//重置历史记录没有搬运完break;

主main中的搬运、发送历史数据

  //发送历史记录期间且历史记录没有搬运完if(sendingHistoryRemaingTime){//尝试搬运历史记录到缓冲区if(!carryHistoryFinishFlag){carryHistory();}//尝试并触发DMA发送dmaSendHistoryRecord();}

搬运、发送历史数据方法详情

void carryHistory()
{typedef_DMATXBUF* dmaTxbuf;u8 carryBufType = 0; //记录搬的是哪个缓冲区//选择可搬运的缓冲区if(DMATxbuf1Flag == 1){dmaTxbuf = &DMATxbuf1;carryBufType = 1;}else if(DMATxbuf2Flag == 1){dmaTxbuf = &DMATxbuf2;carryBufType = 2;}else{//目前没有可搬运的return;}u8 count = 0;dmaTxbuf->LEN = 0;while(count < 3 && !carryHistoryFinishFlag){u8 cmd2=0;u8 buf[300];structHistory_TypeDef* ptr = (structHistory_TypeDef*)buf;//历史记录已经读完了if(FlashReadSP>=W25QX_RECEND_ADDR){cmd2 = 0x01;FlashReadSP = W25QX_RECSTART_ADDR;     //首条记录carryHistoryFinishFlag = 1;}W25QX_BufferRead((u8*)&ptr->HistoryData,FlashReadSP,sizeof(structEEP_GET_HISTOR_TypeDef)); //读取记录if(ptr->HistoryData.FLAG != 0x7e){FlashReadSP += 4096;FlashReadSP &= 0xfffff000;W25QX_BufferRead((u8*)&ptr->HistoryData,FlashReadSP,sizeof(structEEP_GET_HISTOR_TypeDef)); //读取记录索引if(ptr->HistoryData.FLAG != 0x7e) {cmd2 = 0x01;FlashReadSP = W25QX_RECSTART_ADDR;     //首条记录carryHistoryFinishFlag = 1;}}ptr->CMD1 = 0x8c;ptr->CMD2 = cmd2;ptr->ADDR = 0x01;ptr->SoftVer = SOFTVER;      ptr->checksum = CRC16(buf,sizeof(structHistory_TypeDef)-2);dmaTxbuf->DATA[dmaTxbuf->LEN++] = 0x10;dmaTxbuf->DATA[dmaTxbuf->LEN++] = 0x02;for(u16 i = 0; i < sizeof(structHistory_TypeDef); i++){u8 qq = buf[i];dmaTxbuf->DATA[dmaTxbuf->LEN++] = qq;/* -----0x10加发一个 -----*/if(qq == DLE) dmaTxbuf->DATA[dmaTxbuf->LEN++] = DLE;}dmaTxbuf->DATA[dmaTxbuf->LEN++] = DLE;dmaTxbuf->DATA[dmaTxbuf->LEN++] = ETX;dmaTxbuf->DATA[dmaTxbuf->LEN++] = 0x16; count++;FlashReadSP += 128;}//说明搬运了一些历史记录,需要发送,更新标记if(count > 0){//更新缓冲区1的标志if(carryBufType == 1){DMATxbuf1Flag = 2;//缓冲区1可发送}if(carryBufType == 2){DMATxbuf2Flag = 2;//缓冲区2可发送}//说明还有数据待发送,更新过期时间sendingHistoryRemaingTime = 2000;}
}void dmaSendHistoryRecord()
{//存在发送中的数据if(DMATxbuf1Flag == 3 || DMATxbuf2Flag == 3){return;}if(DMATxbuf1Flag == 2){UART_DMA_Send_History(1);}else if(DMATxbuf2Flag == 2){UART_DMA_Send_History(2);}
}

DMA发送中断处理函数

void DMAC_IRQHandler(void)
{
#if (INT_CALLBACK_ON == INT_CALLBACK_DMAC)    Dmac_IRQHandler();
#endif // DMA 中断处理代码if (M0P_DMAC->CONFB1_f.STAT == 5)  // 传输完成标志101{// 清除传输完成标志M0P_DMAC->CONFB1_f.STAT = 0;  //更新缓冲区标志if(DMATxbuf1Flag == 3){DMATxbuf1Flag = 1;}else if (DMATxbuf2Flag == 3){DMATxbuf2Flag = 1;}}M0P_DMAC->CONFB1_f.STAT = 0; 
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/71029.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为云之使用鲲鹏弹性云服务器部署Node.js环境【玩转华为云】

华为云之使用鲲鹏弹性云服务器部署Node.js环境【玩转华为云】 一、本次实践介绍1.1 实践环境简介1.3 本次实践完成目标 二、 相关服务介绍2.1 华为云ECS云服务器介绍2.2 Node.js介绍 三、环境准备工作3.1 预置实验环境3.2 查看预置环境信息 四、登录华为云4.1 登录华为云4.2 查…

记录深度学习中有用的终端命令

1 查看 CUDA 版本 如果你安装了 CUDA 开发工具包&#xff0c;你可以使用 nvcc 命令来查看 CUDA 的版本。 打开终端&#xff08;或命令提示符&#xff09;&#xff0c;运行&#xff1a; nvcc --version 2. 监控 GPU 状态 使用 nvidia-smi 命令&#xff0c;nvidia-smi 是一个…

PyCharm中通过命令行执行`pip`命令下载到哪里了:虚拟环境目录下

PyCharm中通过命令行执行pip命令下载到哪里了:虚拟环境目录下 在PyCharm中通过命令行执行pip命令安装工具包,包的下载位置取决于多种因素 虚拟环境 如果项目使用了虚拟环境(通常是推荐的做法): Windows:虚拟环境通常位于项目目录下的.venv文件夹(默认情况)或你指定…

PS修复画笔工具

修复画笔工具&#xff1a; 修复画笔工具J&#xff1a;仿制图章工具适配颜色功能&#xff08;模式 正常&#xff1a;仿制图章工具适配颜色功能。替换&#xff1a;仿制图章工具&#xff09;&#xff08;扩散&#xff08;羽化&#xff09;&#xff1a;越高&#xff0c;周围颜色融合…

flink系列之:使用flink cdc3从mysql数据库同步数据到doris和starrocks

flink系列之&#xff1a;使用flink cdc3从mysql数据库同步数据到doris和starrocks 一、下载部署flink二、下载部署flink cdc3三、下载mysql-connector-java到flink和flink cdc的lib目录四、flink设置checkpoint支持增量同步数据五、mysql到doris和starrocks的yaml配置文件六、启…

学睿德毅AI 赋能教育拓展短视频创作边界

在数字技术飞速发展的当下&#xff0c;短视频行业已成为推动社会经济发展的重要力量。学睿德毅紧跟时代步伐&#xff0c;聚焦 AI 技术在教育领域的创新应用&#xff0c;精心打造了一套专业且系统的短视频剪辑课程体系。该体系以 “技术与创意并重&#xff0c;理论共实践一色” …

AI 数据集生成和模型微调框架 Distilabel 高级指南:深度功能与最佳实践

系列文章: AI 数据集生成和模型微调框架 Distilabel 入门指南:基本概念、安装与快速开始 AI 数据集生成和模型微调框架 Distilabel 基础指南:概念与入门(一) AI 数据集生成和模型微调框架 Distilabel 基础指南:概念与入门(二) AI 数据集生成和模型微调框架 Distila…

java后端开发day23--面向对象进阶(四)--抽象类、接口、内部类

&#xff08;以下内容全部来自上述课程&#xff09; 1.抽象类 父类定义抽象方法后&#xff0c;子类的方法就必须重写&#xff0c;抽象方法在的类就是抽象类。 1.定义 抽象方法 将共性的行为&#xff08;方法&#xff09;抽取到父类之后。由于每一个子类执行的内容是不一样…

第48天:Web开发-JavaEE应用依赖项Log4j日志Shiro验证FastJson数据XStream格式

#知识点 1、安全开发-JavaEE-第三方依赖开发安全 2、安全开发-JavaEE-数据转换&FastJson&XStream 3、安全开发-JavaEE-Shiro身份验证&Log4j日志处理 一、Log4j 一个基于Java的日志记录工具&#xff0c;当前被广泛应用于业务系统开发&#xff0c;开发者可以利用该工…

JavaScript——前端基础3

目录 JavaScript简介 优点 可做的事情 运行 第一个JavaScript程序 搭建开发环境 安装的软件 操作 在浏览器中使用JavaScript文件 分离JS 使用node运行JS文件 语法 变量与常量 原生数据类型 模板字符串 字符串的内置方法 数组 对象 对象数组和JSON if条件语…

坐标变换及视图变换和透视变换(相机透视模型)

文章目录 2D transformationScaleReflectionShear&#xff08;切变&#xff09;Rotation around originTranslationReverse变换顺序复杂变换的分解 齐次坐标&#xff08;Homogenous Coordinates&#xff09;3D transformationScale&TranslationRotation Viewing / Camera t…

DBGPT安装部署使用

简介 DB-GPT是一个开源的AI原生数据应用开发框架(AI Native Data App Development framework with AWEL(Agentic Workflow Expression Language) and Agents)。 目的是构建大模型领域的基础设施&#xff0c;通过开发多模型管理(SMMF)、Text2SQL效果优化、RAG框架以及优化、Mul…

【windows driver】 开发环境简明安装教程

一、下载路径 https://learn.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads 二、安装步骤&#xff1a; 1、安装Visual Studio IDE 笔者建议安装最新版本&#xff0c;可以向下兼容。发文截止到目前&#xff0c;VS2022是首选&#xff0c;当前笔者由于项…

回文重新排序

回文串就两种情况&#xff0c;一种是有一个奇数个的字母&#xff0c;另一种是没有的。所以我们需要统计出题目给出的字母是否为奇数个&#xff0c;且奇数个只能有一个&#xff0c;如果超过一个就不能构成回文串了。 #include<iostream> #include<string> #include…

如何在docker上部署java服务

目录结构 首先 Dockerfile FROM bladex/alpine-java:openjdk17_cn_slimMAINTAINER admin@rsz.comENV TZ=Asia/ShanghaiRUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezoneRUN mkdir -p /xhWORKDIR /xhEXPOSE 8106ADD ./blade-system.…

FinRobot:一个使用大型语言模型进行金融分析的开源AI代理平台

文章目录 前言一、生态系统1. 金融AI代理&#xff08;Financial AI Agents&#xff09;2. 金融大型语言模型&#xff08;Financial LLMs&#xff09;3. LLMOps4. 数据操作&#xff08;DataOps&#xff09;5. 多源LLM基础模型&#xff08;Multi-Source LLM Foundation Models&am…

《SegFace: Face Segmentation of Long-Tail Classes》论文分享(侵删)

author{Kartik Narayan and Vibashan VS and Vishal M. Patel} 原文链接&#xff1a;[2412.08647] SegFace: Face Segmentation of Long-Tail Classes 摘要 人脸解析是指将人脸语义分割为眼睛、鼻子、头发等关键面部区域。它是各种高级应用程序的先决条件&#xff0c;包括人脸…

readline模块详解!!【Node.js】

‌“书到用时方恨少&#xff0c;事非经过不知难。”‌ —— 陆游 目录 ‌readline 是什么&#xff1f;‌基本用法&#xff1a;‌创建 Interface 类&#xff1a;核心流程‌&#xff1a; ‌Interface 类的关键事件&#xff1a;line&#xff1a;close&#xff1a;pause&#xff1a…

基于POI的Excel下拉框自动搜索,包括数据验证的单列删除

目录 目标 例子 1.搜索下拉框页 2.数据源页 3.效果 代码以及注意事项 1.代码 2.注意事项 1.基于Excel的话&#xff0c;相当于加入了一个【数据验证】 2.代码中的一些方法说明 目标 期望在Excel利用代码创建具备自动搜索功能的下拉框 例子 1.搜索下拉框页 2.数据源…

UWB人员定位:精准、高效、安全的智能管理解决方案

在现代企业管理、工业生产、安全监测等领域&#xff0c;UWB&#xff08;超宽带&#xff09;人员定位系统正逐步成为高精度定位技术的首选。相较于传统的GPS、Wi-Fi、蓝牙等定位方式&#xff0c;UWB具备厘米级高精度、低延迟、高安全性、抗干扰强等突出优势&#xff0c;能够实现…