当前位置: 首页 > news >正文

wordpress做下载站百度推广代运营公司

wordpress做下载站,百度推广代运营公司,工厂生产管理app,义乌网站建设与维护文章目录 DMA简介采用DMA完成串口收发mydma.c文件:简单分析:大致流程:注意事项:mydma.h文件:主函数调用:测试现象1:测试现象2:测试现象3: 简单补充几个其它配置的测试修改…

文章目录

  • DMA简介
  • 采用DMA完成串口收发
    • mydma.c文件:
    • 简单分析:
    • 大致流程:
    • 注意事项:
    • mydma.h文件:
    • 主函数调用:
      • 测试现象1:
      • 测试现象2:
      • 测试现象3:
  • 简单补充几个其它配置的测试
    • 修改发送的测试
    • 修改接收的测试


DMA简介

DMA(Direct Memory Access,直接存储器访问)是一种在不需要CPU干预的情况下,实现外设与存储器之间 或 存储器与存储器之间高速数据传输的技术。DMA的主要目的是减轻CPU的负担,使其能够专注于更复杂的计算和控制任务

简单理解:俩地址之间进行数据搬运,不需要CPU干涉

可以有软件触发DMA进行搬运,也可以硬件触发DMA搬运,取决于配置。

比如:(五)ASCLIN_UART模块串口中断模式 中采用的是借助串口的接收发送中断进行数据传输的。这里可以配置DMA硬件触发,将串口的接收/发送中断,路由到DMA上,每一次触发串口的中断,就触发一次DMA搬运即可。

当然DMA配置很复杂,可以直接借助iLLD库函数进行配置,应用为王。直接分析代码。

采用DMA完成串口收发

mydma.c文件:

