/** ****************************************************************************** * @file VAPC-meter/lib/adc.c * @author "Vladimir N. Shilov" * @version V1 * @date 24-March-2016 * @brief This file contains the ADC functions. ****************************************************************************** * Tim2 регулярно запускат АЦП. * АЦП измеряет два заданных канала и пинает DMA * DMA забирает данные у ADC и складывает их в ADC_Buffer * В прерывании по окончанию транзакции данные из ADC_Buffer * раскладываем по FastBuffers. */ /* Includes ------------------------------------------------------------------*/ #include "adc.h" /** @addtogroup ADC * @{ */ /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ #define VOLTAGE_CHANNEL ADC_Channel_17 #define CURRENT_CHANNEL ADC_Channel_18 #define ADC1_DR_ADDRESS ((uint16_t)0x5344) #define ADC_BUFFER_ADDRESS ((uint16_t)(&ADC_Buffer)) #define ADC_REF 3300 #define ADC_DIV 4095 #define ADC_ODIV 32768 #define ADC_VOLT_K 11 #define ADC_CURR_K 20 // (Частота МК (16 МHz) / Предделитель таймера (8) * Нужное время в секундах (0.0015625)) - 1 #define TIM_PERIOD ((uint16_t)3128) #define TIM_PRESCALER TIM2_Prescaler_8 /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ static __IO uint16_t ADC_Buffer[ADC_BUFFER_SIZE]; static __IO uint16_t VoltageFastBuffer[FAST_BUFFER_SIZE]; static __IO uint16_t CurrentFastBuffer[FAST_BUFFER_SIZE]; /* Private constants ---------------------------------------------------------*/ __near __no_init const unsigned char Factory_VREFINT @ 0x4910; /* Private function prototypes -----------------------------------------------*/ static void ADC_ConfigADC(void); static void ADC_ConfigDMA(void); static void ADC_ConfigTIM2(void); /* Private functions ---------------------------------------------------------*/ /** * @brief Initialize and start ADC * @param None * @retval None */ void ADC_Config(void) { /* ADC configuration */ ADC_ConfigADC(); /* DMA configuration */ ADC_ConfigDMA(); /* TIM2 configuration */ ADC_ConfigTIM2(); } /** * @brief Configure ADC peripheral * @param None * @retval None */ static void ADC_ConfigADC(void) { /* Enable ADC1 clock */ CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE); /* Initialize and configure ADC1 */ ADC_Init(ADC1, ADC_ConversionMode_Single, ADC_Resolution_12Bit, ADC_Prescaler_1); ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_384Cycles); ADC_SamplingTimeConfig(ADC1, ADC_Group_FastChannels, ADC_SamplingTime_384Cycles); /* Enable ADC1 */ ADC_Cmd(ADC1, ENABLE); /* Enable ADC1 Voltage meter channel */ ADC_ChannelCmd(ADC1, VOLTAGE_CHANNEL, ENABLE); ADC_SchmittTriggerConfig(ADC1, VOLTAGE_CHANNEL, DISABLE); /* Enable ADC1 Current meter channel */ ADC_ChannelCmd(ADC1, CURRENT_CHANNEL, ENABLE); ADC_SchmittTriggerConfig(ADC1, CURRENT_CHANNEL, DISABLE); #ifdef ADC_MEASURE_REF_VOLT /* ADC Voltage Reference */ ADC_VrefintCmd(ENABLE); /* Enable ADC1 Vrefint Channel */ ADC_ChannelCmd(ADC1, ADC_Channel_Vrefint, ENABLE); #endif // ADC_MEASURE_REF_VOLT /* Enable ADC1 DMA requests*/ ADC_DMACmd(ADC1, ENABLE); /* Start ADC1 Conversion using TIM1 TRGO*/ ADC_ExternalTrigConfig(ADC1, ADC_ExtEventSelection_Trigger3, ADC_ExtTRGSensitivity_Rising); } /** * @brief Configure DMA peripheral * @param None * @retval None */ static void ADC_ConfigDMA(void) { /* Enable DMA1 clock */ CLK_PeripheralClockConfig(CLK_Peripheral_DMA1, ENABLE); /* Connect ADC to DMA channel 0 */ SYSCFG_REMAPDMAChannelConfig(REMAP_DMA1Channel_ADC1ToChannel0); DMA_Init(DMA1_Channel0, ADC_BUFFER_ADDRESS, ADC1_DR_ADDRESS, ADC_BUFFER_SIZE, DMA_DIR_PeripheralToMemory, DMA_Mode_Circular, DMA_MemoryIncMode_Inc, DMA_Priority_High, DMA_MemoryDataSize_HalfWord); /* DMA Channel0 enable */ DMA_Cmd(DMA1_Channel0, ENABLE); /* Enable DMA1 channel0 Transfer complete interrupt */ DMA_ITConfig(DMA1_Channel0, DMA_ITx_TC, ENABLE); /* DMA enable */ DMA_GlobalCmd(ENABLE); } /** * @brief Configure TIM2 peripheral * @param None * @retval None */ static void ADC_ConfigTIM2(void) { /* Enable TIM2 clock */ CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE); /* Initializes the TIM2 Time Base Unit */ TIM2_TimeBaseInit(TIM_PRESCALER, TIM2_CounterMode_Up, TIM_PERIOD); /* Selects the TIM2 Update Request Interrupt source */ TIM2_UpdateRequestConfig(TIM2_UpdateSource_Regular); /* Master Mode selection: Update event */ TIM2_SelectOutputTrigger(TIM2_TRGOSource_Update); /* Enable TIM2 */ TIM2_Cmd(ENABLE); } /** * @brief DMA1 channel0 and channel1 Interrupt routine. * @param None * @retval None */ INTERRUPT_HANDLER(DMA1_CHANNEL0_1_IRQHandler,2) { static uint8_t idx = 0; VoltageFastBuffer[idx] = ADC_Buffer[0]; CurrentFastBuffer[idx] = ADC_Buffer[1]; idx ++; if(idx >= FAST_BUFFER_SIZE) { idx = 0; } /* Clear IT Pending Bit */ DMA1_Channel0->CSPR &= (uint8_t)~(uint8_t)(DMA1_IT_TC0 & (uint8_t)0x06); } /** * @brief Return average values from fast buffers * @param None * @retval Latest_Voltage */ uint16_t * ADC_GetValues(void) { static uint16_t avgVal[ADC_BUFFER_SIZE]; uint32_t volt=0, curr=0; uint16_t shunt_volt; uint8_t i; /* Summarize buffers values */ for(i=0;i>= 3; volt *= ADC_REF; volt *= ADC_VOLT_K; volt /= ADC_ODIV; #else volt += 32; volt >>= 6; volt *= ADC_REF; volt *= ADC_VOLT_K; volt /= ADC_DIV; #endif // ADC_USE_V_OVERS /* получаем среднее по току, затем фильтруем */ curr += 32; curr >>= 6; #ifdef ADC_USE_C_FILTR uint16_t middle; middle = curr + 8; middle &= 0xFFF0; curr = 0; uint8_t cnt = 0; uint16_t tmp; for(i=1; i 0){ curr /= cnt; } else { curr = middle; } #endif // ADC_USE_C_FILTR curr *= ADC_REF; curr /= ADC_DIV; shunt_volt = curr / ADC_CURR_K; volt -= shunt_volt; avgVal[0] = (uint16_t)volt; avgVal[1] = (uint16_t)curr; return avgVal; } /** * @} */ /************************ (C) Vladimir N. Shilov *****END OF FILE****/