打印

GD32F130之DMA

[复制链接]
楼主: 自动化陈稳
手机看帖
扫描二维码
随时随地手机跟帖
21
自动化陈稳|  楼主 | 2023-9-30 19:33 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
如果设置的存储器和外设的数据宽度不一样,则在数据存储到目的地时会发生截断或者高位补0 的情况。

截断的情况:例如数据源的数据宽度是32bit,而目标数据宽度是16bit,从数据源传输一个0xB3B2B1B0到目标,其结果是目标得到的数据是0xB1B0,即丢掉了高位部分。
补零的情况:例如数据源的数据宽度是16bit,而目标数据宽度是32bit,从数据源传输一个0xB1B0到目标,其结果是目标得到的数据是0x0000B1B0,即高位部分用0填充。

使用特权

评论回复
22
自动化陈稳|  楼主 | 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 :保留

使用特权

评论回复
23
自动化陈稳|  楼主 | 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 :保留

使用特权

评论回复
24
自动化陈稳|  楼主 | 2023-9-30 19:33 | 只看该作者
配置外设地址和存储器地址以及地址生成算法
外设地址就是外设寄存器映射的地址,而存储器地址就是内存缓冲数组的起始地址。由于外设寄存器地址是固定的,所以外设地址生成算法应该选择固定地址模式。而存储器对应的缓冲数组是包含多个数据元素的矢量,所以存储器的地址生成算法应该选择增量地址模式。
————————————————

使用特权

评论回复
25
自动化陈稳|  楼主 | 2023-9-30 19:34 | 只看该作者
当使用固定地址模式时,每次存取数据的地址都不变化。当使用增量地址模式时,每次传输一次数据后,地址就会自动增加一个数据宽度,假设数据宽度是8bit,则地址值会增1;如果数据宽度是2,则地址值增2,;如果数据宽度是32bit,则地址值增4。和C语言中指针的表现一致。

使用特权

评论回复
26
自动化陈稳|  楼主 | 2023-9-30 19:34 | 只看该作者
设置存储器基地址

使用DMA_CHxMADDR寄存器来设置存储器基地址

使用特权

评论回复
27
自动化陈稳|  楼主 | 2023-9-30 19:34 | 只看该作者
设置外设基地址

使用DMA_CHxPADDR寄存器来设置存储器基地址

使用特权

评论回复
28
自动化陈稳|  楼主 | 2023-9-30 19:34 | 只看该作者
设置存储器地址生成算法

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

使用特权

评论回复
29
自动化陈稳|  楼主 | 2023-9-30 19:34 | 只看该作者
设置外设地址生成算法

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

使用特权

评论回复
30
自动化陈稳|  楼主 | 2023-9-30 19:34 | 只看该作者
配置数据传输长度
外设每请求一次DMA传输,只会传输一次数据。通过设置DMA_CHxCNT来指定一共需要DMA传输多少次数据。

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

在传输过程中,DMA_CHxCNT用于指示本次传输周期,还有多少数据没有传输。

使用特权

评论回复
31
自动化陈稳|  楼主 | 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]为本次收到的数据。这样好处可以一直响应外设的传输请求,不用像单次模式那样,代码干预,禁止通道,设置新的传输长度,再使能通道。

使用特权

评论回复
32
自动化陈稳|  楼主 | 2023-9-30 19:35 | 只看该作者
通过DMA_CHxCTL寄存器的CMEN 位来选择是否开启循环模式。

DMA_CHxCTL.CMEN =0:禁止循环模式
DMA_CHxCTL.CMEN =1:使能循环模式

使用特权

评论回复
33
自动化陈稳|  楼主 | 2023-9-30 19:35 | 只看该作者
DMA中断
DMA传输过程中会触发三种中断:

传输完成中断:随着传输进行,当DMA_CHxCNT递减为0时,触发传输完成中断。
传输半完成中断:假设本次传输周期,设置的传输长度DMA_CHxCNT的值为N,则当传输完成一半(整数除法,N/2,例如7/2=3)后,触发传输半完成中断。
传输错误中断:传输过程中发生错误时触发此中断。

使用特权

评论回复
34
自动化陈稳|  楼主 | 2023-9-30 19:35 | 只看该作者

使用特权

评论回复
35
自动化陈稳|  楼主 | 2023-9-30 19:35 | 只看该作者

使用特权

评论回复
36
自动化陈稳|  楼主 | 2023-9-30 19:35 | 只看该作者
DMA配置代码模板
这里给出USART0使用DMA接收和发送的DMA部分配置代码

使用特权

