GD32F130之DMA

[复制链接]
5271|73
 楼主| 自动化陈稳 发表于 2023-9-30 19:33 | 显示全部楼层
如果设置的存储器和外设的数据宽度不一样,则在数据存储到目的地时会发生截断或者高位补0 的情况。

截断的情况:例如数据源的数据宽度是32bit,而目标数据宽度是16bit,从数据源传输一个0xB3B2B1B0到目标,其结果是目标得到的数据是0xB1B0,即丢掉了高位部分。
补零的情况:例如数据源的数据宽度是16bit,而目标数据宽度是32bit,从数据源传输一个0xB1B0到目标,其结果是目标得到的数据是0x0000B1B0,即高位部分用0填充。
 楼主| 自动化陈稳 发表于 2023-9-30 19:33 | 显示全部楼层
设置存储器数据宽度

DMA_CHxCTL.MWIDTH[1:0] = 00 :8bit
DMA_CHxCTL.MWIDTH[1:0] = 01 :16bit
DMA_CHxCTL.MWIDTH[1:0] = 10 :32bit
DMA_CHxCTL.MWIDTH[1:0] = 11 :保留
 楼主| 自动化陈稳 发表于 2023-9-30 19:33 | 显示全部楼层
设置外设数据宽度

DMA_CHxCTL.PWIDTH[1:0] = 00 :8bit
DMA_CHxCTL.PWIDTH[1:0] = 01 :16bit
DMA_CHxCTL.PWIDTH[1:0] = 10 :32bit
DMA_CHxCTL.PWIDTH[1:0] = 11 :保留
 楼主| 自动化陈稳 发表于 2023-9-30 19:33 | 显示全部楼层
配置外设地址和存储器地址以及地址生成算法
外设地址就是外设寄存器映射的地址,而存储器地址就是内存缓冲数组的起始地址。由于外设寄存器地址是固定的,所以外设地址生成算法应该选择固定地址模式。而存储器对应的缓冲数组是包含多个数据元素的矢量,所以存储器的地址生成算法应该选择增量地址模式。
————————————————
 楼主| 自动化陈稳 发表于 2023-9-30 19:34 | 显示全部楼层
当使用固定地址模式时,每次存取数据的地址都不变化。当使用增量地址模式时,每次传输一次数据后,地址就会自动增加一个数据宽度,假设数据宽度是8bit,则地址值会增1;如果数据宽度是2,则地址值增2,;如果数据宽度是32bit,则地址值增4。和C语言中指针的表现一致。
 楼主| 自动化陈稳 发表于 2023-9-30 19:34 | 显示全部楼层
设置存储器基地址

使用DMA_CHxMADDR寄存器来设置存储器基地址
 楼主| 自动化陈稳 发表于 2023-9-30 19:34 | 显示全部楼层
设置外设基地址

使用DMA_CHxPADDR寄存器来设置存储器基地址
 楼主| 自动化陈稳 发表于 2023-9-30 19:34 | 显示全部楼层
设置存储器地址生成算法

DMA_CHxCTL.MNAGA=0:固定地址模式
DMA_CHxCTL.MNAGA=1:增量地址模式
 楼主| 自动化陈稳 发表于 2023-9-30 19:34 | 显示全部楼层
设置外设地址生成算法

DMA_CHxCTL.PNAGA=0:固定地址模式
DMA_CHxCTL.PNAGA=1:增量地址模式

 楼主| 自动化陈稳 发表于 2023-9-30 19:34 | 显示全部楼层
配置数据传输长度
外设每请求一次DMA传输,只会传输一次数据。通过设置DMA_CHxCNT来指定一共需要DMA传输多少次数据。

一旦通道使能,DMA_CHxCNT寄存器为只读的,并在每个 DMA 传输之后值减 1。如果该寄存器的值为 0,无论通道开启与否,都不会有数据传输。如果该通道工作在循环模式下,一旦通道的传输任务完成,该寄存器会被自动重装载为初始设置值。

