Ejemplo n.º 1
0
/***************************************************************************//**
* @brief
*   Configure ADC usage for this application.
*******************************************************************************/
static void ADCConfig(void)
{
  ADC_Init_TypeDef       init       = ADC_INIT_DEFAULT;
  ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT;

  /* Init common settings for both single conversion and scan mode */
  init.timebase = ADC_TimebaseCalc(0);
  /* Might as well finish conversion as quickly as possibly since polling */
  /* for completion. */
  /* Set ADC clock to 7 MHz, use default HFPERCLK */
  init.prescale = ADC_PrescaleCalc(7000000, 0);

  /* WARMUPMODE must be set to Normal according to ref manual before */
  /* entering EM2. In this example, the warmup time is not a big problem */
  /* due to relatively infrequent polling. Leave at default NORMAL, */

  ADC_Init(ADC0, &init);

  /* Init for single conversion use. */
  singleInit.reference  = adcRefVDD;
  singleInit.input      = adcSingleInpCh5;
  singleInit.resolution = adcRes12Bit;
  singleInit.prsEnable  = true; /* Enable PRS for ADC */
  ADC_InitSingle(ADC0, &singleInit);

  /* Enable ADC Interrupt when Single Conversion Complete */
  ADC0->IEN = ADC_IEN_SINGLE;

  /* Enable ADC interrupt vector in NVIC*/
  NVIC_EnableIRQ(ADC0_IRQn);
}
Ejemplo n.º 2
0
/******************************************************************//**
* @brief
*	Initialize all ADC module related hardware and register ADC device to kernel
*
* @details
*
* @note
*
*********************************************************************/
void rt_hw_adc_init(void)
{
	struct efm32_adc_device_t 	*adc;
	ADC_Init_TypeDef 			init = ADC_INIT_DEFAULT;

	// TODO: Fixed oversampling rate?
	init.ovsRateSel	= adcOvsRateSel4096;
	init.timebase 	= ADC_TimebaseCalc(0);
	init.prescale 	= ADC_PrescaleCalc(ADC_CONVERT_FREQUENCY, 0);

	
#ifdef RT_USING_ADC0
	adc = rt_malloc(sizeof(struct efm32_adc_device_t));
	if (adc == RT_NULL)
	{
#ifdef RT_ADC_DEBUG
		rt_kprintf("no memory for ADC driver\n");
#endif
		return;
	}
	adc->adc_device	= ADC0;
	adc->mode 		= ADC_MODE_SINGLE;

	/* Enable clock for ADCn module */
	CMU_ClockEnable(cmuClock_ADC0, true);

	/* Reset */
	 ADC_Reset(ADC0);

	/* Configure ADC */
	ADC_Init(adc->adc_device, &init);

	rt_hw_adc_register(&adc0_device, RT_ADC0_NAME, EFM32_NO_DATA, adc);	
#endif
}
/*
 * Function Name: ADC_setup()
 * Description: Configures ADC0
 */
void ADC_Setup(void)

