概述
目录
- 概述
- DMAMUX
- 操作模式
- 功能描述
- 含周期触发
- 不含收起触发
- Always-enabled DMA sources
- 寄存器
- DMA请求源
- DMAMUX操作
- eDMA
- 模块架构
- eDMA engine
- TCD
- 特征
- 内存映射
- TCD
- SADDR、SOFF、DADDR、DOFF
- ATTR
- NBYTES
- SLAST
- DLASTSGA
- CITER、 BITER
- CSR
- 寄存器
概述
本文描述NXP S32K14x的DMAMUX、eDMA,分析其S32SDK,加深对S32K1 DMA的理解与使用。
DMAMUX
S32K14x系列MCU有16个DMA通道,S32K11x系列只有4个DMA通道,而DMA请求却多达61个和多达两个常开槽,MADMUX实现将外设DMA请求(peripheral slots)指定到特定DMA通道(channels)。
前4个DMA通道具有触发功能,DMAMUX有16个独立的通道路由( channel routers)。
操作模式
- Disabled mode
此模式下,DMA channel 失能。因使能失能是在DMA配置寄存器中完成,该模式常用于DMA通道复位,或用于临时挂起DMA。 - Normal mode
此模式下,DMA源直接路由到特定DMA通道。 - Periodic Trigger mode
此模式下,DMA 源可能只请求 DMA 传输,例如当发送缓冲区变空或接收缓冲区变满时,周期性地。
功能描述
DMAMUX channels可以分为2类:
• Channels that implement the normal routing functionality plus periodic triggering capability
• Channels that implement only the normal routing functionality
含周期触发
除了正常的路由功能外,DMAMUX 的前 4 个通道提供特殊的周期性触发功能,可用于提供自动机制以固定间隔传输字节、帧或数据包,而无需处理器干预。触发由外部周期性中断定时器(例如PIT)产生; 这样,周期触发间隔的配置是通过配置外部周期定时器来完成的。
DMA 通道触发功能允许系统安排定期 DMA 传输,通常在某些外设的发送端进行,无需处理器干预。 此触发器的工作原理是将外设的请求门控到 DMA,直到触发事件发生。
DMA 请求得到服务后,外设将取消其请求,有效地重置门控机制,直到外设重新声明其请求并直到下一个触发事件。 这意味着如果观测到触发,但外设未请求传输,则该触发将被忽略。
此触发功能可用于支持 DMA 传输的任何外设,并且对两种情况最有用:
-
定期轮询特定总线上的外部设备
例如,将 SPI 的发送端分配给具有触发器的 DMA 通道。设置完成后,SPI 将请求 DMA 传输,大概来自内存,只要其发送缓冲区为空。通过在该通道上使用触发器,可以每 5 μs 自动执行一次 SPI 传输。在SPI的接收端,可以配置SPI和DMA将接收数据传输到内存中,有效地实现了一种无需处理器干预就可以周期性地从外部设备读取数据并将结果传输到内存中的方法。 -
使用 GPIO 端口驱动或采样波形
通过配置 DMA 将数据传输到一个或多个 GPIO 端口,可以使用存储在片上存储器中的表格数据创建复杂的波形。 相反,使用 DMA 从一个或多个 GPIO 端口定期传输数据,可以对复杂波形进行采样并将结果以表格形式存储在片上存储器中。
不含收起触发
Always-enabled DMA sources
除了可用作 DMA 源的外设外,还有 2 个额外的 DMA 源始终处于启用状态。
• 向/从 GPIO 执行 DMA 传输——从/向一个或多个 GPIO 引脚移动数据,或者不受限制(即尽可能快),或者定期(使用 DMA 触发功能)。
• 执行内存到内存的 DMA 传输——将数据从内存移动到内存,通常尽可能快,有时需要软件激活。
• 执行从内存到外部总线的 DMA 传输,反之亦然——类似于内存到内存的传输,这通常是尽快完成的。
• 任何需要软件激活的 DMA 传输——任何应该由软件明确启动的 DMA 传输。
寄存器
DMA请求源
在S32K146_features.h中定义了DMA通道请求源。
typedef enum {
EDMA_REQ_DISABLED = 0U,
EDMA_REQ_LPUART0_RX = 2U,
EDMA_REQ_LPUART0_TX = 3U,
EDMA_REQ_LPUART1_RX = 4U,
EDMA_REQ_LPUART1_TX = 5U,
//省略...
EDMA_REQ_PORTC = 51U,
EDMA_REQ_PORTD = 52U,
EDMA_REQ_PORTE = 53U,
EDMA_REQ_FLEXCAN0 = 54U,
EDMA_REQ_FLEXCAN1 = 55U,
EDMA_REQ_FLEXCAN2 = 56U,
EDMA_REQ_LPTMR0 = 59U,
EDMA_REQ_DMAMUX_ALWAYS_ENABLED0 = 62U,
EDMA_REQ_DMAMUX_ALWAYS_ENABLED1 = 63U
} dma_request_source_t;
DMAMUX操作
在edma_hw_access.h中实现了4个对CHCFG寄存器的操作
void DMAMUX_Init(DMAMUX_Type * base);
static inline void DMAMUX_SetChannelCmd(DMAMUX_Type * base, uint8_t channel, bool enable)
static inline void DMAMUX_SetChannelTrigger(DMAMUX_Type * base, uint8_t channel, bool enable)
static inline void DMAMUX_SetChannelSource(DMAMUX_Type * base, uint8_t channel, uint8_t source)
在EDMA_DRV_SetChannelRequestAndTrigger中,DMAMUX接口被使用:
/* Set request and trigger */
DMAMUX_SetChannelCmd(dmaMuxRegBase, dmaMuxChannel, false);
DMAMUX_SetChannelSource(dmaMuxRegBase, dmaMuxChannel, dmaMuxRequest);
DMAMUX_SetChannelTrigger(dmaMuxRegBase, dmaMuxChannel, enableTrigger);
DMAMUX_SetChannelCmd(dmaMuxRegBase, dmaMuxChannel, true);
eDMA
eDMA( enhanced direct memory access controller)是第二代模块,能够以较小的干扰实现对复杂数据搬运。其硬件微架构包含:
- 一个执行 源和目的地址计算、数据移动操作的 DMA引擎;
- 每个通道的 传输控制描述符的存储空间。
模块架构
eDMA模块主要分为两大部分:eDMA引擎、传输控制描述符(TCD)内存。
eDMA引擎进一步分为四大子模块:Address path、Data path、Program model/channel arbitration和Control。
传输控制描述符内存进一步分为两部分:Memory controller和Memory array。
eDMA engine
TCD
特征
eDMA 是一种高度可编程的数据传输引擎,经过优化,可最大限度地减少主机处理器所需的干预。它旨在用于要传输的数据大小静态已知且未在传输数据本身中定义的应用程序。
- 所有数据移动是通过dual-address transfers: read from source, write to destination
• 可编程的源、目的地址和大小
• 支持增强寻址模式 - 16个通道
- Transfer control descriptor (TCD) 被组织为支持两个深度,嵌套传输操作
• 每个通道的32字节 TCD存储在本地memory
• 内层数据通过minor次要的传输数量定义
• 外层数据通过major主要的传输数量定义 - 通道激活有如下三种方式
• 显式软件启动
• 通过通道到通道的链接机制发起连续传输
• 每个通道的外设请求 - 固定优先级和循环通道仲裁
- 通过可编程中断请求报告通道完成
• 每个通道一个中断,可以在主要迭代计数完成时断言
• 每个通道的可编程错误终止并在逻辑上加在一起形成一个错误中断到中断控制器 - 对 scatter/gather DMA 处理的可编程支持
- 支持复杂的数据结构
内存映射
eDMA 的编程模型分为两个区域:控制功能的寄存器、local transfer control descriptor (TCD)memory。
TCD
每个通道n都有一个 32-byte的TCDn,在激活通道前,必须配置TCD。
struct
{
__IO uint32_t SADDR; /**< TCD Source Address */
__IO uint16_t SOFF; /**< TCD Signed Source Address Offset */
__IO uint16_t ATTR; /**< TCD Transfer Attributes */
union
{
__IO uint32_t MLNO; /**< TCD Minor Byte Count (Minor Loop Mapping Disabled) */
__IO uint32_t MLOFFNO; /**< TCD Signed Minor Loop Offset (Minor Loop Mapping Enabled and Offset Disabled) */
__IO uint32_t MLOFFYES; /**< TCD Signed Minor Loop Offset (Minor Loop Mapping and Offset Enabled) */
} NBYTES;
__IO uint32_t SLAST; /**< TCD Last Source Address Adjustment */
__IO uint32_t DADDR; /**< TCD Destination Address */
__IO uint16_t DOFF; /**< TCD Signed Destination Address Offset */
union
{
__IO uint16_t ELINKNO; /**< TCD Current Minor Loop Link, Major Loop Count (Channel Linking Disabled) */
__IO uint16_t ELINKYES; /**< TCD Current Minor Loop Link, Major Loop Count (Channel Linking Enabled) */
} CITER;
__IO uint32_t DLASTSGA; /**< TCD Last Destination Address Adjustment/Scatter Gather Address */
__IO uint16_t CSR; /**< TCD Control and Status */
union
{
__IO uint16_t ELINKNO; /**< TCD Beginning Minor Loop Link, Major Loop Count (Channel Linking Disabled) */
__IO uint16_t ELINKYES; /**< TCD Beginning Minor Loop Link, Major Loop Count (Channel Linking Enabled) */
} BITER;
} TCD[DMA_TCD_COUNT];
SADDR、SOFF、DADDR、DOFF
当每个源读取完成时,符号扩展偏移量应用于当前源地址以形成下一个状态值。
static inline void EDMA_TCDSetSrcAddr(DMA_Type * base, uint8_t channel, uint32_t address)
{
base->TCD[channel].SADDR = address;
}
static inline void EDMA_TCDSetDestAddr(DMA_Type * base, uint8_t channel, uint32_t address)
{
base->TCD[channel].DADDR = address;
}
static inline void EDMA_TCDSetSrcOffset(DMA_Type * base, uint8_t channel, int16_t offset)
{
base->TCD[channel].SOFF = (uint16_t)offset;
}
static inline void EDMA_TCDSetDestOffset(DMA_Type * base, uint8_t channel, int16_t offset)
{
base->TCD[channel].DOFF = (uint16_t)offset;
}
在edma_hw_access.h实现了硬件抽象层对上述四个寄存器的操作。
source_read_size = 2^SSIZE
destination_write_size = 2^DSIZE
transferOffset = (uint8_t) (1U << ((uint8_t)transferSize));
/* Configure source and destination addresses */
EDMA_TCDSetSrcAddr(edmaRegBase, dmaChannel, srcAddr);
EDMA_TCDSetDestAddr(edmaRegBase, dmaChannel, destAddr);
/* Set transfer size (1B/2B/4B/16B/32B) */
EDMA_TCDSetAttribute(edmaRegBase, dmaChannel, EDMA_MODULO_OFF, EDMA_MODULO_OFF, transferSize, transferSize);
/* Configure source/destination offset. */
switch (type)
{
case EDMA_TRANSFER_PERIPH2MEM:
EDMA_TCDSetSrcOffset(edmaRegBase, dmaChannel, 0);
EDMA_TCDSetDestOffset(edmaRegBase, dmaChannel, (int8_t) transferOffset);
break;
case EDMA_TRANSFER_MEM2PERIPH:
EDMA_TCDSetSrcOffset(edmaRegBase, dmaChannel, (int8_t) transferOffset);
EDMA_TCDSetDestOffset(edmaRegBase, dmaChannel, 0);
break;
case EDMA_TRANSFER_MEM2MEM:
EDMA_TCDSetSrcOffset(edmaRegBase, dmaChannel, (int8_t) transferOffset);
EDMA_TCDSetDestOffset(edmaRegBase, dmaChannel, (int8_t) transferOffset);
break;
case EDMA_TRANSFER_PERIPH2PERIPH:
EDMA_TCDSetSrcOffset(edmaRegBase, dmaChannel, 0);
EDMA_TCDSetDestOffset(edmaRegBase, dmaChannel, 0);
break;
default:
/* This should never be reached - all the possible values have been handled. */
break;
}
在驱动层的EDMA_DRV_ConfigSingleBlockTransfer中如上对源、目的、偏置的使用。
ATTR
void EDMA_TCDSetAttribute(
DMA_Type * base, uint8_t channel,
edma_modulo_t srcModulo, edma_modulo_t destModulo,
edma_transfer_size_t srcTransferSize, edma_transfer_size_t destTransferSize)
NBYTES
union
{
__IO uint32_t MLNO; /**< TCD Minor Byte Count (Minor Loop Mapping Disabled) */
__IO uint32_t MLOFFNO; /**< TCD Signed Minor Loop Offset (Minor Loop Mapping Enabled and Offset Disabled) */
__IO uint32_t MLOFFYES; /**< TCD Signed Minor Loop Offset (Minor Loop Mapping and Offset Enabled) */
} NBYTES;
defines the number of bytes to transfer per request. Which register to use depends on whether minor loop mapping is disabled, enabled but not used for this channel, or enabled and used.
MLNO:Minor loop mapping is disabled (CR[EMLM] = 0)
Number of bytes to be transferred in each service request of the channel.
MLOFFNO:CR[EMLM] = 1 and SMLOE = 0 + DMLOE = 0
bit31: SMLOE Source Minor Loop Offset Enable
bit30: DMLOE Destination Minor Loop Offset enable
NBYTES: Minor Byte Transfer Count
MLOFFYES: CR[EMLM] = 1 and SMLOE = 1 or DMLOE = 1
bit31: SMLOE Source Minor Loop Offset Enable
bit30: DMLOE Destination Minor Loop Offset enable
bit29-10: MLOFF represents a sign-extended offset applied to the source or destination address to form the next-state value after the minor loop completes.
NBYTES: Minor Byte Transfer Count
EDMA_TCDSetSrcMinorLoopOffsetCmd(DMA_Type * base, uint8_t channel, bool enable)
EDMA_TCDSetDestMinorLoopOffsetCmd(DMA_Type * base, uint8_t channel, bool enable)
EDMA_TCDSetNbytes(DMA_Type * base, uint8_t channel, uint32_t nbytes)
EDMA_TCDSetMinorLoopOffset(DMA_Type * base, uint8_t channel, int32_t offset)
控制NBYTES
void EDMA_SetMinorLoopMappingCmd(DMA_Type * base, bool enable)
控制CR[EMLM]
SLAST
DLASTSGA
CITER、 BITER
union
{
__IO uint16_t ELINKNO; /**< TCD Current Minor Loop Link, Major Loop Count (Channel Linking Disabled) */
__IO uint16_t ELINKYES; /**< TCD Current Minor Loop Link, Major Loop Count (Channel Linking Enabled) */
} CITER;
ELINK: As the channel completes the minor loop, this flag enables linking to another channel, defined by the LINKCH field.
CITER: Current Major Iteration Count.This field is the current major loop count for the channel. It is decremented each time the minor loop is completed and updated in the transfer control descriptor memory.
LINKCH: Minor Loop Link Channel Number
union
{
__IO uint16_t ELINKNO; /**< TCD Beginning Minor Loop Link, Major Loop Count (Channel Linking Disabled) */
__IO uint16_t ELINKYES; /**< TCD Beginning Minor Loop Link, Major Loop Count (Channel Linking Enabled) */
} BITER;
位域结构同CITER,只是CITER域变为BITER
BITER:Starting Major Iteration Count
CSR
BWC: Bandwidth Control, eDMA engine stalls for X cycles after each R/W
MAJORLINKCH: Major Loop Link Channel Number, 0:No channel-to-channel linking, or chaining
DONE: eDMA has completed the major loop. The eDMA engine sets it as the CITER count
reaches zero.
ACTIVE: This flag signals the channel is currently in execution.
MAJORELINK: Enable channel-to-channel linking on major loop complete
ESG: Enable Scatter/Gather Processing
…
寄存器
Control Register (CR)
Error Status Register (ES)
DCHPRIn 通道优先级
fixed-priority:CR[ERCA] = 0时,通过DCHPRIn配置每个通道优先级,高优先级(数字越大)的先执行;
round-robin:忽略优先级,从通道高到低循环执行。
ECP:Enable Channel Preemption,使能抢占,为1时通道被高优先级通道请求临时挂起;
DPA:Disable Preempt Ability,为1时,忽略优先级,不能被抢占;
CHPRI:通道优先级,从0-15,数字越大优先级越高。
Enable Request Register (ERQ)
0b - The DMA request signal for the corresponding channel is disabled
1b - The DMA request signal for the corresponding channel is enabled
Clear Enable Request Register (CERQ)
NOP: No Op enable
CAER: Clear All Enable Requests
CERQ: Clear Enable Request
Set Enable Request Register (SERQ)
结构同CERQ,不过由Clear变为Set ERQ.
Enable Error Interrupt Register (EEI)
为每个通道使能错误中断。
0b - The error signal for corresponding channel does not generate an error interrupt
1b - The assertion of the error signal for corresponding channel generates an error interrupt request
Clear Enable Error Interrupt Register (CEEI)
结构同CERQ,不过操作的是EEI.
Set Enable Error Interrupt Register (SEEI)
结构同SERQ,不过操作的是EEI.
Clear DONE Status Bit Register (CDNE)
结构同CERQ,不过操作的是TCDn_CSR[DONE].
Set START Bit Register (SSRT)
结构同SERQ,不过操作的是TCDn_CSR[START].
Error Register (ERR)
0b - An error in this channel has not occurred
1b - An error in this channel has occurred
The outputs of this register are enabled by the contents of the EEI register, and then routed to the interrupt controller.
若EEI使能,有错误是将导致ERR对应位置位,然后进入中断处理。
Clear Error Register (CERR)
结构同CERQ,不过操作的是ERR.
Interrupt Request Register (INT)
结构同EEI,16个bit,当数据传输完成,eDMA engin产生,该中断直接路由到中断控制器,处理中断。
Clear Interrupt Request Register (CINT)
结构同CERQ,不过操作的是INT.
Hardware Request Status Register (HRS)
16个bit,代表是否由硬件请求,当请求完成通道自由后,自动清楚。
0b - A hardware service request for channel 15 is not present
1b - A hardware service request for channel 15 is present
Enable Asynchronous Request in Stop Register (EARS)
16个bit,每个BIT与 Enable Request Register (ERQ) 进行与运算去使能或失能DMA请求。
最后
以上就是糊涂枫叶为你收集整理的NXP S32K1 DMA模块的全部内容,希望文章能够帮你解决NXP S32K1 DMA模块所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复