EFM32片内外设--ADC之多通道采样+Timer+PRS触发+DMA

来源:互联网 发布:php成绩管理系统源码 编辑:程序博客网 时间:2024/05/16 16:05

在Application note中,ADC已经有了很多的例子,唯独缺少一个多通道定时触发进行扫描的例程。从理论上讲,将ADC配置为多通道ADC转换,配合DMA进行数据传输,而且使用Timer+PRS的方式,进行自动触发,这个功能应该是完全OK的。但是只是缺少一个例程,以及自行研究的过程。

首先配置ADC。

将ADC配置为多通道采样,例程中将ADC配置为通道2~通道4输入,唯一不一样的就是需要使能PRS,因为PRS需要将Timer与ADC相连接,这样的话,Timer就能通过PRS来触发ADC扫描了。

ADC_Init_TypeDef     init     = ADC_INIT_DEFAULT;

ADC_InitScan_TypeDef scanInit = ADC_INITSCAN_DEFAULT;

...................

scanInit.prsEnable = true;

 

配置Timer。

Timer决定了ADC会隔多久会进行一次多通道扫描。例程里将Timer配置成一个简单的溢出计数器,溢出的周期为32KHz左右。

配置DMA。

由于ADC Scan的结果寄存器只有一个,因此必须使用DMA将ADC的结果转到RAM中。配置参考了ADC Scan的例程,DMA数据搬运的触发信号配置为DMAREQ_ADC0_SCAN。另外需要使能DMA中断,并且设置DMA传输完成函数。在传输完成函数中,刷新DMA。

void transferComplete(unsigned int channel, bool primary, void *user)
{
    DMA_ActivateBasic(DMA_CHANNEL,
                      true,
                      false,
                      samples,
                      (void *)((uint32_t) &(ADC0->SCANDATA)),
                      NUM_SAMPLES - 1);
   
    printf("%d, %d, %d \r\n", samples[0], samples[1], samples[2]);
   
    GPIO_PinOutToggle(gpioPortD, 7);
}

 

配置PRS。

连接Timer与ADC,使用PRS通道0

 

工作流程:

系统初始化,包括PRS初始化及配置。

1.初始化ADC

2.初始化DMA,并且初始化一次DMA传输DMA_ActivateBasic(),等待Timer触发ADC进行扫描

3.初始化Timer

4.Timer定时溢出,通过PRS触发ADC Scan. 每次ADC Scan有数据时即DMAREQ_ADC0_SCAN信号成立时,通过DMA传输到RAM中。

5.当DMA传输完毕,调用DMA回调函数完成DMA刷新,等待下一次Timer触发。回到步骤4。

6.在例程中加入了SWO输出,以及ADC扫描溢出中断等测试条件。

 

例程如下,可能比较多些,各位看官请耐心。

 

#include <stdio.h>
#include "efm32.h"
#include "em_chip.h"
#include "em_emu.h"
#include "em_cmu.h"
#include "em_adc.h"
#include "em_prs.h"
#include "em_timer.h"
#include "em_dma.h"
#include "em_gpio.h"
#include "stdio.h"

/** DMA control block, requires proper alignment. */
#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 callback structure */
DMA_CB_TypeDef cb;


/** DMA channel used for scan sequence sampling adc channel 2, 3 and 4. */
#define DMA_CHANNEL    0
#define NUM_SAMPLES    3

uint32_t samples[NUM_SAMPLES];

void setupSWO(void)
{
    uint32_t *dwt_ctrl = (uint32_t *) 0xE0001000;
    uint32_t *tpiu_prescaler = (uint32_t *) 0xE0040010;
    uint32_t *tpiu_protocol = (uint32_t *) 0xE00400F0;
   
    CMU->HFPERCLKEN0 |= CMU_HFPERCLKEN0_GPIO;
    /* Enable Serial wire output pin */
    GPIO->ROUTE |= GPIO_ROUTE_SWOPEN;
#if defined(_EFM32_GIANT_FAMILY)
    /* Set location 0 */
    GPIO->ROUTE = (GPIO->ROUTE & ~(_GPIO_ROUTE_SWLOCATION_MASK)) | GPIO_ROUTE_SWLOCATION_LOC0;
   
    /* Enable output on pin - GPIO Port F, Pin 2 */
    GPIO->P[5].MODEL &= ~(_GPIO_P_MODEL_MODE2_MASK);
    GPIO->P[5].MODEL |= GPIO_P_MODEL_MODE2_PUSHPULL;
#else
    /* Set location 1 */
    GPIO->ROUTE = (GPIO->ROUTE & ~(_GPIO_ROUTE_SWLOCATION_MASK)) | GPIO_ROUTE_SWLOCATION_LOC1;
    /* Enable output on pin */
    GPIO->P[2].MODEH &= ~(_GPIO_P_MODEH_MODE15_MASK);
    GPIO->P[2].MODEH |= GPIO_P_MODEH_MODE15_PUSHPULL;
#endif
    /* Enable debug clock AUXHFRCO */
    CMU->OSCENCMD = CMU_OSCENCMD_AUXHFRCOEN;
   
    while(!(CMU->STATUS & CMU_STATUS_AUXHFRCORDY));
   
    /* Enable trace in core debug */
    CoreDebug->DHCSR |= 1;
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
   
    /* Enable PC and IRQ sampling output */
    *dwt_ctrl = 0x400113FF;
    /* Set TPIU prescaler to 16. */
    *tpiu_prescaler = 0xf;
    /* Set protocol to NRZ */
    *tpiu_protocol = 2;
    /* Unlock ITM and output data */
    ITM->LAR = 0xC5ACCE55;
    ITM->TCR = 0x10009;
}


