使用Platformio平臺的libopencm3開發框架來開發STM32G0,以下為多通道ADC與DMA的使用。
1 新建項目
- 建立adc_dma項目
在PIO的Home頁面新建項目,項目名稱adc_dma,選擇開發板為 MonkeyPi_STM32_G070RB,開發框架選擇libopencm3;
1upload_protocol = cmsis-dap
2debug_tool = cmsis-dap
2 編寫程序
2.1 ADC 設置
這里設置PA0、PA1、PA2、PA3四個引腳為ADC:
1static void adc_setup(void)
2{
3 rcc_periph_clock_enable(RCC_ADC);
4 rcc_periph_clock_enable(RCC_GPIOA);
5
6 gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO0);
7 gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1);
8 gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO2);
9 gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO3);
10
11 adc_power_off(ADC1);
12 adc_set_clk_prescale(ADC1, ADC_CCR_PRESC_DIV2);
13 adc_set_single_conversion_mode(ADC1);
14 adc_set_right_aligned(ADC1);
15 adc_set_sample_time_on_all_channels(ADC1, ADC_SMPTIME_160DOT5);
16
17 uint8_t channel_array[16] = {0};
18 channel_array[0] = 0;
19 channel_array[1] = 1;
20 channel_array[2] = 2;
21 channel_array[3] = 3;
22 adc_set_regular_sequence(ADC1, ADC_CHAN_CNT, channel_array);
23 adc_enable_dma_circular_mode(ADC1);
24 adc_set_resolution(ADC1, ADC_CFGR1_RES_12_BIT);
25 adc_power_on(ADC1);
26
27 /* Wait for ADC starting up. */
28 delay_ms(10);
29}
2.2 DMA配置
1static void dma_setup(void *data, int size)
2{
3 dma_channel_reset(DMA1, DMA_CHANNEL1);
4 dma_set_peripheral_address(DMA1, DMA_CHANNEL1, (uint32_t)&ADC_DR(ADC1));
5 dma_set_memory_address(DMA1, DMA_CHANNEL1, (uint32_t)data);
6 dma_set_number_of_data(DMA1, DMA_CHANNEL1, size);
7 dma_set_read_from_peripheral(DMA1, DMA_CHANNEL1);
8 dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL1);
9 dma_set_peripheral_size(DMA1, DMA_CHANNEL1, DMA_CCR_PSIZE_16BIT);
10 dma_set_memory_size(DMA1, DMA_CHANNEL1, DMA_CCR_MSIZE_16BIT);
11 dma_enable_circular_mode(DMA1, DMA_CHANNEL1);
12 dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL1);
13 dma_enable_channel(DMA1, DMA_CHANNEL1);
14
15 dmamux_reset_dma_channel(DMAMUX1, DMA_CHANNEL1);
16 dmamux_set_dma_channel_request(DMAMUX1, DMA_CHANNEL1, DMAMUX_CxCR_DMAREQ_ID_ADC);
17}
主要是設置DMA的外設地址為ADC數據寄存器 ADC_DR;并設置內存地址為定義的buff,size為需要緩存的數據大小:
1#define ADC_CHAN_CNT 4
2#define ADC_FILETER_SIZE 32
3
4int16_t adc_values[ADC_FILETER_SIZE*ADC_CHAN_CNT];
2.3 ADC配置為DMA讀取和Timer觸發
- 定時器設置
1void tim3_setup(void)
2{
3 /* Enable TIM3 clock. */
4 rcc_periph_clock_enable(RCC_TIM3);
5
6 /* Enable TIM3 interrupt. */
7 nvic_enable_irq(NVIC_TIM3_IRQ);
8
9 /* Reset TIM3 peripheral to defaults. */
10 rcc_periph_reset_pulse(RST_TIM3);
11
12 /* Timer global mode:
13 * - No divider
14 * - Alignment edge
15 * - Direction up
16 * (These are actually default values after reset above, so this call
17 * is strictly unnecessary, but demos the api for alternative settings)
18 */
19 timer_set_mode(TIM3, TIM_CR1_CKD_CK_INT,
20 TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
21
22 /*
23 * Please take note that the clock source for STM32 timers
24 * might not be the raw APB1/APB2 clocks. In various conditions they
25 * are doubled. See the Reference Manual for full details!
26 * In our case, TIM3 on APB1 is running at double frequency, so this
27 * sets the prescaler to have the timer run at 5kHz
28 */
29 timer_set_prescaler(TIM3, 64-1);
30
31 /* Disable preload. */
32 timer_disable_preload(TIM3);
33 timer_continuous_mode(TIM3);
34
35 timer_set_period(TIM3, 20000-1); //100Hz
36
37 timer_set_master_mode(TIM3, TIM_CR2_MMS_UPDATE);
38
39 timer_enable_irq(TIM3, TIM_DIER_UIE);
40}
41
42void tim3_enable_counter(bool en)
43{
44 if(en){
45 timer_enable_counter(TIM3);
46 }else{
47 timer_disable_counter(TIM3);
48 }
49}
50
51void tim3_isr(void)
52{
53 if (timer_get_flag(TIM3, TIM_SR_UIF)) {
54
55 /* Clear compare interrupt flag. */
56 timer_clear_flag(TIM3, TIM_SR_UIF);
57 }
58}
- DMA設置和Timer觸發
1 rcc_periph_clock_enable(RCC_DMA);
2 nvic_set_priority(NVIC_DMA1_CHANNEL1_IRQ, 3);
3 nvic_enable_irq(NVIC_DMA1_CHANNEL1_IRQ);
4
5 adc_setup();
6
7 dma_setup(adc_values, ADC_CHAN_CNT*ADC_FILETER_SIZE);
8
9 adc_enable_overrun_interrupt(ADC1);
10
11 adc_enable_dma(ADC1);
12
13 ADC_CFGR1(ADC1) = (ADC_CFGR1(ADC1) & ~(0x3<<10)) | (0x1<<10); // Hardware trigger detection on the rising edge
14 ADC_CFGR1(ADC1) = (ADC_CFGR1(ADC1) & ~ADC_CFGR1_EXTSEL) | (3<1_EXTSEL_SHIFT); // toggle by tim3
15
16 tim3_setup();
17
18 adc_start_conversion_regular(ADC1);
19
20
21 tim3_enable_counter(true);
22
23 delay_ms(100);
DMA中斷時候即準備好讀取ADC數據,因此在DMA中斷中先把定時器關閉,讀取數據后再次打開:
1void dma1_channel1_isr(void)
2{
3
4 if ((DMA1_ISR &DMA_ISR_TCIF1) != 0) {
5 DMA1_IFCR |= DMA_IFCR_CTCIF1;
6 }
7
8 tim3_enable_counter(false);
9
10}
2.4 ADC讀取
1void adc_sample(void)
2{
3 uint32_t sum_val1 = 0;
4 uint32_t sum_val2 = 0;
5 uint32_t sum_val3 = 0;
6 uint32_t sum_val4 = 0;
7
8 for(int i=0; i9 sum_val1 += adc_values[ADC_CHAN_CNT*i + 0];
10 sum_val2 += adc_values[ADC_CHAN_CNT*i + 1];
11 sum_val3 += adc_values[ADC_CHAN_CNT*i + 2];
12 sum_val4 += adc_values[ADC_CHAN_CNT*i + 3];
13 }
14
15 uint32_t filter_val1 = sum_val1/ADC_FILETER_SIZE;
16 uint32_t filter_val2 = sum_val2/ADC_FILETER_SIZE;
17 uint32_t filter_val3 = sum_val3/ADC_FILETER_SIZE;
18 uint32_t filter_val4 = sum_val4/ADC_FILETER_SIZE;
19
20 printf("adc:%d %d %d %d\\r\\n", filter_val1, filter_val2, filter_val3, filter_val4);
21
22 tim3_enable_counter(true);
23}
讀取時候按照通道的順序從buff中取出,這里做了簡單的過濾;
3 燒寫測試
將程序燒寫到開發板,然后打開串口可以看到四個ADC通道的數據,在PA0/PA1/PA3/PA4四個引腳連接不同電壓可以看到變化:
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
寄存器
+關注
關注
31文章
5325瀏覽量
120052 -
adc
+關注
關注
98文章
6452瀏覽量
544147 -
STM32
+關注
關注
2266文章
10876瀏覽量
354926 -
dma
+關注
關注
3文章
559瀏覽量
100446 -
PIO
+關注
關注
0文章
18瀏覽量
6191
發布評論請先 登錄
相關推薦
STM32G0開發筆記:FreeRTOS和FreeModbus庫使用
使用Platformio平臺的libopencm3開發框架來開發STM32G0,以下為FreeRTOS和FreeModbus庫使用。
STM32G0開發筆記:使用FreeRTOS系統的隊列Queue
使用Platformio平臺的libopencm3開發框架來開發STM32G0,下面為使用FreeRTOS系統的隊列Queue。
STM32G0開發筆記:GPIO接按鍵的使用方式
使用Platformio平臺的libopencm3開發框架來開發STM32G0,下面為GPIO接按鍵的使用方式。
評論