分享到plurk 分享到twitter 分享到facebook

ADC (Analog-to-Digital Converter)

Introduction To ADC

ADC即數位類比轉換器,為一個將連續的類比訊號或者物理量(通常為電壓)轉換成數位訊號

ADC經常用於通訊、儀器和測量以及電腦系統中,可方便數位訊號處理和資訊的儲存。大多數情況下,ADC的功能會與數位電路整合在同一晶片上,但部份設備仍需使用獨立的ADC。

行動電話是數位晶片中整合ADC功能的例子,而具有更高要求的蜂巢式基地台則需依賴獨立的ADC以提供最佳性能。

ADC具備一些特性,包括:

  1. 類比輸入,可以是單通道或多通道類比輸入

  2. 參考輸入電壓,該電壓可由外部提供,也可以在ADC內部產生

  3. 時脈輸入,通常由外部提供,用於確定ADC的轉換速率

  4. 電源輸入,通常有類比和數位電源接腳

  5. 數位輸出,ADC可以提供平行或串列的數位輸出

基本概念

數位類比轉換器(Analog-to-digital coverter)

  • 用於將類比形式的連續訊號轉換為數位形式的離散訊號的一類設備。
  • 當嵌入式電子產品必須根據週遭環境的物理條件如溫度、壓力等產生適當反應,就必須由 ADC 將感測器採得的類比訊號轉為數位訊號。
  • 自然界的訊號主要為類比訊號,時間與大小是連續的;adc 負責將類比訊號轉為數位訊號,時間與大小變成離散的。

ADC的規格

根據取樣率解晰度決定產生的數位訊號在時間、大小的離散程度。

取樣率(Sampling rate)

  • 多久對輸入的類比訊號進行一次轉換。取樣率越高,所得到的數位訊號越連續,但要求較大空間存放資料及較快的資料處理速率。

解析度(Resolution)

  • 能將當下的類比值轉為多準確的數位值。解析度越高,所得的訊號越精准,但要求每筆資料佔更多的位元數。
  • 說明
    • 類比訊號圖:橫軸表示時間,縱軸表示大小。取樣率是對橫軸做切割,解析度則對縱軸做切割。
    • 因為訊號以二進位方式儲存,所以通常解析度會以位元作為單位。
    • 例如 8 位元解析度(假設電壓上限為 0~5V)
    • 表示可以將2^8 = 256個不同的類比訊號解碼,其值根據狀況可表示成0~255(unsigned integer)或者-128~127(signed integer)
    • 則我們的訊號在接收時每個單位為(5V-0V)/ (2^8-1)=0.0196V,表示數位訊號上升一個單位需要0.0196V
    • 若收到的值為100,8bits解析度的數位訊號為01100100,所需的電壓100*0.0196 = 1.96V

ADC 轉換公式

  • 以一個解析度為n bits的ADC來說,其轉換公式如下
ConvertedVoltage = ConvertedValue * Vref / (2 ^ n - 1);

其中Vref為參考電壓,通常介於VDD與VSS之間。

欲轉換的訊號電壓不可以高過Vref。

如果不再0 ~ Vref 的範圍內

  1. 可以考慮使用分壓器來處理,但必須注意輸入阻抗與輸出阻抗之匹配問題。
  2. 使用交流變壓器,使用條件為交流訊號。

如果要轉換的電壓變化太小欲放大,則可以使用 OP Amplifier 之電路來做放大。

運算放大器,為一種具有高增益,利用電壓回授來穩定電壓增益。
所謂“運算”,意謂放大器可應用來操作許多數學運算,如加、滅、乘、除、反相、微積分等。
其使用原理為利用 OPA 虛短路之特性來調整輸出電壓與輸入電壓之關係。

1.反相放大電路(Vo = - A * Vin)

此電路的放大倍率為-R2/R1。其中負號代表輸出電壓與輸入電壓的相位相反:當 VIN為正時,VOUT為負值

放大倍率計算方式:

2.正相放大電路(Vo = A * Vin)

此電路的放大倍率為1+R2/R1。輸入電壓為正時,輸出訊號亦為正值;輸入值為負時,輸出值亦為負

放大倍率計算方式:

運算放大器詳細

運算放大器投影片

Sampling Theorem

對於一個連續訊號取樣的時候,會參考Sampling Theorem定最低取樣頻率。

Nyquist–Shannon sampling theorem 說明了當取樣頻率為原訊號之最高頻率之兩倍時,才可以正確的重建原始訊號

2015-embedded-Team6 解說證明:ADC - Sampling Theorem

  • 證明:

但是通常會使用OverSampling,用遠高於 2f 的頻率來取樣,提升訊號的品質。

Youtube 解說:

https://www.youtube.com/watch?v=vbjC-aCmMUM

https://www.youtube.com/watch?v=saFTvnIVeEY

https://www.youtube.com/watch?v=Gu8x_k54tq0

jolly Good

STM32F4xx OnChip ADC 介紹

簡介

  • 共有3個12-bit ADC 在開發板上,且可量測16個外部訊號源及2個內部訊號源。
  • 有12-bit, 10-bit, 8-bit or 6-bit共4種可選擇的解析度。
  • 每個通道的A/D轉換可以使用單次、連續、掃描或間斷模式執行。
  • ADC的結果可以左對齊或右對齊的方式儲存於16-bit暫存器中。
  • ADC都在APB2上面
  • ADC使用獨立電源,VDDA、VSSA,並且需要提供參考電壓Vref(VDDA > Vref > 1.8V)
  • 在不同的VDDA下面,其取樣時間會有所差異
    • 2.4V <= VDDA <= VDD for Full Speed
    • 1.8 <= VDDA <= VDD for Reduced Speed
  • 在DISCO板子上面,VRef = VDDA = VDD = 2.95V (3V)
  • 這一塊晶片使用Successive approximation ADC,運作模式是使用DAC生成不同的電壓,來跟輸入比較,來測量輸入的值。

