打印
[学习笔记]

寄存器学习之DMA

[复制链接]
749|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
JasonLee27|  楼主 | 2020-9-11 15:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
硬件环境:AC7801x 通用开发板  ATC-LINK
软件环境:keil 5.23
前几周我们使用了uart和adc模块,但实现上比较简陋,今天打算把dma用起来,实现一个uart dma的打印输出以及adc 多通道采样数据通过dma搬运的功能。

一、DMA模块注意事项
DMA模块可以支持memsize 8位,16位,32位,在选择的时候需要注意一点,那就是传输地址需要和选择的size对齐,如果选择32位的,则需要四字节对齐。

二、可编程数据宽度
我从参考手册DMA章节中摘录了一部分可编程数据宽度表格,用于解释下列配置的意义,方便大家理解我们芯片DMA的实现。
源宽度指的就是memory的访问size,是8位,16位还是32位。目标宽度指的就是外设寄存器的访问size。传输方向TX就是memory到外设。RX就是外设到memory。
注;这里提一嘴,DMA传输当然不只是memory到外设和外设到memory,对于外设到外设,只需要把其中一个外设寄存器当作memory也是一样。而memory到memory则是纯软件触发。
Byte模式指的是源,也就是memory的传输模式,即分几次传输,如第一条为0,则32位memory就分一次传输。而外设size只有8位,所以最后只有低八位的memory数据写入了外设,高24位都被丢弃了。
而这个传输数目,则可以理解为传输次数,像第一条Byte模式为0,那么一个32位memory就传输一次。如果Byte模式为1,则一个32位memory分两次传输,那么传输数据为4其实指使用了2个32位memory。
源端宽度
(MSIZE)
目标宽度
(PSIZE)
传输数目
(Length)
Byte
模式
源:地址/数据
(MSIZE)
传输方向
(Dir)
传输操作 目标: 地址/数据
(PSIZE)
32 8 4 000x00/03020100
0x04/07060504
0x08/0B0A0908
0x0C/0F0E0D0C
1(TX)1. 在 0x00 读 03020100,
往 0x00 写入 00
2. 在 0x04 读 07060504,
往 0x01 写入 04
3.在 0x08 读 0B0A0908,
往 0x02 写入 08
4.在0x0C读0F0E0D0C,往0x03写入0C
0x00/00
0x01/04
0x02/08
0x03/0C
32 16 4 000x00/03020100
0x04/07060504
0x08/0B0A0908
0x0C/0F0E0D0C
1(TX)1.在 0x00 读 03020100,
往 0x00 写入 0100
2.在 0x04 读 07060504,
往 0x02 写入 0504
3.在 0x08 读 0B0A0908,
往 0x04 写入 0908
4.在 0x0C 读 0F0E0D0C,
往 0x06 写入 0D0C
0x00/0100
0x02/0504
0x04/0908
0x06/0D0C
32 32 4 000x00/03020100
0x04/07060504
0x08/0B0A0908
0x0C/0F0E0D0C
1(TX)1.在 0x00 读 03020100,
往 0x00 写入 03020100
2.在 0x04 读 07060504,
往 0x04 写入 07060504。
3.在 0x08 读 0B0A0908,
往 0x08 写入 0B0A0908
4.在 0x0C 读 0F0E0D0C,
往 0x0C 写入 0F0E0D0C
0x00/03020100
0x04/07060504
0x08/0B0A0908
0x0C/0F0E0D0C
32 8 4 010x00/03020100
0x04/07060504
1(TX)1.在 0x00 读 03020100,
再拆分成 0302 和 0100
往 0x00 写入 00
往 0x01 写入 02
2.在 0x04 读 07060504,
再拆分成 0706 和 0504
往 0x02 写入 04
往 0x03 写入 06
0x00/00
0x01/02
0x02/04
0x03/06
32 16 4 010x00/03020100
0x04/07060504
1(TX)1.在 0x00 读 03020100,
再拆分成 0302 和 0100
往 0x00 写入 0100
往 0x02 写入 0302
2.在 0x04 读 07060504,
再拆分成 0706 和 0504
往 0x04 写入 0504
往 0x06 写入 0706
0x00/0100
0x02/0302
0x04/0504
0x06/0706
32 32 4 010x00/03020100
0x04/07060504
1(TX)1.在 0x00 读 03020100,
再拆分成 0302 和 0100
往 0x00 写入 00000100
往 0x04 写入 00000302
2.在 0x04 读 07060504,
再拆分成 0706 和 0504
往 0x08 写入 00000504
往 0x0C 写入 00000706
0x00/00000100
0x04/00000302
0x08/00000504
0x0C/00000706
在文档表格的最后面,我们可以看到如下注解,即作为发送源,只能设置为32,那么我们在使用的时候就要根据接收源的大小来设置Byte mode了。
当 dir=1(TX)时,MSIZE 只有 32, 表示 DMA 从 MEM 恒定读 32bit 数据。
当 dir=0(RX)时, PSIZE 只有 32, 表示 DMA 从 PERIPH 恒定读 32bit 数据,即使外设寄存器有效位只有 8bit。

例如:我当前UART DMA发送,是从mem->periph,那么我的msize只能为32(此处同时要确保memory起始地址四字节对齐),但我的UART是8bit发送,所以我需要设置外设size为8bit,为了保证32bit memory都能发送出去,需要设置Byte mode为3,即分割为四次传输。

再例如:我的ADC模块采用DMA接收,是从periph->mem,那么外设size只能是32,但我的ADC寄存器里面只有前16bit是有效的,所以我只想使用一个uint16的数组来接收每一个采样值,那么我的memsize会设置为16,Byte mode为0,即不分割,这样DMA搬运的时候就会自动舍弃高16bit数据,只将低16bit数据填入我的数组中。



dma.rar (584.06 KB)



使用特权

评论回复

相关帖子

沙发
huquanz711| | 2020-9-16 07:29 | 只看该作者
感谢楼主分享

使用特权

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

本版积分规则

66

主题

415

帖子

10

粉丝