/**************************************************************************//**
 * @file
 * @brief High Frequaency ADC Sampling using Timer, DMA and PRS
 * @author Energy Micro AS
 * @version 1.0.0
 ******************************************************************************
 * @section License
 * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
 *******************************************************************************
 *
 * This file is licensed under the Silicon Labs Software License Agreement. See  
 * "http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt"   
 * for details. Before using this software for any purpose, you must agree to the  
 * terms of that agreement.
 *
 ******************************************************************************/
 
#include <stdlib.h>
#include <stdio.h>
#include "efm32.h"
#include "em_chip.h"
#include "em_emu.h"
#include "em_cmu.h"
#include "em_adc.h"
#include "em_lcd.h"
#include "em_prs.h"
#include "em_dma.h"
#include "em_timer.h"
 
/* Drivers */
#include "segmentlcd.h"
 
/* Support functions */
#include "support.h"
 
/* Defines */
#define ADC_SAMPLE_RATE       100000
#define HFPER                 14000000
#define TIMER_TOP             (HFPER / ADC_SAMPLE_RATE)
#define BUFFER_SIZE_SHIFT     9
#define BUFFER_SIZE           (1 << BUFFER_SIZE_SHIFT)
#define BUFFERS_PER_SECOND    (ADC_SAMPLE_RATE / BUFFER_SIZE)
#define DMA_CHANNEL           0
#define PRS_CHANNEL           0
 
/* Uncomment to use Fahrenheit instead of Celsius */
/* #define FAHRENHEIT */
 
/* 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
 
/* Variables */
uint16_t              ramBufferA[BUFFER_SIZE];
uint16_t              ramBufferB[BUFFER_SIZE];
bool                  usingRamBufferA;
static DMA_CB_TypeDef cbInData;
char                  string[8];
 
/**************************************************************************//**
 * @brief ADC0 interrupt handler. Simply clears interrupt flag.
 *****************************************************************************/
static void preampDMAInCb(unsigned int channel, bool primary, void *user)
{
  (void) user; /* Unused parameter */
 
  /* Refresh DMA */
  DMA_RefreshPingPong(channel,     /* channel */
                      primary,         /* descriptor to update */
                      false,           /* do not use burst */
                      NULL,            /* do not change destination */
                      NULL,            /* do not change source */
                      BUFFER_SIZE - 1, /* number of transfers */
                      false);          /* do not stop after completing this cycle */
 
  /* Switch buffer */
  usingRamBufferA = primary;
 
  /* Set software interrupt */
  SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
}
 
/**************************************************************************//**
 * @brief Software interrupt handler
 * Computes and displays the average temperature
 *****************************************************************************/
void PendSV_Handler(void)
{
  static bool     enableAntenna = false;
  static uint32_t display_count = 0;
  int32_t         temp;
  uint32_t        i;
 
  uint32_t        avg = 0;
  /* Show Celsius on alphanumeric part of display */
  if (usingRamBufferA)
  {
    for (i = 0; i < BUFFER_SIZE; i++)
    {
      avg += ramBufferA[i];
    }
  }
  else
  {
    for (i = 0; i < BUFFER_SIZE; i++)
    {
      avg += ramBufferB[i];
    }
  }
 
  /* The buffer size is a power of two, so rightshift can be used instead of
   * division */
  avg = avg >> BUFFER_SIZE_SHIFT;
   
#if defined(_EFM32_GIANT_FAMILY)
  avg += 112;
#endif
 
  /* Show Celsius or Fahrenheit on alphanumeric part of display */
#ifndef FAHRENHEIT
  temp = (int32_t)(convertToCelsius(avg) * 10);
  snprintf(string, 8, "%2d,%1d%%C", (temp / 10), abs(temp) % 10);
#else
  temp = (int32_t)(convertToFahrenheit(avg) * 10);
  snprintf(string, 8, "%2d,%1d%%F", (temp / 10), abs(temp) % 10);
#endif
 
  /* Display result on LCD once a second */
  if (++display_count == BUFFERS_PER_SECOND)
  {
    display_count = 0;
 
    SegmentLCD_Write(string);
 
    /* Indicate update */
    SegmentLCD_Symbol(LCD_SYMBOL_ANT, enableAntenna);
    enableAntenna = !enableAntenna;
  }
}
 
/**************************************************************************//**
 * @brief Configure ADC with DMA
 *****************************************************************************/