Successive approximation ADC

這一種ADC由一個DAC與電壓比較器組成 轉換時會由邏輯電路迭代,依序由MSB往LSB更改DAC的輸出電壓。

流程:

  • 由MSB開始
  • 啟動DAC的第n bit
  • 將輸入的訊號與DAC的輸出做比較,若輸入訊號較大,則設定輸出的第n bit為HIGH,並保留DAC上面的設定,反之若較小,清除DAC的第n bit,ADC輸出的第n bit設為LOW
  • 由這一個狀態迭代至LSB為止

ADC Block Diagram

1. Analog MUX 類比多工器:

將多個訊號源連接至 ADC(也就是ADC上的channel), 可在上圖中的左側看到有 16 組外部輸入 (ADCx_IN0~15)與兩組內部輸入, 經過類比多工器來做訊號源的選擇。

2. Injected/Regular data register:

每個 channel 都能配置成 injected or regular group, regular 在啟動後 scan 時會依序進行轉換,而 injected 表示會等待外部訊號觸發轉換,觸發後以 injected 的轉換為優先處理。(可往下參考 ADC mode)

3. External/Internal Reference Voltage:

ADC 所接受的電壓值在 GND 與參考電壓之間,注意其必須接上穩定的電壓源,否則計算上會不穩定。

4. GPIO Port:

當我們將GPIO Port設定成類比輸入的模式時,進來GPIO pin的原始訊號源在還沒經過施密特觸發器(Schmitt trigger)會有另一個線路將訊號做導向(導到ADC)

/* 將GPIO轉為類比用途 */
GPIO_initStructre.GPIO_Mode = GPIO_Mode_AN;

Refer to GPIO Presentation

5. Analog Watchdog:

用來監控採樣結果,如果超出預設範圍就打斷轉換並發出中斷。

6. Analog PreScalar:

ADC都在APB2上面,Clock來自APB2,頻率為

ADC Clock = APB2 Clock / Analog PreScalar;

ADC Unit & External Channel Bus Connections

CHANNEL ADC1 ADC2 ADC3

APB

2
2
2

ADC Channel 0

PA0

PA0

PA0

ADC Channel 1

PA1

PA1

PA1

ADC Channel 2

PA2

PA2

PA2

ADC Channel 3

PA3

PA3

PA3

ADC Channel 4

PA4

PA4

PF6

ADC Channel 5

PA5

PA5

PF7

ADC Channel 6

PA6

PA6

PF8

ADC Channel 7

PA7

PA7

PF9

ADC Channel 8

PB0

PB0

PF10

ADC Channel 9

PB1

PB1

PF3

ADC Channel 10

PC0

PC0

PC0

ADC Channel 11

PC1

PC1

PC1

ADC Channel 12

PC2

PC2

PC2

ADC Channel 13

PC3

PC3

PC3

ADC Channel 14

PC4

PC4

PF4

ADC Channel 15

PC5

PC5

PF5

STM32F4xx Internal Channel

  • 我們所使用的
    • STM32F407 Discovery其溫度感測器連接到ADC1_IN16 channel
    • STM32F429 Discovery其溫度感測器連接到ADC1_IN18 channel
  • TSVREFE bit 必需要設為enable,讓 ADC1_IN16 和 ADC1_IN17 (VREFINT)可以運作
  • 在F42x上面VBAT與VREFINT共用同一個Channel,需選擇要對誰做Sampling

  • 設定TSVREFE bit,參考下圖

STM32F4xx ADC Control

  • 可設 ADON 打開ADC電源,重設來關掉電源
  • 可使用SWSTART/JSWSTART開始ADC的轉換
  • 版子上共有 3 組ADC, 可測量 16 個外部訊號源兩個(F407) / 三個(F429)內部訊號源。每個外部訊號源對應一個通道。
  • 每個通道能自己設置不同的採樣時間,可根據不同的應用改變採樣時間。
  • 總轉換時間即採樣時間加上 ADC core 等其他元件(ex:溫度感測器的讀取)所需時間。
  • ADC 正式運作前必需做 calibration 以避免電容的狀態不是預期而造成誤差。
  • 由於有多個ADC與多個通道,因此可以排列組合出非常多變化的運作模式。

ADC之轉換時間

Timing Diagram

Tconv(Total Conversion Time) = Sampling time + N Cycles - N = 12 cycles (12 bits resolution) - N = 10 cycles (10 bits resolution) - N = 8 cycles (8 bits resolution) - N = 6 cycles (6 bits resolution)

由於是Successive Approximation ADC 所以有n bits就需要n的cycle來迭代,可參考上面的Successive Approximation ADC說明

  • Sampling time

    • ADCCLK cycles that can be modified using the SMP[2:0] bits in the ADC_SMPR1 and ADC_SMPR2 registers
    • Each channel can be sampled with a different sampling time.
    • Sample Time = [3 - 480] cycles
  • Example:

    • With ADCCLK = 30 MHz and sampling time = 3 cycles:

    • Tconv = 3 + 12 = 15 cycles = 0.5 µs with APB2 at 60 MHz

ADC的轉換速度範圍

不一定,隨著條件而變,Sample Time跟温度以及内部電路的rc有關

對於12-bits Resolution而言

Tconv = Sample Time + 12 cycles ( 12-bits resolution <參考上節 12bits部分> )
Sample Time = [3 - 480] cycles
Total conversion time = [0.50 - 16.40] µs,with ADCCLK = 30MHz.

Refer from: STM32F4xx Datasheet P125

ADC Max Sampling Rate & BandWidth

在ADC Clock = 30Mhz、12-bits Resolution的情況下,最小的Sampling Time可以達成0.5us一個Sample

