当前位置: 首页 > news >正文

关于APM32F407配置串口DMA收发没有数据的问题记录

一.问题环境

​ 整活了一套APM32F407的板子,用了APM32F4xx_SDK_V1.4的标准外设库,正在搭建移植底层BSP框架串口部分,BSP底层配置逻辑是从STM32F407移植过来的。DMA发送时才使能通道及配置外设地址及缓存大小。

​ 串口1DMA配置过程如下:


static USART_DMAConfig_t USART_ComDmaTx(DMA_ChannelType_t channel,DMA_StreamType_t stream,uint32_t peripheralBaseAddr,uint8_t IRQChannel,uint32_t dmaFlag)
{USART_DMAConfig_t dmaConfig = {0};dmaConfig.channel = channel;dmaConfig.stream = stream;dmaConfig.dma.channel = channel;dmaConfig.dma.peripheralBaseAddr = peripheralBaseAddr;			//DMA外设地址:USART数据寄存器地址dmaConfig.dma.memoryBaseAddr = (uint32_t)0;									//内存地址,使用时再配置dmaConfig.dma.dir = DMA_DIR_MEMORYTOPERIPHERAL;									//外设地址为目的地址dmaConfig.dma.bufferSize = (uint32_t)0;										//传输时缓冲区大小,使用时再配置dmaConfig.dma.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;					//外设地址固定,不递增dmaConfig.dma.memoryInc = DMA_MEMORY_INC_ENABLE;								//内存地址递增dmaConfig.dma.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_BYTE;				//外设数据格式为字节dmaConfig.dma.memoryDataSize = DMA_MEMORY_DATA_SIZE_BYTE;						//内存数据格式为字节dmaConfig.dma.loopMode = DMA_MODE_NORMAL;										//工作在正常模式,不循环dmaConfig.dma.priority = DMA_PRIORITY_HIGH;									//DMA传输优先级为高(VeryHigh/High/Medium/Low)dmaConfig.dma.fifoMode = DMA_FIFOMODE_DISABLE;										//禁能DMA的两个Memory中变量相互访问dmaConfig.dma.peripheralBurst = DMA_PERIPHERALBURST_SINGLE;						dmaConfig.dma.fifoThreshold = DMA_FIFOTHRESHOLD_QUARTER;dmaConfig.dma.memoryBurst = DMA_MEMORYBURST_SINGLE;dmaConfig.nvic.NVIC_IRQChannel = IRQChannel;dmaConfig.nvic.NVIC_IRQChannelPreemptionPriority = 6;							//抢占优先级dmaConfig.nvic.NVIC_IRQChannelSubPriority = 0;									//响应优先级dmaConfig.nvic.NVIC_IRQChannelCmd = DISABLE;									//使能中断dmaConfig.dmaFlag = dmaFlag;return dmaConfig;
}static USART_DMAConfig_t USART_Com1DmaTx(void)
{DMA_ChannelType_t channel;DMA_StreamType_t stream;uint32_t peripheralBaseAddr;uint8_t IRQChannel;uint32_t dmaFlag;channel = DMA_CHANNEL_4;stream = DMA2_Stream7;peripheralBaseAddr = (uint32_t)(&(USART1->DATA));IRQChannel = DMA2_STR7_IRQn;dmaFlag = DMA_INT_TCIFLG7;return USART_ComDmaTx(channel,stream,peripheralBaseAddr,IRQChannel,dmaFlag);
};static void USART_DmaTxConfig(USART_t USART)
{NVIC_InitType_t		NVIC_InitStructure;/* 使能时钟 */if ((uint32_t)USART->config.dmaTx.stream > (uint32_t)DMA2){GPIO_RcmAHB1PeriphClockCmd(RCM_AHB1_PERIPH_DMA2, ENABLE);		//开启DMA时钟,用于USART发射}else{GPIO_RcmAHB1PeriphClockCmd(RCM_AHB1_PERIPH_DMA1, ENABLE);		//开启DMA时钟,用于USART发射}NVIC_InitStructure = USART->config.dmaTx.nvic;DMA_Disable(USART->config.dmaTx.stream);									//先禁止DMA通道,若之前有DMA传输,则会终止 ,必须先关闭DMA通道才能配置DMA_Reset(USART->config.dmaTx.stream);														//复位DMA1通道2的初始化DMA_Config(USART->config.dmaTx.stream,&USART->config.dmaTx.dma);		//DMA初始化if (NVIC_InitStructure.NVIC_IRQChannelCmd)  {  NVIC_EnableIRQRequest((IRQn_Type)NVIC_InitStructure.NVIC_IRQChannel,NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority,NVIC_InitStructure.NVIC_IRQChannelSubPriority);									//使能中断}  DMA_ClearStatusFlag(USART->config.dmaTx.stream,USART->config.dmaTx.dmaFlag);	//清除 全部标志DMA_EnableInterrupt(USART->config.dmaTx.stream,DMA_INT_TCIFLG);			//使能DMA通道4传输完成中断DMA_Disable(USART->config.dmaTx.stream);								//更新内存地址和传输大小之后再使能}void USART_TypeInit(USART_t USART)
{USART_Reset(USART->usart);USART_DisableDMA(USART->usart,USART_DMA_TX);USART_DisableDMA(USART->usart,USART_DMA_RX);USART_Construct(USART);USART_RccConfig(USART);USART_GpioConfig(USART);USART_Disable(USART->usart);USART_InitConfig(USART);USART_NvicConfig(USART);if (USART->config.isDmaTxEnable){USART_DmaTxConfig(USART);USART_EnableDMA(USART->usart, USART_DMA_TX);}if (USART->config.isDmaRxEnable){USART_DmaRxConfig(USART);USART_EnableDMA(USART->usart, USART_DMA_RX);}
}static void USART_SendMessage(USART_t USART, uint8_t *sendBuf, uint32_t len)
{if (USART->config.isRs485Enable){USART_Rs485TxEnable(USART);}if (USART->config.isDmaTxEnable){DMA_Disable(USART->config.dmaTx.stream);			//先禁止DMA通道,若之前有DMA传输,则会终止 ,必须先关闭DMA通道才能配置while (DMA_ReadCmdStatus(USART->config.dmaTx.stream) != DISABLE);		//确保DMA可以被设置//=======直接操作寄存器更新内存地址和传输大小-----------------------------------------------------------USART->config.dmaTx.stream->M0ADDR = (uint32_t)(sendBuf);	//更新内存地址USART->config.dmaTx.stream->NDATA = len;	//更新传输时缓冲区大小DMA_ClearStatusFlag(USART->config.dmaTx.stream,USART->config.dmaTx.dmaFlag);//清除Channel2全部标志,主要是清除传输完成标志DMA_Enable(USART->config.dmaTx.stream);//等待DMA发送结束while(DMA_ReadIntFlag(USART->config.dmaTx.stream,USART->config.dmaTx.dmaFlag) == RESET);//清除标志DMA_ClearStatusFlag(USART->config.dmaTx.stream,USART->config.dmaTx.dmaFlag);if (USART->config.isRs485Enable){USART_Rs485TxDisable(USART);}USART->send->flag = true;}
}

二.问题现象

​ 串口DMA接收和中断接收都没有问题,发送中断也没有问题。但发送配置为DMA就不能发送数据。所有串口端口配置都有这个问题,确定同样的板子刷入STM32F407的的程序也能正常使用,唯独使用APM的外设库就不行。

三.原因分析

​ 当同时使用APM32F4的DMA接收和发送时,虽然同时配置了USART_EnableDMA(USART->usart, USART_DMA_TX)和USART_EnableDMA(USART->usart, USART_DMA_RX),但USART_EnableDMA这个函数你看他是怎么实现的:

/*!* @brief     Enables the USART DMA interface** @param     usart:   Select the USART or the UART peripheral** @param     dmaReq:  Specifies the DMA request*                     This parameter can be one of the following values:*                     @arg USART_DMA_TX    : USART DMA receive request*                     @arg USART_DMA_RX    : USART DMA transmit request*                     @arg USART_DMA_TX_RX : USART DMA transmit/receive request** @retval    None** @note      The usart can be USART1, USART2, USART3, UART4, UART5, USART6, UART7 and UART8*/
void USART_EnableDMA(USART_T* usart, USART_DMA_T dmaReq)
{usart->CTRL3_B.DMARXEN = dmaReq & 0x01;usart->CTRL3_B.DMATXEN = dmaReq >> 1;
}

是不是很明显的看出了问题所在,原来usart->CTRL3_B.DMARXEN = dmaReq & 0x01;这一句用的是直接赋值操作,而不是我们熟悉的按位或,这样当配置了USART_EnableDMA(USART->usart, USART_DMA_RX)后,原来的USART_EnableDMA(USART->usart, USART_DMA_TX);就被重置了,所以只能接收不能发送。

四.问题解决

发现问题后,对代码初始化部分进行改进,经过测试,正常收发。代码如下:

	if (USART->config.isDmaTxEnable && USART->config.isDmaRxEnable){USART_DmaTxConfig(USART);USART_DmaRxConfig(USART);USART_EnableDMA(USART->usart, USART_DMA_TX_RX);}else if (USART->config.isDmaTxEnable){USART_DmaTxConfig(USART);USART_EnableDMA(USART->usart, USART_DMA_TX);}else if (USART->config.isDmaRxEnable){USART_DmaRxConfig(USART);USART_EnableDMA(USART->usart, USART_DMA_RX);}

相关文章:

关于APM32F407配置串口DMA收发没有数据的问题记录

一.问题环境 ​ 整活了一套APM32F407的板子,用了APM32F4xx_SDK_V1.4的标准外设库,正在搭建移植底层BSP框架串口部分,BSP底层配置逻辑是从STM32F407移植过来的。DMA发送时才使能通道及配置外设地址及缓存大小。 ​ 串口1DMA配置过程如下&…...

基于python实现的深度学习web多格式纠错系统

基于python实现的深度学习web多格式纠错系统 开发语言:Python 数据库:MySQL所用到的知识:Django框架工具:pycharm、Navicat、Maven 系统功能实现 用户登录 登录功能是本系统一个非常重要的功能,这极大的保护了系统的安全。登录…...

UE5文件操作

首先在虚幻引擎中创建UMyBlueprintFunctionLibrary类,可以在该类中写我们重复利用的功能,并且这些功能不依赖于特定的游戏对象,方便全局调用。 1.文件的读取和写入 UFUNCTION(BlueprintCallable, Category "File")static bool lo…...

element plus 去掉select选择框的边框,并修改右侧图标

1.去掉选择框边框 ::v-deep .el-select__wrapper{ box-shadow: none; } ::v-deep .is-hovering{ box-shadow: none !important; }2.修改选择框右侧图标 新建CaretBottom.vue文件内容&#xff1a; <template><el-icon><CaretBottom /></el-icon> <…...

Ceph KernelFuse GetSet Quota

Kernel fuse set示例...

JVM学习-字节码指令集(二)

对象的创建与访问指令 创建指令 虽然类实例和数组都是对象&#xff0c;但Java虚拟机对类实例和数组的创建和操作使用了不同的字节码指令创建类实例指令&#xff1a;new 它接收一个操作数&#xff0c;指向常量池的索引&#xff0c;表示要创建的类型&#xff0c;执行完成后&am…...

解密网络流量监控:优化IT运维的利器

引言&#xff1a; 在当今数字化时代&#xff0c;网络流量监控是维护网络稳定与业务连续性的关键。作为一名资深网络工程师&#xff0c;我将分享一些关于网络流量监控的重要知识&#xff0c;并探讨如何在IT运维中运用这一工具优化网络性能&#xff0c;确保业务的顺畅进行。 1. 网…...

oracle 分区表常用语句(2)

给分区表增加分区 第一种不存在MAXVALUE(直接添加即可&#xff09; ALTER TABLE T6 ADD PARTITION P5 VALUES LESS THAN(TO_DATE( 2018-08-01 00:00:00, SYYYY-MM-DD HH24:MI:SS, NLS_CALENDARGREGORIAN));第二种存在MAXVALUE alter table T6 split PARTITION P4 at(TO_DAT…...

Python函数式编程进阶:用函数实现设计模式

文章目录 函数式编程进阶&#xff1a;用函数实现设计模式案例实现&#xff1a;构建“策略”模式使用函数实现”策略“模式享元 选择最佳策略&#xff1a;简单的方式 globals关键字 函数式编程进阶&#xff1a;用函数实现设计模式 案例实现&#xff1a;构建“策略”模式 策略模…...

Ingress controller:Kubernetes 的瑞士军刀

原文作者&#xff1a;Brian Ehlert of F5 原文链接&#xff1a;Ingress controller&#xff1a;Kubernetes 的瑞士军刀 转载来源&#xff1a;NGINX 中文官网 NGINX 唯一中文官方社区 &#xff0c;尽在 nginx.org.cn 许多人认为 Ingress controller&#xff08;Ingress 控制器&…...

uniapp tabBar app页面滚动闪屏的问题

我在做app的时候&#xff0c;调试tabBar页面滚动时莫名其妙的闪屏&#xff0c;其他页面不闪屏&#xff0c;可能跟新建的项目样式有关。 修改方法如下。 在pages.json中 "tabBar": {"selectedColor": "#204AFF","color": "#ccc…...

【计算机毕业设计】388微信小程序足球赛事及队伍管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…...

监控易监测对象及指标之:华为FusionInsight Kafka服务全方位监控

监控易提供对华为FusionInsight Kafka服务的全方位监控功能。该功能可以帮助用户实时监测Kafka服务的各项性能指标&#xff0c;确保服务的稳定运行和高效性能。 具体功能点包括&#xff1a; 服务状态监测&#xff1a;监控易能够实时监测华为FusionInsight Kafka服务的运行状态…...

Python装饰器的应用

Python 中的装饰器是一种语法糖&#xff0c;可以在运行时&#xff0c;动态的给函数或类添加功能。装饰器本质上是一个函数&#xff0c;使用 函数名就是可实现绑定给函数的第二个功能 。它的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。 …...

【数据结构与算法 | 基础篇】力扣232, 225

1. 力扣232 : 用栈实现队列 (1). 题 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移…...

内网(极空间)搭建gitlab跳板机转发端口及域名配置

背景说明 https://blog.csdn.net/GodDavide/article/details/139182475 上文说到: 我已经用docker搭好了gitlab-ce服务&#xff0c;但我是部署在自己的家庭nas-极空间z4pro里的&#xff0c;属于内网环境。 另外我有一台阿里云服务器&#xff0c;做跳板机。 我有一个阿里的域名…...

如何知道自己电脑的 Shell类型是什么?

在macOS中&#xff0c;你可以通过以下几种方法来确定当前正在使用的shell类型&#xff0c;并了解相关的配置文件&#xff1a; 1. 使用终端命令确定shell类型 打开终端应用程序&#xff08;Terminal&#xff09;。输入以下命令并按回车键&#xff1a;echo $SHELL。该命令会输出…...

Axios的使用简单说明

axios 请求方式和参数 axios 可以发送 ajax 请求&#xff0c;不同的方法可以发送不同的请求: axios.get&#xff1a;发送get请求 axios.post&#xff1a;发送post请求 axios.put&#xff1a;发送put请求 axios.delete&#xff1a;发送delete请求 无论哪种方法&#xff0c;第一…...

查找list集合中,持续时间>=ContinueTime的数据集合,保存在新的list中

在给定的包含时间戳的list中&#xff0c;查找连续continueNum次的且时间间隔为needDiff的集合。 eg&#xff1a;相邻两个数据的时间戳间隔为1分钟&#xff0c;且超过30分钟有数据 /**** param list 包含时间戳&#xff08;10位&#xff09;的list* param continueNum 至少持续…...

nginx 反向代理配置详解

Nginx 反向代理是一种常用的部署策略&#xff0c;用于将客户端请求转发到内部网络中的一个或多个服务器&#xff0c;这些服务器直接处理请求并返回响应给Nginx&#xff0c;再由Nginx转交给客户端。这种设置可以提高网站的可用性和安全性&#xff0c;同时也能实现负载均衡、缓存…...

微信小程序毕业设计-农场驿站平台系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…...

CAN总线应用协议CANopen

作为一种真正开放的CAN总线高层协议&#xff0c;CANopen协议允许不同的CAN设备以标准化的方式进行通讯&#xff0c;这使得CAN 设备具有互操作性。随着CANopen协议的日益完善&#xff0c;它已经广泛应用于多个行业。本文将对CANopen协议的对象字典、通讯对象、网络管理等几个方面…...

htop安装不了怎么解决

&#x1f31f;&#x1f30c; 欢迎来到知识与创意的殿堂 — 远见阁小民的世界&#xff01;&#x1f680; &#x1f31f;&#x1f9ed; 在这里&#xff0c;我们一起探索技术的奥秘&#xff0c;一起在知识的海洋中遨游。 &#x1f31f;&#x1f9ed; 在这里&#xff0c;每个错误都…...

vue 笔记02

目录 01 事件修饰符 02 按键修饰符 03 v-bind属性 04 vue-axios的基本使用 05 vue的生命周期 06 vue生命周期涉及到的其他的知识点 01 事件修饰符 vue的事件修饰符 事件名称.修饰符1.修饰符2...事件驱动函数 stop 阻止冒泡修饰符 prevent 阻止默认行为 once 当前事件只触…...

MySQL8.0免安装及phpmyadmin配置

安装包解压&#xff0c;运行mysqld文件后&#xff0c;启动net start&#xff0c;提示成功&#xff0c;但进入phpmyadmin登录页面后&#xff0c;输入用户名&#xff0c;提示不支持空密码&#xff0c;config.default.php设置密码后&#xff0c;提示 mysqli::real_connect(): (HY…...

【目标解算】相机内外参数详细解读+坐标系转换

一、相机参数介绍 1.1 相机内参矩阵 概念&#xff1a;内参矩阵用于描述相机的内部参数&#xff0c;它包含了相机的焦距、主点坐标和图像的畸变等信息。内参矩阵的形式通常为一个3x3的矩阵&#xff0c;常用表示为K。内参矩阵可以将相机坐标系中的三维点映射到图像平面上的二维…...

【Unity】颜色混合计算

在图形渲染中&#xff0c;颜色混合&#xff08;Color Blending&#xff09;是指将多个颜色值组合在一起以生成最终显示的颜色。颜色混合技术广泛用于处理半透明效果、光照效果和后期处理效果。以下是一些常见的颜色混合模式&#xff1a; 1. 正常混合&#xff08;Normal Blendi…...

Vue源码解析

入门级 <body><div id"app"></div><script>class Vue {constructor(options) {// thisVue 把options.created的this 指向Vue实例options.created.bind(this)();// this.$el 指向#appthis.$el document.querySelector(options.el);// 把opt…...

Linux---网络相关配置

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 一台主机需要配置必要的网络信息&#xff0c;才可以连接到互联网&#xff0c;需要的配置网络信息包括IP&#xff0c;子网掩码&#xff0c;网关和DNS。 一.查看网络信息 查看IP信息可以通…...

MATLAB分类与判别模型算法:基于Fisher算法的分类程序【含Matlab源码 MX_002期】

算法思路介绍&#xff1a; 费舍尔线性判别分析&#xff08;Fishers Linear Discriminant Analysis&#xff0c;简称 LDA&#xff09;&#xff0c;用于将两个类别的数据点进行二分类。以下是代码的整体思路&#xff1a; 生成数据&#xff1a; 使用 randn 函数生成随机数&#x…...