STM32的DMA解释

一句话解释:

DMA的特点就是无需CPU的参与就可以直接访问内存(可以直接读取内存的数据,也可以直接传数据给内存)

这个内存一般指的是片内SRAM、片内Flash

我举个例子:

有一个温度传感器,它以较高的频率(例如每秒1000次)采样温度数据,并通过SPI(Serial Peripheral Interface)接口将数据发送到STM32。你需要将这些数据存储到内存中,以便后续进行数据分析或处理。

如果用CPU的话,CPU需要频繁的从SPI接口读取数据并写入内存,会占用大量的CPU时间影响其它任务的执行。另外,CPU在数据搬运上的效率低。

那怎么办呢?

我们可以不通过CPU,让DMA当这个中间人,外设读到什么数据就直接写入到内存。让CPU做别的事情去,不会影响到CPU正常处理。

步入正题

STM32F103有 2 个 DMA 控制器,分别是DMA1和DMA2

DMA1 有 7 个通道、DMA2 有 5个通道

每个通道专门用来管理来自于一个或多个外设对存储器访问的请求

在同一个DMA模块上,多个请求间的优先权可以通过软件设置。

如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优先权。举个例子,通道2优先于通道4

代码设计

定义全局变量

#define SPI_RX_BUFFER_SIZE 1000  // 缓冲区大小,假设每秒采样1000次
uint8_t SPI_RxBuffer[SPI_RX_BUFFER_SIZE];  // 存储接收到的数据
volatile uint8_t DMA_TcFlag = 0;  // DMA传输完成标志

初始化结构体

typedef struct
{uint32_t DMA_PeripheralBaseAddr;   // 外设地址uint32_t DMA_MemoryBaseAddr;       // 存储器地址uint32_t DMA_DIR;                  // 传输方向uint32_t DMA_BufferSize;           // 传输数目uint32_t DMA_PeripheralInc;        // 外设地址增量模式uint32_t DMA_MemoryInc;            // 存储器地址增量模式uint32_t DMA_PeripheralDataSize;   // 外设数据宽度uint32_t DMA_MemoryDataSize;       // 存储器数据宽度uint32_t DMA_Mode;                 // 模式选择uint32_t DMA_Priority;             // 通道优先级uint32_t DMA_M2M;                  // 存储器到存储器模式
} DMA_InitTypeDef;

DMA初始化函数

void My_DMA_Init(void)
{// 1. 打开DMA1控制器时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);// 2. 配置DMA2通道3作为SPI1接收 : 外设 -> 内存DMA_InitTypeDef DMA_Config;DMA_Config.DMA_Channel = DMA_Channel_3;  // SPI1_RXDMA_Config.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;  // SPI1数据寄存器地址DMA_Config.DMA_MemoryBaseAddr = (uint32_t)SPI_RxBuffer;  // 内存缓冲区地址DMA_Config.DMA_DIR = DMA_DIR_PeripheralSRC;  // 外设 -> 内存DMA_Config.DMA_BufferSize = SPI_RX_BUFFER_SIZE;  // 缓冲区大小DMA_Config.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  // 外设地址不递增DMA_Config.DMA_MemoryInc = DMA_MemoryInc_Enable;  // 内存地址递增DMA_Config.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  // 数据大小为字节DMA_Config.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_Config.DMA_Mode = DMA_Mode_Normal;  // 普通模式DMA_Config.DMA_Priority = DMA_Priority_High;  // 高优先级DMA_Config.DMA_FIFOMode = DMA_FIFOMode_Disable;  // 禁用FIFODMA_Config.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;DMA_Config.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_Config.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA2_Stream3, &DMA_Config);// 3. 配置DMA2通道3支持DMA_IT_TC中断 DMA_ITConfig(DMA2_Stream3, DMA_IT_TC, ENABLE);// 4. 配置NVIC支持DMA2通道3中断 NVIC_InitTypeDef NVIC_Config;NVIC_Config.NVIC_IRQChannel = DMA2_Stream3_IRQn;  // DMA2通道3中断NVIC_Config.NVIC_IRQChannelPreemptionPriority = 0;NVIC_Config.NVIC_IRQChannelSubPriority = 0;NVIC_Config.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_Config);
}
有一些参数可以更改:

SPI初始化函数

void My_SPI_Init(void)
{// 1. 打开SPI1控制器时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);// 2. 配置SPI1SPI_InitTypeDef SPI_Config;SPI_Config.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //表示SPI使用两条线(MOSI和MISO)进行全双工通信//表示SPI1工作在主模式(Master Mode)。主模式下,SPI1可以主动发送数据并控制时钟线(SCK)。SPI_Config.SPI_Mode = SPI_Mode_Master;SPI_Config.SPI_DataSize = SPI_DataSize_8b;SPI_Config.SPI_CPOL = SPI_CPOL_High;SPI_Config.SPI_CPHA = SPI_CPHA_2Edge;SPI_Config.SPI_NSS = SPI_NSS_Soft;SPI_Config.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;SPI_Config.SPI_FirstBit = SPI_FirstBit_MSB;SPI_Config.SPI_CRCPolynomial = 7;SPI_Init(SPI1, &SPI_Config);// 3. 启用SPI1SPI_Cmd(SPI1, ENABLE);// 4. 配置SPI1支持DMA接收。//这使得SPI1可以在接收到数据时自动触发DMA传输,将数据存储到内存。SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
}