static void adc_setup(void)
{
  /* Configure ADC single conversion */
  CMU_ClockEnable(cmuClock_ADC0, true);
 
  ADC_Init_TypeDef       init       = ADC_INIT_DEFAULT;
  ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT;
 
  init.timebase   = ADC_TimebaseCalc(0);
  init.warmUpMode = adcWarmupKeepADCWarm;
 
  init.prescale = ADC_PrescaleCalc(7000000, 0);
  ADC_Init(ADC0, &init);
 
  singleInit.reference  = adcRef1V25;
  singleInit.input      = adcSingleInpTemp;
  singleInit.resolution = adcRes12Bit;
  singleInit.prsSel     = adcPRSSELCh0;
  singleInit.prsEnable  = true;
 
  singleInit.acqTime = adcAcqTime32;
 
  ADC_InitSingle(ADC0, &singleInit);
 
  /* Configure DMA usage by ADC */
  CMU_ClockEnable(cmuClock_DMA, true);
 
  DMA_CfgDescr_TypeDef   descrCfg;
  DMA_CfgChannel_TypeDef chnlCfg;
 
  cbInData.cbFunc  = preampDMAInCb;
  cbInData.userPtr = NULL;
 
  chnlCfg.highPri   = true;
  chnlCfg.enableInt = true;
  chnlCfg.select    = DMAREQ_ADC0_SINGLE;
  chnlCfg.cb        = &cbInData;
  DMA_CfgChannel(0, &chnlCfg);
 
  descrCfg.dstInc  = dmaDataInc2;
  descrCfg.srcInc  = dmaDataIncNone;
  descrCfg.size    = dmaDataSize2;
  descrCfg.arbRate = dmaArbitrate1;
  descrCfg.hprot   = 0;
  DMA_CfgDescr(DMA_CHANNEL, true, &descrCfg);
  DMA_CfgDescr(DMA_CHANNEL, false, &descrCfg);
 
  DMA_ActivatePingPong(DMA_CHANNEL,                              /* channel */
                       false,                                    /* do not use burst */
                       (void *) &ramBufferA,                     /* primary destination */
                       (void *)((uint32_t) &(ADC0->SINGLEDATA)), /* primary source */
                       BUFFER_SIZE - 1,                          /* primary number of transfers */
                       (void *) &ramBufferB,                     /*altenate deststination */
                       (void *)((uint32_t) &(ADC0->SINGLEDATA)), /* alternate source */
                       BUFFER_SIZE - 1);                         /* alternate number of transfers */
 
  /* Select ramBufferA as current */
  usingRamBufferA = true;
}
 
/**************************************************************************//**
 * @brief Configure PRS
 *****************************************************************************/
static void prs_setup(unsigned int prsChannel)
{
  PRS_LevelSet(0, 1 << (prsChannel + _PRS_SWLEVEL_CH0LEVEL_SHIFT));
  PRS_SourceSignalSet(prsChannel,
                      PRS_CH_CTRL_SOURCESEL_TIMER0,
                      PRS_CH_CTRL_SIGSEL_TIMER0OF,
                      prsEdgePos);
}
 
 
/**************************************************************************//**
 * @brief Configure Timer
 *****************************************************************************/
void timer_setup(void)
{
  /* Enable clock for TIMER0 module */
  CMU_ClockEnable(cmuClock_TIMER0, true);
 
  CMU_ClockEnable(cmuClock_PRS, true);
 
  /* Select TIMER0 parameters */
  TIMER_Init_TypeDef timerInit =
  {
    .enable     = true,
    .debugRun   = true,
    .prescale   = timerPrescale1,
    .clkSel     = timerClkSelHFPerClk,
    .fallAction = timerInputActionNone,
    .riseAction = timerInputActionNone,
    .mode       = timerModeUp,
    .dmaClrAct  = false,
    .quadModeX4 = false,
    .oneShot    = false,
    .sync       = false,
  };
 
  /* Set TIMER Top value */
  TIMER_TopSet(TIMER0, TIMER_TOP);
 
  /* Configure TIMER */
  TIMER_Init(TIMER0, &timerInit);
}
 
/**************************************************************************//**
 * @brief SWO Setup
 * Enables code view in energyAware Profiler
 *****************************************************************************/
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  Main function
 *****************************************************************************/
int main(void)
{
  /* Initialize chip */
  CHIP_Init();
   
  /* Enable code view */
  setupSWO();
 
  SegmentLCD_Init(false);
 
  /* Enable clocks required */
  CMU_ClockEnable(cmuClock_HFPER, true);
 
 
  DMA_Init_TypeDef dmaInit;
  dmaInit.hprot        = 0;
  dmaInit.controlBlock = dmaControlBlock;
  DMA_Init(&dmaInit);
 
  /* Configure Timer, PRS and ADC */
  timer_setup();
  prs_setup(PRS_CHANNEL);
  adc_setup();
 
  /* Enable software interrupt */
  NVIC_EnableIRQ(PendSV_IRQn);
 
  /* Set priorities */
  NVIC_SetPriority(DMA_IRQn, 0);                              /* Highest priority */
  NVIC_SetPriority(PendSV_IRQn, (1 << __NVIC_PRIO_BITS) - 1); /* Lowest priority */
 
  /* Stay in this loop forever */
  while (1)
  {
    EMU_EnterEM1();
  }
}