{
    CMU_ClockEnable(cmuClock_ADC0, true);

    // Default Declarations
    ADC_Init_TypeDef       init       = ADC_INIT_DEFAULT;
    ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT;

    // ADC Parameters
    init.timebase = ADC_TimebaseCalc(0);
    init.prescale = ADC_PrescaleCalc(857000,0);

    // Initializing ADC
    ADC_Init(ADC0, &init);

    // Single Conversion setup
    // Single Conversion with Repeat ON
    singleInit.reference  = ADC_REF;
    singleInit.input      = adcSingleInpTemp;
    singleInit.resolution = adcRes12Bit;
    singleInit.acqTime = adcAcqTime2;
    singleInit.rep = true;

    // ADC single setup on
    ADC_InitSingle(ADC0, &singleInit);
}
Ejemplo n.º 4
0
//================================================================================
// ADC0_enter_DefaultMode_from_RESET
//================================================================================
extern void ADC0_enter_DefaultMode_from_RESET(void) {

	// $[ADC_Init]
	ADC_Init_TypeDef init = ADC_INIT_DEFAULT;
	ADC_InitScan_TypeDef scanInit = ADC_INITSCAN_DEFAULT;

	init.ovsRateSel = false;//关闭过采样
	init.timebase = ADC_TimebaseCalc(0);
	init.prescale = ADC_PrescaleCalc(7000000, 0);

	ADC_Init(ADC0, &init);
	// [ADC_Init]$

	// $[ADC_InitSingle]
	// [ADC_InitSingle]$

	// $[ADC_InitScan]
	scanInit.reference = adcRefVDD;//3.31V
	scanInit.input     = ADC_SCANCTRL_INPUTMASK_CH4 |	//轮询通道CH4、CH5、CH6(PD4\PD5\PD6)
	                     ADC_SCANCTRL_INPUTMASK_CH5 |
	                     ADC_SCANCTRL_INPUTMASK_CH6;
	scanInit.resolution = adcRes8Bit;//8位分辨率
	// [ADC_InitScan]$
	ADC_InitScan(ADC0, &scanInit);

}
/***************************************************************************//**
* @brief
*   Configure ADC and DMA for this application.
*******************************************************************************/
static void guitarADCConfig(void)
{
  DMA_CfgDescr_TypeDef   descrCfg;
  DMA_CfgChannel_TypeDef chnlCfg;
  ADC_Init_TypeDef       init     = ADC_INIT_DEFAULT;
  ADC_InitScan_TypeDef   scanInit = ADC_INITSCAN_DEFAULT;

  /* Configure DMA usage by ADC */

  cbInData.cbFunc  = guitarDMAInCb;
  cbInData.userPtr = NULL;

  /* Set up high pri channel with callback with request from ADC scan complete. */ 
  chnlCfg.highPri   = true; 
  chnlCfg.enableInt = true;
  chnlCfg.select    = DMAREQ_ADC0_SCAN;
  chnlCfg.cb        = &cbInData;
  DMA_CfgChannel(GUITAR_DMA_AUDIO_IN, &chnlCfg);

  /* Configure datasize, increment and primary, alternate structure for pingpong. */
  descrCfg.dstInc  = dmaDataInc2;
  descrCfg.srcInc  = dmaDataIncNone;
  descrCfg.size    = dmaDataSize2;
  descrCfg.arbRate = dmaArbitrate1;
  descrCfg.hprot   = 0;
  DMA_CfgDescr(GUITAR_DMA_AUDIO_IN, true, &descrCfg);
  DMA_CfgDescr(GUITAR_DMA_AUDIO_IN, false, &descrCfg);

  DMA_ActivatePingPong(GUITAR_DMA_AUDIO_IN,
                       false,
                       guitarAudioInBuffer1,
                       (void *)((uint32_t) &(ADC0->SCANDATA)),
                       (GUITAR_AUDIO_BUFFER_SAMPLES * 2) - 1,
                       guitarAudioInBuffer2,
                       (void *)((uint32_t) &(ADC0->SCANDATA)),
                       (GUITAR_AUDIO_BUFFER_SAMPLES * 2) - 1);

  /* Configure ADC */

  /* Keep warm due to "high" frequency sampling */
  init.warmUpMode = adcWarmupKeepADCWarm;
  /* Init common issues for both single conversion and scan mode */
  /* 0 means, figure out the base frequency based on current cmu config. */
  init.timebase = ADC_TimebaseCalc(0); 
  /* Calculate necessary prescaler to get 4MHz adc clock with current cmu configuration. */
  init.prescale = ADC_PrescaleCalc(4000000, 0); 
  /* Sample potentiometer by tailgating in order to not disturb fixed rate */
  /* audio sampling. */
  init.tailgate = true;
  ADC_Init(ADC0, &init);

  /* Init for scan sequence use (audio in right/left channels). */
  scanInit.prsSel    = adcPRSSELCh0;
  scanInit.prsEnable = true;
  scanInit.reference = adcRefVDD;
  scanInit.input     = ADC_SCANCTRL_INPUTMASK_CH6 | ADC_SCANCTRL_INPUTMASK_CH7;
  ADC_InitScan(ADC0, &scanInit);
}
Ejemplo n.º 6
0
static void ADCConfig(void)
{
  DMA_CfgDescr_TypeDef   descrCfg;
  DMA_CfgChannel_TypeDef chnlCfg;
  ADC_Init_TypeDef       init     = ADC_INIT_DEFAULT;
  ADC_InitScan_TypeDef   scanInit = ADC_INITSCAN_DEFAULT;

  /* Configure DMA usage by ADC */

  cbInData.cbFunc  = adcCb;
  cbInData.userPtr = NULL;

  chnlCfg.highPri   = true;
  chnlCfg.enableInt = true;
  chnlCfg.select    = DMAREQ_ADC0_SCAN;
  chnlCfg.cb        = &cbInData;
  DMA_CfgChannel(DMA_CHANNEL_ADC, &chnlCfg);

  descrCfg.dstInc  = dmaDataInc2;
  descrCfg.srcInc  = dmaDataIncNone;
  descrCfg.size    = dmaDataSize2;
  descrCfg.arbRate = dmaArbitrate1;
  descrCfg.hprot   = 0;
  DMA_CfgDescr(DMA_CHANNEL_ADC, true, &descrCfg);
  DMA_CfgDescr(DMA_CHANNEL_ADC, false, &descrCfg);

  DMA_ActivatePingPong(DMA_CHANNEL_ADC,
                       false,
                       sourceP,
                       (void *)((uint32_t) &(ADC0->SCANDATA)),
                       N - 1,
                       sourceS,
                       (void *)((uint32_t) &(ADC0->SCANDATA)),
                       N - 1);

  /* Indicate starting with primary in-buffer (according to above DMA setup) */
  bufferPrimary = true;

  /* Configure ADC */

  /* Keep warm due to "high" frequency sampling */
  init.warmUpMode = adcWarmupKeepADCWarm;
  /* Init common issues for both single conversion and scan mode */
  init.timebase = ADC_TimebaseCalc(0);
  init.prescale = ADC_PrescaleCalc(4000000, 0);
  /* Sample potentiometer by tailgating in order to not disturb fixed rate */
  /* audio sampling. */
  init.tailgate = true;
  ADC_Init(ADC0, &init);

  /* Init for scan sequence use (audio in right/left channels). */
  scanInit.prsSel    = adcPRSSELCh0;
  scanInit.prsEnable = true;
  scanInit.reference = adcRefVDD;
  scanInit.input     = ADC_SCANCTRL_INPUTMASK_CH6 | ADC_SCANCTRL_INPUTMASK_CH7;
  ADC_InitScan(ADC0, &scanInit);
}
Ejemplo n.º 7
0
/**
 * Initialize ADC Module
 */
