STM32 hal库使用笔记(四)DMA—内存到内存/内存到外设

这篇具有很好参考价值的文章主要介绍了STM32 hal库使用笔记(四)DMA—内存到内存/内存到外设。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、简介

1.DMA简介

2.一些概念

3.工作原理

二、HAL库的配置

1.时钟树的设置

2.DMA配置

2.1 内存到内存(代码对应3.1)

2.2 内存到外设(代码对应3.2)

三、代码编写


一、简介

1.DMA简介

    DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源 12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道) 每个通道都支持软件触发和特定的硬件触发。

2.一些概念

关于DMA的一些概念,个人认为比较基础,必须要知道,欢迎补充。

地址:DMA的传输过程中,必须要确定源地址和目的地址,在后面代码会有明显体现。

传输模式:内存到内存,内存到外设,外设到内存。本次实验主要验证前两个,原理在实验前会有说明,只做简单验证。

数据宽度:字节,半字,字(4字节)。一般数据传输都用一个字节宽度。

DMA工作模式:正常(Normal)/循环(Circular)。个人认为,除非数据的传输的时间是无法预测,比如串口接收,大部分用正常模式(传输一次后自动关闭)即可,下次需要传递数据时再启动DMA传输。

DMA流的优先级别:非常高/高/中等/低。跟DMA中断非常类似,但不要混淆,流的优先级别越高,会优先进行DMA传输。

    其余的概念会在需要补充的地方补充。

3.工作原理

stm32 memset在哪个库,STM32的hal库使用,stm32,笔记,嵌入式硬件

    这张图将DMA的工作原理描述的非常清楚,不再赘述。补充一点,外设/内存的地址是否自增看实际情况,像第一个实验,内存到内存,两个内存块的大小大于一个数据宽度,显然需要自增;第二个实验中,将内存的数据通过串口发出,内存的数据块需要自增,而串口发送字寄存器是固定的,不需要自增,理解就好。

二、HAL库的配置

1.时钟树的设置

STM32 hal库使用笔记(一)GPIO的使用—流水灯_乱码小伙的博客-CSDN博客

参考这篇文章中的配置即可。

2.DMA配置
2.1 内存到内存(代码对应3.1)

stm32 memset在哪个库,STM32的hal库使用,stm32,笔记,嵌入式硬件

    按照如图所示配置,本次实验通过按键来触发DMA传输并通过LED验证,所以选择正常模式。流的优先级随便,只有一个DMA传输。

配置完成后生成代码即可。

2.2 内存到外设(代码对应3.2)

stm32 memset在哪个库,STM32的hal库使用,stm32,笔记,嵌入式硬件

   主要记录关于DMA的配置,串口相关参数默认即可。流的级别也随便,与2.1是两个实验,如果在同一个工程中可按照需要配置;模式是正常模式,本次实验通过按键触发DMA传输;外设非自增,寄存器自增模式,原因前边已经解释。

配置完成后,生成代码即可。

三、代码编写

3.1

用户主要完成的工作就是在每次DMA传输的时候开启DMA传输即可。

以下代码均在dam.c中编写

添加两个数组:

   uint8_t src_buf[10] = {0x0a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
   uint8_t dest_buf[10] = {0};

void MX_DMA_Init(void) 
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* Configure DMA request hdma_memtomem_dma1_channel1 on DMA1_Channel1 */
  hdma_memtomem_dma1_channel1.Instance = DMA1_Channel1;
  hdma_memtomem_dma1_channel1.Init.Direction = DMA_MEMORY_TO_MEMORY;
  hdma_memtomem_dma1_channel1.Init.PeriphInc = DMA_PINC_ENABLE; // 增量模式
  hdma_memtomem_dma1_channel1.Init.MemInc = DMA_MINC_ENABLE;//增量模式,指针自动向下,否则只会传输/收到第一个字节的数据
  hdma_memtomem_dma1_channel1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_memtomem_dma1_channel1.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
  hdma_memtomem_dma1_channel1.Init.Mode = DMA_NORMAL;
  hdma_memtomem_dma1_channel1.Init.Priority = DMA_PRIORITY_HIGH;
  if (HAL_DMA_Init(&hdma_memtomem_dma1_channel1) != HAL_OK)
  {
    Error_Handler();
  }

  HAL_DMA_Start(&hdma_memtomem_dma1_channel1, (uint32_t)src_buf, (uint32_t)dest_buf, 0);//开启DMA传输,由于初始化不需要传输数据,所以数据传输个数是0

}
void dma_enable_transmit(uint16_t cndtr)//DMA传输完成后,传输个数会清零,使能后赋值并开启
{
    __HAL_DMA_DISABLE(&hdma_memtomem_dma1_channel1);
    
//    DMA1_Channel1->CNDTR = cndtr;
    hdma_memtomem_dma1_channel1.Instance->CNDTR = cndtr;
    
    __HAL_DMA_ENABLE(&hdma_memtomem_dma1_channel1);
}

