#include "gd32_adc.h" #include "gpio.h" #include "clock.h" #include "libs/shark_types.h" #include "libs/shark_task.h" /* For 12-bits resolution, the total conversion time is *sampling time + 12.5 ADCCLK cycles *all channel is enabled oversample to reach 16bit accurate */ static int volatile adc_work = ADC_WORK_IDLE; //#define DMA_ADC_CH DMA_CH0 #ifdef DMA_ADC_CH #define dma_irq DMA_Channel0_IRQn #define dma_buf_len 66 static uint16_t dma_buf[dma_buf_len]; #endif int gd32_adc_error = 0; void gd32_adc_init(void){ rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_GPIOB); gpio_mode_analog_input(GPIOA, GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7); gpio_mode_analog_input(GPIOB, GPIO_PIN_1|GPIO_PIN_0); /* config ADC clock */ rcu_adc_clock_config(RCU_ADCCK_APB2_DIV6); //adc clock:7M rcu_periph_clock_enable(RCU_ADC); adc_deinit(); /* ADC trigger config */ adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE); /* ADC data alignment config */ adc_data_alignment_config(ADC_DATAALIGN_RIGHT); /* ADC channel length config */ adc_channel_length_config(ADC_REGULAR_CHANNEL, 1); adc_resolution_config(ADC_RESOLUTION_12B); //adc_special_function_config(ADC_SCAN_MODE,ENABLE); adc_discontinuous_mode_config(ADC_REGULAR_CHANNEL, 1); adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE); #ifdef DMA_ADC_CH dma_config(); #endif } void gd32_adc_deinit(void){ adc_deinit(); rcu_periph_clock_disable(RCU_ADC); } #ifdef DMA_ADC_CH void dma_config(void) { /* ADC_DMA_channel configuration */ dma_parameter_struct dma_data_parameter; /* ADC DMA_channel configuration */ dma_deinit(DMA_ADC_CH); /* initialize DMA single data mode */ dma_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA); dma_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE; dma_data_parameter.memory_addr = (uint32_t)dma_buf; dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_DISABLE; dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT; dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT; dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY; dma_data_parameter.number = 1U; dma_data_parameter.priority = DMA_PRIORITY_HIGH; dma_init(DMA_ADC_CH, &dma_data_parameter); dma_circulation_disable(DMA_ADC_CH); dma_interrupt_enable(DMA_ADC_CH, DMA_INT_FTF); nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0); nvic_irq_enable(dma_irq, 4U, 0U); } /* step 1 */ int adc_is_idle(void){ return adc_work == ADC_WORK_IDLE; } int adc_start_sample(int chan, int number){ //hardware oversample to 16bit adc_oversample_mode_config(ADC_OVERSAMPLING_ALL_CONVERT, ADC_OVERSAMPLING_SHIFT_4B, ADC_OVERSAMPLING_RATIO_MUL256); adc_oversample_mode_enable(); /* use max convert time to make sure the adc work fine */ adc_regular_channel_config(0, chan, ADC_SAMPLETIME_55POINT5);//55.5 + 12.5 = 68 cycle, 68/(7*1000000) adc_enable(); delay_us(1000); //MUST delay, for adc work fine adc_calibration_enable(); DMA_CHCNT(DMA_ADC_CH) = (number & DMA_CHANNEL_CNT_MASK); dma_channel_enable(DMA_ADC_CH); /* ADC DMA function enable */ adc_dma_mode_enable(); /* ADC software trigger enable */ adc_software_trigger_enable(ADC_REGULAR_CHANNEL); adc_work = ADC_WORK_ING; } void DMA_Channel0_IRQHandler(void){ adc_disable(); dma_channel_disable(DMA_ADC_CH); dma_interrupt_flag_clear(DMA_ADC_CH, DMA_INT_FLAG_FTF); adc_work = ADC_WORK_SAMPLE_COMPLTE } int adc_is_complete(void){ return adc_work == ADC_WORK_SAMPLE_COMPLTE; } int adc_get_sample(void){ if (adc_work != ADC_WORK_SAMPLE_COMPLTE){ return adc_work; } int value = 0; int count = DMA_CHCNT(DMA_ADC_CH) & DMA_CHANNEL_CNT_MASK; int min = 0xFFFFF; int max = -0xFFFFF; int i; for (i = 0; i < count; i++){ int one = dma_buf[i]; value += one; if (one > max){ max = one; } if (one < min) { min = one; } } adc_work = ADC_WORK_IDLE; return (value - min - max)/(count - 2); } int adc_sample_avg(int chan, int times){ int value = 0; int count = 0; int min = 0xFFFFF; int max = -0xFFFFF; if (adc_work == ADC_WORK_ING){ adc_disable(); dma_channel_disable(DMA_ADC_CH); adc_dma_mode_disable(); dma_interrupt_flag_clear(DMA_ADC_CH, DMA_INT_FLAG_FTF); adc_work = ADC_WORK_INTERTUPED; } //hardware oversample to 16bit adc_oversample_mode_config(ADC_OVERSAMPLING_ALL_CONVERT, ADC_OVERSAMPLING_SHIFT_2B, ADC_OVERSAMPLING_RATIO_MUL64); adc_oversample_mode_enable(); /* use max convert time to make sure the adc work fine */ adc_regular_channel_config(0, chan, ADC_SAMPLETIME_55POINT5);////55.5 + 12.5 = 68 cycle, 68 * 256/(7*1000000) adc_enable(); delay_us(1000); //MUST delay, for adc work fine /* ADC calibration and reset calibration */ adc_calibration_enable(); while(count < times){ adc_software_trigger_enable(ADC_REGULAR_CHANNEL); while(SET != adc_flag_get(ADC_FLAG_EOC)); int one = adc_regular_data_read(); adc_flag_clear(ADC_FLAG_EOC); value += (one & 0xFFFF); count ++; if (one > max){ max = one; } if (one < min) { min = one; } } adc_disable(); return (value - min - max)/(times-2); } #else int adc_sample(int chan, int calibration){ int value = -0xFFFFFF; int mask = 0xFFFF; //hardware oversample to 16bit adc_oversample_mode_config(ADC_OVERSAMPLING_ALL_CONVERT, ADC_OVERSAMPLING_SHIFT_2B, ADC_OVERSAMPLING_RATIO_MUL64); adc_oversample_mode_enable(); /* use max convert time to make sure the adc work fine */ adc_regular_channel_config(0, chan, ADC_SAMPLETIME_55POINT5);//239.5 + 12.5 = 242 cycle, 242/(28*1000000) adc_enable(); delay_us(1000); //MUST delay, for adc work fine if (calibration) { /* ADC calibration and reset calibration */ adc_calibration_enable(); } adc_software_trigger_enable(ADC_REGULAR_CHANNEL); while(SET != adc_flag_get(ADC_FLAG_EOC)); value = adc_regular_data_read(); adc_flag_clear(ADC_FLAG_EOC); adc_disable(); return value & mask; } static int adc_sample_internal(int chan, int times, int *error) { int value = 0; int count = 0; int min = 0xFFFFF; int max = -0xFFFFF; adc_regular_channel_config(0, chan, ADC_SAMPLETIME_55POINT5);////55.5 + 12.5 = 68 cycle, 68 * 256/(7*1000000) adc_enable(); delay_us(1000); //MUST delay, for adc work fine /* ADC calibration and reset calibration */ adc_calibration_enable(); *error = 0; while(count < times){ u64 start_time = shark_get_mseconds(); adc_software_trigger_enable(ADC_REGULAR_CHANNEL); while(SET != adc_flag_get(ADC_FLAG_EOC)){ if (shark_get_mseconds() - start_time >= 10){ *error = -1; break; } }; int one = adc_regular_data_read(); adc_flag_clear(ADC_FLAG_EOC); value += (one & 0xFFF); count ++; if (one > max){ max = one; } if (one < min) { min = one; } } adc_disable(); if (times <= 2) { return value/times; } return (value - min - max)/(times-2); } //times * 0.6ms + 1ms int adc_sample_avg(int chan, int times){ int error = 0; int value = adc_sample_internal(chan, times, &error); if (error < 0) { gd32_adc_error ++; gd32_adc_deinit(); delay_us(5 * 1000); gd32_adc_init(); value = adc_sample_internal(chan, times, &error); } return value; } #endif /* DMA_ADC_CH */