AT32F437 是雅特力科技推出的高性能 32 位微控制器,采用 ARM®Cortex®-M4 内核,最高主频 288MHz,拥有最高 4032KB 闪存和 512KB SRAM,工作电压 2.6V 至 3.6V,支持 - 40°~105° 工业级温度范围,有多种低功耗模式,外设资源丰富,还具备安全特性。
其 ADC 功能强大,有 3 组高速 ADC 独立引擎,支持最高 5.33Msps 采样速率,分辨率 12/10/8/6 位可选,有多种触发源,具备数据处理、转换中止、电压监测等功能,有多种中断及状态标志,支持 DMA 和 CPU 两种数据获取方式。
对于3 组 ADC 通道,有多种工作模式,其中3组ADC可以同时工作,实现最高5.33Msps*3(16Msps)的高采样速率。下面举例288MHz主频下3路ADC实现12位14.4MHZ采样频率。
1、PLL时钟源配置:在亚特力官网下载AT32F437最新的固件库,一般在32f435_437_clock.c文件中配置时钟相关内容,将主频配置为288Hz。
//8MHz*72/1/2 = 288MHz crm_pll_config(CRM_PLL_SOURCE_HEXT, 72, 1, CRM_PLL_FR_2);
2、GPIO配置:选择GPIOC_0作为模拟信号输入;其中,3路ADC可以使用一个GPIO口作为输入,也可以各使用一个GPIO口作为输入。
void gpio_config(void) { crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE); gpio_init_type gpio_initstructure; gpio_default_para_init(&gpio_initstructure); gpio_initstructure.gpio_mode = GPIO_MODE_ANALOG; gpio_initstructure.gpio_pins = GPIO_PINS_0; gpio_init(GPIOC, &gpio_initstructure); }
3、计时器配置:计时器需要配置为4.8M,这样在3路ADC使用普通位移模式(一主双从)使对同一路输入信号采样时,才能实现最高4.8M*3=14.4M的采样频率。
void tmr1_config(void) { crm_clocks_freq_type crm_clocks_freq_struct = {0}; crm_clocks_freq_get(&crm_clocks_freq_struct); crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE); //288M/10/6=4.8M tmr_base_init(TMR1, 6-1, 10-1); tmr_cnt_dir_set(TMR1, TMR_COUNT_UP); tmr_clock_source_div_set(TMR1, TMR_CLOCK_DIV1); tmr_primary_mode_select(TMR1, TMR_PRIMARY_SEL_OVERFLOW); }
4、dma功能配置:数据传输使用dma从硬件传输至内存
#define ADC_SAMPLE_POINT (1500) __IO uint32_t adc_dma_buffer[ADC_SAMPLE_POINT]; void dma_config(void) { crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE); nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0); dma_reset(DMA1_CHANNEL1); dma_init_type dma_init_struct; dma_default_para_init(&dma_init_struct); dma_init_struct.buffer_size = ADC_SAMPLE_POINT; dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY; dma_init_struct.memory_base_addr = (uint32_t)adc_dma_buffer; dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_WORD; dma_init_struct.memory_inc_enable = TRUE; dma_init_struct.peripheral_base_addr = (uint32_t)&(ADCCOM->codt); dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_WORD; 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); dmamux_enable(DMA1, TRUE); dmamux_init(DMA1MUX_CHANNEL1, DMAMUX_DMAREQ_ID_ADC1); /* enable dma transfer complete interrupt */ dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE); dma_channel_enable(DMA1_CHANNEL1, TRUE); }
dma中断处理:
void DMA1_Channel1_IRQHandler(void) { if(dma_interrupt_flag_get(DMA1_FDT1_FLAG) != RESET) { dma_flag_clear(DMA1_FDT1_FLAG); dma1_trans_complete_flag = 1; } }
5、ADC配置:3路ADC选择普通位移(一主双从)模式
void adc_config(void) { adc_common_config_type adc_common_struct; adc_base_config_type adc_base_struct; crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_ADC2_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_ADC3_PERIPH_CLOCK, TRUE); nvic_irq_enable(ADC1_2_3_IRQn, 0, 0); adc_common_default_para_init(&adc_common_struct); /* config combine mode */ adc_common_struct.combine_mode = ADC_ORDINARY_SHIFT_ONLY_TWOSLAVE_MODE; /* config division,adcclk is division by hclk */ adc_common_struct.div = ADC_HCLK_DIV_2; /* config common dma mode,it's useful for ordinary group in combine mode */ adc_common_struct.common_dma_mode = ADC_COMMON_DMAMODE_2; /* config common dma request repeat */ adc_common_struct.common_dma_request_repeat_state = TRUE; /* config adjacent adc sampling interval,it's useful for ordinary shifting mode */ adc_common_struct.sampling_interval = ADC_SAMPLING_INTERVAL_5CYCLES; //位移5周期 /* config inner temperature sensor and vintrv */ adc_common_struct.tempervintrv_state = FALSE; /* config voltage battery */ adc_common_struct.vbat_state = FALSE; adc_common_config(&adc_common_struct); adc_base_default_para_init(&adc_base_struct); adc_base_struct.sequence_mode = FALSE; adc_base_struct.repeat_mode = FALSE; adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT; adc_base_struct.ordinary_channel_length = 1; adc_base_config(ADC1, &adc_base_struct); adc_resolution_set(ADC1, ADC_RESOLUTION_12B); /* config ordinary channel */ adc_ordinary_channel_set(ADC1, ADC_CHANNEL_4, 1, ADC_SAMPLETIME_2_5); //采样2.5周期 /* config ordinary trigger source and trigger edge */ //adc_ordinary_conversion_trigger_set(ADC1, ADC_ORDINARY_TRIG_TMR1TRGOUT, ADC_ORDINARY_TRIG_EDGE_RISING); adc_ordinary_conversion_trigger_set(ADC1, ADC_ORDINARY_TRIG_TMR1TRGOUT, ADC_ORDINARY_TRIG_EDGE_RISING); /* config dma mode,it's not useful when common dma mode is use */ adc_dma_mode_enable(ADC1, FALSE); /* config dma request repeat,it's not useful when common dma mode is use */ adc_dma_request_repeat_enable(ADC1, FALSE); /* enable adc overflow interrupt */ adc_interrupt_enable(ADC1, ADC_OCCO_INT, TRUE); adc_base_config(ADC2, &adc_base_struct); adc_resolution_set(ADC2, ADC_RESOLUTION_12B); //12位分辨率 adc_ordinary_channel_set(ADC2, ADC_CHANNEL_7, 1, ADC_SAMPLETIME_2_5); // adc_ordinary_conversion_trigger_set(ADC2, ADC_ORDINARY_TRIG_TMR1TRGOUT, ADC_ORDINARY_TRIG_EDGE_NONE); adc_dma_mode_enable(ADC2, FALSE); adc_dma_request_repeat_enable(ADC2, FALSE); adc_interrupt_enable(ADC2, ADC_OCCO_INT, TRUE); adc_base_config(ADC3, &adc_base_struct); adc_resolution_set(ADC3, ADC_RESOLUTION_12B); adc_ordinary_channel_set(ADC3, ADC_CHANNEL_10, 1, ADC_SAMPLETIME_2_5); //adc_ordinary_conversion_trigger_set(ADC3, ADC_ORDINARY_TRIG_TMR1TRGOUT, ADC_ORDINARY_TRIG_EDGE_NONE); adc_dma_mode_enable(ADC3, FALSE); adc_dma_request_repeat_enable(ADC3, FALSE); adc_interrupt_enable(ADC3, ADC_OCCO_INT, TRUE); /* adc enable */ adc_enable(ADC1, TRUE); adc_enable(ADC2, TRUE); adc_enable(ADC3, TRUE); while(adc_flag_get(ADC1, ADC_RDY_FLAG) == RESET); while(adc_flag_get(ADC2, ADC_RDY_FLAG) == RESET); while(adc_flag_get(ADC3, ADC_RDY_FLAG) == RESET); /* adc calibration */ adc_calibration_init(ADC1); while(adc_calibration_init_status_get(ADC1)); adc_calibration_start(ADC1); while(adc_calibration_status_get(ADC1)); adc_calibration_init(ADC2); while(adc_calibration_init_status_get(ADC2)); adc_calibration_start(ADC2); while(adc_calibration_status_get(ADC2)); adc_calibration_init(ADC3); while(adc_calibration_init_status_get(ADC3)); adc_calibration_start(ADC3); while(adc_calibration_status_get(ADC3)); /*set resolution to 8bit.this because calibration must perform at 12 bit resolution */ adc_resolution_set(ADC1,ADC_RESOLUTION_12B); adc_resolution_set(ADC2,ADC_RESOLUTION_12B); adc_resolution_set(ADC3,ADC_RESOLUTION_12B); while(adc_flag_get(ADC1, ADC_RDY_FLAG) == RESET); while(adc_flag_get(ADC2, ADC_RDY_FLAG) == RESET); while(adc_flag_get(ADC3, ADC_RDY_FLAG) == RESET); }
ADC中断处理:
void ADC1_2_3_IRQHandler(void) { if(adc_interrupt_flag_get(ADC1, ADC_OCCO_FLAG) != RESET) { adc_flag_clear(ADC1, ADC_OCCO_FLAG); adc1_overflow_flag++; } if(adc_interrupt_flag_get(ADC2, ADC_OCCO_FLAG) != RESET) { adc_flag_clear(ADC2, ADC_OCCO_FLAG); adc2_overflow_flag++; } if(adc_interrupt_flag_get(ADC3, ADC_OCCO_FLAG) != RESET) { adc_flag_clear(ADC3, ADC_OCCO_FLAG); adc3_overflow_flag++; } }
6、具体使用:将上述配置初始化在main函数中调用初始化,然后根据中断标志使用printf输出相关关结果或进行其他处理
int main(void) { __IO uint32_t index = 0; nvic_priority_group_config(NVIC_PRIORITY_GROUP_4); /* config the system clock */ system_clock_config(); /* init at start board */ delay_init(); uart_print_init(115200); gpio_config(); tmr1_config(); dma_config(); adc_config(); tmr_counter_enable(TMR1, TRUE); while(dma1_trans_complete_flag == 0); tmr_counter_enable(TMR1, FALSE); if((adc1_overflow_flag != 0) || (adc2_overflow_flag != 0) || (adc3_overflow_flag != 0)) { /* printf flag when error occur */ printf("error occur\r\n"); printf("adc1_overflow_flag = %d\r\n",adc1_overflow_flag); printf("adc2_overflow_flag = %d\r\n",adc2_overflow_flag); printf("adc3_overflow_flag = %d\r\n",adc3_overflow_flag); } else { for(index = 0; index < 1500; index++) { printf("0x%x\r\n",index, adc_dma_buffer[index]); } } while(1) { } }
7、重复采样:
if (dma1_trans_complete_flag != 0) { dma1_trans_complete_flag = 0; adc1_overflow_flag = 0; adc2_overflow_flag = 0; adc3_overflow_flag = 0; dma_channel_enable(DMA1_CHANNEL1, FALSE); dma_data_number_set(DMA1_CHANNEL1, ADC_SAMPLE_POINT); dma_channel_enable(DMA1_CHANNEL1, TRUE); } tmr_counter_enable(TMR1, TRUE); while(dma1_trans_complete_flag == 0); tmr_counter_enable(TMR1, FALSE);