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不在运行(除非硬件触发)

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值