//Mostly from: http://www.pezzino.ch/stm32-adc-voltage-monitor/ //Also: http://www.micromouseonline.com/2009/05/26/simple-adc-use-on-the-stm32/ #include "adc.h" #include #include #include #include #include static int calibration_value; extern RCC_ClocksTypeDef RCC_Clocks; void InitADC() { ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; /* Configure the ADC clock */ RCC_ADCCLKConfig( RCC_ADC34PLLCLK_Div2 ); /* Enable ADC1 clock */ RCC_AHBPeriphClockCmd( RCC_AHBPeriph_ADC34, ENABLE ); /* ADC Channel configuration */ /* GPIOC Periph clock enable */ RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOB, ENABLE ); /* Configure ADC Channel7 as analog input */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init( GPIOB, &GPIO_InitStructure ); ADC_StructInit( &ADC_InitStructure ); /* Calibration procedure */ ADC_VoltageRegulatorCmd( ADC4, ENABLE ); /* Insert delay equal to 10 µs */ _delay_us( 10 ); ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_OneShot; ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0; ADC_CommonInit( ADC4, &ADC_CommonInitStructure ); ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable; ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0; ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable; ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable; ADC_InitStructure.ADC_NbrOfRegChannel = 1; ADC_Init( ADC4, &ADC_InitStructure ); /* ADC4 regular channel3 configuration */ ADC_RegularChannelConfig( ADC4, ADC_Channel_3, 1, ADC_SampleTime_181Cycles5 ); /* Enable ADC4 */ ADC_Cmd( ADC4, ENABLE ); /* wait for ADRDY */ while( !ADC_GetFlagStatus( ADC4, ADC_FLAG_RDY ) ); NVIC_InitTypeDef NVIC_InitStructure; /* Enable the TIM2 gloabal Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init (&NVIC_InitStructure); /* TIM2 clock enable */ RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM2, ENABLE); /* Time base configuration */ RCC->CFGR |= 0X1400; TIM_TimeBaseStructure.TIM_Period = (RCC_Clocks.HCLK_Frequency/(ADCFS*ADCOVERSAMP)) - 1; TIM_TimeBaseStructure.TIM_Prescaler = 1 - 1; // Operate at clock frequency TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit (TIM2, &TIM_TimeBaseStructure); /* TIM IT enable */ TIM_ITConfig (TIM2, TIM_IT_Update, ENABLE); /* TIM2 enable counter */ TIM_Cmd (TIM2, ENABLE); /* Start ADC4 Software Conversion */ ADC_StartConversion( ADC4 ); } void TIM2_IRQHandler (void) { static uint8_t oversamp = 0; static int32_t average = 0; static int32_t oversampout = 0; if (TIM_GetITStatus (TIM2, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit (TIM2, TIM_IT_Update); int16_t value = ADC_GetConversionValue(ADC4); ADC_StartConversion( ADC4 ); oversampout += value; oversamp++; if( oversamp >= ADCOVERSAMP ) { value = oversampout / ADCOVERSAMP; average = ((average*1023) + (value*1024))/1024; value = value-(average/1024); oversamp = 0; ADCCallback( value ); oversampout = 0; } } }