所以

Sampling Rate = 1 / (0.5 * 10^(-6)) = 2Msp/s

由取樣定理可以知道,這樣等效的BandWidth為Sampling Rate的一半,即1MHz

ADC Clock 最大可容忍頻率

在Datasheet中,因為DISCO的參考電壓VREF為VDD為2.97V,故ADC Clock Frequency為[0.6-36]MHz

Refer from: STM32F4xx Datasheet P124

  • 舉例來說,下面的初始化即為把SMP10[2:0]這三個bit設為001
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles);

ADC mode

  • Independent-modeMulti-mode (Dual-mode or Triple-mode)

    • Independent mode 表示此 ADC 獨立運作。

    • multi-mode 表示ADC同時合作執行。

Independent mode

ADC 通道配置 通道可分成 regular, injected 二組,每個通道能任意屬於哪一組。

Regular group

  • 會依序被轉換,但順序可自由配置,最多 16 個 (由ADC_SQRx 暫存器來控制順序)。

  • 可以選擇 ADC 開始運作時就進行轉換或等待外來觸發轉換。

  • 有二種控制條件(連續轉換、單複數通道),組合出四種模式:

    • ADC_InitStruct->ADC_ScanConvMode = ENABLE or DISABLE ;

    • ADC_InitStruct->ADC_ContinuousConvMode = ENABLE or DISABLE;

1.Single Channel Single conversion mode: 單一通道進行一次轉換。

2.Single Channel Continuous conversion mode: 單一通道持續進行轉換。

3&4.Scan mode: 也分為轉換一次與連續轉換,但因為 data register 只有一個,所以要用 DMA 避免資料遺失。

  • DMA: 每個通道轉換完成都發出一個 DMA request, 可設定為每當 DMA 發生就觸發一次中斷,即可讀出每個通道所轉換的值,也可以全部轉換後一次讀取全部通道的值。

  • 好處是可以節省CPU的負擔,不用在轉換過程中中斷ADC而去使用不同的取樣時間對下一個通道做轉換(透過ADC_SMPRx 暫存器設定)。

5.Discontinuous mode

  • 允許 scan 時不是全部掃完,可以「分批」進行。

  • 兩種 group 皆可設為此模式,但同時只有最多一個 group 採用它。

  • 此模式必須配合「外部觸發轉換」方式使用。

  • 先設置每批有幾個通道,至多八個。 (透過 ADC_CR1 register 中的DISCNUM[2:0] 去設定)

  • 之後各次訊號觸發時轉換一批。

  • 以每批三個 (n=3), 通道為 {1, 2, 3, 4, 5, 6, 7, 8} 舉例:

    • 1st 觸發,轉換 {1, 2, 3}.

    • 2nd 觸發,轉換 {4, 5, 6}.

    • 3rd 觸發,轉換 {7, 8}, 並因為 scan 結束而發 EOC 中斷。

    • 4th 觸發,轉換 {1, 2, 3}, 以此類推。

  • 註:上例順序可以藉由設定暫存器改變順序,channel 不一定要按大小排列順序

Injected group

  • 最多 4 個通道,且只能設為等待觸發而轉換。(插隊)

  • 觸發時若正在轉換規則(Regular)通道則會暫停而先處理注入(Injected)通道,完畢後恢復原運作。

  • 如果轉換注入通道過程中規則通道轉換被觸發,不會中止注入通道轉換,而是轉換完畢才進行規則通道轉換。

  • Auto-injected mode 可設注入通道轉換於規則通道 scan 完成後,可實現一個 iteration 執行 20 次轉換。

  • Discontinuous mode: 見regular group,但在 injected group 強迫每批只能一個通道(n=1)。

Multi Mode

有別於STM32F407,STM32F429可以將3個ADC都開成Multi Mode,也就是說原本Multi Mode只有Dual Mode,現在多了Triple Mode.

  • ADC1, ADC2 ADC3分別擔任 master & 兩個slave.

  • 可分為四種基本模式模式與Combined模式,每種又都有dual & triple mode

1.Injected simultaneous mode - 使用JEXTSEL[3:0] bits 選擇外部觸發源

Dual Mode:

  • 兩個 ADCs 同時觸發而轉換 injected groups.

Triple Mode:

  • 三個 ADCs 同時觸發而轉換 injected groups.

2.Regular simultaneous mode

  • 使用EXTSEL[3:0] bits 選擇外部觸發源

Dual Mode:

  • 2 ADCs 外部訊號同時觸發,一起對所負責通道依序轉換,結果存在 ADC1 DR.

  • 禁止二個 ADCs 同時對同一通道轉換以免誤差。

Triple Mode:

  • 以上兩者的差別在於不同的group (Injected 、 Regular)

3.Interleaved mode

  • 透過兩個以上的ADC交互轉換同一個通道可以達到更高的取樣頻率

  • 由於同使只能有一個ADC對同一個通道做採樣,因此必須要增加兩個cycle的Delay time以免 phase overlap.

  • 只能用在 regular groups,通常針對一個通道使用。

Dual Mode:

Triple Mode:

  • 又分為 fast / slow interleaved mode

    • fast:藉由兩個以上的ADC交互對同一個通道取樣,可以縮減到7 個cycle就取樣一次

    • slow:假設在訊號頻率的限制下,為了使RAIN (External input impedance)符合要求,特別延長了取樣的週期間隔。又依照datasheet 上RAIN的公式算法,可以知道可容忍的RAIN會變大。

4.Alternate trigger mode

  • 只能用在雙方的 injected groups, 用同樣外部訊號輪流接受觸發。

  • 如單數次觸發到 ADC1 injected group; 雙數次觸發到 ADC2 injected group.

  • 在fast interleaved mode 最快同一個通道要7 個cycle就取樣一次,而在這個模式下“不同通道”可以在1.5個ADC cycle的間隔就取樣一次

  • 應用在馬達的控制上,PWM的duty cycle可以最大化,在最短時間內再次驅動馬達

