1.概述
DMA的中文名称是直接内存访问,它不需要CPU的参与,实现数据传输的技术(但是也会占用总线带宽,所以有时候使用DMA虽然会降低CPU负载,但提高访问数据速度并不高)。
1.1 旗芯微FC4150系列芯片DMA特征
·所有数据的传输都是从源地址写入到目标地址,源地址和目标地址以及传输大小都是可编程的
·支持不同地址模式并且支持源地址和目标地址不对齐模块
·通过配置传输配置模块(CFG)实现两层嵌套传输操作,通过定义 inner loop count来设置内部数据传输循环的次数,通过定义 outer loop count来设置外部数据传输循环的次数
·32字节的传输配置模块(CFG)存储在DMA外设的内部内存中为DMA的每个通道服务(即每个DMA通道具有32字节的CFG配置)
·支持三种方式激活DMA的通道
直接通过软件初始化
通过连续转换中的通道连接机制进行初始化
每个通道一个外设请求的硬件机制
·支持通道固定优先级和通道轮询仲裁
·支持可编程的中断请求报告通道完成情况
每个通道都可以独立产生中断,可以在主循环计数完成(或者达到一半主循环完成次数)时产生断言
每个通道的可编程错误结果,被逻辑地加在一起形成一个中断控制器的错误中断
·支持前四个通道的周期性触发方式
·支持多达61个外设卡槽和两个常用卡槽路由到16个DMA通道上通过DMAMUX
·支持DMA ECC功能
1.2 总结
直接存储器访问(DMA)控制器模块,作为一个高度可编程的数据传输引擎,有能力执行复杂的数据传输,从主机处理器的干预最小。它可以灵活地传输数据。主要硬件微控制器构包括三个部分:
·一个DMA引擎,进行源地址和目的地址的计算,并进行从源地址到目的地址的数据移动。
·本地存储器包含16个通道中的每个通道的传输配置。在访问本地内存之前必须初始化。内存的取值范围从CFG_SADDRn到CFG_BLC_CHTRGENYESn (N: 0 ~ 15)。
·直接内存访问多路复用器(DMAMUX)将DMA源路由到16个DMA通道中的任何一个。
2.功能介绍
2.1 DMA初始化
1)通过配置CR寄存器来得到想要的配置
图1
寄存器解读:
ACTIVE: DMA激活状态位:0:DMA处于空闲状态 1:DMA处于激活状态,有通道在执行任务
CX: 取消传输位: 0:正常操作,不取消 1:取消正在传输的DMA,内部循环传输被强制终止,该bit位在取消执行完成后自动清除,取消的作用就像通道正常完成内部转换后一样
ECX: 取消传输产生错误状态位: 0:正常操作,不取消 1:和CX的区别是该位被置起后会产生错误状态更新到错误状态寄存器里面,如果使能了对应的中断会产生错误中断
EILM:使能内部循环映射: 0:失能内部循环映射,这会导致 DMA_CFG_NBYTES_MLNOn被定义为一个32bits的NBYTES表格,如下图2所示 1:使能内部循环映射,这会使得DMA_CFG_NBYTES_MLOFFYESn被重新定义为一个包含独立使能,offset,以及 NBYTES的表格,如图3所示,细心的朋友会发现这两个表格寄存器的地址是重复的,偏移地址都是0x1008h,所以EILM是否使能决定了你应用哪个表格
图2
图3
CTM: 连续触发模式 :0:失能连续触发模式,触发信号会进入通道仲裁来选择哪个通道工作
1:使能连续触发模式,当一个inner loop完成的时候,这时候不会再使用通道仲裁来选择通道,会直接触发通道本身
HALT: 0: 正常工作模式 1:停止一切新的通道开启,会让上一个通道数据传输完成,手动清0会再次恢复正常工作
HOE: 0:正常工作模式 1:使能这个位的时候任何产生的错误都会让HALT置位
ERCA: 0: 使用固定通道优先级来仲裁通道 1:使用轮询仲裁来选择通道
DBGS: 0:在debug模式的时候DMA保持工作 1:在debug模式的时候会停止新的通道服务,之前的通道会继续执行完成,离开调试模式或者手动清除该bit位会恢复
2)配置DCHPRIn寄存器来配置通道的固定优先级
图4
如图4所示,每个通道(16个通道)都有对应的寄存器设置固定优先级,优先级最大可以设置到16,数值越高,优先级越大
3)配置EEI寄存器可选通道的使能错误中断
图5
4)配置32字节的CFG寄存器来确定通道请求的服务
图6
5)配置ERQ寄存器来选择通道是否由硬件触发
图7
6)开始通道服务通过配置CFG_CSRn[START]或者硬件请求信号生成
2.2 流程框图
通道根据配置的CR[ERCA]bit位确定通道仲裁是固定通道优先级还是轮询仲裁来选择通道。DMA引擎读取整个CFG到所选通道的内部地址路径模块中。在内部总线上作为CFG初始化第一次传输,除非检测到通道配置错误。从源(由CFG_SADDRn定义)到目标(由CFG_DADDRn定义)的传输一直持续到传输CFG_NBYTESn定义的字节数为止。
传输完成后,DMA引擎的本地CFG_SADDRn、CFG_DADDRn和CFG_CLCn被写回主CFG内存并且内部循环通道触发中断(如果启用)。如果外部循环完成,则执行进一步的后处理,如外部循环通道触发中断(如果启用)。
下图解释了DMA请求在没有CPU干预的情况下启用一个内部循环传输的过程。DMA仲裁在每个内部循环之后发生,并且可以抢占内部循环。开始循环计数(BLC)设置外部循环中内部循环的数量。
图8
DMA传输可以分为一个主循环,多个次循环,每个DMA REQUEST完成一个副循环,当CITER计数为0,意味着主循环完成,触发相应的完成中断。
图9
2.2 相关操作
2.2.1 单次请求
.pSrcBuffer = g_strSrc,
.pDestBuffer = g_strDest,
.u32BlockSize = 12,
.u16BlockCount = 1U,
.u8ChannelPriority = 0U,
.eSrcDataSize = DMA_TRANSFER_SIZE_1B,
.eDestDataSize = DMA_TRANSFER_SIZE_1B,
.eSrcIncMode = DMA_INCREMENT_DATA_SIZE,
.eDestIncMode = DMA_INCREMENT_DATA_SIZE,
.bSrcBlockOffsetEn = false,
.bDestBlockOffsetEn = false,
.s32BlockOffset = 0,
.bSrcAddrLoopbackEn = true,
.bDestAddrLoopbackEn = true,
.bAutoStop = true,
.bSrcCircularBufferEn = false,
.u32SrcCircBufferSize = 0U,
.bDestCircularBufferEn = false,
.u32DestCircBufferSize = 0U,
.eTriggerSrc = DMA_REQ_DISABLED
参数解读:
.pSrcBuffer :源地址
.pDestBuffer: 目标地址
.u32BlockSize: innerloop搬运的字节数
u16BlockCount: outloop的次数
u8ChannelPriority: 设置通道的固定优先级
eSrcDataSize:源地址每次搬运后偏移的字节数
eDestDataSize:目标地址每次写入后偏移的字节数
eSrcIncMode:源地址搬运后是否偏移
eDestIncMode: 目标地址写入后是否偏移
bSrcBlockOffsetEn:一次innnerloop循环后是否设置源地址字节偏移
bDestBlockOffsetEn: 一次innnerloop循环后是否设置目标地址字节偏移
s32BlockOffset:一次innerloop循环后源地址和目标地址偏移的字节数
bSrcAddrLoopbackEn: 最后一次innerloop循环之后源地址是否偏移到最初地址
bDestAddrLoopbackEn:最后一次innerloop循环之后目标地址是否偏移到最初地址
bAutoStop: 是否使能自动停止,使能之后u16BlockCount执行完毕之后不再触发DMA,不使能的话u16BlockCount执行完毕之后还会继续触发DMA
bSrcCircularBufferEn:是否使能源地址buffer数据循环搬运(和bSrcAddrLoopbackEn的区别是这个可以设置任意大小,需要是2的幂次方的大小)
u32SrcCircBufferSize:源地址buffer数据循环的大小
bDestCircularBufferEn:是否使能目标地址buffer数据循环搬运(和bDestAddrLoopbackEn的区别是这个可以设置任意大小,需要是2的幂次方的大小)
u32DestCircBufferSize: 目标地址buffer数据循环的大小
执行过程:
设置的是一次外部循环,传输的数据量是12字节,源地址和目标地址偏移都是1字节的大小,所以只有一次DMA的请求,内部循环迭代12次,步长是一字节,迭代12次后内部循环结束,因为没有使能bSrcBlockOffsetEn,所以内部循环结束后字节没有偏移,使能了bSrcAddrLoopbackEn,所以外部循环传输结束后当前地址回到最初的地址
2.2.1 多次请求
.pSrcBuffer = g_strSrc,
.pDestBuffer = g_strDest,
.u32BlockSize = 12,
.u16BlockCount = 3U,
.u8ChannelPriority = 0U,
.eSrcDataSize = DMA_TRANSFER_SIZE_1B,
.eDestDataSize = DMA_TRANSFER_SIZE_1B,
.eSrcIncMode = DMA_INCREMENT_DATA_SIZE,
.eDestIncMode = DMA_INCREMENT_DATA_SIZE,
.bSrcBlockOffsetEn = false,
.bDestBlockOffsetEn = false,
.s32BlockOffset = 0,
.bSrcAddrLoopbackEn = true,
.bDestAddrLoopbackEn = false,
.bAutoStop = true,
.bSrcCircularBufferEn = false,
.u32SrcCircBufferSize = 0U,
.bDestCircularBufferEn = true,
.u32DestCircBufferSize = 25,
.eTriggerSrc = DMA_REQ_DISABLED
执行过程:
设置的是三次外部循环,第一次内部循环迭代12次,内部循环结束后源地址和目标地址都没有字节偏移,依次内推第二次内部循环也迭代12次,内部循环结束后源地址和目标地址都没有字节偏移,第三次内部循环的时候,由于设置了bDestCircularBufferEn,所以目标地址写完第25字节后从首地址重新写入,第三次内部循环结束后,由于使能了bSrcAddrLoopbackEn,所以源地址回到最初的地址;
标签:DMA,源地址,CFG,地址,旗芯微,FC4150,循环,通道 From: https://blog.csdn.net/qq_44807488/article/details/142363165