GD32F330 | ADC實例 基於DMA方式

GD32F330 | ADC實例 基於DMA方式


 

  簡單記錄一下 ADC多通道轉換 DMA搬運 的使用,以 GD32F330G8U6 為例:

 

一、ADC 基礎知識

  12位ADC是一種採用逐次逼近方式的模擬數字轉換器。
  轉換模式:
    – 轉換單個通道,或者掃描一序列的通道;
    – 單次模式,每次觸發轉換一次選擇的輸入通道;
    – 連續模式,連續轉換所選擇的輸入通道;
    – 間斷模式;
    – 同步模式(適用於具有兩個或多個ADC的設備)。
 

二、軟件配置過程

  常規通道轉換 DMA 搬運:通過ADC轉換,在ADC 轉換完成後 觸發DMA 進行數據搬運。

1、開啟工作時鐘

// 1. 開啟時鐘
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_ADC);
rcu_periph_clock_enable(RCU_DMA);
rcu_adc_clock_config(RCU_ADCCK_APB2_DIV6);

 

2、GPIO 初始化

  GPIO 用於 AD 轉換功能必須配置為模擬輸入模式

// 2. GPIO配置
gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_3 | GPIO_PIN_4);

   註:ADC 的通道與引腳的對應關係可查閱具體芯片的數據手冊 (Pin definitions 章節):

 

 

 

3、ADC 初始化

  配置 ADC 模式、對齊方式、轉換長度、採樣周期以及觸發方式等等
// 3. ADC配置
adc_deinit();
adc_special_function_config(ADC_SCAN_MODE, ENABLE);                     // 掃描模式
adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE);               // 連續轉換

adc_resolution_config(ADC_RESOLUTION_12B);
adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
adc_channel_length_config(ADC_REGULAR_CHANNEL, 2);
adc_regular_channel_config(0, ADC_CHANNEL_3, ADC_SAMPLETIME_55POINT5);
adc_regular_channel_config(1, ADC_CHANNEL_4, ADC_SAMPLETIME_55POINT5);

adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);  // 軟件觸發
adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);                           // 觸發使能

adc_dma_mode_enable();  // 使能DMA接收

adc_enable();           // 使能ADC模塊
delay_1ms(0x03);        // ADC在使能之後需要進行短暫的延時,時間周期約為2毫秒左右,以保證ADC能正常啟動。
adc_calibration_enable();

 

 

4、DMA 初始化

  使用 DMA,最核心就是配置要傳輸的數據,包括數據從哪裡來,要到哪裡去,傳輸的數據的單位是什麼,要傳多少數據,是一次傳輸還是循環傳輸等等。

  • 從哪裡來到哪裡去        —  DMA 傳輸數據的方向有三個:(1)從外設到存儲器  (2)從存儲器到外設 (3)從存儲器到存儲器
  • 要傳多少,單位是什麼 —  要想數據傳輸正確,源和目標地址存儲的數據寬度一般會設置成一致
  • 什麼時候傳輸完成        —  傳輸完成分兩種模式,是一次傳輸還是循環傳輸,一次傳輸很好理解,即是傳輸一次之後就停止,要想再傳輸的話,必須關斷 DMA 使能後再重新配置後才能繼續傳輸。循環傳輸則是一次傳輸完成之後又恢復第一次傳輸時的配置循環傳輸,不斷的重複。
// 4. DMA配置
dma_parameter_struct dma_data_parameter;

dma_deinit(DMA_CH0);
dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA);
dma_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
dma_data_parameter.memory_addr = DstAddress;
dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT;
dma_data_parameter.number = DataLength;
dma_data_parameter.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA_CH0, &dma_data_parameter);
dma_circulation_enable(DMA_CH0);
dma_memory_to_memory_disable(DMA_CH0);
dma_channel_enable(DMA_CH0);

   註: DstAddress —  存儲器地址,一般設置為我們自定義存儲區的首地址。

 

 

5、觸發 ADC 轉換

  開啟 ADC 轉換,在ADC 轉換完成後 ADC 轉換結果 就會保存在 DMA配置的 DstAddress 地址里,在我們需要 最新的 ADC 轉換結果 時直接讀取即可。

adc_software_trigger_enable(ADC_REGULAR_CHANNEL);   // 開啟ADC轉換

 

 

三、ADC 使用注意事項

  1. ADC通道的採集引腳未配置為模擬輸入,GD32要求通道IO口必須配置為模擬輸入;
  2. ADC時鐘過高,ADC採樣時鐘高於ADC最高採樣時鐘獲取到的數據不具有參考意義,需要手動分頻到合適的ADC 要求的頻率;
  3. ADC採樣值偏小或不穩定,應該適當的降低ADC時鐘,加大採樣周期的值;
  4. ADC的查詢法在獲取ADC數值的時候,不允許重入,即不允許在同一時間調用ADC的數據讀取函數