Dual Mode:

Triple Mode:

Combined mode

  • Injected simultaneous mode + Regular simultaneous mode
    • 在執行regular group轉換時可被injected group中斷
  • Regular simultaneous mode + Alternate trigger mode
    • injected 事件會在每次trigger 後馬上執行
    • 若有regular 正在轉換,為了同步性,所有(master/slave) ADC都會停下來等injected 事件做完才重新開始
  • Injected simultaneous + Interleaved mode
    • 2個 ADC對同一個通道做 interleaved 轉換,而在事件觸發後,2個ADC可以針對各自設定的通道做取樣
    • 用在 UPS system
      • 2個ADC對ADC watchdog作轉換監控,並且定時對power consumption作測量(一個量電壓、一個量電流)

詳細可參考STM32’s ADC modesand their applicationsSTM32F407xx Reference Manual

STM32F4xx Internal Temperature Sensor

  • 須先設定TSVREFINT Bit才可使用
  • 由於啟動Temperature Sensor需要時間(waking from power down mode),啟動ADC也需要時間(startup time after power-on),因此在設定時同時對兩個做設定才能達到最快的取樣速度。
  • Datasheet有提到,內建的溫度感測器適合用來測量溫度的變化,不適合用來得到精準的溫度值。
  • 文件皆未提到其實做材料與方法,尤其特性推測為一熱電偶,原理是當導體加熱時會產生熱電效應,產生一個電動勢,就由測量這個電動勢變化,就可以線性推測它的溫度。
  • 由於每顆晶元製成時的差異,其熱電偶堆的offset會不同,官方在memory有存放3.3V時25度C與110度C的實際測量校準值,可以拿來做offset校準使用。

ADC Temperature Measurement

溫度測量公式如下

ConvertedVoltage = ConvertedValue*VDD/4095;
ConverTemp= ((((ConverValue*VDD)/4095)-V25)/Slope + 25;

溫度的範圍

STM32F4xx Reference Manual 在 10.10 Temperature sensor 中提到

Supported temperature range: –40 to 125 °C, Precision: ±1.5 °C。

設定的方法只要

ADC_TempSensorVrefintCmd(ENABLE);
  • 其實做如下:
void ADC_TempSensorVrefintCmd(FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    if (NewState != DISABLE)
    {   
        /* Enable the temperature sensor and Vrefint channel*/
        ADC->CCR |= (uint32_t)ADC_CCR_TSVREFE;
    }   
    else
    {   
        /* Disable the temperature sensor and Vrefint channel*/
        ADC->CCR &= (uint32_t)(~ADC_CCR_TSVREFE);
    }   
}

使用Stm32F4xx的ADC

  • ADC clock 來自 PCLK2 (APB2), 啟動 ADC 前須先設置好。

    • AHB for 記憶體

    • APB for 硬體周邊

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
  • ADC 可設 ADON 打開電源,重設來關掉電源
  • 版子上共有 3 組ADC, 可測量 16 個外部訊號源2 個內部訊號源。每個外部訊號源對應一個通道。
  • 每個通道能自己設置不同的採樣時間,可根據不同的應用改變採樣時間。
  • 總轉換時間即採樣時間加上 ADC core 等其他元件(ex:溫度感測器的讀取)所需時間。
  • ADC 正式運作前必需做 calibration 以避免電容的狀態不是預期而造成誤差。
ADC_ResetCalibration(ADC1);

  • 由於有多個ADC與多個通道,因此可以排列組合出非常多變化的運作模式。

Sample Code

  • 以下Sample Code為使用ADC最基本之設定
void config_GPIO(){
 
    /* --------------------------- System Clocks Configuration -----------------*/
    RCC_ClocksTypeDef RCC_Clocks;
    RCC_GetClocksFreq(&RCC_Clocks);
    /* SysTick end of count event each 10ms */
    SysTick_Config(RCC_Clocks.HCLK_Frequency / 100);
    /* GPIOA clock enable */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    //Clock configuration for ADC 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//ADC1 is connected to APB2 peripheral bus
    
    /* --------------------------- GPIO input for ADC --------------------------- */
    GPIO_InitTypeDef GPIO_initStructre; //Structure for analog input pin
    RCC_AHB1PeriphClockCmd(RCC_AHB1ENR_GPIOCEN, ENABLE);//Clock for the ADC port!! GPIOC pin10 for channel 10
    //Analog input pin configuration
    GPIO_initStructre.GPIO_Pin = GPIO_Pin_0;//The channel 10 is connected to PC0
    GPIO_initStructre.GPIO_Mode = GPIO_Mode_AN; //The PC0 pin is configured in analog mode
    GPIO_initStructre.GPIO_PuPd = GPIO_PuPd_NOPULL; //We don't need any pull up or pull down
    GPIO_Init(GPIOC, &GPIO_initStructre);
}
/* --------------------------- ADC Configuration --------------------------- */
void config_ADC(){
 
    ADC_InitTypeDef ADC_init_structure; //Structure for adc confguration
 
    //ADC structure configuration
    ADC_DeInit(); //reset all parameters to their default values
    ADC_init_structure.ADC_DataAlign = ADC_DataAlign_Right; //converted data will be shifted to right
    ADC_init_structure.ADC_Resolution = ADC_Resolution_12b; //Input voltage is converted into a 12-bit number whose maximum value is 4095
    ADC_init_structure.ADC_ContinuousConvMode = ENABLE; //the conversion is continuous, the input data is converted more than once
    ADC_init_structure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; //use timer 1 capture/compare channel 1 for external trigger
    ADC_init_structure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //no trigger for conversion
    ADC_init_structure.ADC_NbrOfConversion = 1; //Number of used ADC channels
    ADC_init_structure.ADC_ScanConvMode = DISABLE; //No scan (only one channel)
    ADC_Init(ADC1, &ADC_init_structure);
 
    // use channel 10 from ADC1, with sample time 144 cycles
    ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_144Cycles);
 
    ADC_Cmd(ADC1, ENABLE);
}
  • 以下Sample Code為使用DMA之ADC設定

  • github