EFM32 DMA/PRS例程的更多相关文章

  1. mmap DMA【转】

    转自:http://blog.csdn.net/lihaoweiv/article/details/6275241 第 13 章  mmap 和 DMA 本章将深入探讨 Linux 内存管理部分,并强 ...

  2. DriverStudio开发PCI设备DMA数据传输

    DriverWizard向导可以创建基本的wDM驱动程序框架,包括总线类型,地址空间,中断源,DMA资源,以及IOCTL(i/o控制代码)的定义等等.详细情况可参看DriverStudio的帮助文档, ...

  3. DMA内存申请--dma_alloc_coherent 及 寄存器与内存【转】

    转自:https://blog.csdn.net/ic_soc_arm_robin/article/details/8203933 在项目驱动过程中会经常用到dma传输数据,而dma需要的内存有自己的 ...

  4. LDD3 第15章 内存映射和DMA

    本章内容分为三个部分: 第一部分讲述了mmap系统调用的实现过程.将设备内存直接映射到用户进程的地址空间,尽管不是所有设备都需要,但是能显著的提高设备性能. 如何跨越边界直接访问用户空间的内存页,一些 ...

  5. linux 简单的DMA例程

    一个简单的使用DMA 例子 示例:下面是一个简单的使用DMA进行传输的驱动程序,它是一个假想的设备,只列出DMA相关的部分来说明驱动程序中如何使用DMA的. 函数dad_transfer是设置DMA对 ...

  6. 【GMT43智能液晶模块】例程十:DMA实验——存储器到存储器的传输

    实验原理: DMA(直接存储器访问)传输不需要占用CPU,可以在存储器至存储器实现高速的数据 传输.本实验采用DMA2控制器的数据流0,选用通道0进行数据传输.通过液晶控制传输 和结果显示. 示例截图 ...

  7. 【iCore4 双核心板_ARM】例程十一:DMA实验——存储器到存储器的传输

    实验原理: DAM(直接存储器访问)传输不需要占用CPU,可以在存储器至存储器实现高速的数据 传输.本实验采用DAM2控制器的数据流0,选用通道0进行数据传输.通过LED的颜色来 判断传输是否成功. ...

  8. 【iCore1S 双核心板_ARM】例程十二:DMA实验——存储器到存储器的传输

    实验原理: DAM(直接存储器访问)传输不需要占用CPU,可以在存储器至存储器实现高速的数据 传输.本实验采用DAM2控制器的数据流0,选用通道0进行数据传输.通过LED的颜色来 判断传输是否成功. ...

  9. 【iCore3 双核心板】例程十一:DMA实验——存储器到存储器的传输

    实验指导书及代码包下载: http://pan.baidu.com/s/1bcY5JK iCore3 购买链接: https://item.taobao.com/item.htm?id=5242294 ...

随机推荐

  1. shell随机读取一行

    使用shell随机读取文件的一行数据 shuf -n1 file_name

  2. <%@ include file="">和<jsp:include file="">区别

    <%@include file="a.jsp"%>是在编译时加入,所谓静态,就是在编译的时候将jsp的代码加入进来再编译,之后运行. <jsp:include p ...

  3. python练习笔记——丑数的计算

    只包含因子2,3,5的正整数被称作丑数,比如4,10,12都是丑数,而7,23,111则不是丑数,另外1也不是丑数.——摘自百度百科 get_num = int(input("请您输入丑数的 ...

  4. 使用用户自定义类型作为map的key

    有时候我们想把用户自定义类型作为std::map的键值.方法一)最简单的方法就是实现该自定义类型的<操作符,代码如下:class Foo{public:    Foo(int num_)     ...

  5. MAR 27 解决华为手机访问Google Play:从服务器检索信息时出错。[DF-DFERH-01]

    虽然路由器已经设置了梯子,但是用华为手机访问Google Play时,还是提示:从服务器检索信息时出错.[DF-DFERH-01].   虽然在手机上把梯子设置成全局模式,连接Google Play后 ...

  6. 解决windows server2012 评估版本过期,系统会自动关机

    解决windows server2012 评估版本过期,系统在1小时后会自动关机. 重置方法:以管理员方式运行命令行,执行slmgr.vbs /rearm,可以使授权延长180天,但是仅能延长5次.

  7. nginx https ssl 设置受信任证书[转然哥]

    nginx https ssl 设置受信任证书[原创] 1. 安装nginx 支持ssl模块 http://nginx.org/en/docs/configure.html yum -y instal ...

  8. Google大脑科学家贾杨清(Caffe缔造者)-微信讲座

    Google大脑科学家贾杨清(Caffe缔造者)-微信讲座 机器学习Caffe 贾扬清 caffe   一.讲座正文: 大家好!我是贾扬清178,目前在Google Brain69,今天有幸受雷鸣师兄 ...

  9. Eclipse中导入Git项目

    1.先将项目git到本地 2.导入刚刚git到本地项目 if(如果project带.calsspath .project 文件){ 直接用genaral导入或andorid project导入即可. ...

  10. 使用配置hadoop中常用的Linux(ubuntu)命令

    生成key: $ ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa $ cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized ...