在很多时候,如果使用DMA来做一些数据传输的话,效率会高很多.
举例来说,读写SPI.
硬件准备:
使用TG STK, 因为软件没有使用loopback模式,因此,需要将TG STK 20PIN扩展口的第4脚和第6脚短接.
软件准备:
Tx的缓冲区为:ucSPITxBuffer[] , Rx的缓冲区为:ucSPIRxBuffer . 软件里使用了两个通道的DMA, 对应SPI的发送和接收. 针对SPI的发送, 设置了一个回调函数(SPITxTransferComplete()),该函数会在DMA传输完毕之后调用.在回调函数里,使用ucComplete变量来标志一次SPI总共9字节的数据传输完毕.主函数会查询这个变量,如果发现有被置1,则开始另外一次SPI的DMA传输. 针对SPI的接收, 在回调函数(SPIRxTransferComplete())里面重新开始一次DMA传输.
#include <stdint.h>
#include <stdbool.h>
#include "efm32.h"
#include "efm32_chip.h"
#include "efm32_cmu.h"
#include "efm32_gpio.h"
#include "efm32_usart.h"
#include "efm32_dma.h"
unsigned char ucComplete = 0;
#define DMA_CHANNEL_SPI_TX 0
#define DMA_CHANNEL_SPI_RX 1
#define SPITXSAMPLES 9
/* DMA init structure */
DMA_Init_TypeDef dmaInit;
/* DMA callback structure */
DMA_CB_TypeDef cb[DMA_CHAN_COUNT];
unsigned char ucSPITxBuffer[SPITXSAMPLES] = {0x07,0x1f,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0x7f};
unsigned char ucSPIRxBuffer[SPITXSAMPLES];
#pragma data_alignment=256
DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMA_CHAN_COUNT * 2];
void SPI_Initial(void)
{
CMU_ClockEnable(cmuClock_HFPER, true);
CMU_ClockEnable(cmuClock_GPIO, true);
CMU_ClockEnable(cmuClock_USART1, true);
USART_InitSync_TypeDef SPI_init = USART_INITSYNC_DEFAULT;
SPI_init.baudrate = 200000;
USART_InitSync(USART1, &SPI_init);
GPIO_PinModeSet(gpioPortD,0,gpioModePushPull,1); //tx
GPIO_PinModeSet(gpioPortD,1,gpioModeInput,1); //rx
GPIO_PinModeSet(gpioPortD,2,gpioModePushPull,1); //clk
GPIO_PinModeSet(gpioPortD,3,gpioModePushPull,1); //cs
USART1->ROUTE |= USART_ROUTE_CSPEN | USART_ROUTE_CLKPEN | USART_ROUTE_TXPEN | USART_ROUTE_RXPEN | USART_ROUTE_LOCATION_LOC1;
}
void SPITxTransferComplete(unsigned int channel, bool primary, void *user)
{
ucComplete = 1;
}
void SPIRxTransferComplete(unsigned int channel, bool primary, void *user)
{
DMA_ActivateBasic(DMA_CHANNEL_SPI_RX,
true,
false,
NULL,
NULL,
SPITXSAMPLES - 1);
}
void DMA_for_SPI_Tx(void)
{
DMA_CfgChannel_TypeDef chnlCfg;
DMA_CfgDescr_TypeDef descrCfg;
/* Setting up call-back function */
cb[DMA_CHANNEL_SPI_TX].cbFunc = SPITxTransferComplete;
cb[DMA_CHANNEL_SPI_TX].userPtr = NULL;
/* Setting up channel */
chnlCfg.highPri = false;
chnlCfg.enableInt = true;
chnlCfg.select = DMAREQ_USART1_TXBL;
chnlCfg.cb = &(cb[DMA_CHANNEL_SPI_TX]);
DMA_CfgChannel(DMA_CHANNEL_SPI_TX, &chnlCfg);
/* Setting up channel descriptor */
descrCfg.dstInc = dmaDataIncNone;
descrCfg.srcInc = dmaDataInc1;
descrCfg.size = dmaDataSize1;
descrCfg.arbRate = dmaArbitrate1;
descrCfg.hprot = 0;
DMA_CfgDescr(DMA_CHANNEL_SPI_TX, true, &descrCfg);
/*Starting transfer. Using Basic since every transfer must be initiated
by the ADC. */
DMA_ActivateBasic(DMA_CHANNEL_SPI_TX,
true,
false,
(void *)&(USART1->TXDATA),
(void *)&ucSPITxBuffer,
SPITXSAMPLES - 1);
}
void DMA_for_SPI_Rx(void)
{
DMA_CfgChannel_TypeDef chnlCfg;
DMA_CfgDescr_TypeDef descrCfg;
/* Setting up call-back function */
cb[DMA_CHANNEL_SPI_RX].cbFunc = SPIRxTransferComplete;
cb[DMA_CHANNEL_SPI_RX].userPtr = NULL;
/* Setting up channel */
chnlCfg.highPri = false;
chnlCfg.enableInt = true;
chnlCfg.select = DMAREQ_USART1_RXDATAV;
chnlCfg.cb = &(cb[DMA_CHANNEL_SPI_RX]);
DMA_CfgChannel(DMA_CHANNEL_SPI_RX, &chnlCfg);
/* Setting up channel descriptor */
descrCfg.dstInc = dmaDataInc1;
descrCfg.srcInc = dmaDataIncNone;
descrCfg.size = dmaDataSize1;
descrCfg.arbRate = dmaArbitrate1;
descrCfg.hprot = 0;
DMA_CfgDescr(DMA_CHANNEL_SPI_RX, true, &descrCfg);
/*Starting transfer. Using Basic since every transfer must be initiated
by the ADC. */
DMA_ActivateBasic(DMA_CHANNEL_SPI_RX,
true,
false,
(void *)&ucSPIRxBuffer,
(void *)&(USART1->RXDATA),
SPITXSAMPLES - 1);
}
void DMAInit(void)
{
CMU_ClockEnable(cmuClock_DMA, true);
/* Initializing the DMA */
dmaInit.hprot = 0;
dmaInit.controlBlock = dmaControlBlock;
DMA_Init(&dmaInit);
}
/**************************************************************************//**
* @brief Main function
*****************************************************************************/
int main(void)
{
/* Chip errata */
CHIP_Init();
DMAInit();
SPI_Initial();
DMA_for_SPI_Tx();
DMA_for_SPI_Rx();
ucComplete = 0;
/* Infinite blink loop */
while (1)
{
if(ucComplete)
{
unsigned long ulDelay = 4000;
while(ulDelay--);
DMA_ActivateBasic(DMA_CHANNEL_SPI_TX,
true,
false,
NULL,
NULL,
SPITXSAMPLES - 1);
ucComplete = 0;
}
}
}