文章目录
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_TX
IfxDma_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; //源地址自增加+1
cfg.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