版本 13781610bedbf7a340d85f1e853e94c38e571ace
Changes from 13781610bedbf7a340d85f1e853e94c38e571ace to current
---
title: ADC
categories: 數位類比轉換器, ADC, Peripherals, STM32F4
title: ADC (Analog-to-Digital Converter)
categories: 數位類比轉換器, ADC, Peripherals, STM32F4, STM32F429
...
Introduction
============
Introduction To ADC
===================
**ADC即數位類比轉換器,為一個將連續的類比訊號或者物理量(通常為電壓)轉換成數位訊號**
ADC經常用於通訊、儀器和測量以及電腦系統中,可方便數位訊號處理和資訊的儲存。大多數情況下,ADC的功能會與數位電路整合在同一晶片上,但部份設備仍需使用獨立的ADC。
行動電話是數位晶片中整合ADC功能的例子,而具有更高要求的蜂巢式基地台則需依賴獨立的ADC以提供最佳性能。
ADC具備一些特性,包括:
1. 類比輸入,可以是單通道或多通道類比輸入
2. 參考輸入電壓,該電壓可由外部提供,也可以在ADC內部產生
3. 時脈輸入,通常由外部提供,用於確定ADC的轉換速率
4. 電源輸入,通常有類比和數位電源接腳
5. 數位輸出,ADC可以提供平行或串列的數位輸出
![](/embedded/ADC/introduction)
基本概念
-------
**數位類比轉換器(Analog-to-digital coverter)**
- 用於將類比形式的連續訊號轉換為數位形式的離散訊號的一類設備。
.. image:: /embedded/ADC/圖片2.png
![](/embedded/ADC/圖片2.png)
- 當嵌入式電子產品必須根據週遭環境的物理條件如溫度、壓力等產生適當反應,就必須由 ADC 將感測器採得的類比訊號轉為數位訊號。
- 自然界的訊號主要為類比訊號,時間與大小是連續的;adc 負責將類比訊號轉為數位訊號,時間與大小變成離散的。
.. image:: http://www.planetoftunes.com/digiaudio/dig_media/sampling_in_4_bit_convertor.gif
.. image:: /embedded/ADC/adc_convert.png
![](http://www.msbtech.com/support/DAC-sampling_in_4_bit_convertor.gif)
![](/embedded/ADC/adc_convert.png)
ADC的規格
========
--------
根據**取樣率**與**解晰度**決定產生的數位訊號在時間、大小的離散程度。
**取樣率(Sampling rate)**
- 多久對輸入的類比訊號進行一次轉換。取樣率越高,所得到的數位訊號越連續,但要求較大空間存放資料及較快的資料處理速率。
**解析度(Resolution)**
- 能將當下的類比值轉為多準確的數位值。解析度越高,所得的訊號越精准,但要求每筆資料佔更多的位元數。
- 說明
- 類比訊號圖:橫軸表示時間,縱軸表示大小。取樣率是對橫軸做切割,解析度則對縱軸做切割。
- 因為訊號以二進位方式儲存,所以通常解析度會以位元作為單位。
- 例如 8 位元解析度(假設電壓上限為 0~5V)
- 則我們的訊號在接收時每個單位為(5V-0V)/(2^8-1)=0.0196V
- 若所得到的值為100則其實際上的電壓為 100 × 0.0196 = 1.96V
- 類比訊號圖:橫軸表示時間,縱軸表示大小。取樣率是對橫軸做切割,解析度則對縱軸做切割。
- 因為訊號以二進位方式儲存,所以通常解析度會以位元作為單位。
- 例如 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 轉換公式
===========
-----------
- 以一個解析度為12bits的ADC來說,電壓範圍為0-5V,其轉換公式如下
- 以一個解析度為n bits的ADC來說,其轉換公式如下
```c
ConvertedVoltage = ConvertedValue * Vref / (2 ^ n - 1);
```
其中Vref為參考電壓,通常介於VDD與VSS之間。
::
欲轉換的訊號電壓不可以高過Vref。
ConvertedVoltage = ConvertedValue * VDD/(2^12-1);
如果不再0 ~ Vref 的範圍內
ADC on STM32F4
===============
1. 可以考慮使用分壓器來處理,但必須注意輸入阻抗與輸出阻抗之匹配問題。
2. 使用交流變壓器,使用條件為交流訊號。
如果要轉換的電壓變化太小欲放大,則可以使用 OP Amplifier 之電路來做放大。
```
運算放大器,為一種具有高增益,利用電壓回授來穩定電壓增益。
所謂“運算”,意謂放大器可應用來操作許多數學運算,如加、滅、乘、除、反相、微積分等。
其使用原理為利用 OPA 虛短路之特性來調整輸出電壓與輸入電壓之關係。
```
1.反相放大電路(Vo = - A * Vin)
此電路的放大倍率為-R2/R1。其中負號代表輸出電壓與輸入電壓的相位相反:當 VIN為正時,VOUT為負值
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_FoYwIS8lBIN_p.84729_1385972297699_OPA1.jpg)
放大倍率計算方式:
![](/embedded/ADC/OPA_Inverting)
2.正相放大電路(Vo = A * Vin)
此電路的放大倍率為1+R2/R1。輸入電壓為正時,輸出訊號亦為正值;輸入值為負時,輸出值亦為負
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_FoYwIS8lBIN_p.84729_1385972307523_OPA2.jpg)
放大倍率計算方式:
![](/embedded/ADC/OPA_pos)
[運算放大器詳細](http://memo.cgu.edu.tw/shin-yan/0909_Electronics(I)/2_OP.pdf)
[運算放大器投影片](http://140.116.155.39/OP%20AMP%20Yuntech.pdf)
Sampling Theorem
-----------------
對於一個連續訊號取樣的時候,會參考Sampling Theorem定最低取樣頻率。
```
Nyquist–Shannon sampling theorem 說明了當取樣頻率為原訊號之最高頻率之兩倍時,才可以正確的重建原始訊號
```
2015-embedded-Team6 解說證明:[ADC - Sampling Theorem](http://wiki.csie.ncku.edu.tw/embedded/ADC/Sampling_Theorem)
- 證明:
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_FoYwIS8lBIN_p.84729_1386001249929_%E6%96%B0%E5%BB%BA%E6%AA%94%E6%A1%88%209_1.jpg)
但是通常會使用OverSampling,用遠高於 2f 的頻率來取樣,提升訊號的品質。
Youtube 解說:
[https://www.youtube.com/watch?v=vbjC-aCmMUM](https://www.youtube.com/watch?v=vbjC-aCmMUM)
[https://www.youtube.com/watch?v=saFTvnIVeEY](https://www.youtube.com/watch?v=saFTvnIVeEY)
[https://www.youtube.com/watch?v=Gu8x_k54tq0](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為止
![](https://upload.wikimedia.org/wikipedia/commons/thumb/6/61/SA_ADC_block_diagram.png/300px-SA_ADC_block_diagram.png)
ADC Block Diagram
=================
.. image:: https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383311801212_%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202013-11-01%20%E4%B8%8B%E5%8D%889.14.26.png
------------------
![](http://wiki.csie.ncku.edu.tw/ADC%20Block%20Diagram%20HiRes)
**1. Analog MUX 類比多工器:**
將多個訊號源連接至 ADC, 可在上圖中的左下角看到有 16 組輸入 (ADCx_IN0~15), 經過類比多工器來做訊號源的選擇。
將多個訊號源連接至 ADC(也就是ADC上的channel), 可在上圖中的左側看到有 16 組外部輸入 (ADCx_IN0~15)與兩組內部輸入, 經過類比多工器來做訊號源的選擇。
**2. Injected/Regular data register:**
每個 channel 都能配置成 injected or regular, regular 在啟動後 scan 時會依序進行轉換,而 injected 表示會等待外部訊號觸發轉換,觸發後以 injected 的轉換為優先處理。
每個 channel 都能配置成 injected or regular group, regular 在啟動後 scan 時會依序進行轉換,而 injected 表示會等待外部訊號觸發轉換,觸發後以 injected 的轉換為優先處理。(可往下參考 [ ADC mode](#ADC mode))
**3. External/Internal Reference Voltage:**
ADC 所接受的電壓值在 GND 與參考電壓之間,注意其必須接上穩定的電壓源,否則計算上會不穩定。
**4. GPIO Port:**
當我們將GPIO Port設定成類比輸入的模式時,進來GPIO pin的原始訊號源在還沒經過施密特觸發器(Schmitt trigger)會有另一個線路將訊號做導向(導到ADC)
.. code-block::
/* 將GPIO轉為類比用途 */
GPIO_initStructre.GPIO_Mode = GPIO_Mode_AN;
```c
/* 將GPIO轉為類比用途 */
GPIO_initStructre.GPIO_Mode = GPIO_Mode_AN;
```
.. image:: https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1384160168223_GPIO_basic_src.PNG
------------------------------
![](http://wiki.csie.ncku.edu.tw/ADC%20GPIO%20Path)
Refer to `GPIO Presentation<http://wiki.csie.ncku.edu.tw/embedded/GPIO>`_
Refer to [GPIO Presentation](http://wiki.csie.ncku.edu.tw/embedded/GPIO)
**5. Analog Watchdog:**
用來監控採樣結果,如果超出預設範圍就打斷轉換並發出中斷。
啟動 STM32 之 ADC
================
**6. Analog PreScalar:**
- ADC clock 來自 **PCLK2 (APB2)**, 啟動 ADC 前須先設置好。
ADC都在APB2上面,Clock來自APB2,頻率為
- AHB for 記憶體
```c
ADC Clock = APB2 Clock / Analog PreScalar;
```
- APB for 硬體周邊
ADC Unit & External Channel Bus Connections
--------------------------------------------
.. code-block::
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
+--------------+------+------+------+
|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|
+--------------+------+------+------+
- ADC 可設 ADON 打開電源,重設來關掉電源
.. image:: https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1384161281907_adcon.jpeg
- 版子上共有 **3 組ADC**, 可測量 **16 個外部訊號源**和 **2 個內部訊號源**。每個外部訊號源對應一個通道。
STM32F4xx Internal Channel
---------------------------
- 我們所使用的
- STM32F407 Discovery其溫度感測器連接到ADC1_IN16 channel
- STM32F429 Discovery其溫度感測器連接到ADC1_IN18 channel
.. image:: /embedded/ADC/ADC on STM32F4
- TSVREFE bit 必需要設為enable,讓 ADC1_IN16 和 ADC1_IN17 (VREFINT)可以運作
- 在F42x上面VBAT與VREFINT共用同一個Channel,需選擇要對誰做Sampling
- 設定TSVREFE bit,參考下圖
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1384075370541_temp.jpeg)
STM32F4xx ADC Control
---------------------
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1384161281907_adcon.jpeg)
- 可設 ADON 打開ADC電源,重設來關掉電源
- 可使用SWSTART/JSWSTART開始ADC的轉換
- 版子上共有 **3 組ADC**, 可測量 **16 個外部訊號源**和 **兩個(F407) / 三個(F429)內部訊號源**。每個外部訊號源對應一個通道。
![](/embedded/ADC/ADC on STM32F4)
- 每個通道能自己設置不同的採樣時間,可根據不同的應用改變採樣時間。
- 總轉換時間即採樣時間加上 ADC core 等其他元件(ex:溫度感測器的讀取)所需時間。
- ADC 正式運作前必需做 calibration 以避免電容的狀態不是預期而造成誤差。
- 由於有多個ADC與多個通道,因此可以排列組合出非常多變化的運作模式。
.. code-block::
ADC之轉換時間
============
ADC_ResetCalibration(ADC1);
### Timing Diagram
- 由於有多個ADC與多個通道,因此可以排列組合出非常多變化的運作模式。
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383732301081_adctime.jpeg)
**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
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383727784220_AA.jpeg)
- 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而言
```c
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.
```
-----------------------------
![](/embedded/ADC/table7.jpg)
Refer from: STM32F4xx Datasheet P125
ADC Max Sampling Rate & BandWidth
----------------------------------
在ADC Clock = 30Mhz、12-bits Resolution的情況下,最小的Sampling Time可以達成0.5us一個Sample
所以
```c
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**。
![](/embedded/ADC/table6.jpg)
Refer from: STM32F4xx Datasheet P124
- 舉例來說,下面的初始化即為把SMP10[2:0]這三個bit設為001
```c
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles);
```
ADC mode
========
**Independent-mode** 和 **Dual-mode(multi-mode)**
* **Independent-mode** 和 **Multi-mode (Dual-mode or Triple-mode)**
**Independent mode** 表示此 ADC 獨立運作。
* **Independent mode** 表示此 ADC 獨立運作。
**multi-mode** 表示ADC同時合作執行。
* **multi-mode** 表示ADC同時合作執行。
Independent mode
----------------
**ADC 通道配置**
通道可分成 **regular**, **injected** 二組,每個通道能任意屬於哪一組。
.. image:: https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383586655329_test.jpeg
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383586655329_test.jpeg)
**Regular group**
- 會依序被轉換,但順序可自由配置,最多 16 個。
- 會依序被轉換,但順序可自由配置,最多 16 個 (由ADC_SQRx 暫存器來控制順序)。
- 可以選擇 ADC 開始運作時就進行轉換或等待外來觸發轉換。
- 有二種控制條件,組合出四種模式:
- 有二種控制條件(連續轉換、單複數通道),組合出四種模式:
.. image:: https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383626797723_jus2.jpeg
* ADC_InitStruct->ADC_ScanConvMode = ENABLE or DISABLE ;
- ADC_InitStruct->ADC_ScanConvMode = ENABLE or DISABLE ;
* ADC_InitStruct->ADC_ContinuousConvMode = ENABLE or DISABLE;
- ADC_InitStruct->ADC_ContinuousConvMode = ENABLE or DISABLE;
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383626797723_jus2.jpeg)
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 暫存器設定)。
**Injected group**
5.Discontinuous mode
- 允許 scan 時不是全部掃完,可以「分批」進行。
- 最多 4 個通道,且只能設為等待觸發而轉換。(插隊)
- 兩種 group 皆可設為此模式,但同時只有最多一個 group 採用它。
- 觸發時若正在轉換規則通道則會暫停而先處理注入通道,完畢後恢復原運作。
- 此模式必須配合「外部觸發轉換」方式使用。
- 如果轉換注入通道過程中規則通道轉換被觸發,不會中止注入通道轉換,而是轉換完畢才進行規則通道轉換。
- 先設置每批有幾個通道,至多八個。 (透過 ADC_CR1 register 中的DISCNUM[2:0] 去設定)
- 之後各次訊號觸發時轉換一批。
- Auto-injected mode 可設注入通道轉換於規則通道 scan 完成後,可實現一個 iteration 執行 20 次轉換。
- 以每批三個 (n=3), 通道為 {1, 2, 3, 4, 5, 6, 7, 8} 舉例:
- 1st 觸發,轉換 {1, 2, 3}.
- < Discontinuous mode >
- 2nd 觸發,轉換 {4, 5, 6}.
- 允許 scan 時不是全部掃完,可以「分批」進行。
- 3rd 觸發,轉換 {7, 8}, 並因為 scan 結束而發 EOC 中斷。
- 兩種 group 皆可設為此模式,但同時只有最多一個 group 採用它。
- 4th 觸發,轉換 {1, 2, 3}, 以此類推。
- 此模式必須配合「外部觸發轉換」方式使用。
- 註:上例順序可以藉由設定暫存器改變順序,channel 不一定要按大小排列順序
- 先設置每批有幾個通道,至多八個,但 injected group 強迫每批一個通道。
- 之後各次訊號觸發時轉換一批。
**Injected group**
- 以每批三個 (n=3), 通道為 {1, 2, 3, 4, 5} 舉例:
- 1st 觸發,轉換 {1, 2, 3}.
- 2nd 觸發,轉換 {4, 5}, 並因為 scan 結束而發 EOC 中斷。
- 最多 4 個通道,且只能設為等待觸發而轉換。(插隊)
- 3rd 觸發,轉換 {1, 2, 3}, 以此類推。
- 觸發時若正在轉換規則(Regular)通道則會暫停而先處理注入(Injected)通道,完畢後恢復原運作。
- 如果轉換注入通道過程中規則通道轉換被觸發,不會中止注入通道轉換,而是轉換完畢才進行規則通道轉換。
Multi Mode (Dual mode)
-----------------------
- Auto-injected mode 可設注入通道轉換於規則通道 scan 完成後,可實現一個 iteration 執行 20 次轉換。
- 有一組ADC是無法開啟dual mode,只能使用independent mode
- Discontinuous mode: 見regular group,但在 injected group 強迫每批只能一個通道(n=1)。
- 在我們的參考資料中ADC3只能開啟independent mode
- 此資訊來自stm32 ADC mode and their application P9
- ADC1, ADC2 分別擔任 master & slave.
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 選擇外部觸發源
.. image:: https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383621324167_1.jpeg
Dual Mode:
兩個 ADCs 同時觸發而轉換 injected groups.
- 兩個 ADCs 同時觸發而轉換 injected groups.
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383621324167_1.jpeg)
Triple Mode:
- 三個 ADCs 同時觸發而轉換 injected groups.
![](http://i.imgur.com/UkbQN4t.png)
**2.Regular simultaneous mode**
.. image:: https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383621427303_2.jpeg
- 使用EXTSEL[3:0] bits 選擇外部觸發源
Dual Mode:
- 2 ADCs 外部訊號同時觸發,一起對所負責通道依序轉換,結果存在 ADC1 DR.
- 禁止二個 ADCs 同時對同一通道轉換以免誤差。
- 以上兩者的差別在於不同的group
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383621427303_2.jpeg)
Triple Mode:
**3.Interleaved mode**
![](http://i.imgur.com/UcUn2il.png)
.. image:: https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383621695343_3.jpeg
- 以上兩者的差別在於不同的group (Injected 、 Regular)
**3.Interleaved mode**
- 透過兩個以上的ADC交互轉換同一個通道可以達到更高的取樣頻率
- 由於同使只能有一個ADC對同一個通道做採樣,因此必須要增加兩個cycle的Delay time以免 phase overlap.
- 只能用在 regular groups,通常針對一個通道使用。
**4.Alternate trigger mode**
Dual Mode:
.. image:: https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383624981460_6.jpeg
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383621695343_3.jpeg)
- 只能用在雙方的 injected groups, 用同樣外部訊號輪流接受觸發。
Triple Mode:
- 如單數次觸發到 ADC1 injected group; 雙數次觸發到 ADC2 injected group.
![](http://i.imgur.com/vDDkT9j.png)
ADC之 Time Diagram
==================
- 又分為 fast / slow interleaved mode
.. image:: https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383732301081_adctime.jpeg
- fast:藉由兩個以上的ADC交互對同一個通道取樣,可以縮減到7 個cycle就取樣一次
- slow:假設在訊號頻率的限制下,為了使R~AIN~ (External input impedance)符合要求,特別延長了取樣的週期間隔。又依照datasheet 上R~AIN~的公式算法,可以知道可容忍的R~AIN~會變大。
ADC之轉換時間
============
**4.Alternate trigger mode**
**Tconv(Total Conversion Time) = Sampling time + 12 cycles (12 bits resolution)**
- 只能用在雙方的 injected groups, 用同樣外部訊號輪流接受觸發。
- Sampling time
- 如單數次觸發到 ADC1 injected group; 雙數次觸發到 ADC2 injected group.
- ADCCLK cycles that can be modified using the SMP[2:0] bits in the ADC_SMPR1 and ADC_SMPR2 registers
- 在fast interleaved mode 最快同一個通道要7 個cycle就取樣一次,而在這個模式下"不同通道"可以在1.5個ADC cycle的間隔就取樣一次
.. image:: https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383727784220_AA.jpeg
- 應用在馬達的控制上,PWM的duty cycle可以最大化,在最短時間內再次驅動馬達
- 舉例來說,下面的初始化即為把SMP10[2:0]這三個bit設為001
Dual Mode:
::
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1383624981460_6.jpeg)
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles);
Triple Mode:
![](http://i.imgur.com/lKt5MAG.png)
**Combined mode**
- Each channel can be sampled with a different sampling time.
- Injected simultaneous mode + Regular simultaneous mode
- 在執行regular group轉換時可被injected group中斷
- Example:
- Regular simultaneous mode + Alternate trigger mode
- injected 事件會在每次trigger 後馬上執行
- 若有regular 正在轉換,為了同步性,所有(master/slave) ADC都會停下來等injected 事件做完才重新開始
- With ADCCLK = 30 MHz and sampling time = 3 cycles:
- Injected simultaneous + Interleaved mode
- 2個 ADC對同一個通道做 interleaved 轉換,而在事件觸發後,2個ADC可以針對各自設定的通道做取樣
- 用在 UPS system
- 2個ADC對ADC watchdog作轉換監控,並且定時對power consumption作測量(一個量電壓、一個量電流)
- Tconv = 3 + 12 = 15 cycles = 0.5 µs with APB2 at 60 MHz
詳細可參考[STM32's ADC modesand their applications](http://www.st.com/web/en/resource/technical/document/application_note/CD00258017.pdf)、[STM32F407xx Reference Manual](http://measure.feld.cvut.cz/system/files/files/cs/vyuka/predmety/A4M38KRP/DM00031020.pdf)
STM32F4xx Internal Temperature Sensor
======================================
STM32F4 Discovery 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校準使用。
- 我們所使用的STM32F4 Discovery其溫度感測器連接到ADC1_IN16 channel
![](http://wiki.csie.ncku.edu.tw/Temp%20sensor%20Cal%20value)
- 除了設定通道以外,也必須要設定TSVREFE bit,參考下圖
ADC Temperature Measurement
----------------------------
溫度測量公式如下
.. image:: https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1384075370541_temp.jpeg
```
ConvertedVoltage = ConvertedValue*VDD/4095;
ConverTemp= ((((ConverValue*VDD)/4095)-V25)/Slope + 25;
```
- ADC1_IN18 為 STM23F42x and STM32F43x 所使用之通道
![](/embedded/ADC/formula.png)
- TSVREFE bit 必需要設為enable,讓 ADC1_IN16 和 ADC1_IN17 (VREFINT)可以運作
溫度的範圍
---------
STM32F4xx Reference Manual 在 10.10 Temperature sensor 中提到
設定的方法只要
```
Supported temperature range: –40 to 125 °C, Precision: ±1.5 °C。
```
::
設定的方法只要
ADC_TempSensorVrefintCmd(ENABLE);
```c
ADC_TempSensorVrefintCmd(ENABLE);
```
- 其實做如下:
::
void ADC_TempSensorVrefintCmd(FunctionalState NewState)
{
```c
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;
}
{
/* 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);
}
}
{
/* Disable the temperature sensor and Vrefint channel*/
ADC->CCR &= (uint32_t)(~ADC_CCR_TSVREFE);
}
}
```
------------------------------
- 由於啟動Temperature Sensor需要時間(waking from power down mode),啟動ADC也需要時間(startup time after power-on),因此在設定時同時對兩個做設定才能達到最快的取樣速度。
使用Stm32F4xx的ADC
================
- 內建的溫度感測器適合用來測量溫度的變化,不適合用來得到精準的溫度值。
- ADC clock 來自 **PCLK2 (APB2)**, 啟動 ADC 前須先設置好。
ADC Temperature Measurement
============================
- AHB for 記憶體
::
- APB for 硬體周邊
```c
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
```
- ADC 可設 ADON 打開電源,重設來關掉電源
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_zDGlbVKfA1D_p.84729_1384161281907_adcon.jpeg)
- 版子上共有 **3 組ADC**, 可測量 **16 個外部訊號源**和 **2 個內部訊號源**。每個外部訊號源對應一個通道。
- 每個通道能自己設置不同的採樣時間,可根據不同的應用改變採樣時間。
- 總轉換時間即採樣時間加上 ADC core 等其他元件(ex:溫度感測器的讀取)所需時間。
- ADC 正式運作前必需做 calibration 以避免電容的狀態不是預期而造成誤差。
```c
ADC_ResetCalibration(ADC1);
```
----------------------------------
- 由於有多個ADC與多個通道,因此可以排列組合出非常多變化的運作模式。
## Sample Code
- 以下Sample Code為使用ADC最基本之設定
```c
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);
}
```
```c
/* --------------------------- 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](https://github.com/tim37021/STM32_ADC_Example/blob/demo_tim/discoveryF4/discovery_demo/main.c)
```c
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);
}
```
```c
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);
}
```
```c
void GPIO_Output_Config(void){
GPIO_InitTypeDef GPIO_InitStructure;
ConvertedVoltage = ConvertedValue*VDD/4095;
ConverTemp= ((((ConverValue*VDD)/4095)-V25)/Slope + 25;
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 );
}
```
```c
void GPIO_Input_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
.. image:: /embedded/ADC/formula.png
// 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
Demo、實驗
=========
ADC + GPIO
-----------
https://www.youtube.com/watch?v=0gAe-xRgk-k
[https://www.youtube.com/watch?v=0gAe-xRgk-k](https://www.youtube.com/watch?v=0gAe-xRgk-k)
![](/embedded/ADC/adc experiment.jpg)
- 本實驗使用電源供應器產生1.9V的電壓當作輸入訊號
- 將所量測到的電壓通過轉換,驗證ADC之轉換公式之正確性
ADC + GPIO + Temperature Sensor
--------------------------------
https://www.youtube.com/watch?v=gRxbnODggjc
[https://www.youtube.com/watch?v=gRxbnODggjc](https://www.youtube.com/watch?v=gRxbnODggjc)
- 本實驗用來測試stm32f4 discovery內建之溫度感測器是否隨著溫度上昇而改變轉換值
- 可以在影片中看到最左邊的led代表最小的bit,因此當溫度不斷升高,最後點亮了影片中最後亮起的右邊那個led燈
ADC + DAC
----------
基本設置:使用8bit模式已提升速度,使用DMA將ADC資料讀入後再用DMA將資料速給DAC做輸出。
![](https://farm8.staticflickr.com/7518/15679849349_048c02e0a8_h.jpg)
12bits vs 8 bits
-----------------
使用不同的解析度對同一訊號做採樣,在reduplicate。
ADC與DAC使用的resolution是相同的
- 1. 12bits
![](https://farm8.staticflickr.com/7566/15678517300_6c992cfc73_h.jpg)
- 2. 8 bits
![](https://farm8.staticflickr.com/7482/15678343048_fdbfc38df0_b.jpg)
Sampling Theorem、訊號 Aliasing
-------------------------------
同ADC + DAC的配置
控制訊號產生器生成的訊號頻率,當平率高過1 / 2 Fs 的時候,輸出訊號除了失真,還發生了頻率改變,已與原本訊號不同。
- 1. 使用手控至訊號
[http://youtu.be/QeFFO7ELrOk](http://youtu.be/QeFFO7ELrOk)
- 2. 使用訊號產生器的Sweep功能
[http://youtu.be/XtGuwkQhKzU](http://youtu.be/XtGuwkQhKzU)
- 3. 使用訊號產生器的Sweep功能(X-Y Plot)
[http://youtu.be/fE0UFiybtD4](http://youtu.be/fE0UFiybtD4)
※X-Y Plot功能是將示波器的兩桿輸入分別作為X與Y軸的量,有別於一般V-t的作圖,對於訊號最常使用在產生Lissajous曲線。
Lissajous曲線可以看出兩個訊號的頻率、相位、強度差異。
假設目前有 Asin(aw + d) 與 Bsin(bw)兩個訊號
當a = b時,頻率相同,所以圖形將會是直線、橢圓或是正圓,端看d大小,參考下圖。
![](http://upload.wikimedia.org/wikipedia/commons/thumb/1/12/Lissajous_phase.svg/600px-Lissajous_phase.svg.png)
如果兩個訊號頻率不同,a != b,則圖形將會是圖形將不再是圓,而會是曲線,由此可以看出兩個訊號已經不相同
如果a/b是有理數,則圖形會有一定的形式。若有示波器的圖,可以透過查表可以知道兩個訊號的的比例。
Questions 2015
==============
1. [Discontinuous mode] 這部分"以每批三個 (n=3), 通道為 {1, 2, 3, 4, 5, 6, 7, 8} 舉例",這個例子是說,在三個channel上各有不同的analog input嗎?還是他的意思是說有8個通道被使用?
- 沒錯,三個通道上各有不同輸入。
2. 因為只有三個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 暫存器設定)
```
3. [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不需要另外多取樣一次來完成,不曉得為何硬體需要這樣設計。
![](/embedded/ADC/embedded2015.hackpad.com_6Je0oGuYmLy_p.png)
- 從馬達的控制來看,PWM上的電晶體開開關關會產生雜訊,所以要讓ADC重新取樣確保值正確。而PWM示意圖如下
![](/embedded/ADC/hackpad.com_IVh4WmkEAIh_p.png)
![](/embedded/ADC/hackpad.com_IVh4WmkEAIh_p (1).png)
- 要計算PWM的時間要多長是藉由timer來控制,上圖的timer為5階。當timer數到我們所設定的值後就會將訊號往下拉直到一個週期結束。在這同時也會將這個timer做為觸發事件去告知ADC,這樣就可以同時計算完成也順便告知ADC這次的轉換可能是有問題的,重新再取樣一次。而不用關閉ADC,再重新啟動(這過程可能是非常耗時的)
從這裡看到PWM timer會更新trigger。
![](/embedded/ADC/hackpad.com_IVh4WmkEAIh_p (2).png)
4. [STM32F4xx OnChip ADC 介紹] 共有3個12-bit ADC 在開發板上,且可量測16個外部訊號源及2個內部訊號源。請問外部訊號源是例如溫度、壓力,那內部訊號源有什麼例子?
- 在STM32F4xx 上有一個內部的溫度senor,[STM32F407xx Reference Manual](http://measure.feld.cvut.cz/system/files/files/cs/vyuka/predmety/A4M38KRP/DM00031020.pdf) 中230頁有提到,兩個內部訊號源一個就是溫度訊號,一個是參考電壓
![](/embedded/ADC/embedded2015.hackpad.com_6Je0oGuYmLy_p (1).png)
5. [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](http://www.st.com/web/en/resource/technical/document/application_note/CD00258017.pdf),不過在這裡面沒有提到Injected simultaneous mode (這是在[STM32F407xx Reference Manual](http://measure.feld.cvut.cz/system/files/files/cs/vyuka/predmety/A4M38KRP/DM00031020.pdf)有提到)。
- 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會變大。
![](/embedded/ADC/embedded2015.hackpad.com_d3IVeuOQe5e_p.png)
- Alternate trigger mode
- 每一次的外部觸發後,某個ADC就會將設定的 injected group都轉換完
- 在fast interleaved mode 最快同一個通道要7 個cycle就取樣一次,而在這個模式下"不同通道"可以在1.5個ADC cycle的間隔就取樣一次
- 應用在馬達的控制上,PWM的duty cycle可以最大化,在最短時間內再次驅動馬達
6. alignment的時候要補SEXT,但不知道為甚麼只有injected group需要,regular group卻不用?
![](/embedded/ADC/embedded2015.hackpad.com_6Je0oGuYmLy_p.474217_1449153349985_Selection_007.png)
- 參考自[STM32F407xx Reference Manual](http://measure.feld.cvut.cz/system/files/files/cs/vyuka/predmety/A4M38KRP/DM00031020.pdf),在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可能會被設定要被減去某個值,所以要考慮負號的產生
7. 在 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](http://www.st.com/web/en/resource/technical/document/application_note/CD00211314.pdf)
- Alternate trigger mode ,在fast interleaved mode 最快同一個通道要7 個cycle就取樣一次,而在這個模式下"不同通道"可以在1.5個ADC cycle的間隔就取樣一次
8. [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
9. [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。
1. 說明如何決定取樣頻率,解釋 Nyquist–Shannon sampling theorem。
```
Nyquist–Shannon sampling theorem 說明了當取樣頻率為原訊號之最高頻率之兩倍時,才可以正確的重建原始訊號
```
- 2.說明當所要量測之輸入訊號電壓範圍不在adc之接受範圍時該如何處理?
- 證明:
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_FoYwIS8lBIN_p.84729_1386001249929_%E6%96%B0%E5%BB%BA%E6%AA%94%E6%A1%88%209_1.jpg)
2. 說明當所要量測之輸入訊號電壓範圍不在adc之接受範圍時該如何處理?
- 假設使用的ADC量測範圍是0~3V
- 如果超出範圍(EX:0~5V):使用分壓方式來降低電壓
- 如果超出範圍(EX:0~5V):
-對於直流訊號來說分壓電路是最簡單的降壓方式,但必須注意輸入阻抗與輸出阻抗之匹配問題。
- 1.對於直流訊號來說分壓電路是最簡單的降壓方式,但必須注意輸入阻抗與輸出阻抗之匹配問題。
-由於 STM32 之手冊上說明 ADC 之輸入阻抗約為10k 因此我們外接分壓之電阻必須選用較小之電阻。
- 由於 STM32 之手冊上說明 ADC 之輸入阻抗約為10k 因此我們外接分壓之電阻必須選用較小之電阻。
-有兩個電感的變壓電路是"交流變壓器"。
- 2.有兩個電感的變壓電路是"交流變壓器"。
-變壓器之使用條件為交流電,變壓器通常使用在高功耗之輸配電系統。
- 變壓器之使用條件為交流電,變壓器通常使用在高功耗之輸配電系統。
-如果需要將輸入訊號放大,則可以使用 OPA 之電路來做放大。
- 3.如果需要將輸入訊號放大,則可以使用 OPA 之電路來做放大。
```
其使用原理為利用 OPA 虛短路之特性來調整輸出電壓與輸入電壓之關係。
```
- 3.說明 ADC Block Diagram 之 Vrefint 與 TIM_TRGO 是什麼?
1.反相放大電路
- 4.說明 ADC 之 calibration。
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_FoYwIS8lBIN_p.84729_1385972297699_OPA1.jpg)
- 5.說明 ADC 之scanmode 與 DMA 之關係。並畫流程圖。
2.正相放大電路
- 6.說明如何利用電阻量測溫度?
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_FoYwIS8lBIN_p.84729_1385972307523_OPA2.jpg)
- 7.說明 EOC 等之術語。
- EOC 即 End of Conversion (為 Regular Group 結束轉換時產生之中斷)
3. 說明 ADC Block Diagram 之 Vrefint 與 TIM1_TRGO 是什麼?
- VREFINT:
- ADC之內部參考電壓
- 當 ScanConvMode Disable 時(也就是 Regular Group 只有一個channel),每次轉換結束都會產生 EOC 中斷。
- TIM1_TRGO:
-
- 當 ScanConvMode Enable 時,只有當所設定之 Regular Group 之最後一個 channel 完成轉換時才會產生 EOC。
4. 說明 ADC 之 calibration。
- 由於ADC上面的電容可能並不是理論上的理想值,因此每次使用時必須量測現在ADC之電容之實際值,可以把這個實際值視為誤差,因此未來所量測的結果都必須使用這個誤差值作為基準點去比較,因此可以量到更加精確的轉換結果。
- JEOC 為 Injected Group 結束轉換時產生之中斷。
```c
/* 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 才能開始使用 */
```
- AWD 為 analog watch dog 所產生之中斷。
------------------------------
5. 說明 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.
```
6. 說明測量溫度的方法
- 使用STM32內建的溫度感測器。
- 可以利用單一電阻的電阻會隨溫度上昇而增加電阻值來反推溫度。
- 電阻隨溫度呈現性上昇
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_FoYwIS8lBIN_p.84729_1386002201111_%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202013-12-03%20%E4%B8%8A%E5%8D%8812.35.27.png)
- 可利用上面之特性搭配 ADC 來做溫度量測
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_FoYwIS8lBIN_p.84729_1386003301130_%E6%96%B0%E5%BB%BA%E6%AA%94%E6%A1%88%2011_1%20(3).jpg)
7. 說明 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 所產生之中斷。
8. 說明為何 sample code 中的 DMA 使用 stream4 channel_0?
- 參考手冊表格如下:
![](https://dchtm6r471mui.cloudfront.net/hackpad.com_FoYwIS8lBIN_p.84729_1385977408698_%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202013-12-02%20%E4%B8%8B%E5%8D%885.42.48.png)
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 。
```
.. image:: /embedded/ADC/table7.jpg
![](/embedded/ADC/table7.jpg)
Refer from: STM32F407xx Datasheet P125
- 2. Bandwidth大小為多少?
- 3. 頻率響應為多少,可容忍的最大頻率呢?
在Datasheet中,因為我們參考電壓VDD為2.97V,故**Frequency為[0.6-36]MHz**。
.. image:: /embedded/ADC/table6.jpg
![](/embedded/ADC/table6.jpg)
Refer from: STM32F407xx Datasheet P124
- 4. 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...**。
.. image:: /embedded/ADC/22.JPG
![](/embedded/ADC/22.JPG)
`STM32F407xx Reference Manual<https://www.google.com.tw/url?sa=t&rct=j&q&esrc=s&source=web&cd=1&ved=0CCwQFjAA&url=http%3A%2F%2Fmeasure.feld.cvut.cz%2Fsystem%2Ffiles%2Ffiles%2Fcs%2Fvyuka%2Fpredmety%2FA4M38KRP%2FDM00031020.pdf&ei=Yd4tUrCbFIyZlQWy5IDAAw&usg=AFQjCNG98i1xkmhMAT5oY4owZfumzgq-3Q&sig2=BW3iz-5aJmyGhiu6HR32tA>`_ 參照P264 ADC block diagram
[STM32F407xx Reference Manual](https://www.google.com.tw/url?sa=t&rct=j&q&esrc=s&source=web&cd=1&ved=0CCwQFjAA&url=http%3A%2F%2Fmeasure.feld.cvut.cz%2Fsystem%2Ffiles%2Ffiles%2Fcs%2Fvyuka%2Fpredmety%2FA4M38KRP%2FDM00031020.pdf&ei=Yd4tUrCbFIyZlQWy5IDAAw&usg=AFQjCNG98i1xkmhMAT5oY4owZfumzgq-3Q&sig2=BW3iz-5aJmyGhiu6HR32tA) 參照P264 ADC block diagram
- 5. 測試的接法?
請參考Demo.
- 6. ADC的公式在哪裡找到?
`STM32F407xx Reference Manual<https://www.google.com.tw/url?sa=t&rct=j&q&esrc=s&source=web&cd=1&ved=0CCwQFjAA&url=http%3A%2F%2Fmeasure.feld.cvut.cz%2Fsystem%2Ffiles%2Ffiles%2Fcs%2Fvyuka%2Fpredmety%2FA4M38KRP%2FDM00031020.pdf&ei=Yd4tUrCbFIyZlQWy5IDAAw&usg=AFQjCNG98i1xkmhMAT5oY4owZfumzgq-3Q&sig2=BW3iz-5aJmyGhiu6HR32tA>`_ 在 10.10 Temperature sensor 中溫度轉換公式為
::
[STM32F407xx Reference Manual](https://www.google.com.tw/url?sa=t&rct=j&q&esrc=s&source=web&cd=1&ved=0CCwQFjAA&url=http%3A%2F%2Fmeasure.feld.cvut.cz%2Fsystem%2Ffiles%2Ffiles%2Fcs%2Fvyuka%2Fpredmety%2FA4M38KRP%2FDM00031020.pdf&ei=Yd4tUrCbFIyZlQWy5IDAAw&usg=AFQjCNG98i1xkmhMAT5oY4owZfumzgq-3Q&sig2=BW3iz-5aJmyGhiu6HR32tA) 在 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)
```
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)
```
- 7. 溫度的範圍?
`STM32F407xx Reference Manual<https://www.google.com.tw/url?sa=t&rct=j&q&esrc=s&source=web&cd=1&ved=0CCwQFjAA&url=http%3A%2F%2Fmeasure.feld.cvut.cz%2Fsystem%2Ffiles%2Ffiles%2Fcs%2Fvyuka%2Fpredmety%2FA4M38KRP%2FDM00031020.pdf&ei=Yd4tUrCbFIyZlQWy5IDAAw&usg=AFQjCNG98i1xkmhMAT5oY4owZfumzgq-3Q&sig2=BW3iz-5aJmyGhiu6HR32tA>`_ 在 10.10 Temperature sensor 中提到 Supported temperature range: –40 to 125 °C, Precision: ±1.5 °C。
[STM32F407xx Reference Manual](https://www.google.com.tw/url?sa=t&rct=j&q&esrc=s&source=web&cd=1&ved=0CCwQFjAA&url=http%3A%2F%2Fmeasure.feld.cvut.cz%2Fsystem%2Ffiles%2Ffiles%2Fcs%2Fvyuka%2Fpredmety%2FA4M38KRP%2FDM00031020.pdf&ei=Yd4tUrCbFIyZlQWy5IDAAw&usg=AFQjCNG98i1xkmhMAT5oY4owZfumzgq-3Q&sig2=BW3iz-5aJmyGhiu6HR32tA) 在 10.10 Temperature sensor 中提到 Supported temperature range: –40 to 125 °C, Precision: ±1.5 °C。
- 8. 當在測量輸出電壓時,三用電表在pin腳上量到的電壓大小與gdb上所取得到的值得誤差有多少?
- 9. 如何先做溫度上的校準?
利用內建溫度感測計在做實驗時,由於無法獨立出一個sensor出來測,所以實驗的環境下是在室溫的環境下,並利用溫度計來量測室溫為多少,來比對板子上所抓到的溫度與溫度計上的溫度.
補:
`STM32F407xx Reference Manual<https://www.google.com.tw/url?sa=t&rct=j&q&esrc=s&source=web&cd=1&ved=0CCwQFjAA&url=http%3A%2F%2Fmeasure.feld.cvut.cz%2Fsystem%2Ffiles%2Ffiles%2Fcs%2Fvyuka%2Fpredmety%2FA4M38KRP%2FDM00031020.pdf&ei=Yd4tUrCbFIyZlQWy5IDAAw&usg=AFQjCNG98i1xkmhMAT5oY4owZfumzgq-3Q&sig2=BW3iz-5aJmyGhiu6HR32tA>`_ 在 10.10 Temperature sensor 中一張中的Note提到,此開發版的內部溫度感測器適合來偵測溫度的變化,依據溫度感測公式來看,是基於25°C下與offset得到的溫度值,也就是適合觀察溫度變化,並不適合來取得室溫上的絕對溫度. 所以若要測量精確的絕對溫度的話,Manual上建議外接溫度感測器較為合適.
[STM32F407xx Reference Manual](https://www.google.com.tw/url?sa=t&rct=j&q&esrc=s&source=web&cd=1&ved=0CCwQFjAA&url=http%3A%2F%2Fmeasure.feld.cvut.cz%2Fsystem%2Ffiles%2Ffiles%2Fcs%2Fvyuka%2Fpredmety%2FA4M38KRP%2FDM00031020.pdf&ei=Yd4tUrCbFIyZlQWy5IDAAw&usg=AFQjCNG98i1xkmhMAT5oY4owZfumzgq-3Q&sig2=BW3iz-5aJmyGhiu6HR32tA) 在 10.10 Temperature sensor 中一張中的Note提到,此開發版的內部溫度感測器適合來偵測溫度的變化,依據溫度感測公式來看,是基於25°C下與offset得到的溫度值,也就是適合觀察溫度變化,並不適合來取得室溫上的絕對溫度. 所以若要測量精確的絕對溫度的話,Manual上建議外接溫度感測器較為合適.
- 10. 整個程式上的架構為如何?
一開始程式先初始化ADC會用到的硬體資源,其中包含Interrupt、ADC、DMA的初始,之後將ADC的TASK註冊到freertos裡面,Task中是做了DMA所註冊的通道與NVIC的channel設定,而當中我們註冊了 DMA_Stream0_IRQHandler(void),此Interrupt handler會在每次資料由peripheral到memory傳完之後,產生DMA的interrupt,去更新溫度值或電壓值.
詳細的設定請參考下方的Sample code
- Structure
.. code-block:: prettyprint
int main()
{
prvSetupHardware();
xTaskCreate(vADC_DMATask, .., .., .., ..);
vTaskStartScheduler();
}
```c
int main()
{
prvSetupHardware();
xTaskCreate(vADC_DMATask, .., .., .., ..);
vTaskStartScheduler();
}
```
- 11. 如何選擇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 )
```
- 12. 若想要取得其他外部Sensor的Anolog值,要如何取得?
利用GPIO,設定要接出的Pin腳,並連接至外部訊號上。
- 13. 頻率除以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。
- 14. ExternalTrigConvEdge和ExternalTrigConv是甚麼?觸發又是在幹嘛?
分別為以下︰
- 1.ExternalTrigConvEdge
.. image:: /embedded/ADC/table9.jpg
![](/embedded/ADC/table9.jpg)
- 2.ExternalTrigConv
.. image:: /embedded/ADC/table10.jpg
![](/embedded/ADC/table10.jpg)
- 15. DMA跟ADC之間是在幹嘛的?
規則通道轉換後的數值儲存在一個唯一的暫存器中,所以當轉換多個規則通道時需要使用DMA,用來避免遺失已經儲存在ADC_DR暫存器的數據。
只有在規則通道轉換結束後才能產生DMA的請求,並且將轉換後的數據從ADC_DR的暫存器傳輸到用戶指定的目的地位址。
- 16. 為什麼要設定DMA,照我們我的作法是跑迴圈的方式去polling溫度的值?要做DMA的話會花幾個cycle?
- 17. DMA_Mode_Circulur這mode在做甚麼用?
主要用來處理circular buffers和連續的data flow(像是ADC的scan mode)。
當此模式啟動時,會將要傳送的資料載入在stream config所設定的初始值,且DMA request會持續服務。
- 18. DMA2_Stream0是甚麼?為什麼是以Stream的方式?
DMA Stream 提供了一個source to destination的單方向傳輸的連結,像是周邊到記憶體或是記憶體到周邊。
- 19. 用while loop可能會取得錯誤的值,也可能會浪費資源?
- 20. 溫度的sampling rate設成20MHz會不會太高,或許1KHz會差不多,開發程式中要call api時,config中值是否可參數化?
溫度的Sample Time是經由公式計算出,無法設定,Datasheet有提供公式,需要設定是Sample Time必須大於取樣時間的MAX值,
您的問題應該是Sampling Rate(取樣頻率),就根據使用者需求來設定轉換模式,並算出轉換頻率。
.. image:: /embedded/ADC/table8.jpg
Sample Code
===========
https://github.com/tim37021/STM32_ADC_Example/blob/demo_tim/discoveryF4/discovery_demo/main.c
::
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);
![](/embedded/ADC/table8.jpg)
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);
}
Reference
=========
- `Analog-to-digital converter - Wikipedia, the free encyclopedia<http://en.wikipedia.org/wiki/Analog-to-digital_converter>`_
- [Analog-to-digital converter - Wikipedia, the free encyclopedia](http://en.wikipedia.org/wiki/Analog-to-digital_converter)
- `稀里糊塗學 STM32 - 第四講:白駒過隙</embedded/learn-stm32-part-4.pdf>`_
- [稀里糊塗學 STM32 - 第四講:白駒過隙](/embedded/learn-stm32-part-4.pdf)
- `STM32F407xx Datasheet<http://www.st.com/web/en/resource/technical/document/datasheet/DM00037051.pdf >`_
- [STM32F407xx Datasheet](http://www.st.com/web/en/resource/technical/document/datasheet/DM00037051.pdf )
- `STM32F407xx Reference Manual<https://www.google.com.tw/url?sa=t&rct=j&q&esrc=s&source=web&cd=1&ved=0CCwQFjAA&url=http%3A%2F%2Fmeasure.feld.cvut.cz%2Fsystem%2Ffiles%2Ffiles%2Fcs%2Fvyuka%2Fpredmety%2FA4M38KRP%2FDM00031020.pdf&ei=Yd4tUrCbFIyZlQWy5IDAAw&usg=AFQjCNG98i1xkmhMAT5oY4owZfumzgq-3Q&sig2=BW3iz-5aJmyGhiu6HR32tA>`_
- [STM32F407xx Reference Manual](https://www.google.com.tw/url?sa=t&rct=j&q&esrc=s&source=web&cd=1&ved=0CCwQFjAA&url=http%3A%2F%2Fmeasure.feld.cvut.cz%2Fsystem%2Ffiles%2Ffiles%2Fcs%2Fvyuka%2Fpredmety%2FA4M38KRP%2FDM00031020.pdf&ei=Yd4tUrCbFIyZlQWy5IDAAw&usg=AFQjCNG98i1xkmhMAT5oY4owZfumzgq-3Q&sig2=BW3iz-5aJmyGhiu6HR32tA)
- `STM32™’s ADC modes and their applications<http://www.st.com/st-web-ui/static/active/cn/resource/technical/document/application_note/CD00258017.pdf>`_
- [STM32™’s ADC modes and their applications](http://www.st.com/st-web-ui/static/active/cn/resource/technical/document/application_note/CD00258017.pdf)
- `stm32學習筆記<http://blog.csdn.net/fouder_li/article/details/6718884>`_
- [stm32學習筆記](http://blog.csdn.net/fouder_li/article/details/6718884)
- `PCM Introdution<http://www.fiberoptics4sale.com/wordpress/what-is-pulse-code-modulation-pcm/>`_
- [PCM Introdution](http://www.fiberoptics4sale.com/wordpress/what-is-pulse-code-modulation-pcm/)
- `頻寬與取樣速率<http://www.ni.com/white-paper/2709/zht/>`_
- [頻寬與取樣速率](http://www.ni.com/white-paper/2709/zht/)
共筆
=========
- `Hackpad link<https://embeddedsystemstudy.hackpad.com/ADC-zDGlbVKfA1D>`_
- [Hackpad link](https://embeddedsystemstudy.hackpad.com/ADC-zDGlbVKfA1D)