S32K344 DMA

DMA的几个要素

  1. 源地址
  2. 目标地址
  3. 传输长度
    S32K344提供的DMA编程非常灵活,每个DMA通道的配置由TCD结构体控制。
    TCD结构体
    在这里插入图片描述
    在这里插入图片描述
    DMA传输DMA传输可以分为一个主循环,多个次循环,每个DMA REQUEST完成一个副循环,当CITER计数为0,意味着主循环完成,触发相应的完成中断。
    在这里插入图片描述源地址和目的地址的偏移计算
    完成一个副循环后:
    现地址=最初地址+offset+minor offset。
    两个offset都可以为0,minor offset在最后一个次循环不会生效,此时last adjustmnet address会被加到当前地址形成最终地址。
    当一个主循环完成后,上一次主循环完成后的最终地址变成此时的最初参考地址。
    minor offset可以使DMA传输两个不连续的地址。也可以通过last adjustmnet address使得传递后的地址回到最初地址。
    参数解释
    biter:设置的minor loop个数
    citer:当前minor loop的个数,开始一个major loop时,会从把biter装载进来,当citer为0,触发DMA传输完成中断。
    smod:
    在这里插入图片描述
    sszie:每次搬运的字节数
    nbytes:一个副循环需要搬运的字节数
    soff:搬运sszie后,源地址的增加量,可以为正负,也可以为0
    minor offset:一个副循环完成后,地址的增量,正,负,0。
    剩下的参数为两个寄存器
    通道状态寄存器CHn_CSR
    主要功能:允许硬件外设产生DMA请求(软件触发DMA不受控制),active位,done位
    通带控制寄存器TCDn_CSR
    主要功能:软件触发DMA,允许传输完成中断,允许传输完成后禁止硬件外设请求DMA

DMA通道的串联

在这里插入图片描述
假设此时CH3在运行,第一个minor loop完成后会设置CH1软件触发DMA位,使得CH1完成自己第一个minor loop,当CH3完成第二个minor loop,会再次设置CH1软件触发DMA位,使得CH1完成第二个minor loop。软件触发DMA位会被自动清处。当CH3完成第三个minor loop,此时major loop完成,CH1不会被触发,即使major loop没有link通道。

通道的link其实没有改变DMA的TCD结构体,会周而复始,循环往复。
通道串联的内部实现是通过软件启动来触发DMA请求的

DMA的scatter/gather

在这里插入图片描述
DMA的scatter/gather 聚散功能允许一个DMA通道使用多个TCD配置。聚散功能启用时,当1次主循环结束后DMA引擎自动从预先输入的地址中调入下一个新的TCD配置,无需软件介入。此功能允许DMA通过TCD数组1次传输多个物理上不连续的块,完成传输后只发起一次中断。

关键函数

在mcl_init初始化实现中,会把你在EB中的配置写入对应DMA通道的TCD寄存器中,EB是无法设置源地址和目的地址的。

Dma_Ip_LogicChannelInit

Static_Dma_Ip_SetLogicChannelTransferConfig