void ADC_Config(void)
{
    ADC_InitTypeDef ADC_InitStructure; // Structure for single-ADC configuration
    ADC_CommonInitTypeDef ADC_CommonInitStructure; // Structure for inter-ADC configuration

    // Clock configuration
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // ADC1 is connected to APB2 peripheral bus
    RCC_AHB1PeriphClockCmd(RCC_AHB1ENR_GPIOCEN, ENABLE); // Clock for the ADC port!! (do not forget it)

    // ADC structure configuration
    ADC_DeInit(); // Reset all parameters to their default values
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; // Input voltage is converted into a 12-bit number whose maximum value is 4095
    ADC_InitStructure.ADC_ScanConvMode = ENABLE; // No scan (only one channel)
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // the conversion is continuous (periodic)
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; // no external trigger for conversion
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; // use timer 1 capture/compare channel 1 for external trigger (may be forced)
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // converted data will be shifted to the right
    ADC_InitStructure.ADC_NbrOfConversion = 2; // Number of used ADC channels
    ADC_Init(ADC1, &ADC_InitStructure);      

    // ADC common structure configuration
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; // independent mode
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; // f(ADC3)=84/4=21MHz
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; // disable DMA_MODE
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; // there are 5 clock cycles between 2 samplings
    ADC_CommonInit(&ADC_CommonInitStructure);

    //Enable temperature sensor
    ADC_TempSensorVrefintCmd(ENABLE);

    // use channel 10 from ADC1, with sample time 15 cycles
    ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 2, ADC_SampleTime_15Cycles);

    ADC_ITConfig(ADC1, ADC_IT_EOC, DISABLE); // not ready for interrupt
    
    ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

    ADC_DMACmd(ADC1, ENABLE);
    ADC_Cmd(ADC1, ENABLE);
}
void DMA_Config(){
    DMA_InitTypeDef DMA_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

    DMA_DeInit(DMA2_Stream4);
    DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) ADC1_DR_Address;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &ADCConvertedValues[0];

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

    DMA_InitStructure.DMA_BufferSize = 2;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

    DMA_Init(DMA2_Stream4, &DMA_InitStructure);
    DMA_Cmd(DMA2_Stream4, ENABLE);

    //DMA_ITConfig(DMA2_Stream4, DMA_IT_TC, ENABLE);
}
void NVIC_Config()
{
    NVIC_InitTypeDef NVIC_InitStructure;
    /* ADC interrupt configure */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
void GPIO_Output_Config(void){
    GPIO_InitTypeDef GPIO_InitStructure;
  
    GPIO_PinAFConfig(GPIOE,
GPIO_PinSource3|GPIO_PinSource4|GPIO_PinSource5|GPIO_PinSource6|GPIO_PinSource7|GPIO_PinSource8|GPIO_PinSource9|GPIO_PinSource10|GPIO_PinSource11|GPIO_PinSource12|GPIO_PinSource13|GPIO_PinSource14|GPIO_PinSource15, GPIO_AF_TIM3);
  
    GPIO_InitStructure.GPIO_Pin =   GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;            // Alt Function -   Push Pull
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init( GPIOE, &GPIO_InitStructure ); 
}
void GPIO_Input_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    // Set GPIO clock
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    GPIO_StructInit(&GPIO_InitStructure);

    //Analog input pin configuration
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//The channel 10 is connected to PC0
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; //The PC0 pin is configured in analog mode
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //We don't need any pull up or pull down
    GPIO_Init(GPIOC, &GPIO_InitStructure);
}

Demo、實驗

ADC + GPIO

https://www.youtube.com/watch?v=0gAe-xRgk-k

- 本實驗使用電源供應器產生1.9V的電壓當作輸入訊號

  • 將所量測到的電壓通過轉換,驗證ADC之轉換公式之正確性

ADC + GPIO + Temperature Sensor

https://www.youtube.com/watch?v=gRxbnODggjc

  • 本實驗用來測試stm32f4 discovery內建之溫度感測器是否隨著溫度上昇而改變轉換值

  • 可以在影片中看到最左邊的led代表最小的bit,因此當溫度不斷升高,最後點亮了影片中最後亮起的右邊那個led燈

ADC + DAC

基本設置:使用8bit模式已提升速度,使用DMA將ADC資料讀入後再用DMA將資料速給DAC做輸出。

12bits vs 8 bits

使用不同的解析度對同一訊號做採樣,在reduplicate。

ADC與DAC使用的resolution是相同的

    1. 12bits
    1. 8 bits

Sampling Theorem、訊號 Aliasing

同ADC + DAC的配置

控制訊號產生器生成的訊號頻率,當平率高過1 / 2 Fs 的時候,輸出訊號除了失真,還發生了頻率改變,已與原本訊號不同。

※X-Y Plot功能是將示波器的兩桿輸入分別作為X與Y軸的量,有別於一般V-t的作圖,對於訊號最常使用在產生Lissajous曲線。

Lissajous曲線可以看出兩個訊號的頻率、相位、強度差異。

假設目前有 Asin(aw + d) 與 Bsin(bw)兩個訊號 當a = b時,頻率相同,所以圖形將會是直線、橢圓或是正圓,端看d大小,參考下圖。

如果兩個訊號頻率不同,a != b,則圖形將會是圖形將不再是圓,而會是曲線,由此可以看出兩個訊號已經不相同

