STM32-15-DMA

STM32-01-认识单片机
STM32-02-基础知识
STM32-03-HAL库
STM32-04-时钟树
STM32-05-SYSTEM文件夹
STM32-06-GPIO
STM32-07-外部中断
STM32-08-串口
STM32-09-IWDG和WWDG
STM32-10-定时器
STM32-11-电容触摸按键
STM32-12-OLED模块
STM32-13-MPU
STM32-14-FSMC_LCD

文章目录

  • STM32-15-DMA
    • 1. DMA与中断的区别
      • 1. DMA
      • 2. 中断
    • 2. DMA介绍
    • 3. DMA结构框图
      • 1. DMA框图
      • 2. DMA处理过程
      • 3. DMA通道
    • 4. DMA相关寄存器
    • 5. DMA相关HAL库驱动
    • 6. 代码实现

STM32-15-DMA

1. DMA与中断的区别

DMADirect Memory Access,直接内存访问) 和中断是两种不同的机制,用于管理计算机系统中外围设备与处理器之间的数据传输和处理。

1. DMA

工作原理:

  • 独立传输:DMA允许外设直接与系统内存交换数据,而不需要通过处理器(CPU)。当需要大量数据传输时,DMA控制器接管传输任务,释放CPU去执行其他任务。
  • 传输过程:DMA传输数据时,CPU启动DMA传输,然后DMA控制器接管整个传输过程。传输完成后,DMA控制器通过中断通知CPU传输完成。

作用:

  • 提高效率:DMA减少了CPU在数据传输过程中的参与,使得CPU能够执行其他任务,从而提高系统的整体效率。
  • 减少延迟:由于DMA可以独立进行传输,因此数据传输的延迟更低,特别是在处理大块数据时。
  • 应用场景:DMA广泛应用于音频视频数据流网络数据包的传输存储设备的数据读写等场景。

对程序的影响:

  • 复杂度增加:引入DMA需要对DMA控制器进行配置,可能增加程序的复杂性。
  • 同步问题:在DMA传输过程中,程序需要处理好数据同步问题,避免数据不一致性问题。

2. 中断

工作原理:

  • 中断触发:中断是外设通过中断信号通知CPU某个事件发生,如输入设备有新数据可读取,定时器到期等。
  • 中断处理:CPU响应中断后,暂停当前任务,跳转到相应的中断处理程序(ISR)执行。当中断处理程序执行完毕后,CPU恢复先前任务的执行。

作用:

  • 实时响应:中断机制使CPU能够实时响应外设事件,保证系统对外部事件的快速反应。
  • 事件驱动:中断使得程序可以基于事件驱动,而不是定期轮询外设状态,从而节省CPU资源。
  • 应用场景键盘输入鼠标移动网络数据包到达定时器事件等。

对程序的影响:

  • 中断处理程序设计:中断处理程序需要尽可能简短、快速,避免长时间占用CPU。
  • 中断优先级管理:系统中可能有多个中断源,需要合理设计中断优先级,以确保关键中断能够及时响应。
  • 上下文切换开销:中断会引起上下文切换,带来一定的性能开销。

总结

  • DMA:适用于大量数据传输,降低CPU负载,提高系统效率。
  • 中断:适用于实时事件响应,保证系统对外部事件的快速处理。

两者结合使用,可以构建高效、实时的嵌入式系统。例如,DMA用于大数据块的传输,而中断用于触发DMA传输和处理传输完成事件。

2. DMA介绍

  • DMA: 即直接存储器访问。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,能使CPU的效率大为提高。
  • STM32F103内部有2个DMA控制器,DMA17个通道,DMA25个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求,还有一个仲裁器来协调各个DMA请求的优先权。
  • 特性:
    • 每个通道都直接连接专用的硬件DMA请求,每个通道都支持软件触发。这些功能通过软件来配置。
    • 在七个请求间的优先权可以通过软件编程设置,当软件相同时,由硬件决定。
    • 独立的源和目标数据区的传输宽度,模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
    • 支持循环的缓冲器管理。
    • 每个通道都有3个事件标志,这3个事件标志逻辑或成为一个单独的中断请求。
    • 存储器和存储器间的传输。
    • 外设和存储器,存储器和外设的传输。
    • 闪存、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和目标。
    • 可编程的数据传输数目最大为65535。