以下在main.c中编写

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  /* USER CODE BEGIN 2 */
//    memset(dest_buf, 0, 10);
//    dma_enable_transmit(10);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      
    if(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==0)
    {
        HAL_Delay(20);
          if(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==0)
       {
            src_buf[0]++;
            src_buf[1]++;
            memset(dest_buf, 0, 10);//初始化dest_buf
            dma_enable_transmit(10);// 由于内存到内存的传输无法循环,所以需要不断重装载传输的个数
           while(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == 0);

           if(dest_buf[0]==src_buf[0])
           {
           HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
           }
           if(dest_buf[1]==0x03)
           {
            HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);
           }
           while (__HAL_DMA_GET_FLAG(&hdma_memtomem_dma1_channel1, DMA_FLAG_TC1)!=HAL_OK)//如果DMA传输完成,获取标志位,返回值是1
           {
              __HAL_DMA_CLEAR_FLAG(&hdma_memtomem_dma1_channel1, DMA_FLAG_TC1);  //清除标志位
           }           
       }          
    }
  
      
      }
  /* USER CODE END 3 */
}

只做简单验证,按键每次按下,src_buf[0]++,src_buf[1]++,进行验证。

实现现象:

DMA_内存到内存

3.2

定义发送字符串:uint8_t TEXT_TO_SEND[] = {"正点原子 STM32 DMA 串口实验"};

主函数:

int main(void)
{
  /* USER CODE BEGIN 1 */
  uint8_t TEXT_TO_SEND[] = {"正点原子 STM32 DMA 串口实验"};
  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    if(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==0)
    {
      HAL_Delay(20);
      if(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==0)
      {
          
             HAL_UART_Transmit_DMA(&huart1, TEXT_TO_SEND, sizeof(TEXT_TO_SEND));//DMA的发送不是循环模式
              while ( __HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC4)!=HAL_OK)   /* 等待 DMA1_Channel4 传输完成 */
                {
                    __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx, DMA_FLAG_TC4);
                }
          while(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == 0);         
          HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
      }          
    }
  
      
      }
  /* USER CODE END 3 */
}

 HAL_UART_Transmit_DMA(&huart1, TEXT_TO_SEND, sizeof(TEXT_TO_SEND));已经完成了DMA启动的功能。

实现现象:

stm32 memset在哪个库,STM32的hal库使用,stm32,笔记,嵌入式硬件

   关于串口发送和接收中使用DMA的实验过于简单,后期会再测试复杂些的实验,例如接收不定长字符串/发送不定长字符串。

欢迎大家交流和指正!!!文章来源地址https://www.toymoban.com/news/detail-764845.html

到了这里,关于STM32 hal库使用笔记(四)DMA—内存到内存/内存到外设的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32-HAL库串口DMA空闲中断的正确使用方式+解析SBUS信号

    能够点进这篇文章的小伙伴肯定是对STM32串口DMA空闲中断接收数据感兴趣的啦,今天用这一功能实现串口解析航模遥控器sbus信号时,查阅了很多网友发布的文章(勤劳的搬运工~),包括自己之前写过一篇博客 STM32_HAL库_CubeMx串口DMA通信(DMA发送+DMA空闲接收不定长数据)。本文

    2024年02月09日
    浏览(47)
  • stm32 hal库uart使用 DMA中断只能发送一次的问题

    1.stm32 uart使用DMA,无论发送还是接收都各自有一个数据流中断。这个数据流中断是框架代码不必过多关心。 2.使用了DMA后,uart的global中断是否要使用?标准做法是在cubemx上要勾选的,不然,就会产生只能发送一次的问题。 问题的原因? 我相信这是hal库的问题,理论上讲有一

    2024年02月11日
    浏览(31)
  • 【STM32】HAL库 STM32CubeMX——DMA (串口DMA发送接收)

    软件: STM32CubeMX KEIL5 mcuisp 串口通信助手 硬件: STM32F103C8Tx 杜邦线,面包板,USB转TTL DMA,全称Direct Memory Access,即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。 我们知道系统的运

    2024年02月12日
    浏览(52)
  • STM32外设天造地设的一对:ADC和DMA

    引言:这篇文章主要介绍ADC和DMA配置的注意事项,适合懂得如何配置最基本的ADC和DMA,但是对它们两个的模式不是太理解的朋友们看,本文将重点介绍ADC和DMA模式的注意事项 DMA是CPU的小助手,负责完成数据转运的任务,一般的数据转运可以在主函数完成,但是如果数据量巨大

    2024年02月14日
    浏览(29)
  • A11 STM32_HAL库函数 之 DMA通用驱动所有函数的介绍及使用

    序号 函数名 描述 1 HAL_DMA_Init() 初始化DMA通道。 2 HAL_DMA_DeInit() 反初始化DMA通道。 3 HAL_DMA_Start() 启动DMA传输。 4 HAL_DMA_Start_IT() 启动DMA传输并使用中断处理传输完成。 5 HAL_DMA_Abort() 中止DMA传输。 6 HAL_DMA_Abort_IT() 中止DMA传输并使用中断处理中止完成。 7 HAL_DMA_PollForTransfer() 轮询

    2024年04月12日
    浏览(22)
  • STM32 HAL DMA中断配置

    使用HAL库方式DMA中断时,在网上找了好多资料都没有怎么介绍。所以就自己研究了一下,并做个记录。我的芯片型号是STM32G030。下面我以I2C传数据为例介绍下HAL库是如何使用DMA中断的。 我使用的是I2C2,简单配置下参数,加上DMA通道。 DMA貌似默认开启了中断,蓝色的勾勾是我

    2024年04月23日
    浏览(34)
  • STM32 HAL库 ADC+DMA

       软件触发:STM32 HAL库 软件触发ADC 多通道连续转换_随风飘零翼的博客-CSDN博客 配置如图      注意采样周期不要过小,不然频繁中断会导致在RTOS中卡死 写了部分关键代码,在两个任务中OLED和串口打印分别显示的通道值。 后来发现使用的杜邦线接触不良,固定好之后,接

    2024年02月14日
    浏览(26)
  • 一个简单的HAL库STM32使用DMA+硬件IIC驱动0.96寸OLED的方法

    自己在刚入坑嵌入式的时候,加入学校科协的一道免试题是开发一个简易的示波器,当时萌新不会做,中间又在准备比赛没时间,最近帮女朋友做课设需要做一个简易的交流电压表,而且终于有空做一下自己感兴趣的项目了,就想到了之前想做有没得做的一个简易示波器。

    2024年02月19日
    浏览(34)
  • # HAL库STM32常用外设教程(四)—— 基础定时器

    1、STM32F407ZGT6 2、STM32CubeMx软件 3、keil5 内容简述: 通篇文章将涉及以下内容,如有错误,欢迎指出 : 1、基础定时器特性 2、基础定时器的结构和功能 3、基础定时器HAL库驱动程序 (1)CubeMx配置 (2)TIM驱动程序   STM32F407有2个高级控制定时器(TIM1、TIM8)、8个通用定时器和

    2024年02月04日
    浏览(37)
  • # HAL库STM32常用外设教程(四)—— 定时器 基本定时

    1、STM32F407ZGT6 2、STM32CubeMx软件 3、keil5 内容简述: 通篇文章将涉及以下内容,如有错误,欢迎指出 : 1、基础定时器特性 2、基础定时器的结构和功能 3、基础定时器HAL库驱动程序 (1)CubeMx配置 (2)TIM驱动程序   STM32F407有2个高级控制定时器(TIM1、TIM8)、8个通用定时器和

    2024年02月02日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包