如果a/b是有理數,則圖形會有一定的形式。若有示波器的圖,可以透過查表可以知道兩個訊號的的比例。

Questions 2015

  1. [Discontinuous mode] 這部分“以每批三個 (n=3), 通道為 {1, 2, 3, 4, 5, 6, 7, 8} 舉例”,這個例子是說,在三個channel上各有不同的analog input嗎?還是他的意思是說有8個通道被使用?
  • 沒錯,三個通道上各有不同輸入。
  1. 因為只有三個ADC,不同觸發順序就會去轉換哪個channel,可是那這樣假如今天是2nd觸發,可是需要轉換的是channel 7 ,那這樣就出現問題了?
  • 在2nd的觸發絕對不會去轉換channel 7 ,因為有暫存器去控制每一輪要轉換的通道(ADC_SQRx 或者 ADC_JSQR),所以甚至通道序列可以亂排不用由通道小到大。

    首先定義`channel`:通道數量代表ADC 有幾個多工器,每次藉由多工器去選擇要對哪個通道去做ADC 轉換
    再定義`scan mode`:一次可以對一群的通道做轉換
    最後`discontinuous mode`:他是scan 模式的變形,允許 scan 時不是全部掃完所有通道,可以「分批」進行
    每個通道對應著不同的輸入源,ex. 溫度訊號、慣性感測值等,每種輸入源的取樣時間可能不同。連續模式好處是可以節省CPU的負擔,不用在轉換過程中中斷ADC而去使用不同的取樣時間對下一個通道做轉換(透過ADC_SMPRx 暫存器設定)
  1. [Injected group] 因為不懂這個東西何時會需要用到,所以自己找了些資料, 發現在 STM32™’s ADC modes and their applications 中的 1.5.2 提到 Using a timer, the injected conversion mode can thus be implemented to delay the ADC measurements to after the transistor switching. 可是我覺得delay不需要另外多取樣一次來完成,不曉得為何硬體需要這樣設計。
  • 從馬達的控制來看,PWM上的電晶體開開關關會產生雜訊,所以要讓ADC重新取樣確保值正確。而PWM示意圖如下

  • 要計算PWM的時間要多長是藉由timer來控制,上圖的timer為5階。當timer數到我們所設定的值後就會將訊號往下拉直到一個週期結束。在這同時也會將這個timer做為觸發事件去告知ADC,這樣就可以同時計算完成也順便告知ADC這次的轉換可能是有問題的,重新再取樣一次。而不用關閉ADC,再重新啟動(這過程可能是非常耗時的) 從這裡看到PWM timer會更新trigger。
  1. STM32F4xx OnChip ADC 介紹 共有3個12-bit ADC 在開發板上,且可量測16個外部訊號源及2個內部訊號源。請問外部訊號源是例如溫度、壓力,那內部訊號源有什麼例子?
  • 在STM32F4xx 上有一個內部的溫度senor,STM32F407xx Reference Manual 中230頁有提到,兩個內部訊號源一個就是溫度訊號,一個是參考電壓
  1. Multi Mode 請問 這四種mode (1)Injected simultaneous mode, (2)Regular simultaneous mode, (3)Interleaved mode, (4)Alternate trigger mode 會分別在什麼樣的情況下使用呢?
  • 以下回答參考自STM32™’s ADC modes and their applications,不過在這裡面沒有提到Injected simultaneous mode (這是在STM32F407xx Reference Manual有提到)。
    • Regular simultaneous mode
      • measure the single-phase instantaneous electrical power
      • 因為要同時測量電流與電壓來計算瞬時的功率,所以用2個ADC對不同通道做測量轉換
    • Interleaved mode
      • 其中又分為fast/slow interleaved mode
      • Dual fast interleaved mode
        • 藉由兩個以上的ADC交互對同一個通道取樣,可以縮減到7 個cycle就取樣一次,加速取樣頻率
      • Dual slow interleaved mode
        • 假設在訊號頻率的限制下,為了使RAIN (External input impedance)符合要求,特別延長了取樣的週期間隔。又依照RAIN的公式算法,可以知道可容忍的RAIN會變大。