3. DMA结构框图

1. DMA框图

在这里插入图片描述

  • DMA请求

    如果外设想要通过DMA来传输数据,必须先给DMA控制器发送DMA请求,DMA收到请求信号之后,控制器会给外设一个应答信号,当外设应答后且DMA控制器收到应答信号之后,就会启动DMA的传输,直到传输完毕。

  • DMA通道

    DMA具有12个独立可编程的通道,其中DMA1有7个通道,DMA2有5个通道,每个通道对应不同的外设的DMA请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。

  • DMA优先级

    当发生多个DMA通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器管理。仲裁器管理DMA通道请求分为两个阶段。第一阶段属于软件阶段,可以在DMA_CCRx寄存器中设置,有4个等级:非常高四个优先级。第二阶段属于硬件阶段,如果两个或以上的DMA通道请求设置的优先级一样,则他们优先级取决于通道编号,编号越低优先权越高,比如通道0高于通道1。在大容量产品和互联型产品中,DMA1控制器拥有高于DMA2控制器的优先级。

2. DMA处理过程

在这里插入图片描述

DMA(Direct Memory Access,直接内存访问)是一种允许外设直接与系统内存进行数据传输的机制,不需要CPU的直接干预。以下是DMA处理过程的详细描述:

DMA处理过程

  1. 配置DMA控制器
    • 源地址:设置数据传输的源地址(可以是外设寄存器地址或内存地址)。
    • 目标地址:设置数据传输的目标地址(可以是外设寄存器地址或内存地址)。
    • 传输方向:指定数据传输的方向,是从外设到内存,还是从内存到外设。
    • 数据长度:设置需要传输的数据长度(字节数)。
    • 传输模式:选择传输模式,可以是单次传输、块传输或连续传输模式。
  2. 启动DMA传输
    • 触发传输:在配置完成后,通过设置DMA控制器的启动位,开始数据传输。
    • 数据搬运:DMA控制器接管数据传输任务,将数据从源地址搬运到目标地址。这个过程中,DMA控制器直接与内存控制器和外设总线进行交互,不需要CPU干预。
  3. 中断通知
    • 传输完成中断:数据传输完成后,DMA控制器产生中断信号,通知CPU传输已经完成。CPU执行相应的中断服务程序(ISR)处理后续任务。
    • 错误处理:如果在传输过程中发生错误(如总线错误),DMA控制器也会产生中断,通知CPU进行错误处理。

3. DMA通道

DMA1通道与外设的对应关系
在这里插入图片描述

DMA2通道与外设的对应关系
在这里插入图片描述

4. DMA相关寄存器