void adc_init(void)
{
  ADC_Init_TypeDef init = ADC_INIT_DEFAULT;

  /* Enable ADC Clock */
  CMU_ClockEnable(cmuClock_ADC0, true);

  /* Initialize timebases */
  init.timebase = ADC_TimebaseCalc(0);
  init.prescale = ADC_PrescaleCalc(400000,0);
  ADC_Init(ADC0, &init);

  /* Setup interrupt generation on completed conversion. */
  ADC_IntEnable(ADC0, ADC_IF_SINGLE);
  NVIC_EnableIRQ(ADC0_IRQn);
}
Ejemplo n.º 8
0
void setupADC( void ) 
{
	ADC_Init_TypeDef adcInit = ADC_INIT_DEFAULT;
	adcInit.timebase = ADC_TimebaseCalc(0);
	adcInit.prescale = ADC_PrescaleCalc(4000000, 0);
  adcInit.warmUpMode = adcWarmupKeepADCWarm;
	adcInit.tailgate = true;
	ADC_Init(ADC0, &adcInit);

	ADC_InitScan_TypeDef adcInitScan = ADC_INITSCAN_DEFAULT;
	adcInitScan.prsSel    = adcPRSSELCh0;
	adcInitScan.prsEnable = true;
	adcInitScan.reference = adcRefVDD;
	adcInitScan.input     = ADC_SCANCTRL_INPUTMASK_CH6 | ADC_SCANCTRL_INPUTMASK_CH7;
	ADC_InitScan(ADC0, &adcInitScan);
}
Ejemplo n.º 9
0
/***************************************************************************//**
 * @brief
 *   Configure ADC usage for this application.
 *******************************************************************************/
static void accelADCConfig(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(4000000, 0);
  ADC_Init(ADC0, &init);

  /* Init for scan sequence use (accelerometer X, Y and Z axis). */
  scanInit.reference = adcRefVDD;
  scanInit.input = ADC_SCANCTRL_INPUTMASK_CH2 |
                   ADC_SCANCTRL_INPUTMASK_CH3 |
                   ADC_SCANCTRL_INPUTMASK_CH4;
  ADC_InitScan(ADC0, &scanInit);
}
Ejemplo n.º 10
0
/**************************************************************************//**
 * @brief Initialize ADC for temperature sensor readings in single poin
 *****************************************************************************/
void setupSensor(void)
{
  /* Base the ADC configuration on the default setup. */
  ADC_Init_TypeDef init = ADC_INIT_DEFAULT;
  ADC_InitSingle_TypeDef sInit = ADC_INITSINGLE_DEFAULT;

  /* Initialize timebases */
  init.timebase = ADC_TimebaseCalc(0);
  init.prescale = ADC_PrescaleCalc(400000,0);
  ADC_Init(ADC0, &init);

  /* Set input to temperature sensor. Reference must be 1.25V */
  sInit.reference = adcRef1V25;
  sInit.input = adcSingleInpTemp;
  ADC_InitSingle(ADC0, &sInit);

  /* Setup interrupt generation on completed conversion. */
  ADC_IntEnable(ADC0, ADC_IF_SINGLE);
  NVIC_EnableIRQ(ADC0_IRQn);
}
Ejemplo n.º 11
0
/**************************************************************************//**
 * @brief Configure TIMER to trigger ADC through PRS at a set sample rate
 *****************************************************************************/