评论回复
37
自动化陈稳|  楼主 | 2023-9-30 19:35 | 只看该作者
//=====================[USART0_TX = DMA_CH1]=====================
dma_deinit(USART0_TX_DMA_CH);  //复位DMA通道的相关寄存器
dma_memory_to_memory_disable(USART0_TX_DMA_CH);   //CTL.M2M=0,禁用存储器到存储器模式
dma_transfer_direction_config(USART0_TX_DMA_CH,DMA_MEMORY_TO_PERIPHERAL);  //CTL.DIR,传输方向为存储器到外设
dma_circulation_disable(USART0_TX_DMA_CH);     //CTL.CMEN=0禁用循环模式
dma_priority_config(USART0_TX_DMA_CH,DMA_PRIORITY_HIGH); //CTL.PRIO[1:0]通道的软件优先级
dma_memory_width_config(USART0_TX_DMA_CH,DMA_MEMORY_WIDTH_8BIT);      //CTL.MWIDTH[1:0]配置存储器单个数据宽度
dma_periph_width_config(USART0_TX_DMA_CH,DMA_PERIPHERAL_WIDTH_16BIT); //CTL.PWIDTH[1:0]配置外设单个数据宽度
dma_memory_increase_enable(USART0_TX_DMA_CH);  //CTL.MNAGA存储器地址生成算法为递增
dma_periph_increase_disable(USART0_TX_DMA_CH); //CTL.PNAGA外设地址生成算法为固定不变
//dma_interrupt_enable(USART0_TX_DMA_CH,DMA_INT_FTF);  //CTL.FTFIE 使能传输完成中断
//dma_interrupt_enable(USART0_TX_DMA_CH,DMA_INT_HTF);  //CTL.HTFIE 使能半传输完成中断
//dma_interrupt_enable(USART0_TX_DMA_CH,DMA_INT_ERR);  //CTL.ERRIE 使能传输错误中断
dma_memory_address_config(USART0_TX_DMA_CH, (uint32_t)USART0_tx_dma_buf);   //配置存储器基地址
dma_periph_address_config(USART0_TX_DMA_CH, (uint32_t)&USART_TDATA(USART0));  //配置外设基地址为USART0的TDATA寄存器地址
dma_transfer_number_config(USART0_TX_DMA_CH,0);  //CNT寄存器,设置传输长度
//dma_channel_enable(USART0_TX_DMA_CH);//使能通道

//=====================[USART0_RX = DMA_CH2]=====================
dma_deinit(USART0_RX_DMA_CH);  //复位DMA通道的相关寄存器
dma_memory_to_memory_disable(USART0_RX_DMA_CH);   //CTL.M2M=0,禁用存储器到存储器模式
dma_transfer_direction_config(USART0_RX_DMA_CH,DMA_PERIPHERAL_TO_MEMORY);  //CTL.DIR,传输方向为外设到存储器
dma_circulation_enable(USART0_RX_DMA_CH);     //CTL.CMEN=1  打开循环模式
dma_priority_config(USART0_RX_DMA_CH,DMA_PRIORITY_HIGH); //CTL.PRIO[1:0]通道的软件优先级
dma_memory_width_config(USART0_RX_DMA_CH,DMA_MEMORY_WIDTH_8BIT);      //CTL.MWIDTH[1:0]配置存储器单个数据宽度
dma_periph_width_config(USART0_RX_DMA_CH,DMA_PERIPHERAL_WIDTH_16BIT); //CTL.PWIDTH[1:0]配置外设单个数据宽度
dma_memory_increase_enable(USART0_RX_DMA_CH);  //CTL.MNAGA存储器地址生成算法为递增
dma_periph_increase_disable(USART0_RX_DMA_CH); //CTL.PNAGA外设地址生成算法为固定不变
//dma_interrupt_enable(USART0_RX_DMA_CH,DMA_INT_FTF);  //CTL.FTFIE 使能传输完成中断
//dma_interrupt_enable(USART0_RX_DMA_CH,DMA_INT_HTF);  //CTL.HTFIE 使能半传输完成中断
//dma_interrupt_enable(USART0_RX_DMA_CH,DMA_INT_ERR);  //CTL.ERRIE 使能传输错误中断
dma_memory_address_config(USART0_RX_DMA_CH, (uint32_t)USART0_rx_dma_buf);   //配置存储器基地址
dma_periph_address_config(USART0_RX_DMA_CH, (uint32_t)&USART_RDATA(USART0));  //配置外设基地址为USART0的RDATA寄存器地址
dma_transfer_number_config(USART0_RX_DMA_CH,USART0_RX_DMA_BUF_SIZE);  //CNT寄存器,设置传输长度
//dma_channel_enable(USART0_RX_DMA_CH);//使能通道

使用特权

评论回复
38
jackcat| | 2023-10-5 21:25 | 只看该作者
GD32F130系列单片机配备了一个DMA控制器,该控制器包含7个DMA通道(CH0~CH6)。每个通道可以独立地服务一个外设与存储器之间的DMA数据传输。

使用特权

评论回复
39
mmbs| | 2023-10-5 21:37 | 只看该作者
GD32F130 提供了丰富的外设,其中包括 DMA(直接内存访问)功能,这使得数据传输变得更加高效和便捷。

使用特权

评论回复
40
iyoum| | 2023-10-5 22:10 | 只看该作者
GD32F130 提供了多个 DMA 通道,您可以选择合适的通道来满足应用需求。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则