/***************************************************************************//** * @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); }
/**************************************************************************//** * @brief ADC0 interrupt handler. Simply clears interrupt flag. *****************************************************************************/ void ADC0_IRQHandler(void) { ADC_IntClear(ADC0, ADC_IF_SINGLE); }
/**************************************************************************//** * @brief ADC0 interrupt handler. Simply clears interrupt flag. *****************************************************************************/ void ADC0_IRQHandler(void) { _u8_conv_complete = 1; ADC_IntClear(ADC0, ADC_IF_SINGLE); }
int main(void) { /** Number of samples/channels taken from accelerometer. */ #define ACCEL_SAMPLES 3 /** X axis sample index. */ #define ACCEL_X 0 /** Y axis sample index. */ #define ACCEL_Y 1 /** Z axis sample index. */ #define ACCEL_Z 2 /* * Tilt levels: Midpoint is theoretically half value of max sampling value * (ie 0x800 for 12 bit sampling). In real world, some sort of calibration * is required if more accurate sensing is required. We just use set some * fixed limit, that should be sufficient for this basic example. */ /** Tilt left limit */ #define TILT_LEFT 0x750 /** Tilt right limit */ #define TILT_RIGHT 0x8b0 SYSTEM_ChipRevision_TypeDef chipRev; uint32_t leds; uint32_t samples[ACCEL_SAMPLES]; int errataShift = 0; int i; /* 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 DK 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 accelerometer to EFM32. */ BSP_PeripheralAccess(BSP_ACCEL, true); /* Enable clocks required */ CMU_ClockEnable(cmuClock_HFPER, true); CMU_ClockEnable(cmuClock_ADC0, true); CMU_ClockEnable(cmuClock_DMA, true); /* Configure ADC and DMA used for scanning accelerometer */ accelADCConfig(); accelDMAConfig(); /* Main loop, keep polling accelerometer */ leds = 0x0180; while (1) { DMA_ActivateBasic(ACCEL_DMA_CHANNEL, true, false, samples, (void *)((uint32_t)&(ADC0->SCANDATA)), ACCEL_SAMPLES - 1); /* Scan all axis', even though this app only use the X axis */ ADC_IntClear(ADC0, ADC_IF_SCAN); ADC_Start(ADC0, adcStartScan); /* Poll for completion, entering EM2 when waiting for next poll */ while (!(ADC_IntGet(ADC0) & ADC_IF_SCAN)) { RTCDRV_Trigger(5, NULL); EMU_EnterEM2(true); } if (errataShift) { for (i = 0; i < ACCEL_SAMPLES; i++) { samples[i] <<= errataShift; } } if (samples[ACCEL_X] < TILT_LEFT) { if (leds < 0xc000) { leds <<= 1; } } else if (samples[ACCEL_X] > TILT_RIGHT) { if (leds > 0x0003) { leds >>= 1; } } else { if (leds > 0x0180)
/***************************************************************************//** * @brief * Interrupt handler is executed with frequency ~28Hz when panel is not pressed * and with frequency ~140Hz when panel is pressed - this will give ~50 readings per second ******************************************************************************/ void ADC0_IRQHandler(void) { switch (touch_state) { case TOUCH_INIT: /* enter this state if touch panel is not pressed */ GPIO_PinModeSet(TOUCH_Y1, gpioModePushPull, 1); GPIO_PinModeSet(TOUCH_Y2, gpioModePushPull, 1); GPIO_PinModeSet(TOUCH_X1, gpioModeInputPullFilter , 0); GPIO_PinModeSet(TOUCH_X2, gpioModeInput, 0); sInit.input = ADC_Y; sInit.reference = adcRefVDD; sInit.resolution = adcResOVS; sInit.acqTime = adcAcqTime128; /* used to slow down */ if(GPIO_PinInGet(TOUCH_X2)) { touch_state = TOUCH_MEASURE_Y; GPIO_PinModeSet(TOUCH_X1, gpioModePushPull, 1); GPIO_PinModeSet(TOUCH_X2, gpioModePushPull, 0); GPIO_PinModeSet(TOUCH_Y1, gpioModeInput, 0); GPIO_PinModeSet(TOUCH_Y2, gpioModeInput, 0); sInit.input = ADC_X; sInit.acqTime = adcAcqTime16; /* pressed, so speed-up */ } ADC_InitSingle(ADC0, &sInit); break; case TOUCH_CHECK_PRESS: /* checks if touch panel is still pressed */ if( GPIO_PinInGet(TOUCH_X2) ) { touch_state = TOUCH_MEASURE_Y; GPIO_PinModeSet(TOUCH_X1, gpioModePushPull, 1); GPIO_PinModeSet(TOUCH_X2, gpioModePushPull, 0); GPIO_PinModeSet(TOUCH_Y1, gpioModeInput, 0); GPIO_PinModeSet(TOUCH_Y2, gpioModeInput, 0); sInit.input = ADC_X; sInit.acqTime = adcAcqTime16; /* pressed, so speed-up */ ADC_InitSingle(ADC0, &sInit); current_pos.pen = newpos.pen; TOUCH_RecalculatePosition(&newpos); if (newpos.pen) { int call_upcall = TOUCH_StateChanged(); if (call_upcall) { current_pos.x = newpos.x; current_pos.y = newpos.y; } current_pos.adcx = newpos.adcx; current_pos.adcy = newpos.adcy; current_pos.pen = 1; if (call_upcall) TOUCH_CallUpcall(); } newpos.pen = 1; } else { touch_state = TOUCH_INIT; newpos.pen = 0; current_pos.pen = 0; TOUCH_CallUpcall(); } break; case TOUCH_MEASURE_Y: /* touch panel pressed, measure Y position */ newpos.adcy = (ADC_DataSingleGet(ADC0) + 31) >> 6; /* reduce ADC resolution to 10-bits */ GPIO_PinModeSet(TOUCH_Y1, gpioModePushPull, 0); /* to avoid overflow in calibration routines */ GPIO_PinModeSet(TOUCH_Y2, gpioModePushPull, 1); GPIO_PinModeSet(TOUCH_X1, gpioModeInput, 0); GPIO_PinModeSet(TOUCH_X2, gpioModeInput, 0); sInit.input = ADC_Y; ADC_InitSingle(ADC0, &sInit); touch_state = TOUCH_MEASURE_X; break; case TOUCH_MEASURE_X: /* touch panel pressed, measure X position */ newpos.adcx = (ADC_DataSingleGet(ADC0) + 31) >> 6; GPIO_PinModeSet(TOUCH_Y1, gpioModePushPull, 1); GPIO_PinModeSet(TOUCH_Y2, gpioModePushPull, 1); GPIO_PinModeSet(TOUCH_X1, gpioModeInputPullFilter , 0); GPIO_PinModeSet(TOUCH_X2, gpioModeInput, 0); sInit.input = ADC_Y; ADC_InitSingle(ADC0, &sInit); touch_state = TOUCH_CHECK_PRESS; break; default: touch_state = TOUCH_INIT; } ADC_IntClear(ADC0, ADC_IF_SINGLE); ADC_Start(ADC0, adcStartSingle); }
void adc_clear_interrupt() { ADC_IntClear(ADC0, ADC_IFC_SINGLEOF); }
/**************************************************************************//** * @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); } }
int main(void) { DMA_Init_TypeDef dmaInit; TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT; SYSTEM_ChipRevision_TypeDef chipRev; uint32_t volSample; uint32_t vpot; uint32_t rpot; uint32_t leds; /* 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)) { preampErrataShift = 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); /* Connect audio in/out to ADC/DAC */ BSP_PeripheralAccess(BSP_AUDIO_IN, true); BSP_PeripheralAccess(BSP_AUDIO_OUT, true); /* Wait a while in order to let signal from audio-in stabilize after */ /* enabling audio-in peripheral. */ RTCDRV_Trigger(1000, NULL); EMU_EnterEM2(true); /* Current example gets by at 14MHz core clock (also with low level of compiler */ /* optimization). That may however change if modified, consider changing to */ /* higher HFRCO band or HFXO. */ /* Use for instance one of below statements to increase core clock. CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); CMU_HFRCOBandSet(cmuHFRCOBand_28MHz); */ /* Enable clocks required */ CMU_ClockEnable(cmuClock_HFPER, true); CMU_ClockEnable(cmuClock_ADC0, true); CMU_ClockEnable(cmuClock_DAC0, true); CMU_ClockEnable(cmuClock_PRS, true); CMU_ClockEnable(cmuClock_DMA, true); CMU_ClockEnable(cmuClock_TIMER0, true); /* Ensure DMA interrupt at higher priority than PendSV. */ /* (PendSV used to process sampled audio). */ NVIC_SetPriority(DMA_IRQn, 0); /* Highest priority */ NVIC_SetPriority(PendSV_IRQn, (1 << __NVIC_PRIO_BITS) - 1); /* Lowest priority */ /* Configure peripheral reflex system used by TIMER to trigger ADC/DAC */ preampPRSConfig(PREAMP_PRS_CHANNEL); /* Configure general DMA issues */ dmaInit.hprot = 0; dmaInit.controlBlock = dmaControlBlock; DMA_Init(&dmaInit); /* Configure DAC used for audio-out */ preampDACConfig(); /* Configure ADC used for audio-in */ preampADCConfig(); /* Trigger sampling according to configured sample rate */ TIMER_TopSet(TIMER0, CMU_ClockFreqGet(cmuClock_HFPER) / PREAMP_AUDIO_SAMPLE_RATE); TIMER_Init(TIMER0, &timerInit); /* Main loop, only responsible for checking volume */ while (1) { /* Triggered to check volume setting? */ if (preampCheckVolume) { preampCheckVolume = false; /* Trigger single conversion, and wait for it to complete */ ADC_IntClear(ADC0, ADC_IF_SINGLE); ADC_Start(ADC0, adcStartSingle); while (!(ADC_IntGet(ADC0), ADC_IF_SINGLE)) { /* Just wait for an interrupt to wake us up (DMA interrupts occur */ /* regularly). Thus, we don't need to enable ADC interrupt. */ EMU_EnterEM1(); } volSample = ADC_DataSingleGet(ADC0) << preampErrataShift; /* 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 * volSample) / 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; } /* Precalculate adjustment factor to avoid repeated calculation when used. */ /* Scale down Rpot a bit to use in integer calculation without overflowing 32 bit reg. */ preampAdjustFactor = rpot / PREAMP_ADJUST_DIVISOR; /* Use 14 right leds for volume control indicating. Leftmost led is used to indicate */ /* clipping of audio out signal (in order to limit volume out). Add half interval */ /* for improving integer rounding effects. */ leds = rpot + (POTENTIOMETER_MAX_OHM / (14 * 2)); leds = (1 << ((14 * leds) / POTENTIOMETER_MAX_OHM)) - 1; /* Audio out clipped? */ if (preampAudioOutClipped) { preampAudioOutClipped = false; leds |= 0x8000; } BSP_LedsSet((uint16_t)leds); } EMU_EnterEM1(); } }
/**************************************************************************//** * @brief ADC0 interrupt handler. Simply clears interrupt flag. *****************************************************************************/ void ADC0_IRQHandler(void) { ADC_IntClear(ADC0, ADC_IF_SINGLE); /* Set temperature flag */ read_temperature = 1; }