static Dma_Ip_ReturnType Static_Dma_Ip_SetLogicChannelTransferConfig(const uint32 LogicCh, const Dma_Ip_TransferConfigType * const TransferConfig)
{
    Dma_Ip_LogicChannelTransferListType LocList[DMA_IP_LOC_TRANSFER_PARAM_LIST_DIMENSION];
    const Dma_Ip_LogicChannelIdType * LocLogicChId;
    uint32 LocHwVers;
    uint32 LocHwInst;
    uint32 LocHwCh;
    Dma_Ip_TcdRegType * PxTcd = NULL_PTR;

    DMA_IP_DEV_ASSERT(NULL_PTR != Dma_Ip_pxInit);
    DMA_IP_DEV_ASSERT(NULL_PTR != Dma_Ip_pxInit->ppxLogicChannelConfigArray[LogicCh]);
    DMA_IP_DEV_ASSERT(DMA_IP_NOF_CFG_LOGIC_CHANNELS > LogicCh);
    DMA_IP_DEV_ASSERT(NULL_PTR != TransferConfig);

    LocLogicChId = (const Dma_Ip_LogicChannelIdType *)&(Dma_Ip_pxInit->ppxLogicChannelConfigArray[LogicCh]->LogicChId);
    LocHwVers = LocLogicChId->HwVersId;
    LocHwInst = LocLogicChId->HwInstId;
    LocHwCh = LocLogicChId->HwChId;

    LocList[0U].Param = DMA_IP_CH_SET_SOURCE_ADDRESS;
    LocList[0U].Value = (uint32)TransferConfig->Source.Addr;
    LocList[1U].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
    LocList[1U].Value = (uint32)TransferConfig->Source.SignedOffset;
    LocList[2U].Param = DMA_IP_CH_SET_SOURCE_SIGNED_LAST_ADDR_ADJ;
    LocList[2U].Value = (uint32)TransferConfig->Source.LastAddrAdj;
    LocList[3U].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    LocList[3U].Value = (uint32)TransferConfig->Source.TransferSize;
    LocList[4U].Param = DMA_IP_CH_SET_SOURCE_MODULO;
    LocList[4U].Value = (uint32)TransferConfig->Source.Modulo;
    LocList[5U].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    LocList[5U].Value = (uint32)TransferConfig->Destination.Addr;
    LocList[6U].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET;
    LocList[6U].Value = (uint32)TransferConfig->Destination.SignedOffset;
    LocList[7U].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_LAST_ADDR_ADJ;
    LocList[7U].Value = (uint32)TransferConfig->Destination.LastAddrAdj;
    LocList[8U].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    LocList[8U].Value = (uint32)TransferConfig->Destination.TransferSize;
    LocList[9U].Param = DMA_IP_CH_SET_DESTINATION_MODULO;
    LocList[9U].Value = (uint32)TransferConfig->Destination.Modulo;
    LocList[10U].Param = DMA_IP_CH_SET_MINORLOOP_EN_SRC_OFFSET;
    LocList[10U].Value = (TransferConfig->MinorLoop.EnSrcOffset ? TRUE : FALSE);
    LocList[11U].Param = DMA_IP_CH_SET_MINORLOOP_EN_DST_OFFSET;
    LocList[11U].Value = (TransferConfig->MinorLoop.EnDstOffset ? TRUE : FALSE);
    LocList[12U].Param = DMA_IP_CH_SET_MINORLOOP_SIGNED_OFFSET;
    LocList[12U].Value = (uint32)TransferConfig->MinorLoop.Offset;
    LocList[13U].Param = DMA_IP_CH_SET_MINORLOOP_EN_LINK;
    LocList[13U].Value = (TransferConfig->MinorLoop.EnLink ? TRUE : FALSE);
    LocList[14U].Param = DMA_IP_CH_SET_MINORLOOP_LOGIC_LINK_CH;
    LocList[14U].Value = (uint32)TransferConfig->MinorLoop.LogicLinkCh;
    LocList[15U].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    LocList[15U].Value = (uint32)TransferConfig->MinorLoop.Size;
    LocList[16U].Param = DMA_IP_CH_SET_MAJORLOOP_EN_LINK;
    LocList[16U].Value = (TransferConfig->MajorLoop.EnLink ? TRUE : FALSE);
    LocList[17U].Param = DMA_IP_CH_SET_MAJORLOOP_LOGIC_LINK_CH;
    LocList[17U].Value = (uint32)TransferConfig->MajorLoop.LogicLinkCh;
    LocList[18U].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    LocList[18U].Value = (uint32)TransferConfig->MajorLoop.Count;
    LocList[19U].Param = DMA_IP_CH_SET_CONTROL_EN_MAJOR_INTERRUPT;
    LocList[19U].Value = (TransferConfig->Control.EnMajorInt ? TRUE : FALSE);
    LocList[20U].Param = DMA_IP_CH_SET_CONTROL_EN_HALF_MAJOR_INTERRUPT;
    LocList[20U].Value = (TransferConfig->Control.EnHalfMajorInt ? TRUE : FALSE);
    LocList[21U].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;
    LocList[21U].Value = (TransferConfig->Control.DisAutoHwRequest ? TRUE : FALSE);
#if (STD_ON == DMA_IP_END_OF_PACKET_SIGNAL_IS_AVAILABLE)
    LocList[22U].Param = DMA_IP_CH_SET_CONTROL_EN_END_OF_PACKET_SIGNAL;
    LocList[22U].Value = (TransferConfig->Control.EnEndOfPacketSignal == TRUE) ? 1U : 0U;
#else
    LocList[22U].Param = DMA_IP_CH_SET_CONTROL_BANDWIDTH;
    LocList[22U].Value = (uint32)TransferConfig->Control.BandwidthControl;
#endif /* #if (STD_ON == DMA_IP_END_OF_PACKET_SIGNAL_IS_AVAILABLE) */
#if (STD_ON == DMA_IP_TRANSFER_MODE_CONTROL_IS_AVAILABLE)
    if(DMA_IP_HARDWARE_VERSION_4 == LocHwVers)
    {
        LocList[23U].Param = DMA_IP_CH_SET_CONTROL_TRANSFER_MODE;
        LocList[23U].Value = (uint32)TransferConfig->Control.TransferModeControl;
    }
    else
    {
        LocList[23U].Param = DMA_IP_CH_SET_CONTROL_BANDWIDTH;
        LocList[23U].Value = (uint32)TransferConfig->Control.BandwidthControl;
    }
#else
    LocList[23U].Param = DMA_IP_CH_SET_CONTROL_BANDWIDTH;
    LocList[23U].Value = (uint32)TransferConfig->Control.BandwidthControl;
#endif /* STD_ON == DMA_IP_TRANSFER_MODE_CONTROL_IS_AVAILABLE */
    /* Start bit is loaded last into the TCD */
    LocList[24U].Param = DMA_IP_CH_SET_CONTROL_SOFTWARE_REQUEST;
    LocList[24U].Value = (TransferConfig->Control.EnStart ? TRUE : FALSE);


#if (STD_ON == DMA_IP_HWV3_IS_AVAILABLE)
    if(DMA_IP_HARDWARE_VERSION_3 == LocHwVers)
    {
        PxTcd = &DMA_IP_HWV3_TCD_TCD_VALUE(LocHwInst, LocHwCh);
    }
#endif /* #if (STD_ON == DMA_IP_HWV3_IS_AVAILABLE) */


    /* Done shall be cleared before a new transfer is configured. */
    HwAccDmaCh_SetCommand((uint32)DMA_IP_CH_CLEAR_DONE, LocHwVers, LocHwInst, LocHwCh);
    if(NULL_PTR != PxTcd)
    {
    	***//关键调用,通过list.param的值来调用数组中的函数指针***
        Static_Dma_Ip_SetLogicChannelTransferList(LogicCh, PxTcd, LocList, DMA_IP_LOC_TRANSFER_PARAM_LIST_DIMENSION);
    }
    return DMA_IP_STATUS_SUCCESS;
}

