EFM32片内外设--DMA之LeUart Tx Rx

一直没有具体的自己写过和测试过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;
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值