寄存器名称作用
DMA_CCRxDMA通道x配置寄存器用于配置DMA(核心控制寄存器)
DMA_ISRDMA中断状态寄存器用于查询当前DMA传输状态
DMA_IFCRDMA中断标志清除寄存器用来清除DMA_ISR对应位
DMA_CNDTRxDMA通道x传输数量寄存器用于控制DMA通道x每次传输的数据量
DMA_CPARxDMA通道x外设地址寄存器用于存储STM32外设地址
DMA_CMARxDMA通道x存储器地址寄存器用于存放存储器的地址
USART_CR3USART控制寄存器3用于使能串口DMA发送
  • DMA通道x配置寄存器(DMA_CCRx
    在这里插入图片描述

  • DMA中断状态寄存器(DMA_ISR
    在这里插入图片描述

  • DMA 中断标志清除寄存器(DMA_IFCR
    在这里插入图片描述

  • DMA通道x传输数量寄存器(DMA_CNDTRx)
    在这里插入图片描述

    该寄存器控制着DMA通道x的每次传输所要传输的数据量。其设置范围为0~65535。并且该寄存器的值随着传输的进行而减少,当该寄存器的值为0的时候就代表此次数据传输己经全部发送完成。可以通过这个寄存器的值来获取当前DMA传输的进度

  • DMA通道x外设地址寄存器(DMA_CPARx
    在这里插入图片描述

    用来存储 STM32 外设的地址。

  • DMA通道x存储器地址寄存器(DMA_CMARx
    在这里插入图片描述

    用来存放存储器的地址。

5. DMA相关HAL库驱动

  1. 使能DMA时钟

    __HAL_RCC_DMA1_CLK_ENABLE();
    
  2. 初始化DMA

    HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma);typedef struct
    { uint32_t Direction; /* 传输方向,例如存储器到外设 DMA_MEMORY_TO_PERIPH */uint32_t PeriphInc; /* 外设(非)增量模式,非增量模式 DMA_PINC_DISABLE */ uint32_t MemInc; /* 存储器(非)增量模式,增量模式 DMA_MINC_ENABLE */ uint32_t PeriphDataAlignment; /* 外设数据大小:8/16/32 位 */uint32_t MemDataAlignment; /* 存储器数据大小:8/16/32 位 */uint32_t Mode; /* 模式:循环模式/普通模式 */ uint32_t Priority; /* DMA 优先级:低/中/高/非常高 */
    }DMA_InitTypeDef;__HAL_LINKDMA(&g_uart1_handler, hdmatx, g_dma_handle);
    
  3. 使能串口的DMA发送,启动传输

    HAL_UART_Transmit_DMA()HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart); /* 停止 */
    HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart); /* 暂停 */
    HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart); /* 恢复 */
    
  4. 查询DMA传输状态

    //查询DMA传输通道的状态
    __HAL_DMA_GET_FLAG(&g_dma_handle, DMA_FLAG_TC4);//获取当前传输剩余数据量
    __HAL_DMA_GET_COUNTER(&g_dma_handle);//设置对应的DMA数据流传输的数据量大小
    __HAL_DMA_SET_COUNTER (&g_dma_handle, 1000);
    
  5. DMA中断使用

    //通用中断处理函数
    void HAL_DMA_IRQHandler();//相关中断回调函数
    //发送完成回调函数
    void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
    //发送一半回调函数
    void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);
    //接收完成回调函数
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
    //接收一半回调函数
    void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);
    //传输出错回调函数
    void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);
    