在传输过程中,DMA_CHxCNT用于指示本次传输周期,还有多少数据没有传输。
 楼主| 自动化陈稳 发表于 2023-9-30 19:34 | 显示全部楼层
配置DMA传输模式
有两种传输模式。

单次模式:当DMA_CHxCNT寄存器指定的传输数据长度传输完成后,DMA_CHxCNT寄存器为0,使得DMA停止传输。
循环模式:当DMA_CHxCNT寄存器指定的传输数据长度传输完成后,DMA_CHxCNT寄存器会自动重载恢复为最开始配置的长度初始值,并再次从内存的起始地址进行后续传输,这些操作都是硬件自动完成,无需代码参与。例如DMA_CHxCNT最开始配置为10,内存缓冲区长度也是10,第一次传输了6字节数据,则此时DMA_CHxCNT=4,内存缓冲区的[0:5]为本次收到的数据;第二次收到5字节,此时DMA_CHxCNT=9,内存缓冲区的[6:9]+[0]为本次收到的数据。这样好处可以一直响应外设的传输请求,不用像单次模式那样,代码干预,禁止通道,设置新的传输长度,再使能通道。
 楼主| 自动化陈稳 发表于 2023-9-30 19:35 | 显示全部楼层
通过DMA_CHxCTL寄存器的CMEN 位来选择是否开启循环模式。

DMA_CHxCTL.CMEN =0:禁止循环模式
DMA_CHxCTL.CMEN =1:使能循环模式
 楼主| 自动化陈稳 发表于 2023-9-30 19:35 | 显示全部楼层
DMA中断
DMA传输过程中会触发三种中断:

传输完成中断:随着传输进行,当DMA_CHxCNT递减为0时,触发传输完成中断。
传输半完成中断:假设本次传输周期,设置的传输长度DMA_CHxCNT的值为N,则当传输完成一半(整数除法,N/2,例如7/2=3)后,触发传输半完成中断。
传输错误中断:传输过程中发生错误时触发此中断。
 楼主| 自动化陈稳 发表于 2023-9-30 19:35 | 显示全部楼层
 楼主| 自动化陈稳 发表于 2023-9-30 19:35 | 显示全部楼层
 楼主| 自动化陈稳 发表于 2023-9-30 19:35 | 显示全部楼层