DMA中断处理函数

void DMA2_Stream3_IRQHandler(void)
{// 1. 判断是否为传输完成中断if(DMA_GetITStatus(DMA2_Stream3, DMA_IT_TCIF3) != RESET){// 2. 清除中断标志DMA_ClearITPendingBit(DMA2_Stream3, DMA_IT_TCIF3);// 3. 关闭DMA通道DMA_Cmd(DMA2_Stream3, DISABLE);// 4. 设置传输完成标志DMA_TcFlag = 1;}
}

测试函数

void SPI_DMA_Rx_Test(void)
{// 1. 初始化缓冲区。清空接收缓冲区,确保没有残留数据。memset(SPI_RxBuffer, 0, SPI_RX_BUFFER_SIZE);// 2. 关闭DMA通道DMA_Cmd(DMA2_Stream3, DISABLE);// 3. 设置DMA传输长度DMA_SetCurrDataCounter(DMA2_Stream3, SPI_RX_BUFFER_SIZE);// 4. 启动DMA接收SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);DMA_Cmd(DMA2_Stream3, ENABLE);// 5. 等待DMA传输完成while(!DMA_TcFlag){// 可以在这里执行其他任务}// 6. 遍历缓冲区,打印接收到的数据for(int i = 0; i < SPI_RX_BUFFER_SIZE; i++){printf("Data[%d]: %d\n", i, SPI_RxBuffer[i]);}// 7. 清除标志DMA_TcFlag = 0;
}

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

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

相关文章

DIN:引入注意力机制的深度学习推荐系统,

实验和完整代码 完整代码实现和jupyter运行&#xff1a;https://github.com/Myolive-Lin/RecSys--deep-learning-recommendation-system/tree/main 引言 在电商与广告推荐场景中&#xff0c;用户兴趣的多样性和动态变化是核心挑战。传统推荐模型&#xff08;如Embedding &…

网页五子棋——用户模块

目录 用户注册 注册时序图 约定前后端交互接口 后端实现 controller 层接口设计 service 层接口设计 dao 层接口设计 全局异常处理 接口测试 前端实现 register.html css common.css register.css js 注册模块测试 用户登录 登录时序图 约定前后端交互接口 …

深度学习04 数据增强、调整学习率

目录 数据增强 常用的数据增强方法 调整学习率 学习率 调整学习率 ​调整学习率的方法 有序调整 等间隔调整 多间隔调整 指数衰减 余弦退火 ​自适应调整 自定义调整 数据增强 数据增强是通过对训练数据进行各种变换&#xff08;如旋转、翻转、裁剪等&#xff09;&am…

Ubuntu22.04 Deepseek-R1本地容器化部署/内网穿透/OPENWEBUI,打造个人AI助手!

1. 前言 本地部署DeepSeek并实现内网穿透&#xff0c;为家庭成员提供强大的AI支持。通过使用Ollama、Docker、OpenWebUI和Nginx&#xff0c;内网穿透&#xff0c;我们可以轻松实现快速响应和实时搜索功能。 2.软硬件环境 系统&#xff1a;ubuntu22.04, cuda12GPU: RTX2080Ti …

DeepSeek与ChatGPT的全面对比

在人工智能&#xff08;AI&#xff09;领域&#xff0c;生成式预训练模型&#xff08;GPT&#xff09;已成为推动技术革新的核心力量。OpenAI的ChatGPT自发布以来&#xff0c;凭借其卓越的自然语言处理能力&#xff0c;迅速占据市场主导地位。然而&#xff0c;近期中国AI初创公…

[HarmonyOS]鸿蒙(添加服务卡片)推荐商品 修改卡片UI(内容)

什么是服务卡片 &#xff1f; 鸿蒙系统中的服务卡片&#xff08;Service Card&#xff09;就是一种轻量级的应用展示形式&#xff0c;它可以让用户在不打开完整应用的情况下&#xff0c;快速访问应用内的特定功能或信息。以下是服务卡片的几个关键点&#xff1a; 轻量级&#…

【数据结构】 栈和队列

在计算机科学的世界里&#xff0c;数据结构是构建高效算法的基础。栈&#xff08;Stack&#xff09;和队列&#xff08;Queue&#xff09;作为两种基本且重要的数据结构&#xff0c;在软件开发、算法设计等众多领域都有着广泛的应用。今天&#xff0c;我们就来深入探讨一下栈和…

「软件设计模式」桥接模式(Bridge Pattern)

