本帖最后由 alexyzhov 于 2017-6-4 21:55 编辑
------------------------------------------------------------------------ 以上是个人吐槽,下面是正文。 Kinetis的外设风格是非常灵活的,我第一次感受到这种灵活,是因为LPLD的一篇文档:《K60实现ADC四通道自动连续采集 无需CPU干预》。看着样例里PDB、ADC、DMA模块的互相配合,感觉简直骚操作。随着后来自己研究底层的深入,发现FSL从硬件设计上就设计的非常灵活,从而给各种外设间的紧密配合留下了可能。 我们知道,DMA是一个数据搬运引擎,一般用于大数据块的搬运,和CPU挂载在同一条数据总线上。当信号触发DMA请求时,DMA引擎抢占数据总线,根据配置好的源地址、目的地址、搬运长度、搬运次数等核心参数开始搬运,如图示:
可以看到,DMA的特点是在不需要CPU的介入的前提下,高速地搬运连续的数据(块)。
Kinetis的DMA
以K66为例,参考手册可以看到Kinetis的DMA功能分为两部分: DMAMultiplexer(DMAMUX)和Enhanced DMA(eDMA)。
Kinetis的DMA有52个触发源和32个搬运通道,其中有16个可以独立编程的通道,并且可以选择映射到一个对应的影子通道上(16*2=32),并且前4个通道可以利用PIT模块轮流出发。eDMA的每个通道都可以通过DMAMUX,一个交叉矩阵,灵活配置触发源。这个过程和管脚复用类似,都是通过交叉矩阵,将信号链接到需要的地方。这是一个很灵活的地方,可以根据需要灵活分配触发源和DMA通道。
根据图示,可以看到eDMA主要由两部分组成,一部分是DMA Engine,一部分是TCD。DMAEngine和普通的DMA结构类似,具有基本的控制器,地址、数据控制和通道仲裁逻辑。TCD则是一系列寄存器结构(一个TCD包含11个寄存器),每个TCD结构(TCD[n])存储着DMA_CHn的搬运属性(每个通道拥有一个对应的TCD结构)。我们对eDMA的配置,主要是对TCD编程。比如DMA搬运的源地址(TCD[n].SADDR)、目的地址(TCD[n].DADDR)、每次搬运(Minor Loop)的源数据长度(TCD[n].ATTR:SSIZE)、每次搬运(Minor Loop)的目的数据长度(TCD[n]. ATTRSIZE)、每次搬运(Minor Loop)的源地址偏移量(TCD[n].SOFF)、每次搬运(Minor Loop)的目的地址偏移量(TCD[n].DOFF)、总搬运(Major Loop)循环次数(TCD[n].NBYTES);以及有关通道映射和Major Loop计数的CITER/BITER寄存器,还有可以用来方便构造环形队列的TCD[n]. ATTR:SMOD/TCD[n].ATTR:DMOD。
值得一提的一点是,通过TCD,eDMA可以实现一种链式结构,进行碎片化数据的搬运。这是Kinetis的一大特色,可以将地址不连续的数据(比如多个不同外设),只经过一次触发就能汇及起来,一定程度上缓解了DMA只能搬运块状数据的瓶颈。
|