void setupAdc(void)
{
  ADC_Init_TypeDef        adcInit       = ADC_INIT_DEFAULT;
  ADC_InitSingle_TypeDef  adcInitSingle = ADC_INITSINGLE_DEFAULT;
  
  /* Configure ADC single mode to sample Ref/2 */
  adcInit.prescale = ADC_PrescaleCalc(7000000, 0); /* Set highest allowed prescaler */
  ADC_Init(ADC0, &adcInit);
  
  adcInitSingle.input     =  adcSingleInpVrefDiv2;  /* Reference */
  adcInitSingle.prsEnable = true;                  
  adcInitSingle.prsSel    = adcPRSSELCh0;           /* Triggered by PRS CH0 */
  ADC_InitSingle(ADC0, &adcInitSingle);
  
  /* Connect PRS channel 0 to TIMER overflow */
  PRS_SourceSignalSet(0, PRS_CH_CTRL_SOURCESEL_TIMER0, PRS_CH_CTRL_SIGSEL_TIMER0OF, prsEdgeOff);
  
  /* Configure TIMER to trigger 100 kHz sampling rate */
  TIMER_TopSet(TIMER0,  CMU_ClockFreqGet(cmuClock_TIMER0)/ADCSAMPLESPERSEC);
  TIMER_Enable(TIMER0, true);
}
Ejemplo n.º 12
0
//================================================================================
// ADC0_enter_DefaultMode_from_RESET
//================================================================================
extern void ADC0_enter_DefaultMode_from_RESET(void) {

	// $[ADC0_Init]
	ADC_Init_TypeDef ADC0_init = ADC_INIT_DEFAULT;

	ADC0_init.ovsRateSel = adcOvsRateSel2;
	ADC0_init.warmUpMode = adcWarmupNormal;
	ADC0_init.timebase = ADC_TimebaseCalc(0);
	ADC0_init.prescale = ADC_PrescaleCalc(7000000, 0);
	ADC0_init.tailgate = 0;
	ADC0_init.em2ClockConfig = adcEm2Disabled;

	ADC_Init(ADC0, &ADC0_init);
	// [ADC0_Init]$

	// $[ADC0_InputConfiguration]
	ADC_InitSingle_TypeDef ADC0_init_single = ADC_INITSINGLE_DEFAULT;

	/* PRS settings */
	ADC0_init_single.prsEnable = 0;
	ADC0_init_single.prsSel = adcPRSSELCh0;
	/* Input(s) */
	ADC0_init_single.diff = 0;
	ADC0_init_single.posSel = adcPosSelAPORT1XCH10;
	ADC0_init_single.negSel = adcNegSelVSS;
	ADC0_init_single.reference = adcRef2V5;
	/* Generic conversion settings */
	ADC0_init_single.acqTime = adcAcqTime1;
	ADC0_init_single.resolution = adcRes12Bit;
	ADC0_init_single.leftAdjust = 0;
	ADC0_init_single.rep = 0;
	ADC0_init_single.singleDmaEm2Wu = 0;
	ADC0_init_single.fifoOverwrite = 0;

	ADC_InitSingle(ADC0, &ADC0_init_single);
	// [ADC0_InputConfiguration]$

}
Ejemplo n.º 13
0
/***************************************************************************//**
 * @brief
 *   Configure ADC usage for this application.
 *******************************************************************************/
void initAdc(void)
{
  ADC_Init_TypeDef init = ADC_INIT_DEFAULT;
  ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT;
  
  /* Init common issues for both single and scan mode */
  /* TIMERBASE should be set >= 1us for ADC warmup */
  /* When HFPERCLK is running at 48MHz, the maximum TIMERBASE */
  /* is (0x1f + 1) x 1/48M = 6.67us, less (1 - 0.67) = 0.33us if VDD as ref */
  /* If using internal ref, 6 x 0.67us = 4us, less (6 - 4) = 2us */
  /* Use acquisition time in channel configuration to compensate TIMEBASE */ 
  init.ovsRateSel = adcOvsRateSel16; 
  init.prescale = ADC_PrescaleCalc(ADC_CLOCK, 0);
  ADC_Init(ADC0, &init);

  /* Init for single conversion use, enable PRS channel for ADC */
  /* Default reference voltage is 1.25V */
  /* Internal ref, compensate 2us = 24 ADC clock + 1 = 25 minimum */
  singleInit.acqTime = adcAcqTime32;
#if ADC_REF_SELECT == 1
  /* Set reference voltage to 2.5V */
  singleInit.reference = adcRef2V5;
#elif ADC_REF_SELECT == 2
  /* Set reference voltage to VDD */
  singleInit.reference = adcRefVDD;
  /* VDD ref, compensate 0.33us = 4 ADC clock + 1 = 5 minimum */
  singleInit.acqTime = adcAcqTime8;
#endif
  singleInit.prsSel = ADC_PRS_SEL;
  singleInit.leftAdjust = true;
  singleInit.input = ADC_CHANNEL;
#if ADC_OVS_16 == 1
  /* Use oversampling to 16 bit resolution */
  singleInit.resolution = adcResOVS;
#endif
  
  ADC_InitSingle(ADC0, &singleInit);
}
Ejemplo n.º 14
0
/***************************************************************************//**
 * @brief
 *	Initialize touch panel driver
 *
 * @param config
 *	Driver configuration data.
 ******************************************************************************/