/**************************************************************************//**
 * @brief  Call-back called when transfer is complete
 *****************************************************************************/
void transferComplete(unsigned int channel, bool primary, void *user)
{
    DMA_ActivateBasic(DMA_CHANNEL,
                      true,
                      false,
                      samples,
                      (void *)((uint32_t) &(ADC0->SCANDATA)),
                      NUM_SAMPLES - 1);
   
    printf("%d, %d, %d \r\n", samples[0], samples[1], samples[2]);//打印log信息
   
    GPIO_PinOutToggle(gpioPortD, 7); //用来测试ADC扫描是否正常工作
}

/**************************************************************************//**
 * @brief ADC0_IRQHandler
 * Interrupt Service Routine for ADC
 *****************************************************************************/
void ADC0_IRQHandler(void)
{
    /* Clear ADC0 interrupt flag */
    ADC0->IFC = ADC_IFC_SCANOF;
   
    printf("ADC Scan overflow");//用来判断是否有ADC扫描结果溢出的情况发生
   
}

/***************************************************************************//**
* @brief
*   Configure ADC usage for this application.
*******************************************************************************/
static void ADCConfig(void)
{
    ADC_Init_TypeDef     init     = ADC_INIT_DEFAULT;
    ADC_InitScan_TypeDef scanInit = ADC_INITSCAN_DEFAULT;
   
    /* Init common issues for both single conversion and scan mode */
    init.timebase = ADC_TimebaseCalc(0);
    init.prescale = ADC_PrescaleCalc(7000000, 0);
    ADC_Init(ADC0, &init);
   
    /* Init for scan sequence use ( for dvk: accelerometer X, Y and Z axis). */
    scanInit.reference = adcRefVDD;
    scanInit.input     = ADC_SCANCTRL_INPUTMASK_CH2 | ADC_SCANCTRL_INPUTMASK_CH3 | ADC_SCANCTRL_INPUTMASK_CH4;
    scanInit.prsEnable = true;
    ADC_InitScan(ADC0, &scanInit);
   
    /* Enable ADC Interrupt when Single Conversion Complete */
    ADC0->IEN = ADC_IEN_SCANOF;
   
    /* Enable ADC interrupt vector in NVIC*/
    NVIC_EnableIRQ(ADC0_IRQn);
}

/***************************************************************************//**
* @brief
*   Configure Timer for this application.
*******************************************************************************/
static void TimerConfig(void)
{
    /* Use default timer settings */
    TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT;
   
    /* Change prescaler to 64, gives roughly 3 overflows per
    * second at 14MHz with 0xffff as top value */
    timerInit.prescale = timerPrescale1;
   
    TIMER_TopSet(TIMER0, 440);
   
    TIMER_Init(TIMER0, &timerInit);
}


/***************************************************************************//**
* @brief
*   Configure DMA usage for this application.
*******************************************************************************/
static void DMAConfig(void)
{
    DMA_Init_TypeDef       dmaInit;
    DMA_CfgDescr_TypeDef   descrCfg;
    DMA_CfgChannel_TypeDef chnlCfg;
   
    /* Configure general DMA issues */
    dmaInit.hprot        = 0;
    dmaInit.controlBlock = dmaControlBlock;
    DMA_Init(&dmaInit);
   
    /* Setting up call-back function */ 
    cb.cbFunc  = transferComplete;
    cb.userPtr = NULL;
   
    /* Configure DMA channel used */
    chnlCfg.highPri   = false;
    chnlCfg.enableInt = true;
    chnlCfg.select    = DMAREQ_ADC0_SCAN;
    chnlCfg.cb        = &cb;
    DMA_CfgChannel(DMA_CHANNEL, &chnlCfg);
   
    descrCfg.dstInc  = dmaDataInc4;
    descrCfg.srcInc  = dmaDataIncNone;
    descrCfg.size    = dmaDataSize4;
    descrCfg.arbRate = dmaArbitrate1;
    descrCfg.hprot   = 0;
    DMA_CfgDescr(DMA_CHANNEL, true, &descrCfg);
   
    DMA_ActivateBasic(DMA_CHANNEL,
                      true,
                      false,
                      samples,
                      (void *)((uint32_t) &(ADC0->SCANDATA)),
                      NUM_SAMPLES - 1);
}

/******************************************************************************
 * @brief  Main function
 * The main file starts a timer and uses PRS to trigger an ADC conversion.
 * It waits in EM1 until the ADC conversion is complete, then prints the
 * result on the lcd.
 *****************************************************************************/
int main(void)
{
  /* Initialize chip */
  CHIP_Init();
  setupSWO();

  CMU_ClockEnable(cmuClock_HFPER, true);
  /* Enable clocks required */
  CMU_ClockEnable(cmuClock_ADC0, true);
  CMU_ClockEnable(cmuClock_PRS, true);
  CMU_ClockEnable(cmuClock_TIMER0, true);
  CMU_ClockEnable(cmuClock_DMA, true);
  CMU_ClockEnable(cmuClock_GPIO, true);
 
  GPIO_PinModeSet(gpioPortD, 7, gpioModePushPull, 1);

  /* Select TIMER0 as source and TIMER0OF (Timer0 overflow) as signal (rising edge) */
  PRS_SourceSignalSet(0, PRS_CH_CTRL_SOURCESEL_TIMER0, PRS_CH_CTRL_SIGSEL_TIMER0OF, prsEdgePos);

 
  ADCConfig();
  DMAConfig();
  TimerConfig();

  /* Stay in this loop forever */
  while (1)
  {
     
  }
}

 

工程链接:

http://download.csdn.net/download/efm32/4753643

原创粉丝点击