初始化后,此时在我们自己的程序主体想要设置源地址和目标地址

Dma_Ip_LogicChannelScatterGatherListType list[2U];
list[0].Param=DMA_IP_CH_SET_SOURCE_ADDRESS;
list[0].Value=(uint32)&mysrc;
list[1].Param=DMA_IP_CH_SET_DESTINATION_ADDRESS;
list[1].Value=(uint32)&mydes;
Dma_Ip_SetLogicChannelTransferList(1,list,2);

Dma_Ip_SetLogicChannelTransferList

Static_Dma_Ip_SetLogicChannelTransferList
{
for(LocParamIdx = 0U; LocParamIdx < ListDimension; LocParamIdx++)
{
#if (STD_ON == DMA_IP_TRANSFER_MODE_CONTROL_IS_AVAILABLE)
DMA_IP_DEV_ASSERT(DMA_IP_CH_SET_CONTROL_TRANSFER_MODE >= List[LocParamIdx].Param);
#else
DMA_IP_DEV_ASSERT(DMA_IP_CH_SET_CONTROL_BANDWIDTH >= List[LocParamIdx].Param);
#endif
HwAccDmaCh_SetTransferParam((uint32)List[LocParamIdx].Param, LocHwVers, PxTcd, List[LocParamIdx].Value);
}
}