void TOUCH_Init(TOUCH_Config_TypeDef *config)
{
  ADC_Init_TypeDef init = ADC_INIT_DEFAULT;
#ifndef TOUCH_WITHOUT_STORE
  touch_LoadCalibration();
#endif
  CMU_ClockEnable(cmuClock_ADC0, true);
  ADC_IntDisable(ADC0, _ADC_IF_MASK);
  init.prescale     = ADC_PrescaleCalc(config->frequency, 0);
  touch_ignore_move = config->ignore;
  init.ovsRateSel   = config->oversampling;
  ADC_Init(ADC0, &init);
  BSP_PeripheralAccess(BSP_TOUCH, true);
  sInit.input      = ADC_Y;
  sInit.reference  = adcRefVDD;
  sInit.resolution = adcResOVS;
  ADC_InitSingle(ADC0, &sInit);
  ADC_IntClear(ADC0, _ADC_IF_MASK);
  touch_state = TOUCH_INIT;
  NVIC_ClearPendingIRQ(ADC0_IRQn);
  NVIC_EnableIRQ(ADC0_IRQn);
  ADC_IntEnable(ADC0, ADC_IF_SINGLE);
  ADC_Start(ADC0, adcStartSingle);
}
Ejemplo n.º 15
0
/**************************************************************************//**
 * @brief Configure ADC for single conversions
 *****************************************************************************/
static void ADCConfig(void)
{
  ADC_Init_TypeDef       init       = ADC_INIT_DEFAULT;
  ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT;

  /* Init common settings for both single conversion and scan mode */
  init.timebase = ADC_TimebaseCalc(0);

  /* Might as well finish conversion as quickly as possibly since polling */
  /* for completion. Set ADC clock to 7 MHz, use default HFPERCLK */
  init.prescale = ADC_PrescaleCalc(7000000, 0);

  /* WARMUPMODE must be set to Normal according to ref manual before
   * entering EM2. In this example, the warmup time is not a big problem
   * due to relatively infrequent polling. Leave at default NORMAL, */
  ADC_Init(ADC0, &init);

  /* Init for single conversion use, measure DAC output with 1.25 reference. */
  singleInit.reference = adcRef1V25;

#ifdef EXTERNAL
  /* ADC channel 3 as ADC input */
  singleInit.input = adcSingleInpCh3;
#else
  /* DAC otput channel 0 as ADC input */
  singleInit.input = adcSingleInpDACOut0;
#endif

  singleInit.resolution = adcRes12Bit;

  /* The datasheet specifies a minimum aquisition time when sampling vdd/3 */
  /* 32 cycles should be safe for all ADC clock frequencies */
  singleInit.acqTime = adcAcqTime32;

  ADC_InitSingle(ADC0, &singleInit);
}
void adc_init(ADC_Reference reference, ADC_Input input, uint32_t adc_frequency)
{
	// Initialises clocks
	CMU_ClockEnable(cmuClock_HFPER, true);
	CMU_ClockEnable(cmuClock_ADC0, true);

	/* Base the ADC configuration on the default setup. */
	ADC_Init_TypeDef init = ADC_INIT_DEFAULT;
	ADC_InitSingle_TypeDef sInit = ADC_INITSINGLE_DEFAULT;

	/* Initialize timebases */
	init.timebase = ADC_TimebaseCalc(0);
	init.prescale = ADC_PrescaleCalc(adc_frequency,0);
	ADC_Init(ADC0, &init);

	switch (reference)
	{
	/** Internal 1.25V reference. */
	case adcReference1V25:
		sInit.reference = adcRef1V25;
		break;

	/** Internal 2.5V reference. */
	case adcReference2V5:
		sInit.reference = adcRef2V5;
		break;

	/** Buffered VDD. */
	case adcReferenceVDD:
		sInit.reference = adcRefVDD;
		break;

	/** Internal differential 5V reference. */
	case adcReference5VDIFF:
		sInit.reference = adcRef5VDIFF;
		break;

	/** Single ended ext. ref. from 1 pin. */
	case adcReferenceExtSingle:
		sInit.reference = adcRefExtSingle;
		break;

	/** Differential ext. ref. from 2 pins */
	case adcReference2xExtDiff:
		sInit.reference = adcRef2xExtDiff;
		break;

	/** Unbuffered 2xVDD. */
	case adcReference2xVDD:
		sInit.reference = adcRef2xVDD;
		break;
	}

	switch (input)
		{
			/** Temperature reference. */
		case adcInputSingleTemp:
			sInit.input = adcSingleInpTemp;
			break;
		/** VDD / 3. */
		case adcInputSingleVDDDiv3:
			sInit.input = adcSingleInpVDDDiv3;
			break;
			/** Positive Ch4, negative Ch5. */
		case adcInputSingleCh4Ch5:
			sInit.input = adcSingleInpCh4Ch5;
			sInit.diff = true;
			break;
		}

	ADC_InitSingle(ADC0, &sInit);

	/* Setup interrupt generation on completed conversion. */
	ADC_IntEnable(ADC0, ADC_IF_SINGLE);
}
Ejemplo n.º 17
0
/**************************************************************************//**
 * @brief  Main function
 *****************************************************************************/