#include "IfxAsclin_Asc.h"#include "IfxDma_Dma.h"
#include "IfxDma.h"#include "Bsp.h"
#include "string.h"/*********************************************************************************************************************/
/*------------------------------------------------------Macros-------------------------------------------------------*/
/*********************************************************************************************************************/
#define UART_BAUDRATE           460800                                  /* UART baud rate in bit/s                  */#define UART_PIN_RX             IfxAsclin2_RXE_P33_8_IN                 /* UART receive port pin                    */
#define UART_PIN_TX             IfxAsclin2_TX_P33_9_OUT                 /* UART transmit port pin                   */#define DMA_CHANNEL_RX             INTPRIO_ASCLIN2_RX
#define DMA_CHANNEL_TX             INTPRIO_ASCLIN2_TXIfxDma_Dma_Channel g_rxchn;                                             /* DMA channel handle                       */
IfxDma_Dma_Channel g_txchn;/* Definition of the interrupt priorities */
#define INTPRIO_ASCLIN2_TX      11                                       /* Triggered when AscLin transmits         */
#define INTPRIO_ASCLIN2_RX      12                                       /* Triggered when AscLin receives          */#define INTPRIO_DMA_TX          13                          /* Triggered when a DMA transaction is finished         */
#define INTPRIO_DMA_RX          14                          /* Triggered when a DMA transaction is finished         */#define UART_RX_BUFFER_SIZE     16                                      /* Definition of the receive buffer size    */
#define UART_TX_BUFFER_SIZE     16                                      /* Definition of the transmit buffer size   *//* Declaration of the ASC handle */
static IfxAsclin_Asc g_ascHandle;/* Declaration of the FIFOs parameters */
_Alignas(16) static  uint8 g_ascTxBuffer[UART_TX_BUFFER_SIZE];//只要开启了自增+循环,必须保证与循环范围保持一致!!!!!!
_Alignas(16) static  uint8 g_ascRxBuffer[UART_RX_BUFFER_SIZE];/* Definition of txData  */
_Alignas(16) uint8 g_txData[] = "Hello World!";//只要开启了自增+循环,必须保证与循环范围保持一致!!!!!!/* Size of the message */
Ifx_UReg_32Bit g_count = sizeof(g_txData)-1;int rxcnt = 0;
int txcnt = 0;
IFX_INTERRUPT(prio_DMA_RX, 0, INTPRIO_DMA_RX);
void prio_DMA_RX(void)
{rxcnt++;IfxDma_clearChannelInterrupt(&MODULE_DMA, g_rxchn.channelId);
}/* Interrupt triggered when the DMA finishes a transaction*/
IFX_INTERRUPT(prio_DMA_TX, 0, INTPRIO_DMA_TX);
void prio_DMA_TX(void)
{txcnt++;IfxDma_clearChannelInterrupt(&MODULE_DMA, g_txchn.channelId);
}/* This function initializes the ASCLIN UART module */
void init_asclin_uart(void)
{/* Initialize an instance of IfxAsclin_Asc_Config with default values */IfxAsclin_Asc_Config ascConfig;IfxAsclin_Asc_initModuleConfig(&ascConfig, &MODULE_ASCLIN2);/* Set the desired baud rate */ascConfig.baudrate.baudrate = UART_BAUDRATE;/* ISR priorities and interrupt target */ascConfig.interrupt.txPriority = INTPRIO_ASCLIN2_TX;ascConfig.interrupt.rxPriority = INTPRIO_ASCLIN2_RX;ascConfig.interrupt.typeOfService = IfxSrc_Tos_cpu0 ;/* FIFO configuration */  //没用到串口接收/发送的缓存可以不绑定,直接删除即可(如出现问题,可以直接删除)ascConfig.txBuffer = &g_ascTxBuffer;ascConfig.txBufferSize = UART_TX_BUFFER_SIZE;ascConfig.rxBuffer = &g_ascRxBuffer;ascConfig.rxBufferSize = UART_RX_BUFFER_SIZE;/* Pin configuration */const IfxAsclin_Asc_Pins pins ={NULL_PTR,       IfxPort_InputMode_pullUp,     /* CTS pin not used */&UART_PIN_RX,   IfxPort_InputMode_pullUp,     /* RX pin           */NULL_PTR,       IfxPort_OutputMode_pushPull,  /* RTS pin not used */&UART_PIN_TX,   IfxPort_OutputMode_pushPull,  /* TX pin           */IfxPort_PadDriver_cmosAutomotiveSpeed1};ascConfig.pins = &pins;IfxAsclin_Asc_initModule(&g_ascHandle, &ascConfig); /* Initialize module with above parameters *//* Modification of the TOS for the Rx related interruption *//* Change from CPU0 (previously defined above) to DMA */volatile Ifx_SRC_SRCR *src;src = IfxAsclin_getSrcPointerTx(ascConfig.asclin);/* Assign DMA as Service Provider when INTPRIO_ASCLIN2_TX is triggered */IfxSrc_init(src, IfxSrc_Tos_dma, INTPRIO_ASCLIN2_TX);IfxAsclin_enableTxFifoFillLevelFlag(ascConfig.asclin, TRUE);IfxSrc_enable(src);/* Modification of the TOS for the Rx related interruption *//* Change from CPU0 (previously defined above) to DMA */src = IfxAsclin_getSrcPointerRx(ascConfig.asclin);/* Assign DMA as Service Provider when INTPRIO_ASCLIN2_RX is triggered */IfxSrc_init(src, IfxSrc_Tos_dma, INTPRIO_ASCLIN2_RX);IfxAsclin_enableRxFifoFillLevelFlag(ascConfig.asclin, TRUE);IfxSrc_enable(src);
}/* This function is called from main in order to initialize the DMA module */
void init_dma(void)
{/* Initialize an instance of IfxDma_Dma_Config with default values */IfxDma_Dma_Config dmaConfig;IfxDma_Dma_initModuleConfig(&dmaConfig, &MODULE_DMA);/* Initialize module */IfxDma_Dma dma;IfxDma_Dma_initModule(&dma, &dmaConfig);/* Initial configuration for all channels */IfxDma_Dma_ChannelConfig cfg;IfxDma_Dma_initChannelConfig(&cfg, &dma);/* Following configuration is used by the DMA channel */cfg.moveSize = IfxDma_ChannelMoveSize_8bit;cfg.blockMode = IfxDma_ChannelMove_1;/*********************************************** TX部分**************************************************************/cfg.transferCount = 0;//一次触发搬运多少个字节数据(后面写入的时候会修改)/* DMA completes a full transaction on requests */cfg.requestMode = IfxDma_ChannelRequestMode_oneTransferPerRequest;  //一个请求触发一个单一DMA传输 即请求启动单个事务/* DMA as Interrupt Service Provider */cfg.hardwareRequestEnabled = TRUE;                         //  使能UART发送中断触发Dma(硬件触发)/* DMA channel stays enabled after one request */cfg.operationMode = IfxDma_ChannelOperationMode_single;   //DMA单次搬运/*************** Source and destination addresses ***************/cfg.sourceCircularBufferEnabled = TRUE;                           //开启源地址自增cfg.sourceAddressIncrementStep = IfxDma_ChannelIncrementStep_1;  //源地址自增加+1cfg.sourceAddressCircularRange = IfxDma_ChannelIncrementCircular_16; //源地址16字节循环cfg.destinationCircularBufferEnabled = TRUE;                     //开启目的地址自增cfg.destinationAddressCircularRange = IfxDma_ChannelIncrementCircular_none; //目的地址循环范围为0(就是原地不动,即使上面开启了也是在原地踏步)等同于上面FALSE/*************** Channel specific configurations ***************//* Select the Channel 11, related to the interruption on AscLin TX */cfg.channelId = (IfxDma_ChannelId) DMA_CHANNEL_TX;/* Address of the UART TX FIFO */cfg.sourceAddress = (uint32)&g_ascTxBuffer;cfg.destinationAddress = (uint32) &g_ascHandle.asclin->TXDATA.U;/*  DMA中断部分(如果采用环形缓存区,就没必要开启了哈)           */cfg.channelInterruptEnabled = TRUE;/* DMA triggers an interrupt once the full transaction is done */cfg.channelInterruptControl = IfxDma_ChannelInterruptControl_thresholdLimitMatch;/* Priority of the channel interrupt trigger */cfg.channelInterruptPriority = INTPRIO_DMA_TX;/* Interrupt service provider */cfg.channelInterruptTypeOfService = IfxSrc_Tos_cpu0;IfxDma_Dma_initChannel(&g_txchn, &cfg);/********************************************************* RX部分***********************************************************/cfg.transferCount = 1;   //一次触发搬运多少个字节数据/* DMA completes a full transaction on requests */cfg.requestMode = IfxDma_ChannelRequestMode_completeTransactionPerRequest;  //一个请求触发一个完整事务 即请求启动完整的事务/* DMA as Interrupt Service Provider */cfg.hardwareRequestEnabled = TRUE;                         // UART接收中断触发Dma/* DMA channel stays enabled after one request */cfg.operationMode = IfxDma_ChannelOperationMode_continuous; // DMA连续搬运模式/*************** Source and destination addresses ***************/cfg.sourceCircularBufferEnabled = TRUE;                 //源地址自增cfg.sourceAddressCircularRange = IfxDma_ChannelIncrementCircular_none;源地址循环范围为0(就是原地不动,即使上面开启了也是在原地踏步)等同于上面FALSEcfg.destinationCircularBufferEnabled = TRUE;cfg.destinationAddressCircularRange = IfxDma_ChannelIncrementCircular_16;/*************** Channel specific configurations ***************//* Select the Channel 12, related to the interruption on AscLin RX */cfg.channelId = (IfxDma_ChannelId) DMA_CHANNEL_RX;/* Address of the UART RX FIFO */cfg.sourceAddress = (uint32) &g_ascHandle.asclin->RXDATA.U;cfg.destinationAddress = (uint32)&g_ascRxBuffer;/* DMA中断部分(如果采用环形缓存区,就没必要开启了哈)  */cfg.channelInterruptEnabled = TRUE;/* DMA triggers an interrupt once the full transaction is done */cfg.channelInterruptControl = IfxDma_ChannelInterruptControl_thresholdLimitMatch;/* Priority of the channel interrupt trigger */cfg.channelInterruptPriority = INTPRIO_DMA_RX;/* Interrupt service provider */cfg.channelInterruptTypeOfService = IfxSrc_Tos_cpu0;IfxDma_Dma_initChannel(&g_rxchn, &cfg);
}void send_data(char* g_txData,Ifx_UReg_32Bit len)   //发送数据--指定长度大小
{Ifx_DMA_CH *channel = g_txchn.channel;IfxDma_disableChannelTransaction(&MODULE_DMA, g_txchn.channelId);channel->SADR.U   = (uint32)g_txData;channel->CHCFGR.B.TREL     = len;IfxDma_enableChannelTransaction(&MODULE_DMA, g_txchn.channelId);IfxDma_Dma_startChannelTransaction(&g_txchn);//g_ascHandle.asclin->FLAGSSET.B.TFLS = 1;  //发送完成设置,用于通知其它程序的,可以不设置
}void send_1s_pack(void) //对上面 send_data封装而已
{send_data((char *)g_txData,g_count);waitTime(IfxStm_getTicksFromMilliseconds(BSP_DEFAULT_TIMER, 1000));
}void recive_data(void)    //发送接收到的数据缓存区的数据--需要指定数据长度(一般和整个接收缓存数组长度一致)
{Ifx_DMA_CH *channel = g_txchn.channel;IfxDma_disableChannelTransaction(&MODULE_DMA, g_txchn.channelId);channel->SADR.U   = (uint32)&g_ascRxBuffer;channel->CHCFGR.B.TREL     = 16;IfxDma_enableChannelTransaction(&MODULE_DMA, g_txchn.channelId);IfxDma_Dma_startChannelTransaction(&g_txchn);//g_ascHandle.asclin->FLAGSSET.B.TFLS = 1; //发送完成设置,用于通知其它程序的,可以不设置waitTime(IfxStm_getTicksFromMilliseconds(BSP_DEFAULT_TIMER, 1000));
}