- Alternate trigger mode
    - 每一次的外部觸發後,某個ADC就會將設定的 injected group都轉換完
    - 在fast interleaved mode 最快同一個通道要7 個cycle就取樣一次,而在這個模式下"不同通道"可以在1.5個ADC cycle的間隔就取樣一次
    - 應用在馬達的控制上,PWM的duty cycle可以最大化,在最短時間內再次驅動馬達
  1. alignment的時候要補SEXT,但不知道為甚麼只有injected group需要,regular group卻不用?
  • 參考自STM32F407xx Reference Manual,在Data alignment章節提到

    The converted data value from the injected group of channels is decreased by the userdefined offset written in the ADC_JOFRx registers so the result can be a negative value. The SEXT bit represents the extended sign value. 
    For channels in a regular group, no offset is subtracted so only twelve bits are significant.
  • 在injected group可能會被設定要被減去某個值,所以要考慮負號的產生

  1. 在 Multi Mode 的 Interleaved mode 時,透過多個 ADC 以固定間隔對同一個通道取樣以達到取樣頻率的提升。請問 Simultaneous mode 和 Alternate trigger mode 的用途又是什麼呢? Simultaneous mode:應該不能夠像 Interleaved mode 提升取樣頻率,因為取樣間隔不同,但是否能夠用來提升準確度? Alternate trigger mode:為了同時處理多的 injected group 的轉換?
  • 如同上面第5題的回答,Interleaved mode 其中又分為fast/slow interleaved mode,fast 模式可以達到取樣頻率提升,slow 模式則是能讓可容忍的RAIN變大。
  • simultaneous mode 則主要是為了同時取得兩個以上的類比訊號值來做計算(ex.同時測量電流與電壓來計算瞬時的功率)。而減少轉換的誤差切入點有很多,可以參考How to get the best ADC accuracy in STM32Fx Series and STM32L1 Series devices
  • Alternate trigger mode ,在fast interleaved mode 最快同一個通道要7 個cycle就取樣一次,而在這個模式下“不同通道”可以在1.5個ADC cycle的間隔就取樣一次
  1. ADC的規格 “因為訊號以二進位方式儲存,所以通常解析度會以位元作為單位。 例如 8 位元解析度(假設電壓上限為 0~5V) 則我們的訊號在接收時每個單位為(5V-0V)/ (2^8-1)=0.0196V 若所得到的值為100則其實際上的電壓為 100 × 0.0196 = 1.96V” 這邊在算甚麼?
  • Vref = Vcc-Vee即參考電壓為5
  • 8bit解析度=>數位訊號用8個位址空間來表示類比訊號的大小
  • 即用5/2^8(wiki上沒有-1?)以電壓來說,可得知上升一個bit需要0.0196V
  • 所以當接收到的值為100(dec)即解析度為01100100,電壓為1.96V
  1. ADC 轉換公式 “其中Vref為參考電壓,通常介於VDD與VSS之間。” 請問VDD與VSS代表?
  • VCC:電源電壓(雙極器件);電源電壓(74系列數字電路);聲控載波(Voice Controlled Carrier)
  • C=circuit 表示電路的意思, 即接入電路的電壓
  • VDD:電源電壓(單極器件);電源電壓(4000系列數字電 路);漏極電壓(場效應管)
  • D=device 表示器件的意思, 即器件內部的工作電壓,在普通的電子電路中,一般Vcc>Vdd !
  • VSS:地或電源負極
  • S=series 表示公共連接的意思,也就是負極。
  • VEE:負電壓供電;場效應管的源極(S)
  • VPP:編程/擦除電壓。

Questions 2013

  1. 說明如何決定取樣頻率,解釋 Nyquist–Shannon sampling theorem。
Nyquist–Shannon sampling theorem 說明了當取樣頻率為原訊號之最高頻率之兩倍時,才可以正確的重建原始訊號
  • 證明:
  1. 說明當所要量測之輸入訊號電壓範圍不在adc之接受範圍時該如何處理?
  • 假設使用的ADC量測範圍是0~3V

  • 如果超出範圍(EX:0~5V):

    • 1.對於直流訊號來說分壓電路是最簡單的降壓方式,但必須注意輸入阻抗與輸出阻抗之匹配問題。

      • 由於 STM32 之手冊上說明 ADC 之輸入阻抗約為10k 因此我們外接分壓之電阻必須選用較小之電阻。
    • 2.有兩個電感的變壓電路是“交流變壓器”。

      • 變壓器之使用條件為交流電,變壓器通常使用在高功耗之輸配電系統。
    • 3.如果需要將輸入訊號放大,則可以使用 OPA 之電路來做放大。

      其使用原理為利用 OPA 虛短路之特性來調整輸出電壓與輸入電壓之關係。

1.反相放大電路

2.正相放大電路

  1. 說明 ADC Block Diagram 之 Vrefint 與 TIM1_TRGO 是什麼?
    • VREFINT:
      • ADC之內部參考電壓
    • TIM1_TRGO:
      •  
  2. 說明 ADC 之 calibration。
    • 由於ADC上面的電容可能並不是理論上的理想值,因此每次使用時必須量測現在ADC之電容之實際值,可以把這個實際值視為誤差,因此未來所量測的結果都必須使用這個誤差值作為基準點去比較,因此可以量到更加精確的轉換結果。
/* Enable ADC1 reset calibaration register */ 
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */ 
while(ADC_GetResetCalibrationStatus(ADC1)); 
/* Start ADC1 calibaration */ 
ADC_StartCalibration(ADC1); 
/* Check the end of ADC1 calibration */ 
while(ADC_GetCalibrationStatus(ADC1));
/* 完成 calibration 才能開始使用 */

  1. 說明 ADC 之 Scan Mode 與 DMA 之關係。並畫流程圖。

    • 由於 Scan Mode 同時會對一組通道做轉換,並且在該組最後一個通道做完轉換後才產生中斷,因此使用 DMA 讓每次轉換後就直接產生 DMA 將資料寫到記憶體中,才不會造成資料遺失。官方的手冊對此做了以下解釋:

        Since converted regular channel values are stored into a unique data register, it is useful to use DMA for conversion of more than one regular channel. This avoids the loss of the data already stored in the ADC_DR register.
  2. 說明測量溫度的方法

  • 使用STM32內建的溫度感測器。

  • 可以利用單一電阻的電阻會隨溫度上昇而增加電阻值來反推溫度。

    • 電阻隨溫度呈現性上昇

    • 可利用上面之特性搭配 ADC 來做溫度量測

  1. 說明 EOC 等之術語。

    • EOC 即 End of Conversion (為 Regular Group 結束轉換時產生之中斷)

      • 當 ScanConvMode Disable 時(也就是 Regular Group 只有一個channel),每次轉換結束都會產生 EOC 中斷。

      • 當 ScanConvMode Enable 時,只有當所設定之 Regular Group 之最後一個 channel 完成轉換時才會產生 EOC。

    • JEOC 為 Injected Group 結束轉換時產生之中斷。

    • AWD 為 analog watch dog 所產生之中斷。

  2. 說明為何 sample code 中的 DMA 使用 stream4 channel_0?

    • 參考手冊表格如下:

Questions 2012

    1. ADC的轉換時間有多快? 不一定隨著條件而變,Sample Time跟温度以及内部電路的rc有關
  Tconv = Sample Time + 12 cycles ( 12-bit resolution )
  Sample Time = [3 - 480] cycles
  Total conversion time = [0.50 - 16.40] µs,with ADCCLK = 30MHz.
  So, Sample Time must > 16.4µs 。