6. 代码实现

  • 功能

    每按下按键KEY0,串口1就会以DMA方式发送数据,同时在LCD上面显示传送进度。打开串口调试助手,可以收到DMA发送的内容。LED0闪烁用于提示程序正在运行。

  • DMA初始化函数

    void dma_init(DMA_Channel_TypeDef* DMAx_CHx)
    {if((uint32_t)DMAx_CHx > (uint32_t)DMA1_Channel7){__HAL_RCC_DMA2_CLK_ENABLE();}else{__HAL_RCC_DMA2_CLK_ENABLE();}//将DMA与USART1连接起来__HAL_LINKDMA(&g_uart1_handle, hdmatx, g_dma_handle); g_dma_handle.Instance = DMAx_CHx;                   //USART1_TX使用的DMA通道为DMA_Channel4g_dma_handle.Init.Direction = DMA_MEMORY_TO_PERIPH; //模式选择为从存储器到外设g_dma_handle.Init.PeriphInc = DMA_PINC_DISABLE;     //外设非增量模式g_dma_handle.Init.MemInc = DMA_MINC_ENABLE;         //存储器增量模式g_dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外设数据长度为8位g_dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;    //存储器数据长度为8位g_dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;            //中等优先级HAL_DMA_Init(&g_dma_handle);
    }
    
  • 主函数

    int main(void)
    {uint16_t i, k;uint16_t len;uint8_t  mask = 0;float pro = 0;          /* 进度 */HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */usart_init(115200);                 /* 串口初始化为115200 */led_init();                         /* 初始化LED */lcd_init();                         /* 初始化LCD */key_init();                         /* 初始化按键 */dma_init(DMA1_Channel4);            /* 初始化串口1 TX DMA */lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);lcd_show_string(30, 70, 200, 16, 16, "DMA TEST", RED);lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);lcd_show_string(30, 110, 200, 16, 16, "KEY0:Start", RED);len = sizeof(TEXT_TO_SEND);k = 0;for (i = 0; i < SEND_BUF_SIZE; i++) /* 填充ASCII字符集数据 */{if (k >= len)   /* 入换行符 */{if (mask){g_sendbuf[i] = 0x0a;k = 0;}else{g_sendbuf[i] = 0x0d;mask++;}}else     /* 复制TEXT_TO_SEND语句 */{mask = 0;g_sendbuf[i] = TEXT_TO_SEND[k];k++;}}i = 0;while (1){if (key_scan(0) == 1)       /* KEY0按下 */{printf("\r\nDMA DATA:\r\n");lcd_show_string(30, 130, 200, 16, 16, "Start Transimit....", BLUE);lcd_show_string(30, 150, 200, 16, 16, "   %", BLUE);    /* 显示百分号 */HAL_UART_Transmit_DMA(&g_uart1_handle, g_sendbuf, SEND_BUF_SIZE);/* 等待DMA传输完成,此时我们来做另外一些事情,比如点灯  * 实际应用中,传输数据期间,可以执行另外的任务 */while (1){if ( __HAL_DMA_GET_FLAG(&g_dma_handle, DMA_FLAG_TC4))   /* 等待 DMA1_Channel4 传输完成 */{__HAL_DMA_CLEAR_FLAG(&g_dma_handle, DMA_FLAG_TC4);HAL_UART_DMAStop(&g_uart1_handle);                  /* 传输完成以后关闭串口DMA */break;}pro = DMA1_Channel4->CNDTR; /* 得到当前还剩余多少个数据 */len = SEND_BUF_SIZE;        /* 总长度 */pro = 1 - (pro / len);      /* 得到百分比 */pro *= 100;                 /* 扩大100倍 */lcd_show_num(30, 150, pro, 3, 16, BLUE);} lcd_show_num(30, 150, 100, 3, 16, BLUE);    /* 显示100% */lcd_show_string(30, 130, 200, 16, 16, "Transimit Finished!", BLUE); /* 提示传送完成 */}i++;delay_ms(10);if (i == 20){LED0_TOGGLE();  /* LED0闪烁,提示系统正在运行 */i = 0;}}
    }
    
  • 实验结果

    通过LCD屏可以看到数据传输的百分比,通过串口助手可以看到传输的数据

在这里插入图片描述

声明:资料来源(战舰STM32F103ZET6开发板资源包)

  1. Cortex-M3权威指南(中文).pdf
  2. STM32F10xxx参考手册_V10(中文版).pdf
  3. STM32F103 战舰开发指南V1.3.pdf
  4. STM32F103ZET6(中文版).pdf
  5. 战舰V4 硬件参考手册_V1.0.pdf

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

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

相关文章

数据挖掘--认识数据

数据挖掘--引论 数据挖掘--认识数据 数据挖掘--数据预处理 数据挖掘--数据仓库与联机分析处理 数据挖掘--挖掘频繁模式、关联和相关性&#xff1a;基本概念和方法 数据挖掘--分类 数据挖掘--聚类分析&#xff1a;基本概念和方法 数据对象与属性类型 属性&#xff1a;是一…