简单分析:

编写DMA俩个通道的中断:

int rxcnt = 0;
int txcnt = 0;
IFX_INTERRUPT(prio_DMA_RX, 0, INTPRIO_DMA_RX);
void prio_DMA_RX(void)
{rxcnt++;IfxDma_clearChannelInterrupt(&MODULE_DMA, g_rxchn.channelId);
}/* Interrupt triggered when the DMA finishes a transaction*/
IFX_INTERRUPT(prio_DMA_TX, 0, INTPRIO_DMA_TX);
void prio_DMA_TX(void)
{txcnt++;IfxDma_clearChannelInterrupt(&MODULE_DMA, g_txchn.channelId);
}

初始化ASCLIN的UART模块代码和之前的一模一样,多加了串口中断路由到DMA请求触发上面,也就是本来串口中断CPU0来提供服务,现在变成了DMA(就是串口触发DMA搬运,):

    /* Modification of the TOS for the Rx related interruption *//* Change from CPU0 (previously defined above) to DMA */volatile Ifx_SRC_SRCR *src;src = IfxAsclin_getSrcPointerTx(ascConfig.asclin);/* Assign DMA as Service Provider when INTPRIO_ASCLIN2_TX is triggered */IfxSrc_init(src, IfxSrc_Tos_dma, INTPRIO_ASCLIN2_TX);IfxAsclin_enableTxFifoFillLevelFlag(ascConfig.asclin, TRUE);IfxSrc_enable(src);/* Modification of the TOS for the Rx related interruption *//* Change from CPU0 (previously defined above) to DMA */src = IfxAsclin_getSrcPointerRx(ascConfig.asclin);/* Assign DMA as Service Provider when INTPRIO_ASCLIN2_RX is triggered */IfxSrc_init(src, IfxSrc_Tos_dma, INTPRIO_ASCLIN2_RX);IfxAsclin_enableRxFifoFillLevelFlag(ascConfig.asclin, TRUE);IfxSrc_enable(src);