深入解析桥接模式&#xff1a;解耦抽象与实现的艺术 一、模式思想&#xff1a;正交维度的优雅解耦 桥接模式&#xff08;Bridge Pattern&#xff09;通过分离抽象&#xff08;Abstraction&#xff09;与实现&#xff08;Implementation&#xff09;&#xff0c;使二者可以独立…

新建github操作

1.在github.com的主页根据提示新建一个depository。 2.配置用户名和邮箱 git config --global user.name "name" git config --global user.email "email" 3.生成ssh秘钥 ssh-keygen -t rsa 找到public key 对应的文件路径 cat /root/.ssh/id_rsa 复制显…

【力扣】108.将有序数组转换为二叉搜索树

AC截图 题目 思路 因为nums数组是严格递增的&#xff0c;所以只需要每次选出中间节点&#xff0c;然后用左边部分构建左子树&#xff0c;用右边部分构建右子树。 代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* …

如何在 Mac 上解决 Qt Creator 安装后应用程序无法找到的问题

在安装Qt时&#xff0c;遇到了一些问题&#xff0c;尤其是在Mac上安装Qt后&#xff0c;发现Qt Creator没有出现在应用程序中。通过一些搜索和操作&#xff0c;最终解决了问题。以下是详细的记录和解决方法。 1. 安装Qt后未显示Qt Creator 安装完成Qt后&#xff0c;启动应用程…

Spring AI发布!让Java紧跟AI赛道!

1. 序言 在当今技术发展的背景下&#xff0c;人工智能&#xff08;AI&#xff09;已经成为各行各业中不可忽视的重要技术。无论是在互联网公司&#xff0c;还是传统行业&#xff0c;AI技术的应用都在大幅提升效率、降低成本、推动创新。从智能客服到个性化推荐&#xff0c;从语…

数据库脚本MySQL8转MySQL5

由于生产服务器版本上部署的是MySQL5&#xff0c;而开发手里的脚本代码是MySQL8。所以只能降版本了… 升级版本与降级版本脚本转换逻辑一样 MySQL5与MySQL8版本SQL脚本区别 大多数无需调整、主要是字符集与排序规则 MySQL5与MySQL8版本SQL字符集与排序规则 主要操作&…

STM32物联网终端实战:从传感器到云端的低功耗设计

STM32物联网终端实战&#xff1a;从传感器到云端的低功耗设计 一、项目背景与挑战分析 1.1 物联网终端典型需求 &#xff08;示意图说明&#xff1a;传感器数据采集 → 本地处理 → 无线传输 → 云端存储&#xff09; 在工业物联网场景中&#xff0c;终端设备需满足以下核心需…

牛客寒假训练营3

M 牛客传送门 代码如下: const int N2e610,M1e410; const int INF0x3f3f3f3f; const int mod998244353; ll n;void solve(){string s; cin >> s;string ns"nowcoder";sort(s.begin(),s.end(…

BY组态:构建灵活、可扩展的自动化系统

引言 在现代工业自动化领域&#xff0c;BY组态&#xff08;Build Your Own Configuration&#xff09;作为一种灵活、可扩展的解决方案&#xff0c;正逐渐成为工程师和系统集成商的首选。BY组态允许用户根据具体需求自定义系统配置&#xff0c;从而优化生产效率、降低成本并提…

DeepSeek 通过 API 对接第三方客户端 告别“服务器繁忙”

本文首发于只抄博客&#xff0c;欢迎点击原文链接了解更多内容。 前言 上一期分享了如何在本地部署 DeepSeek R1 模型&#xff0c;但通过命令行运行的本地模型&#xff0c;问答的交互也要使用命令行&#xff0c;体验并不是很好。这期分享几个第三方客户端&#xff0c;涵盖了桌…

【第10章:自然语言处理高级应用—10.4 NLP领域的前沿技术与未来趋势】

各位技术探险家们,今天我们要开启一场穿越语言智能奇点的时空之旅。从正在改写物理定律的万亿参数大模型,到能看懂《星际穿越》剧本的跨模态AI,再到正在颠覆编程方式的神经-符号混合系统……这篇万字长文将带你摸清NLP技术进化的七块关键拼图。(建议边读边做笔记,文末有技…

自动驾驶---如何打造一款属于自己的自动驾驶系统

在笔者的专栏《自动驾驶Planning决策规划》中&#xff0c;主要讲解了行车的相关知识&#xff0c;从Routing&#xff0c;到Behavior Planning&#xff0c;再到Motion Planning&#xff0c;以及最后的Control&#xff0c;笔者都做了相关介绍&#xff0c;其中主要包括算法在量产上…

探索 DeepSeek:AI 领域的璀璨新星

在人工智能飞速发展的当下&#xff0c;DeepSeek 作为行业内的重要参与者&#xff0c;正以独特的技术和广泛的应用备受瞩目。 DeepSeek 是一家专注于实现 AGI&#xff08;通用人工智能&#xff09;的中国人工智能公司。它拥有自主研发的深度学习框架&#xff0c;能高效处理海量…