Refer from: STM32F407xx Datasheet P125

    1. Bandwidth大小為多少?
    1. 頻率響應為多少,可容忍的最大頻率呢? 在Datasheet中,因為我們參考電壓VDD為2.97V,故Frequency為[0.6-36]MHz

Refer from: STM32F407xx Datasheet P124

    1. ADC在Stm32的flow中,會經過的,會用到的電路和元件有哪些? 有External Event Trigger(e.g. timer capture,EXTI),GPIO ports,External/Internal Reference Voltage,Analog to Digital convert core, Temperature Sensor,Analog Multiplexer,Injected/Regular data register,Analog watchdog,Address/date bus,ADC Clock…

STM32F407xx Reference Manual 參照P264 ADC block diagram

    1. 測試的接法? 請參考Demo.
    1. ADC的公式在哪裡找到? STM32F407xx Reference Manual 在 10.10 Temperature sensor 中溫度轉換公式為
Temperature (in °C) = {(VSENSE – V25) / Avg_Slope} + 25
Where: V25 = VSENSE value for 25° C、 Avg_Slope = average slope of the temperature vs. VSENSE curve (given in mV/°C or μV/°C)
    1. 溫度的範圍? STM32F407xx Reference Manual 在 10.10 Temperature sensor 中提到 Supported temperature range: –40 to 125 °C, Precision: ±1.5 °C。
    1. 當在測量輸出電壓時,三用電表在pin腳上量到的電壓大小與gdb上所取得到的值得誤差有多少?
    1. 如何先做溫度上的校準? 利用內建溫度感測計在做實驗時,由於無法獨立出一個sensor出來測,所以實驗的環境下是在室溫的環境下,並利用溫度計來量測室溫為多少,來比對板子上所抓到的溫度與溫度計上的溫度.

    補: STM32F407xx Reference Manual 在 10.10 Temperature sensor 中一張中的Note提到,此開發版的內部溫度感測器適合來偵測溫度的變化,依據溫度感測公式來看,是基於25°C下與offset得到的溫度值,也就是適合觀察溫度變化,並不適合來取得室溫上的絕對溫度. 所以若要測量精確的絕對溫度的話,Manual上建議外接溫度感測器較為合適.

    1. 整個程式上的架構為如何? 一開始程式先初始化ADC會用到的硬體資源,其中包含Interrupt、ADC、DMA的初始,之後將ADC的TASK註冊到freertos裡面,Task中是做了DMA所註冊的通道與NVIC的channel設定,而當中我們註冊了 DMA_Stream0_IRQHandler(void),此Interrupt handler會在每次資料由peripheral到memory傳完之後,產生DMA的interrupt,去更新溫度值或電壓值.

    詳細的設定請參考下方的Sample code

    • Structure
int main()
{
    prvSetupHardware();
    xTaskCreate(vADC_DMATask, .., .., .., ..);
    vTaskStartScheduler();
}
    1. 如何選擇mode? Scan or Continuous? Two groups => a.Regular group。(16 channels) b.Injected group。(2 channels)
  1.Single conversion mode => ADC dose one conversions。
 
  2.Continuous conversion mode => ADC stars a new conversion as soon as is finishes one。

  3.Scan mode => This mode is used to scan a groupof analog channels。
 
  4.Discontinuous mode => Regular group。( n conversions,n<=8 )
    1. 若想要取得其他外部Sensor的Anolog值,要如何取得? 利用GPIO,設定要接出的Pin腳,並連接至外部訊號上。
    1. 頻率除以4要幹嘛?不除頻又會怎樣? 頻率目的是方便操作與計算,因為我們設定Sample/Convert Time,單位是cycle,

    而 ADCCLK generates from APB2,fPCLK = 84MHz,1 cycle = 0.0119 µs,溫度感測時間需要17 µs。

    若設定1個cycle=0.0119 µs,則需要1428個cycles,但是ADC_Sample_Time 支援上限為480 Cycles。

    1. ExternalTrigConvEdge和ExternalTrigConv是甚麼?觸發又是在幹嘛? 分別為以下︰
    • 1.ExternalTrigConvEdge
    • 2.ExternalTrigConv
    1. DMA跟ADC之間是在幹嘛的? 規則通道轉換後的數值儲存在一個唯一的暫存器中,所以當轉換多個規則通道時需要使用DMA,用來避免遺失已經儲存在ADC_DR暫存器的數據。

    只有在規則通道轉換結束後才能產生DMA的請求,並且將轉換後的數據從ADC_DR的暫存器傳輸到用戶指定的目的地位址。

    1. 為什麼要設定DMA,照我們我的作法是跑迴圈的方式去polling溫度的值?要做DMA的話會花幾個cycle?
    1. DMA_Mode_Circulur這mode在做甚麼用? 主要用來處理circular buffers和連續的data flow(像是ADC的scan mode)。

    當此模式啟動時,會將要傳送的資料載入在stream config所設定的初始值,且DMA request會持續服務。

    1. DMA2_Stream0是甚麼?為什麼是以Stream的方式? DMA Stream 提供了一個source to destination的單方向傳輸的連結,像是周邊到記憶體或是記憶體到周邊。
    1. 用while loop可能會取得錯誤的值,也可能會浪費資源?
    1. 溫度的sampling rate設成20MHz會不會太高,或許1KHz會差不多,開發程式中要call api時,config中值是否可參數化? 溫度的Sample Time是經由公式計算出,無法設定,Datasheet有提供公式,需要設定是Sample Time必須大於取樣時間的MAX值,

    您的問題應該是Sampling Rate(取樣頻率),就根據使用者需求來設定轉換模式,並算出轉換頻率。

Reference

共筆