接着初始化DMA,里面采用的还是,初始化DMA配置参数的结构体,然后初始化DMA模块,再初始化配置DMA通道的结构体,根据需求,修改对应的结构体成员配置,然后调用DMA通道初始化函数进行初始化(这里配置很多哈)。当然DMA也可以开启搬运完成的中断。

void init_dma(void)
{/* Initialize an instance of IfxDma_Dma_Config with default values */IfxDma_Dma_Config dmaConfig;IfxDma_Dma_initModuleConfig(&dmaConfig, &MODULE_DMA);/* Initialize module */IfxDma_Dma dma;IfxDma_Dma_initModule(&dma, &dmaConfig);/* Initial configuration for all channels */IfxDma_Dma_ChannelConfig cfg;IfxDma_Dma_initChannelConfig(&cfg, &dma);/* Following configuration is used by the DMA channel */cfg.moveSize = IfxDma_ChannelMoveSize_8bit;cfg.blockMode = IfxDma_ChannelMove_1;cfg.transferCount = 0;//..........IfxDma_Dma_initChannel(&g_rxchn, &cfg);
}

封装的发送函数,就是将源地址设为字节要发送的数组,然后根据数组个数,设置DMA要传输多少次数据,然后触发DMA即可。

void send_data(char* g_txData,Ifx_UReg_32Bit len)   //发送数据--指定长度大小
{Ifx_DMA_CH *channel = g_txchn.channel;IfxDma_disableChannelTransaction(&MODULE_DMA, g_txchn.channelId);channel->SADR.U   = (uint32)g_txData;channel->CHCFGR.B.TREL     = len;IfxDma_enableChannelTransaction(&MODULE_DMA, g_txchn.channelId);IfxDma_Dma_startChannelTransaction(&g_txchn);//g_ascHandle.asclin->FLAGSSET.B.TFLS = 1;  //发送完成设置,用于通知其它程序的,可以不设置
}void send_1s_pack(void) //对上面 send_data封装而已
{send_data((char *)g_txData,g_count);waitTime(IfxStm_getTicksFromMilliseconds(BSP_DEFAULT_TIMER, 1000));
}

编写接收并发送的回环(16字节接收缓存数组,就发送16字节):

void recive_data(void)    //发送接收到的数据缓存区的数据--需要指定数据长度(一般和整个接收缓存数组长度一致)
{Ifx_DMA_CH *channel = g_txchn.channel;IfxDma_disableChannelTransaction(&MODULE_DMA, g_txchn.channelId);channel->SADR.U   = (uint32)&g_ascRxBuffer;channel->CHCFGR.B.TREL     = 16;IfxDma_enableChannelTransaction(&MODULE_DMA, g_txchn.channelId);IfxDma_Dma_startChannelTransaction(&g_txchn);//g_ascHandle.asclin->FLAGSSET.B.TFLS = 1; //发送完成设置,用于通知其它程序的,可以不设置waitTime(IfxStm_getTicksFromMilliseconds(BSP_DEFAULT_TIMER, 1000));
}

大致流程:

1.初始化ASCLIN的UART模块:

    /* Initialize an instance of IfxAsclin_Asc_Config with default values */IfxAsclin_Asc_Config ascConfig;IfxAsclin_Asc_initModuleConfig(&ascConfig, &MODULE_ASCLIN2);/* Set the desired baud rate */ascConfig.baudrate.baudrate = UART_BAUDRATE;/* ISR priorities and interrupt target */ascConfig.interrupt.txPriority = INTPRIO_ASCLIN2_TX;ascConfig.interrupt.rxPriority = INTPRIO_ASCLIN2_RX;ascConfig.interrupt.typeOfService = IfxSrc_Tos_cpu0 ;/* FIFO configuration */ascConfig.txBuffer = &g_ascTxBuffer;ascConfig.txBufferSize = UART_TX_BUFFER_SIZE;ascConfig.rxBuffer = &g_ascRxBuffer;ascConfig.rxBufferSize = UART_RX_BUFFER_SIZE;/* Pin configuration */const IfxAsclin_Asc_Pins pins ={NULL_PTR,       IfxPort_InputMode_pullUp,     /* CTS pin not used */&UART_PIN_RX,   IfxPort_InputMode_pullUp,     /* RX pin           */NULL_PTR,       IfxPort_OutputMode_pushPull,  /* RTS pin not used */&UART_PIN_TX,   IfxPort_OutputMode_pushPull,  /* TX pin           */IfxPort_PadDriver_cmosAutomotiveSpeed1};ascConfig.pins = &pins;IfxAsclin_Asc_initModule(&g_ascHandle, &ascConfig); /* Initialize module with above parameters */

2.,再初始化完成串口后,需将CPU0服务串口中断,改成DMA服务串口中断(即将中断路由到DMA上):

    /* Modification of the TOS for the Rx related interruption *//* Change from CPU0 (previously defined above) to DMA */volatile Ifx_SRC_SRCR *src;src = IfxAsclin_getSrcPointerTx(ascConfig.asclin);/* Assign DMA as Service Provider when INTPRIO_ASCLIN2_TX is triggered */IfxSrc_init(src, IfxSrc_Tos_dma, INTPRIO_ASCLIN2_TX);IfxAsclin_enableTxFifoFillLevelFlag(ascConfig.asclin, TRUE);IfxSrc_enable(src);/* Modification of the TOS for the Rx related interruption *//* Change from CPU0 (previously defined above) to DMA */src = IfxAsclin_getSrcPointerRx(ascConfig.asclin);/* Assign DMA as Service Provider when INTPRIO_ASCLIN2_RX is triggered */IfxSrc_init(src, IfxSrc_Tos_dma, INTPRIO_ASCLIN2_RX);IfxAsclin_enableRxFifoFillLevelFlag(ascConfig.asclin, TRUE);IfxSrc_enable(src);

3.初始化DMA模块(先初始化参数,直接用默认参数初始化DMA模块):

    /* Initialize an instance of IfxDma_Dma_Config with default values */IfxDma_Dma_Config dmaConfig;IfxDma_Dma_initModuleConfig(&dmaConfig, &MODULE_DMA);/* Initialize module */IfxDma_Dma dma;IfxDma_Dma_initModule(&dma, &dmaConfig);

4.配置DMA通道,先初始化配置参数,以及配置有点公共参数(当然公共参数,也可以分别给TX/RX通道各自,自己再配置一遍哈),这里配置DMA一次搬运8位也就是一个字节,只使用一个DMA进行搬运

    /* Initial configuration for all channels */IfxDma_Dma_ChannelConfig cfg;IfxDma_Dma_initChannelConfig(&cfg, &dma);/* Following configuration is used by the DMA channel */cfg.moveSize = IfxDma_ChannelMoveSize_8bit;cfg.blockMode = IfxDma_ChannelMove_1;

接下里配置TX/RX各自通道,这里配置参数,还有一样的配置,也被单独拎出来了,只是为了方便理解,甚至可以定义俩变量配置,当然也完全可以不重复配置,

5.配置TX的DMA通道部分:

每配置一步细节
(1)配置一次触发DMA搬运多少个数据,以及配置每次 DMA 请求只触发一次数据传输。每次接收到一个请求信号时,DMA 控制器只会执行单次的数据传输。一般配合DMA单次搬运模式使用(这个就是串口发送中断,触发一个字节发送,DMA搬运一个)。
(2)使能DMA硬件触发(这里就是串口的发送中断触发DMA)
(3)DMA单次搬运模式(就是触发一次DMA,搬运一次)
(4)开启源地址自增模式,设置源地址自增+1,设置源地址16字节循环(这三个是配套使用,这里可以理解在DMA在每搬运一个数据后,DMA源地址指针,自动往后+1,然后达到16字节后,又回到第一个字节位置)这里注意, 一旦开启了循环模式,定义的数组一定要对齐到相应的循环范围,比如16字节循环,那定义的数组要16字节对齐,比如代码里的:(_Alignas(16) uint8 g_txData[] = “Hello World!”; //只要开启了自增+循环,必须保证与循环范围保持一致!!!!!!)
(5)开启目的地地址自增模式,设置目的地址自增范围为0字节循环(这里虽然开启了自增+循环模式,但是也是在原地不动,因为范围是0,圈住了,好似不开启自增模式也就是FALSE模式, 其实不然,即使不开启自增模式,也就是FALSE模式,那么地址依然还是会自增的,但是每一次启动DMA搬运,DMA指针得重新指向头,要不然就是自增后的地址往后了,这样会造成指针越界问题,后面会验证,说白了这个循环模式,就是用来防止指针越界的,可以这么理解)
(6)设置DMA发送的通道号,设置源地址,以及目的地地址
(7)开启DMA中断==(如果开启,一定要编写中断服务函数,否则程序崩溃)==
(8)最后初始化通道配置。
    /*********************************************** TX部分**************************************************************/cfg.transferCount = 0;//一次触发搬运多少个字节数据(后面写入的时候会修改)/* DMA completes a full transaction on requests */cfg.requestMode = IfxDma_ChannelRequestMode_oneTransferPerRequest;  //单一传输/* DMA as Interrupt Service Provider */cfg.hardwareRequestEnabled = TRUE;                         //  使能UART发送中断触发Dma(硬件触发)/* DMA channel stays enabled after one request */cfg.operationMode = IfxDma_ChannelOperationMode_single;   //DMA单次搬运/*************** Source and destination addresses ***************/cfg.sourceCircularBufferEnabled = TRUE;                           //开启源地址自增cfg.sourceAddressIncrementStep = IfxDma_ChannelIncrementStep_1;  //源地址自增加+1cfg.sourceAddressCircularRange = IfxDma_ChannelIncrementCircular_16; //源地址16字节循环cfg.destinationCircularBufferEnabled = TRUE;                     //开启目的地址自增cfg.destinationAddressCircularRange = IfxDma_ChannelIncrementCircular_none; //目的地址循环范围为0(就是原地不动,即使上面开启了也是在原地踏步)等同于上面FALSE/*************** Channel specific configurations ***************//* Select the Channel 11, related to the interruption on AscLin TX */cfg.channelId = (IfxDma_ChannelId) DMA_CHANNEL_TX;/* Address of the UART TX FIFO */cfg.sourceAddress = (uint32)&g_ascTxBuffer;cfg.destinationAddress = (uint32) &g_ascHandle.asclin->TXDATA.U;/*  DMA中断部分(如果采用环形缓存区,就没必要开启了哈)           */cfg.channelInterruptEnabled = TRUE;/* DMA triggers an interrupt once the full transaction is done */cfg.channelInterruptControl = IfxDma_ChannelInterruptControl_thresholdLimitMatch;/* Priority of the channel interrupt trigger */cfg.channelInterruptPriority = INTPRIO_DMA_TX;/* Interrupt service provider */cfg.channelInterruptTypeOfService = IfxSrc_Tos_cpu0;IfxDma_Dma_initChannel(&g_txchn, &cfg);

6.配置RX的DMA通道部分:

每配置一步细节)
(1)配置一次触发DMA搬运多少个数据,以及配置DMA 请求触发一整笔事务的传输,理解就是接收到一个请求信号后,DMA 控制器会自动完成整个事务(例如,传输一个完整的数据块或一组数据,接收串口数据一般都是大量涌入的,不可能是一次发1个或者几个字节把,像那种mavlink数据包,都是很多的,因此这里配置了一次触发,一直搬运), 这里有个思考,明明串口的接收,就是一个字节触发一个中断,为什么DMA和它可以不保持一致,个人理解,没错串口触发一直在触发,DMA只要有数据也是一直在搬运的(好比这样一种场景:串口中断告诉DMA来了一个数据,然后DMA就一直在干活了,串口接收中断呢,一直在那边喊话,又来了一个数据,又来了一个数据)
(2)使能DMA硬件触发(这里就是串口的接收中断触发DMA)
(3)DMA连续搬运模式(就是触发一次DMA,一直搬运)
(4)开启源地址自增,设置地址循环范围为0字节(这里虽然开启了自增+循环模式,但是也是在原地不动,因为范围是0,圈住了,好似不开启自增模式也就是FALSE模式, 其实不然,即使不开启自增模式,也就是FALSE模式,那么地址依然还是会自增的,但是每一次启动DMA搬运,DMA指针得重新指向头,要不然就是自增后的地址往后了,这样会造成指针越界问题,后面会验证)
(5)开启目的地地址自增模式,设置目的地地址自增+1,设置目的地地址16字节循环(这三个是配套使用,这里可以理解在DMA在每搬运一个数据后,DMA目的地地址指针,自动往后+1,然后达到16字节后,又回到第一个字节位置)这里注意,==一旦开启了循环模式,定义的数组一定要对齐到相应的循环范围,比如16字节循环,那定义的数组要16字节对齐,使用关键字!!!!!! Alignas(16) C99版本还支持__attribute_ ((aligned (16)))) 目前英飞凌官方ide只支持_Alignas(16) ==

(6)设置DMA接收的通道号,设置源地址,以及目的地地址
(7)开启DMA中断==(如果开启,一定要编写中断服务函数,否则程序崩溃)==
(8)最后初始化通道配置。

 /********************************************************* RX部分***********************************************************/cfg.transferCount = 1;   //一次触发搬运多少个字节数据/* DMA completes a full transaction on requests */cfg.requestMode = IfxDma_ChannelRequestMode_oneTransferPerRequest;  //一个请求触发一个完整事务 即请求启动完整的事务/* DMA as Interrupt Service Provider */cfg.hardwareRequestEnabled = TRUE;                         // UART接收中断触发Dma/* DMA channel stays enabled after one request */cfg.operationMode = IfxDma_ChannelOperationMode_continuous; // DMA连续搬运模式/*************** Source and destination addresses ***************/cfg.sourceCircularBufferEnabled = TRUE;                 //源地址自增cfg.sourceAddressCircularRange = IfxDma_ChannelIncrementCircular_none;源地址循环范围为0(就是原地不动,即使上面开启了也是在原地踏步)等同于上面FALSEcfg.destinationCircularBufferEnabled = TRUE;cfg.destinationAddressCircularRange = IfxDma_ChannelIncrementCircular_16;/*************** Channel specific configurations ***************//* Select the Channel 12, related to the interruption on AscLin RX */cfg.channelId = (IfxDma_ChannelId) DMA_CHANNEL_RX;/* Address of the UART RX FIFO */cfg.sourceAddress = (uint32) &g_ascHandle.asclin->RXDATA.U;cfg.destinationAddress = (uint32)&g_ascRxBuffer;/* DMA中断部分(如果采用环形缓存区,就没必要开启了哈)  */cfg.channelInterruptEnabled = TRUE;/* DMA triggers an interrupt once the full transaction is done */cfg.channelInterruptControl = IfxDma_ChannelInterruptControl_thresholdLimitMatch;/* Priority of the channel interrupt trigger */cfg.channelInterruptPriority = INTPRIO_DMA_RX;/* Interrupt service provider */cfg.channelInterruptTypeOfService = IfxSrc_Tos_cpu0;IfxDma_Dma_initChannel(&g_rxchn, &cfg);

然后就是编写了一个发送函数,以及接收并发送的函数,这里发送使用g_txData数组,当然也是可以使用g_ascTxBuffer数组的哈,这里只是防止和上一章混淆,不使用同一个数组而已。


注意事项:

1.只要DMA通道开启了循环模式,一定要相应的字节对齐:

比如代码DMA发送通道的配置和发送缓存区字节对齐

    cfg.sourceCircularBufferEnabled = TRUE;                           //开启源地址自增cfg.sourceAddressIncrementStep = IfxDma_ChannelIncrementStep_1;  //源地址自增加+1cfg.sourceAddressCircularRange = IfxDma_ChannelIncrementCircular_16; //源地址16字节循环cfg.destinationCircularBufferEnabled = TRUE;                     //开启目的地址自增cfg.destinationAddressCircularRange = IfxDma_ChannelIncrementCircular_none; //目的地址循环范围为0(就是原地不动,即使上面开启了也是在原地踏步)等同于上面FALSE_Alignas(16) uint8 g_txData[] = "Hello World!";//只要开启了自增+循环,必须保证与循环范围保持一致!!!!!!

同理DMA接收通道的配置和定义接收缓存区对齐:

    cfg.sourceCircularBufferEnabled = TRUE;                 //源地址自增cfg.sourceAddressCircularRange = IfxDma_ChannelIncrementCircular_none;源地址循环范围为0(就是原地不动,即使上面开启了也是在原地踏步)等同于上面FALSEcfg.destinationCircularBufferEnabled = TRUE;cfg.destinationAddressCircularRange = IfxDma_ChannelIncrementCircular_16;_Alignas(16) static  uint8 g_ascRxBuffer[UART_RX_BUFFER_SIZE];

2.如果启动了DMA中断,一定要编写相应的中断服务函数(可以为空,但不能不写);

3.设置DMA源地址,目标地址配置时,一定要检查好,否则会出现问题。

4.配置串口时,默认参数不可以,一定要改,比如过采因子,采样点等。

mydma.h文件:

#ifndef __MYDMA_H_
#define __MYDMA_H_void init_asclin_uart(void);                    /* Initialization function                                          */
void init_dma(void);void send_receive_ASCLIN_UART_message(void);    /* Send and receive function    */
void read2send(void);void send_data(char* g_txData,Ifx_UReg_32Bit len);   //发送数据--指定长度大小
void send_1s_pack(void);
void recive_data(void) ;   //发送接收到的数据缓存区的数据--需要指定数据长度(一般和整个接收缓存数组长度一致)#endif

主函数调用:

调用send_1s_pack();是1s的“Hello world”的心跳包;
调用:recive_data();1s发送16字节的接收缓存区的数据;

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"#include "Blinky_LED.h"
#include "interrupt.h"
#include "mydma.h"IFX_ALIGN(4) IfxCpu_syncEvent g_cpuSyncEvent = 0;void core0_main(void)
{IfxCpu_enableInterrupts();/* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!* Enable the watchdogs and service them periodically if it is required*/IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());/* Wait for CPU sync event */IfxCpu_emitEvent(&g_cpuSyncEvent);IfxCpu_waitEvent(&g_cpuSyncEvent, 1);initLED();initGtmTom();init_asclin_uart();init_dma();while(1){send_1s_pack();//recive_data();}
}

测试现象1:

调用send_1s_pack();

这里发送是每一次发送,都将DMA的指针,重新指向发送数组头部,并且设置一次搬运多少个数据。(因此这里可以不使用循环,就是上面说的FALSE模式,这个模式也是自增的,因为每次都初始化了指针指向头,不会造成指针越界问题,解决了指针越界问题,因此可以取消循环,现象也是一样的),推荐还是用循环模式,后面采用环形数组就很完美。

    cfg.sourceCircularBufferEnabled = FALSE;                           //开启源地址自增

在这里插入图片描述