int main(void)
{
  ADC_Init_TypeDef init = ADC_INIT_DEFAULT;
  ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT;
  uint32_t sample;
  uint32_t vpot;
  uint32_t rpot;
  SYSTEM_ChipRevision_TypeDef chipRev;
  int errataShift = 0;

  /* Chip revision alignment and errata fixes */
  CHIP_Init();

  /* ADC errata for rev B when using VDD as reference, need to multiply */
  /* result by 2 */
  SYSTEM_ChipRevisionGet(&chipRev);
  if ((chipRev.major == 1) && (chipRev.minor == 1))
  {
    errataShift = 1;
  }

  /* Initialize DVK board register access */
  BSP_Init(BSP_INIT_DEFAULT);

  /* If first word of user data page is non-zero, enable eA Profiler trace */
  BSP_TraceProfilerSetup();

  /* Connect potentiometer to EFM32 (and ensure ambient light sensor */
  /* sharing same ADC channel is not enabled). */
  BSP_PeripheralAccess(BSP_AMBIENT, false);
  BSP_PeripheralAccess(BSP_POTMETER, true);

  /* Enable clocks required */
  CMU_ClockEnable(cmuClock_HFPER, true);
  CMU_ClockEnable(cmuClock_ADC0, true);

  /* Init common issues for both single conversion and scan mode */
  init.timebase = ADC_TimebaseCalc(0);
  /* Might as well finish conversion as quickly as possibly since polling */
  /* for completion. */
  init.prescale = ADC_PrescaleCalc(7000000, 0);
  /* WARMUPMODE must be set to Normal according to ref manual before */
  /* entering EM2. In this example, the warmup time is not a big problem */
  /* due to relatively infrequent polling. Leave at default NORMAL, */
  ADC_Init(ADC0, &init);

  /* Init for single conversion use. */
  singleInit.reference = adcRefVDD;
  singleInit.input = adcSingleInpCh5; /* According to DVK HW design */
  singleInit.resolution = adcRes8Bit; /* Use at least 8 bit since unlinear voltage */
  ADC_InitSingle(ADC0, &singleInit);

  /* Ensure internal reference settled */
  RTCDRV_Trigger(1, NULL);
  EMU_EnterEM2(true);

  /* Main loop - just check potentiometer and update LEDs */
  while (1)
  {
    ADC_IntClear(ADC0, ADC_IF_SINGLE);
    ADC_Start(ADC0, adcStartSingle);

    /* Wait for completion */
    while (!(ADC_IntGet(ADC0) & ADC_IF_SINGLE));
    sample = ADC_DataSingleGet(ADC0) << errataShift;

    /*
      DVK potentiometer design:

               | Vdd = 3.3V
              +-+
              | | Rpullup = 10kOhm
              +-+
               |
               +------> Vpot (to ADC)
               |
              +-+
              | | Rpot = 0-100kOhm
              +-+
               | Gnd

       Vpot = Rpot * Vdd / (Rpullup + Rpot)

       This gives a non-linear voltage level measured by ADC with respect to
       pot meter position. In order to determine the actual Rpot setting, which
       is linear with respect to position, rewrite the above formula to:

       Rpot = Rpullup * Vpot / (Vdd - Vpot)
    */

    /* Vpot sampled with 8 bit, divide by max value */
    vpot = (POTENTIOMETER_VDD_mV * sample) / 0xff;

    /* Calculate Rpot determining volume */
    rpot = (POTENTIOMETER_PULLUP_OHM * vpot) / (POTENTIOMETER_VDD_mV - vpot);
    /* The potentiometer may not be exact in upper range, make sure we don't use a higher */
    /* value than assumed by defines. */
    if (rpot > POTENTIOMETER_MAX_OHM)
    {
      rpot = POTENTIOMETER_MAX_OHM;
    }

    /* We have 16 LEDs, add half interval for improving rounding effects. */
    rpot += (POTENTIOMETER_MAX_OHM / (16 * 2));

    BSP_LedsSet((uint16_t)((1 << ((16 * rpot) / POTENTIOMETER_MAX_OHM)) - 1));

    /* Wait some time before polling again */
    RTCDRV_Trigger(100, NULL);
    EMU_EnterEM2(true);
  }
}
Ejemplo n.º 18
0
/***************************************************************************//**
 * @brief
 *   Configure ADC usage for this application.
 *******************************************************************************/