csrf与xss差别 别在弄乱了 直接靶场实操pikachu的csrf题 token绕过可以吗???

我们现在来说说这2个之间的关系&#xff0c;因为昨天的我也没有弄清楚这2者的关系&#xff0c;总感觉迷迷糊糊的。 xss这个漏洞是大家并不怎么陌生&#xff0c;导致xss漏洞的产生是服务器没有对用户提交数据过滤不严格&#xff0c;导致浏览器把用户输入的当作js代码返回客户端…

Selenium时间等待_显示等待

特点&#xff1a; 针对具体元素进行时间等待 可以自定义等待时长和间隔时间 按照设定的时间&#xff0c;不断定位元素&#xff0c;定位到了直接执行下一步操作 如在设定时间内没定位到元素&#xff0c;则报错&#xff08;TimeOutException&#xff09; 显示等待概念&#x…

Android Compose 十:常用组件列表 监听

1 去掉超出滑动区域时的拖拽的阴影 即 overScrollMode 代码如下 CompositionLocalProvider(LocalOverscrollConfiguration provides null) {LazyColumn() {items(list, key {list.indexOf(it)}){Row(Modifier.animateItemPlacement(tween(durationMillis 250))) {Text(text…

腾讯云 TDMQ for Apache Pulsar 多地区高可用容灾实践

作者介绍 林宇强 腾讯云高级工程师 专注于消息队列、API网关、微服务、数据同步等 PaaS 领域。有多年的开发和维护经验&#xff0c;目前在腾讯云从事 TDMQ Pulsar 商业化产品方向的研发工作。 导语 本文将从四个维度&#xff0c;深入剖析 Pulsar 在多可用区高可用领域的容…

[ue5]建模场景学习笔记(5)——必修内容可交互的地形,交互沙(3)

1.需求分析&#xff1a; 我们现在已经能够让这片地形出现在任意地方&#xff0c;只要角色走在这片地形上&#xff0c;就能够产生痕迹&#xff0c;但这片区域总是需要人工指定&#xff0c;又无法把这片区域无限扩大&#xff08;显存爆炸&#xff09;&#xff0c;因此尝试使角色无…

DS:堆的结构与实现

欢迎来到Harper.Lee的学习世界&#xff01;博主主页传送门&#xff1a;Harper.Lee的博客主页想要一起进步的uu可以来后台找我哦&#xff01; 一、堆的概念与结构 1.1 堆的概念 堆&#xff08;Heap&#xff09;是完全二叉树中的一种&#xff0c;分为大根堆和小根堆。 特点&#…

LabVIEW与Python的比较及联合开发

LabVIEW和Python在工业自动化和数据处理领域各具优势&#xff0c;联合开发可以充分发挥两者的优点。本文将从语言特性、开发效率、应用场景等多个角度进行比较&#xff0c;并详细介绍如何实现LabVIEW与Python的联合开发。 语言特性 LabVIEW 图形化编程&#xff1a;LabVIEW使用…

Element-UI入门

目录 1.什么是Element-UI 2.作用 3.版本历史 4.优缺点 4.1.优点 4.2.缺点 5.应用场景 6.代码示例 7.未来展望 8.总结 1.什么是Element-UI Element-UI 是由饿了么前端团队开发的一套基于 Vue.js 的桌面端组件库。提供了一整套 UI 组件&#xff0c;使开发者能够快速构…

C语言笔记第13篇:自定义类型(联合union和枚举enum)

1、联合体 1.1 联合体类型的声明 像结构体一样&#xff0c;联合体也是由一个或多个成员构成&#xff0c;这些成员可以是不同的类型。 但是编译器只为最大的成员分配足够的内存空间&#xff0c;联合体的特点是所有成员共用一块内存空间&#xff0c;所以联合体也叫&#xff1a…

KEIL5如何打开KEIL4的GD工程

GD官方提供的很多KEIL例程为KIEL4的版本&#xff0c;读者使用的时候可能会碰到使用KEIL5打开KEIL4的工程会报错以及无法找到芯片选型的问题&#xff0c;具体表现如下图所示。 我们该怎么办呢&#xff1f; 下面为大家介绍两种方法&#xff1a; 第一种方法是在keil4的工程后缀u…

MySQ中CONCAT函数使用

在MySQL数据库管理系统中&#xff0c;处理和连接字符串是一项常见的操作。本文将介绍几个常用的字符串连接函数&#xff0c;包括CONCAT(), CONCAT_WS(), GROUP_CONCAT()以及其他相关函数&#xff0c;这些功能可以极大地简化数据库查询中的字符串操作。 1. CONCAT() 函数 CONC…

19、Go Gin框架集成Swagger

介绍&#xff1a; Swagger 支持在 Gin 路由中使用一系列注释来描述 API 的各个方面。以下是一些常用的 Swagger 注释属性&#xff0c;这些属性可以在 Gin 路由的注释中使用&#xff1a; Summary: 路由的简短摘要。Description: 路由的详细描述。Tags: 用于对路由进行分类的标…

掌握SVG基础:从零开始学习

格栅图可以实现图片的清晰显示&#xff0c;但这也意味着如果要在各种设备上使用格栅图&#xff0c;就会增加大量不同规格的格栅图&#xff0c;以适应各种尺寸的设备。这也直接导致资源文件体积的增加&#xff0c;矢量图没有这个问题。本文将SVG代码编写与即时设计工具相结合&am…

五款软件推荐:U盘数据不小心删除了?帮你快速找回!

U盘数据不小心删除了怎么恢复&#xff1f;U盘是一种便携式存储设备&#xff0c;因其小巧轻便而广受欢迎。但是&#xff0c;U盘也常常会遇到数据丢失的问题。当U盘数据丢失时&#xff0c;需要找到一款可靠的数据恢复软件来恢复数据。 接下来为大家推荐5款好用的免费U盘数据恢复软…

Soildworks学习笔记(一)

1.如何添加M3,M4等螺丝孔&#xff1a; 有时候异形孔向导显示灰色是因为没有退出草图选项卡&#xff0c;选择异形孔向导就可以进行异形孔的设定和放置&#xff1a; solidwork放置螺丝孔以及显示螺纹的问题_.16-m3 solidwork-CSDN博客 2.如何修剪线条&#xff1a; 如何倒圆角或…

【AI基础】第四步:保姆喂饭级-langchain+chatglm2-6b+m3e-base

在第三步手动安装chatglm2-6b时&#xff0c;已经可以通过web进行交互。langchain重新封装了一下AI框架&#xff0c;提供更加友好的开发功能&#xff0c;类似于AI届的spring框架。langchain的安装过程也类似于上一步说的&#xff1a;【AI基础】第三步&#xff1a;纯天然手动安装…

LabVIEW 用于 MES 系统和卡钳上位机检测

LabVIEW 确实可以用于制造执行系统&#xff08;MES&#xff09;的开发以及卡钳上位机检测。以下是详细说明&#xff1a; 使用 LabVIEW 开发 MES 系统 数据采集与处理&#xff1a;LabVIEW 擅长实时数据采集和处理&#xff0c;可以连接多种传感器和设备&#xff0c;获取生产线上…

在线按模板批量生成文本工具

具体请前往&#xff1a;在线按模板批量生成文本工具

AIGC作答《2024年高考作文|新课标I卷》能拿多少分?

AIGC作答《2024年高考作文&#xff5c;新课标I卷》能拿多少分&#xff1f; 一、前言二、题目三、作答 一、前言 如火如荼的2024年高考圆满落幕&#xff0c;在如此Happy的时刻&#xff0c;AIGC技术正以其前所未有的热度席卷全球。它不仅改变了我们获取信息的方式&#xff0c;也…