一直没有具体的自己写过和测试过DMA+LeUart的功能。只是知道EFM32针对LeUart做了很多的优化。例如在EM2的情况下,无论是发送还是接收,都可以自动唤醒DMA,进行传输,大大的降低了整个板子运行时候的功耗。
硬件准备:
TG STK, LEUart0, Tx:PD4, Rx:PD5. TG STK的20pin扩展口上已经有这两个IO口,分别是12Pin(PD4,Tx),14Pin(PD5,Rx)。
软件准备:
1.使用CMSIS3.0的库了
2.DMA channel 0 作为Rx接收通道,接受数据的长度为1字节。。呵呵。
3.DMA channel 1 作为Tx发送通道,发送数据的长度为10字节。
4.平时进入EM2模式,在接受完毕之后,发送一次10字节的数据。
5.自己犯过一次无限Tx发送的错误,后来发现是逻辑错误。前提是我将Tx发送放在了主循环里面。当Rx接收到数据之后,会触发DMA中断。中断退出之后,在主循环中会触发Tx发送。然后继续进入EM2.而此时Tx发送完毕,又会触发DMA中断,然后又退出EM2,继续运行主程序中的Tx触发函数,周而复始,无限循环。
6.如果要使用call back函数,则必须使能该通道上的DMA中断。每个通道都有一个中断标志。CH0DONE~CH7DONE,外加一个ERROR标志
例程:这次例程会比较长。呵呵
#include "em_chip.h"
#include "efm32.h"
#include "em_cmu.h"
#include "em_emu.h"
#include "em_leuart.h"
#include "em_dma.h"
#include "em_gpio.h"
unsigned char ucRx_Ok = 0;
/* DEFINES */
#define DMA_RX_CHANNEL 0
#define RX_BUF_MAX 1
#define DMA_TX_CHANNEL 1
#define TX_BUF_MAX 10
unsigned char ucRx_Buffer[RX_BUF_MAX];
unsigned char ucTx_Buffer[TX_BUF_MAX] = {'G','e','c','k','o',',','!','!','!','\0',};
/* DMA control block, must be aligned to 256. */
#if defined (__ICCARM__)
#pragma data_alignment=256
DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMA_CHAN_COUNT * 2];
#elif defined (__CC_ARM)
DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMA_CHAN_COUNT * 2] __attribute__ ((aligned(256)));
#elif defined (__GNUC__)
DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMA_CHAN_COUNT * 2] __attribute__ ((aligned(256)));
#else
#error Undefined toolkit, need to define alignment
#endif
/* DMA init structure */
DMA_Init_TypeDef dmaInit;
/* DMA callback structure */
DMA_CB_TypeDef cb[DMA_CHAN_COUNT];
void LeUart_Initial_IO(void)
{
CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);
/* Reseting and initializing LEUART0 */
LEUART_Reset(LEUART0);
LEUART_Init_TypeDef leuart1Init =
{
.enable = leuartEnable, /* Activate data reception on LEUn_RX pin. */
.refFreq = 0, /* Inherit the clock frequenzy from the LEUART clock source */
.baudrate = 9600, /* Baudrate = 9600 bps */
.databits = leuartDatabits8, /* Each LEUART frame containes 8 databits */
.parity = leuartNoParity, /* No parity bits in use */
.stopbits = leuartStopbits1, /* Setting the number of stop bits in a frame to 2 bitperiods */
};
LEUART_Init(LEUART0, &leuart1Init);
/* Route LEUART0 RX pin to DMA location 0 */
LEUART0->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_TXPEN | LEUART_ROUTE_LOCATION_LOC0;
GPIO_PinModeSet(gpioPortD, /* Port */
5, /* Port number */
gpioModeInputPull, /* Pin mode is set to input only, with pull direction given bellow */
1); /* Pull direction is set to pull-up */
GPIO_PinModeSet(gpioPortD, /* Port */
4, /* Port number */
gpioModePushPull, /* Pin mode is set to input only, with pull direction given bellow */
1);
}
void DMAInit(void)
{
/* Initializing the DMA */
dmaInit.hprot = 0;
dmaInit.controlBlock = dmaControlBlock;
DMA_Init(&dmaInit);
}
void LeUartRxReceiveComplete(unsigned int channel, bool primary, void *user)
{
DMA_ActivateBasic(DMA_RX_CHANNEL,
true,
false,
NULL,
NULL,
RX_BUF_MAX - 1);
GPIO_PinOutSet(gpioPortD, 7);
ucRx_Ok = 1;
}
void LeUartTxTransmitComplete(unsigned int channel, bool primary, void *user)
{
/* Disable DMA wake-up from LEUART1 TX */
LEUART0->CTRL &= ~LEUART_CTRL_TXDMAWU;
GPIO_PinOutClear(gpioPortD, 7);
}
void DMA_Initial_IO(void)
{
//Setting up Rx DMA
/* Setting up channel */
/* Setting call-back function */
cb[DMA_RX_CHANNEL].cbFunc = LeUartRxReceiveComplete;
cb[DMA_RX_CHANNEL].userPtr = NULL;
DMA_CfgChannel_TypeDef chnlCfg =
{
.highPri = false, /* Normal priority */
.enableInt = true, /* No interupt enabled for callback functions */
.select = DMAREQ_LEUART0_RXDATAV, /* Set LEUART0 RX data avalible as source of DMA signals */
.cb = &(cb[DMA_RX_CHANNEL]),
};
DMA_CfgChannel(DMA_RX_CHANNEL, &chnlCfg);
/* Setting up channel descriptor */
DMA_CfgDescr_TypeDef descrCfg =
{
.dstInc = dmaDataInc1, /* Increment destination address by one byte */
.srcInc = dmaDataIncNone, /* Do no increment source address */
.size = dmaDataSize1, /* Data size is one byte */
.arbRate = dmaArbitrate1, /* Rearbitrate for each byte recieved*/
.hprot = 0, /* No read/write source protection */
};
DMA_CfgDescr(DMA_RX_CHANNEL, true, &descrCfg);
/* Starting the transfer. Using Basic Mode */
DMA_ActivateBasic(DMA_RX_CHANNEL, /* Activate channel selected */
true, /* Use primary descriptor */
false, /* No DMA burst */
(void *) &ucRx_Buffer, /* Destination address */
(void *) &LEUART0->RXDATA, /* Source address*/
RX_BUF_MAX - 1); /* Size of buffer minus1 */
/* Make sure the LEUART wakes up the DMA on RX data */
LEUART0->CTRL = LEUART_CTRL_RXDMAWU;
//Setting up Tx DMA
/* Setting up channel */
/* Setting call-back function */
cb[DMA_TX_CHANNEL].cbFunc = LeUartTxTransmitComplete;
cb[DMA_TX_CHANNEL].userPtr = NULL;
DMA_CfgChannel_TypeDef chnlCfg1 =
{
.highPri = false, /* Normal priority */
.enableInt = true, /* No interupt enabled for callback functions */
.select = DMAREQ_LEUART0_TXEMPTY, /* Set LEUART0 RX data avalible as source of DMA signals */
.cb = &(cb[DMA_TX_CHANNEL]),
};
DMA_CfgChannel(DMA_TX_CHANNEL, &chnlCfg1);
/* Setting up channel descriptor */
DMA_CfgDescr_TypeDef descrCfg1 =
{
.dstInc = dmaDataIncNone, /* Do no increment source address */
.srcInc = dmaDataInc1, /* Increment destination address by one byte */
.size = dmaDataSize1, /* Data size is one byte */
.arbRate = dmaArbitrate1, /* Rearbitrate for each byte recieved*/
.hprot = 0, /* No read/write source protection */
};
DMA_CfgDescr(DMA_TX_CHANNEL, true, &descrCfg1);
/* Set new DMA destination address directly in the DMA descriptor */
dmaControlBlock[DMA_TX_CHANNEL].DSTEND = &LEUART0->TXDATA;
dmaControlBlock[DMA_TX_CHANNEL].SRCEND = ucTx_Buffer + TX_BUF_MAX - 1;
}
void main(void)
{
/* Initialize chip */
CHIP_Init();
/* Start LFXO, and use LFXO for low-energy modules */
CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);
/* Enabling clocks, all other remain disabled */
CMU_ClockEnable(cmuClock_CORELE, true); /* Enable CORELE clock */
CMU_ClockEnable(cmuClock_DMA, true); /* Enable DMA clock */
CMU_ClockEnable(cmuClock_GPIO, true); /* Enable GPIO clock */
CMU_ClockEnable(cmuClock_LEUART0, true); /* Enable LEUART0 clock */
DMAInit();
LeUart_Initial_IO();
DMA_Initial_IO();
GPIO_PinModeSet(gpioPortD, 7, gpioModePushPull, 0);
while (1)
{
EMU_EnterEM2(true);
if(ucRx_Ok)//判断是否有接收到数据,如果有,则启动一次发送。
{
LEUART0->CTRL = LEUART_CTRL_TXDMAWU;
DMA_ActivateBasic(DMA_TX_CHANNEL, /* Activate channel selected */
true, /* Use primary descriptor */
false, /* No DMA burst */
NULL, /* Keep destination address */
NULL, /* Keep source address*/
TX_BUF_MAX - 1); /* Size of buffer minus1 */
ucRx_Ok = 0;
}
}
}