[AT-START-F425 Review] ADC voltage measurement
[Copy link]
ADC
resolution 12 bits, sampling rate up to 2MSPS, up to 18 channels, 0~15 are external input
Conversion time: 0.5 μs at maximum clock speed of 28 MHz
ADC input range: VSSA ≤ VIN ≤ VDDA
Conversion priority: The priority of the preempted channel is higher than that of the ordinary channel. Even if the ordinary channel is being converted, it will be preempted. After the conversion of the preempted channel is completed, it will be converted again (is it because they are worried that the conversion time of the ordinary channel is too long, which will delay the effectiveness of the preempted channel?)
Internal reference voltage: typical value 1.2V
Operation process : Calibrate first to eliminate capacitance error, then trigger conversion
Trigger source :
Conversion time :
Use CSPTx of ADC_SPT1 and ADC_SPT2 to configure the sampling period of each channel (ADC_INx)
The time required for one conversion (ADCCLK period) = sampling time + 12.5
CSPTx selects 1.5 cycles, and one conversion requires 1.5+12.5=14 ADCCLK cycles.
Conversion Mode:
Sequence Mode:
Preemptive automatic conversion mode:
Repeat mode:
Split Mode:
Data acquisition:
The conversion data of common channels can be obtained by reading the common data register (ADC_ODT) through the CPU or DMA. When multiple channels are continuously converted, it seems that the data can only be read through DMA?
The preempted channel data can only be obtained by the CPU reading the preempted data register xx (ADC_PDTxADC_PDTx).
ADC channel and pin correspondence
ADC1_IN0 |
PA0 |
|
ADC1_IN8 |
PB0 |
ADC1_IN1 |
PA1 |
ADC1_IN9 |
PB1 |
ADC1_IN2 |
PA2 |
ADC1_IN10 |
PC0 |
ADC1_IN3 |
PA3 |
ADC1_IN11 |
PC1 |
ADC1_IN4 |
PA4 |
ADC1_IN12 |
PC2 |
ADC1_IN5 |
PA5 |
ADC1_IN13 |
PC3 |
ADC1_IN6 |
PA6 |
ADC1_IN14 |
PC4 |
ADC1_IN7 |
PA7 |
ADC1_IN15 |
PC5 |
------------------Dividing line---------------------
The following is the conversion code for 2 common channels, which uses DMA to obtain the conversion data of ADC
__IO uint16_t adc1_ordinary_valuetab[2] = {0};
__IO uint16_t dma_trans_complete_flag = 0;
void DMA1_Channel1_IRQHandler(void)
{
if(dma_flag_get(DMA1_FDT1_FLAG) != RESET)
{
dma_flag_clear(DMA1_FDT1_FLAG);
dma_trans_complete_flag = 1;
}
}
static void dma_config(void)
{
dma_init_type dma_init_struct;
crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0);
dma_reset(DMA1_CHANNEL1);
dma_flexible_config(DMA1, FLEX_CHANNEL1, DMA_FLEXIBLE_ADC1);
dma_default_para_init(&dma_init_struct);
dma_init_struct.buffer_size = 2;
dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_base_addr = (uint32_t)adc1_ordinary_valuetab;
dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
dma_init_struct.memory_inc_enable = TRUE;
dma_init_struct.peripheral_base_addr = (uint32_t)&(ADC1->odt);
dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
dma_init_struct.peripheral_inc_enable = FALSE;
dma_init_struct.priority = DMA_PRIORITY_HIGH;
dma_init_struct.loop_mode_enable = FALSE;
dma_init(DMA1_CHANNEL1, &dma_init_struct);
dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
dma_channel_enable(DMA1_CHANNEL1, TRUE);
}
static void gpio_config(void)
{
gpio_init_type gpio_initstructure;
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
gpio_default_para_init(&gpio_initstructure);
gpio_initstructure.gpio_mode = GPIO_MODE_ANALOG;
gpio_initstructure.gpio_pins = GPIO_PINS_4|GPIO_PINS_5;
gpio_init(GPIOA, &gpio_initstructure);
}
void adc_config_ch(void)
{
adc_base_config_type adc_base_struct;
crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
crm_adc_clock_div_set(CRM_ADC_DIV_6);
gpio_config();
dma_config();
adc_base_default_para_init(&adc_base_struct);
adc_base_struct.sequence_mode = TRUE;
adc_base_struct.repeat_mode = FALSE;
adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
adc_base_struct.ordinary_channel_length = 2;
adc_base_config(ADC1, &adc_base_struct);
adc_ordinary_channel_set(ADC1, ADC_CHANNEL_4, 1, ADC_SAMPLETIME_239_5);
adc_ordinary_channel_set(ADC1, ADC_CHANNEL_5, 2, ADC_SAMPLETIME_239_5);
adc_ordinary_conversion_trigger_set(ADC1, ADC12_ORDINARY_TRIG_SOFTWARE, TRUE);
adc_dma_mode_enable(ADC1, TRUE);
adc_enable(ADC1, TRUE);
adc_calibration_init(ADC1);
while(adc_calibration_init_status_get(ADC1));
adc_calibration_start(ADC1);
while(adc_calibration_status_get(ADC1));
}
void adc_channel_sample_dma()
{
dma_trans_complete_flag = 0;
dma_config();
adc_ordinary_software_trigger_enable(ADC1, TRUE);
while(dma_trans_complete_flag == 0);
}
void get_voltage()
{
float v = 0.0f;
uint16_t adc_val = 0;
adc_channel_sample_dma();
adc_val = adc1_ordinary_valuetab[0];
v = (float)adc_val*3.3f/4095.0f;
LCD_printf_line(6," %.3fV",v);
adc_val = adc1_ordinary_valuetab[1];
v = (float)adc_val*3.3f/4095.0f;
LCD_printf_line(7," %.3fV",v);
}
void adc_test()
{
adc_config_ch();
get_voltage();
}
--------------------------------------------------
at last
When converting multiple channels, the data must be taken out immediately after the conversion of one channel is completed. How can we get the data out through the CPU?
|