void HwAccDmaCh_SetTransferParam(const uint32 Parameter, const uint32 LocHwVers, Dma_Ip_TcdRegType * pxLocTcd, const uint32 LocValue)
{
    static void (* const fpHwAcc_DmaCh_SetTransferParam[])(const uint32 LocHwVers, Dma_Ip_TcdRegType * pxLocTcd, const uint32 LocValue) =
    {
        HwAccDmaCh_SetSource_Address,
        HwAccDmaCh_SetSource_SignedOffset,
        HwAccDmaCh_SetSource_LastAddrAdj,
        HwAccDmaCh_SetSource_TransferSize,
        HwAccDmaCh_SetSource_Modulo,
        HwAccDmaCh_SetDestination_Address,
        HwAccDmaCh_SetDestination_SignedOffset,
        HwAccDmaCh_SetDestination_LastAddrAdj,
        HwAccDmaCh_SetDestination_TransferSize,
        HwAccDmaCh_SetDestination_Modulo,
        HwAccDmaCh_SetMinorLoop_enSrcOffset,
        HwAccDmaCh_SetMinorLoop_enDstOffset,
        HwAccDmaCh_SetMinorLoop_Offset,
        HwAccDmaCh_SetMinorLoop_EnLink,
        HwAccDmaCh_SetMinorLoop_LogicLinkCh,
        HwAccDmaCh_SetMinorLoop_Size,
        HwAccDmaCh_SetMajorLoop_EnLink,
        HwAccDmaCh_SetMajorLoop_LogicLinkCh,
        HwAccDmaCh_SetMajorLoop_Count,
#if (STD_ON == DMA_IP_STORE_DST_ADDR_IS_AVAILABLE)
        HwAccDmaCh_SetControl_StoreDestinationAddress,
#else
        HwAccDmaCh_SetTransferDummyFunction,
#endif
        HwAccDmaCh_SetControl_EnStart,
        HwAccDmaCh_SetControl_EnMajor,
        HwAccDmaCh_SetControl_EnHalfMajor,
        HwAccDmaCh_SetControl_DisAutoHwRequest,
#if (STD_ON == DMA_IP_END_OF_PACKET_SIGNAL_IS_AVAILABLE)
        HwAccDmaCh_SetControl_EnEndOfPacketSignal,
#else
        HwAccDmaCh_SetTransferDummyFunction,
#endif
        HwAccDmaCh_SetControl_BandwidthControl,
#if (STD_ON == DMA_IP_TRANSFER_MODE_CONTROL_IS_AVAILABLE)
        HwAccDmaCh_SetControl_TransferModeControl,
#endif
    };
    //根据第
    fpHwAcc_DmaCh_SetTransferParam[Parameter](LocHwVers, pxLocTcd, LocValue);
} 

对于SCATTER/GATHER,都是通过mcl_init做一个基本的初始化,为了实现链表,第一个TCD结构体成员DLAS_SAG会包含下一个TCD结构体地址。

MCL_INIT初始化时有条件选择,普通的单通道以及scatter/gather

 if(NULL_PTR != Dma_Ip_pxInit->ppxLogicChannelConfigArray[LogicCh]->pxTransferConfig)
                {
                    /* Force Disable ScatterGather and Force Reset Address */
                    HwAccDmaCh_SetControl_EnScatterGatherProcessing(LocHwVers, PxTcd, FALSE);
                    HwAccDmaCh_SetControl_ScatterGatherAddress(LocHwVers, PxTcd, 0U);
                    Dma_Ip_SetHwChannelState(LocHwVers, LocHwInst, LocHwCh, DMA_IP_CH_TRANSFER_EVENT);
                    LocStatus = Static_Dma_Ip_SetLogicChannelTransferConfig(LocLogicChId->LogicChId, Dma_Ip_pxInit->ppxLogicChannelConfigArray[LogicCh]->pxTransferConfig);
                }
                else if(NULL_PTR != Dma_Ip_pxInit->ppxLogicChannelConfigArray[LogicCh]->ppxScatterGatherConfigArray)
                {
                    /* Force Disable ScatterGather and Force Reset Address */
                    HwAccDmaCh_SetControl_EnScatterGatherProcessing(LocHwVers, PxTcd, FALSE);
                    HwAccDmaCh_SetControl_ScatterGatherAddress(LocHwVers, PxTcd, 0U);
                    Dma_Ip_SetHwChannelState(LocHwVers, LocHwInst, LocHwCh, DMA_IP_CH_SCATTERGATHER_EVENT);
                    //scather/gather调用这个函数进行初始化
                    LocStatus = Static_Dma_Ip_SetLogicChannelScatterGatherInit(LocLogicChId->LogicChId, 0U);
                }