static void preampADCConfig(void)
{
  DMA_CfgDescr_TypeDef descrCfg;
  DMA_CfgChannel_TypeDef chnlCfg;
  ADC_Init_TypeDef init = ADC_INIT_DEFAULT;
  ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT;
  ADC_InitScan_TypeDef scanInit = ADC_INITSCAN_DEFAULT;

  /* Configure DMA usage by ADC */

  cbInData.cbFunc = preampDMAInCb;
  cbInData.userPtr = NULL;

  chnlCfg.highPri = true;
  chnlCfg.enableInt = true;
  chnlCfg.select = DMAREQ_ADC0_SCAN;
  chnlCfg.cb = &cbInData;
  DMA_CfgChannel(PREAMP_DMA_AUDIO_IN, &chnlCfg);

  descrCfg.dstInc = dmaDataInc2;
  descrCfg.srcInc = dmaDataIncNone;
  descrCfg.size = dmaDataSize2;
  descrCfg.arbRate = dmaArbitrate1;
  descrCfg.hprot = 0;
  DMA_CfgDescr(PREAMP_DMA_AUDIO_IN, true, &descrCfg);
  DMA_CfgDescr(PREAMP_DMA_AUDIO_IN, false, &descrCfg);

  DMA_ActivatePingPong(PREAMP_DMA_AUDIO_IN,
                       false,
                       preampAudioInBuffer1,
                       (void *)((uint32_t)&(ADC0->SCANDATA)),
                       (PREAMP_AUDIO_BUFFER_SIZE * 2) - 1,
                       preampAudioInBuffer2,
                       (void *)((uint32_t)&(ADC0->SCANDATA)),
                       (PREAMP_AUDIO_BUFFER_SIZE * 2) - 1);

  /* Indicate starting with primary in-buffer (according to above DMA setup) */
  preampProcessPrimary = true;

  /* Configure ADC */

  /* Keep warm due to "high" frequency sampling */
  init.warmUpMode = adcWarmupKeepADCWarm;
  /* Init common issues for both single conversion and scan mode */
  init.timebase = ADC_TimebaseCalc(0);
  init.prescale = ADC_PrescaleCalc(4000000, 0);
  /* Sample potentiometer by tailgating in order to not disturb fixed rate */
  /* audio sampling. */
  init.tailgate = true;
  ADC_Init(ADC0, &init);

  /* Init for single conversion use (potentiometer). */
  singleInit.reference = adcRefVDD;
  singleInit.input = adcSingleInpCh5; /* According to DVK HW design */
  singleInit.resolution = adcRes8Bit; /* Use at least 8 bit since unlinear voltage */
  ADC_InitSingle(ADC0, &singleInit);

  /* Init for scan sequence use (audio in right/left channels). */
  scanInit.prsSel = adcPRSSELCh0;
  scanInit.prsEnable = true;
  scanInit.reference = adcRefVDD;
  scanInit.input = ADC_SCANCTRL_INPUTMASK_CH0 | ADC_SCANCTRL_INPUTMASK_CH1;
  ADC_InitScan(ADC0, &scanInit);
}
/***************************************************************************//**
 * @brief
 *   Calibrate offset and gain for the specified reference.
 *   Supports currently only single ended gain calibration.
 *   Could easily be expanded to support differential gain calibration.
 *
 * @details
 *   The offset calibration routine measures 0 V with the ADC, and adjust
 *   the calibration register until the converted value equals 0.
 *   The gain calibration routine needs an external reference voltage equal
 *   to the top value for the selected reference. For example if the 2.5 V
 *   reference is to be calibrated, the external supply must also equal 2.5V.
 *
 * @param[in] adc
 *   Pointer to ADC peripheral register block.
 *
 * @param[in] ref
 *   Reference used during calibration. Can be both external and internal
 *   references.
 *
 * @return
 *   The final value of the calibration register, note that the calibration
 *   register gets updated with this value during the calibration.
 *   No need to load the calibration values after the function returns.
 ******************************************************************************/