DMA配置代码模板
这里给出USART0使用DMA接收和发送的DMA部分配置代码
 楼主| 自动化陈稳 发表于 2023-9-30 19:35 | 显示全部楼层
  1. //=====================[USART0_TX = DMA_CH1]=====================
  2. dma_deinit(USART0_TX_DMA_CH);  //复位DMA通道的相关寄存器
  3. dma_memory_to_memory_disable(USART0_TX_DMA_CH);   //CTL.M2M=0,禁用存储器到存储器模式
  4. dma_transfer_direction_config(USART0_TX_DMA_CH,DMA_MEMORY_TO_PERIPHERAL);  //CTL.DIR,传输方向为存储器到外设
  5. dma_circulation_disable(USART0_TX_DMA_CH);     //CTL.CMEN=0禁用循环模式
  6. dma_priority_config(USART0_TX_DMA_CH,DMA_PRIORITY_HIGH); //CTL.PRIO[1:0]通道的软件优先级
  7. dma_memory_width_config(USART0_TX_DMA_CH,DMA_MEMORY_WIDTH_8BIT);      //CTL.MWIDTH[1:0]配置存储器单个数据宽度
  8. dma_periph_width_config(USART0_TX_DMA_CH,DMA_PERIPHERAL_WIDTH_16BIT); //CTL.PWIDTH[1:0]配置外设单个数据宽度
  9. dma_memory_increase_enable(USART0_TX_DMA_CH);  //CTL.MNAGA存储器地址生成算法为递增
  10. dma_periph_increase_disable(USART0_TX_DMA_CH); //CTL.PNAGA外设地址生成算法为固定不变
  11. //dma_interrupt_enable(USART0_TX_DMA_CH,DMA_INT_FTF);  //CTL.FTFIE 使能传输完成中断
  12. //dma_interrupt_enable(USART0_TX_DMA_CH,DMA_INT_HTF);  //CTL.HTFIE 使能半传输完成中断
  13. //dma_interrupt_enable(USART0_TX_DMA_CH,DMA_INT_ERR);  //CTL.ERRIE 使能传输错误中断
  14. dma_memory_address_config(USART0_TX_DMA_CH, (uint32_t)USART0_tx_dma_buf);   //配置存储器基地址
  15. dma_periph_address_config(USART0_TX_DMA_CH, (uint32_t)&USART_TDATA(USART0));  //配置外设基地址为USART0的TDATA寄存器地址
  16. dma_transfer_number_config(USART0_TX_DMA_CH,0);  //CNT寄存器,设置传输长度
  17. //dma_channel_enable(USART0_TX_DMA_CH);//使能通道

  18. //=====================[USART0_RX = DMA_CH2]=====================
  19. dma_deinit(USART0_RX_DMA_CH);  //复位DMA通道的相关寄存器
  20. dma_memory_to_memory_disable(USART0_RX_DMA_CH);   //CTL.M2M=0,禁用存储器到存储器模式
  21. dma_transfer_direction_config(USART0_RX_DMA_CH,DMA_PERIPHERAL_TO_MEMORY);  //CTL.DIR,传输方向为外设到存储器
  22. dma_circulation_enable(USART0_RX_DMA_CH);     //CTL.CMEN=1  打开循环模式
  23. dma_priority_config(USART0_RX_DMA_CH,DMA_PRIORITY_HIGH); //CTL.PRIO[1:0]通道的软件优先级
  24. dma_memory_width_config(USART0_RX_DMA_CH,DMA_MEMORY_WIDTH_8BIT);      //CTL.MWIDTH[1:0]配置存储器单个数据宽度
  25. dma_periph_width_config(USART0_RX_DMA_CH,DMA_PERIPHERAL_WIDTH_16BIT); //CTL.PWIDTH[1:0]配置外设单个数据宽度
  26. dma_memory_increase_enable(USART0_RX_DMA_CH);  //CTL.MNAGA存储器地址生成算法为递增
  27. dma_periph_increase_disable(USART0_RX_DMA_CH); //CTL.PNAGA外设地址生成算法为固定不变
  28. //dma_interrupt_enable(USART0_RX_DMA_CH,DMA_INT_FTF);  //CTL.FTFIE 使能传输完成中断
  29. //dma_interrupt_enable(USART0_RX_DMA_CH,DMA_INT_HTF);  //CTL.HTFIE 使能半传输完成中断
  30. //dma_interrupt_enable(USART0_RX_DMA_CH,DMA_INT_ERR);  //CTL.ERRIE 使能传输错误中断
  31. dma_memory_address_config(USART0_RX_DMA_CH, (uint32_t)USART0_rx_dma_buf);   //配置存储器基地址
  32. dma_periph_address_config(USART0_RX_DMA_CH, (uint32_t)&USART_RDATA(USART0));  //配置外设基地址为USART0的RDATA寄存器地址
  33. dma_transfer_number_config(USART0_RX_DMA_CH,USART0_RX_DMA_BUF_SIZE);  //CNT寄存器,设置传输长度
  34. //dma_channel_enable(USART0_RX_DMA_CH);//使能通道
jackcat 发表于 2023-10-5 21:25 | 显示全部楼层
GD32F130系列单片机配备了一个DMA控制器,该控制器包含7个DMA通道(CH0~CH6)。每个通道可以独立地服务一个外设与存储器之间的DMA数据传输。
mmbs 发表于 2023-10-5 21:37 | 显示全部楼层
GD32F130 提供了丰富的外设,其中包括 DMA(直接内存访问)功能,这使得数据传输变得更加高效和便捷。
iyoum 发表于 2023-10-5 22:10 | 显示全部楼层
GD32F130 提供了多个 DMA 通道,您可以选择合适的通道来满足应用需求。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部