在这里插入图片描述
补充:DMA的scatter功能是每个TCD加载完后自动加载下一个TCD,每一个TCD是可以选择配置传输结束后是否触发中断,DMA加载下一个TCD后并不一定会DMA传输,如果想要加载后DMA自动启动传输,应该设置下一个TCD的start为1.

Dma_Ip_SetLogicChannelScatterGatherList用来设置DMA属性,比如设置START为1
Dma_Ip_SetLogicChannelScatterGatherConfig这个是将软件TCD写入硬件

因此在设置连续TCD时,后续的TCD应该设置为软件触发,才能使得DMA连续搬运。最后TCD加载后应该重新写入TCD,否则DMA不在运行(除非硬件触发)
因此在设置连续TCD时,后续的TCD应该设置为软件触发,才能使得DMA连续搬运。最后TCD加载后应该重新写入TCD,否则DMA不在运行(除非硬件触发)

### S32K3 Microcontroller DMA Configuration Tutorial #### Overview of DMA on the S32K3 Series The Direct Memory Access (DMA) feature within the S32K3 series allows data transfer between memory and peripherals without CPU intervention, improving system efficiency. The eDMA module supports multiple channels with flexible arbitration mechanisms to manage concurrent requests effectively[^1]. #### Key Components Involved in DMA Setup For configuring DMA operations specifically involving ADC interfaces: - **Hardware Units**: Two hardware units can be configured as `ADC0` and `ADC1`. Users should configure these based on their specific circuit requirements[^3]. - **Channel Management**: When using multiple ADC channels, only the last channel triggers a DMA request upon completion. After one major loop finishes executing, it automatically loads the next Transfer Control Descriptor (TCD)[^2]. #### Step-by-step Guide for Configuring DMA with ADC To set up DMA transfers from an ADC peripheral: 1. Initialize the ADC modules (`ADC0`, `ADC1`) according to project needs. 2. Configure TCD settings including source address, destination address, block size, etc., ensuring proper alignment with the desired buffer structure. 3. Set up interrupt handlers if necessary to handle events such as end-of-conversion or error conditions. 4. Enable DMA requests by setting appropriate bits in control registers associated with each ADC instance used. 5. Ensure that after completing a major loop, subsequent minor loops are correctly initialized via preloaded TCD entries. ```c // Example C code snippet showing basic setup steps void init_DMA_for_ADC(void){ // Assuming initialization functions exist for simplicity /* Initialize ADC */ ADC_Init(ADC0); /* Prepare TCD structures */ edma_config_t dmaConfig; EDMA_GetDefaultConfig(&dmaConfig); EDMA_Init(DMA_BASE_ADDR, &dmaConfig); /* Create and configure TCDs */ uint8_t tcdIndex = 0; // Choose available index EDMA_CreateHandle(&g_edmaHandle[tcdIndex], DMA_BASE_ADDR, tcdIndex); } ``` This example demonstrates initializing DMA alongside ADC configurations but does not cover all possible scenarios or optimizations which may vary depending on application specifics. --related questions-- 1. How do different types of DMA modes affect performance when interfacing with ADC? 2. What considerations must be taken into account while designing buffers for storing ADC samples through DMA? 3. Can you explain how priority levels influence DMA operation among competing peripherals like UART vs SPI? 4. In what ways could interrupts play a role during continuous acquisition mode enabled by DMA?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值