uint32_t ADC_Calibration(ADC_TypeDef *adc, ADC_Ref_TypeDef ref)
{
  int32_t  sample;
  uint32_t cal;

  /* Binary search variables */
  uint8_t high;
  uint8_t mid;
  uint8_t low;

  /* Reset ADC to be sure we have default settings and wait for ongoing */
  /* conversions to be complete. */
  ADC_Reset(adc);

  ADC_Init_TypeDef       init       = ADC_INIT_DEFAULT;
  ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT;

  /* Init common settings for both single conversion and scan mode */
  init.timebase = ADC_TimebaseCalc(0);
  /* Might as well finish conversion as quickly as possibly since polling */
  /* for completion. */
  /* Set ADC clock to 7 MHz, use default HFPERCLK */
  init.prescale = ADC_PrescaleCalc(7000000, 0);

  /* Set an oversampling rate for more accuracy */
  init.ovsRateSel = adcOvsRateSel4096;
  /* Leave other settings at default values */
  ADC_Init(adc, &init);

  /* Init for single conversion use, measure diff 0 with selected reference. */
  singleInit.reference = ref;
  singleInit.input     = adcSingleInpDiff0;
  singleInit.acqTime   = adcAcqTime16;
  singleInit.diff      = true;
  /* Enable oversampling rate */
  singleInit.resolution = adcResOVS;

  ADC_InitSingle(adc, &singleInit);

  /* ADC is now set up for offset calibration */
  /* Offset calibration register is a 7 bit signed 2's complement value. */
  /* Use unsigned indexes for binary search, and convert when calibration */
  /* register is written to. */
  high = 128;
  low  = 0;

  /* Do binary search for offset calibration*/
  while (low < high)
  {
    /* Calculate midpoint */
    mid = low + (high - low) / 2;

    /* Midpoint is converted to 2's complement and written to both scan and */
    /* single calibration registers */
    cal      = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SCANOFFSET_MASK);
    cal     |= (mid - 63) << _ADC_CAL_SINGLEOFFSET_SHIFT;
    cal     |= (mid - 63) << _ADC_CAL_SCANOFFSET_SHIFT;
    adc->CAL = cal;

    /* Do a conversion */
    ADC_Start(adc, adcStartSingle);

    /* Wait while conversion is active */
    while (adc->STATUS & ADC_STATUS_SINGLEACT) ;

    /* Get ADC result */
    sample = ADC_DataSingleGet(adc);

    /* Check result and decide in which part of to repeat search */
    /* Calibration register has negative effect on result */
    if (sample < 0)
    {
      /* Repeat search in bottom half. */
      high = mid;
    }
    else if (sample > 0)
    {
      /* Repeat search in top half. */
      low = mid + 1;
    }
    else
    {
      /* Found it, exit while loop */
      break;
    }
  }

  /* Now do gain calibration, only input and diff settings needs to be changed */
  adc->SINGLECTRL &= ~(_ADC_SINGLECTRL_INPUTSEL_MASK | _ADC_SINGLECTRL_DIFF_MASK);
  adc->SINGLECTRL |= (adcSingleInpCh4 << _ADC_SINGLECTRL_INPUTSEL_SHIFT);
  adc->SINGLECTRL |= (false << _ADC_SINGLECTRL_DIFF_SHIFT);

  /* ADC is now set up for gain calibration */
  /* Gain calibration register is a 7 bit unsigned value. */

  high = 128;
  low  = 0;

  /* Do binary search for gain calibration */
  while (low < high)
  {
    /* Calculate midpoint and write to calibration register */
    mid = low + (high - low) / 2;

    /* Midpoint is converted to 2's complement */
    cal      = adc->CAL & ~(_ADC_CAL_SINGLEGAIN_MASK | _ADC_CAL_SCANGAIN_MASK);
    cal     |= mid << _ADC_CAL_SINGLEGAIN_SHIFT;
    cal     |= mid << _ADC_CAL_SCANGAIN_SHIFT;
    adc->CAL = cal;

    /* Do a conversion */
    ADC_Start(adc, adcStartSingle);

    /* Wait while conversion is active */
    while (adc->STATUS & ADC_STATUS_SINGLEACT) ;

    /* Get ADC result */
    sample = ADC_DataSingleGet(adc);

    /* Check result and decide in which part to repeat search */
    /* Compare with a value atleast one LSB's less than top to avoid overshooting */
    /* Since oversampling is used, the result is 16 bits, but a couple of lsb's */
    /* applies to the 12 bit result value, if 0xffe is the top value in 12 bit, this */
    /* is in turn 0xffe0 in the 16 bit result. */
    /* Calibration register has positive effect on result */
    if (sample > 0xffd0)
    {
      /* Repeat search in bottom half. */
      high = mid;
    }
    else if (sample < 0xffd0)
    {
      /* Repeat search in top half. */
      low = mid + 1;
    }
    else
    {
      /* Found it, exit while loop */
      break;
    }
  }

  return adc->CAL;
}