然后验证,一次DMA传输个数,可以关闭send_data里面每次设置的每次DMA传输多少个数据,然后将默认参数分别改成2或5试试

void send_data(char* g_txData,Ifx_UReg_32Bit len)   //发送数据--指定长度大小
{Ifx_DMA_CH *channel = g_txchn.channel;IfxDma_disableChannelTransaction(&MODULE_DMA, g_txchn.channelId);channel->SADR.U   = (uint32)g_txData;//channel->CHCFGR.B.TREL     = len;  //这里屏蔽掉IfxDma_enableChannelTransaction(&MODULE_DMA, g_txchn.channelId);IfxDma_Dma_startChannelTransaction(&g_txchn);//g_ascHandle.asclin->FLAGSSET.B.TFLS = 1;  //发送完成设置,用于通知其它程序的,可以不设置
}cfg.transferCount = 2; //一次触发搬运多少个字节数据(后面写入的时候会修改)

改成2,现象:

txcnt是DMA中断次数哈

在这里插入图片描述
在这里插入图片描述

改成5,现象:

在这里插入图片描述
在这里插入图片描述

验证成功。

测试现象2:

调用:recive_data();

第一次发送123456:
在这里插入图片描述
第二次发送123456,可以看到依次往后了:
在这里插入图片描述

第三次发送123456,可以看到依次往后,DMA接收指针到了最后,循环回来指到头,然后覆盖了12,变成了56:
在这里插入图片描述
第四次发送123456,继续往后覆盖:
在这里插入图片描述
至此能感受到DMA循环模式的魅力,后面会使用环形换缓存区对接收发;

测试现象3:

两个同时调用,也是没问题的哈,已实测。

简单补充几个其它配置的测试

修改发送的测试

调用的是send_1s_pack();以发送为例

1.修改DMA发送通道的源地址循环范围4字节,则必须修改发送缓存数组4字节对齐:

    cfg.sourceAddressCircularRange = IfxDma_ChannelIncrementCircular_4; _Alignas(4) uint8 g_txData[] = "Hello World!";//

可以看到重复发送了发送数组前四个字节,就是源地址指针只在前四个字节循环了,这就是循环模式。

在这里插入图片描述

2.还可以再修改发送DMA通道的循环范围0字节,则修改数组不对齐即可,当然对齐也没关系:

cfg.sourceAddressCircularRange = IfxDma_ChannelIncrementCircular_none; 

可以看到,发送的12个字节全是H,那是因为DMA发送指针,一直原地不动,发送了12个字节。
在这里插入图片描述

修改接收的测试

调用的是recive_data();以接收为例

修改DMA接收通道的目的地地址循环范围4字节,则必须修改接收缓存数组4字节对齐

    cfg.destinationAddressCircularRange = IfxDma_ChannelIncrementCircular_4;
_Alignas(4) static  uint8 g_ascRxBuffer[UART_RX_BUFFER_SIZE];

用debug看数组数值,可以看到我发送12345,然后接收数组g_ascRxBuffer里面 只有5234,那是因为目的地地址设置了4字节范围循环,其实12345都接收到了,只是5把1给覆盖了,只是接收了1234指针又回到了头部:

在这里插入图片描述

此时指针在第二个位置,然后再发一次12345,123把234覆盖了 ,然后指针又回到了头部,45又把51给覆盖,所以发送回来的是4523


http://www.lryc.cn/news/617016.html

相关文章:

  • 网站空间数据库专门看广告的网站
  • 电商网站话费充值怎么做北京推广优化经理
  • 竞价网站服务器台州网站建设优化
  • 常见网站页面布局类型seo流程
  • 开源企业网站管理系统网络广告营销案例有哪些
  • 遇到灾难网站变灰怎么做3000行业关键词
  • wordpress 教程类主题宁波seo外包引流推广
  • 网站开发有啥作用百度关键字优化价格
  • 来个黑黑的网站腾讯广告
  • 找人做网站被骗能立案吗山东大学经济研究院
  • 做ppt比较好的网站seo项目完整流程
  • 南京企业网西安seo优化
  • 怎么建设手机电影网站seo是什么seo怎么做
  • 建立一个自己的网页seo技术培训教程
  • 2015个人网站如何去工信部备案seo优质友链购买
  • 潍坊做网站建设的公司衡阳seo优化推荐
  • 济南做网站价格足球排行榜前十名
  • 哪家公司做网站合肥网站建设
  • 品牌建设服务合同淘宝关键词优化技巧
  • 博彩网站做代理违法吗企业邮箱哪个好
  • 合肥专业网站制作北京营销网站制作
  • 可以做外链的音乐网站肇庆seo排名外包
  • 支付宝手机网站如何设计一个网页
  • 哪个网站可以做效果图赚钱网站推广内容
  • 如何识别网站的建站程序网站运营怎么做
  • 石家庄做网站排名百度网页版主页
  • 网站做视频怎么赚钱的java培训班学费一般多少
  • 建筑设计app推荐海南seo快速排名优化多少钱
  • 2018江苏省海门市建设局网站百度链接提交
  • wordpress怎么创建菜单重庆seo推广