完整教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980
第76章 STM32H7的FMC總線應用之驅動AD7606(8通道同步采樣, 16bit, 正負10V)
本章節為大家講解FMC總線驅動數模轉換器AD7606,實戰性較強。
76.1 初學者重要提示
76.2 ADC結構分類
76.3 AD7606硬件設計
76.4 AD7606關鍵知識點整理(重要)
76.5 AD7606的FMC接口硬件設計
76.6 AD7606的FMC接口驅動設計
76.7 AD7606板級支持包(bsp_fmc_ad7606)
76.8 J-Scope實時展示AD7606采集數據說明
76.9 AD7606驅動移植和使用
76.10 實驗例程設計框架
76.11 實驗例程說明(MDK)
76.12 實驗例程說明(IAR)
76.13 總結
76.1 初學者重要提示
- 學習本章節前,務必優先學習第47章,了解FMC總線的基礎知識。
- AD7606 的配置很簡單,它沒有內部寄存器,量程范圍和過采樣參數是通過外部IO控制的,采樣速率由MCU或DSP提供的脈沖頻率控制。
- AD7606必須使用單5V供電。而AD7606和MCU之間的通信接口電平由VIO(VDRIVE)引腳控制。也就是說VIO必須接單片機的電源,可以是3.3V也可以是5V(范圍2.3V – 5V)。
- 正確的理解過采樣,比如我們設置是1Ksps采樣率,64倍過采樣。意思是指每次采樣,AD7606會采樣64次數據並求平均,相當於AD7606以64Ksps進行采樣的,只是將每64個采樣點的值做了平均,用戶得到的值就是平均后的數值。因此,如果使用AD7606最高的200Ksps采樣率,就不可以使用過采樣了。
- STM32H7驅動AD7606配合J-Scope實時輸出,效果絕了,堪比示波器http://www.armbbs.cn/forum.php?mod=viewthread&tid=97393 。使用方法詳解本章節77.8小節。
- 本章配套例子的串口數據展示推薦使用SecureCRT,因為數據展示做了特別處理,方便采集數據在串口軟件同一個位置不斷刷新。
- AD7606數據手冊,模塊原理圖(通用版)和接線圖都已經放到本章教程配置例子的Doc文件里。
- ADC 的專業術語詮釋文檔,推薦大家看看:http://www.armbbs.cn/forum.php?mod=viewthread&tid=89414 。
- 測試本章配套例子前重要提示:
-
- 測試時,務必使用外置電源為開發板供電,因為AD7606需要5V供電電壓。板子上插入AD7606模塊時,注意對齊。
- 板子上電后,默認是軟件定時采集,0.5秒一次,適合串口展示數據。
- 如果需要使用J-Scope實時展示采集的波形效果,需要按下K2按鍵切換到FIFO模式。
- 如果使用的JLINK速度不夠快,導致J-Scope無法最高速度實時上傳,可以使用搖桿上下鍵設置過采樣來降低上傳速度。
- 默認情況下,程序僅上傳了AD7606通道1采集的數據。
76.2 ADC結構分類
這里將六種DAC結構為大家做個普及。注,這些知識翻譯自美信和TI的英文技術手冊。
76.2.1 SAR ADC(逐次逼近型)
逐次逼近型ADC通常是中高分辨率的首選架構,采樣速率通常低於5Msps。SAR ADC最常見的分辨率范圍是8位到20位,並具有低功耗和小尺寸的特點。這種組合使其非常適合各種應用,例如自動測試設備,電池供電的設備,數據采集系統,醫療儀器,電機和過程控制,工業自動化,電信,測試和測量,便攜式系統,高速閉環系統和窄帶接收器。
76.2.2 Sigma-Delta ADC
Sigma-delta ADC主要用於低速應用中,該應用需要通過過采樣來權衡速度和分辨率,然后進行濾波以降低噪聲。24位sigma-delta轉換器用於自動化測試設備,高精度便攜式傳感器,醫療和科學儀器以及地震數據采集等應用中。
76.2.3 Integrating ADC
集成ADC提供高分辨率,並且可以提供良好的線路頻率和噪聲抑制。集成架構提供了一種新穎且直接的方法,可將低帶寬模擬信號轉換為數字表示形式。這些類型的轉換器通常包括用於LCD或LED顯示器的內置驅動器,並且在許多便攜式儀器應用中都可以找到,包括數字面板表和數字萬用表。
76.2.4 FLASH ADC
Flash ADC是將模擬信號轉換為數字信號的最快方法。它們適用於需要非常大帶寬的應用。然而,閃存轉換器功率高,具有相對較低的分辨率,並且可能非常昂貴。這將它們限制在通常無法以其他任何方式解決的高頻應用中。示例包括數據采集,衛星通信,雷達處理,示波器和高密度磁盤驅動器。
76.2.5 Pipelined ADC
流水線ADC已成為最受歡迎的ADC體系結構,其采樣率從每秒幾兆采樣(MS / s)到最高100MS / s +,分辨率為8至16位。它們提供的分辨率和采樣率,可覆蓋各種應用,包括CCD成像,超聲醫學成像,數字接收器,基站,數字視頻(例如HDTV),xDSL,電纜調制解調器和快速以太網。
76.2.6 Two Step ADC
兩步ADC也稱為子范圍轉換器,有時也稱為多步或half flash(比Flash架構慢)。這是Flash ADC和流水線ADC的交叉點。與Flash ADC相比,可以實現更高的分辨率或更小的裸片尺寸。
76.3 AD7606硬件設計
這里將開發板上的AD7606硬件接口,普通型AD7606模塊,屏蔽型AD7606模塊和磁耦高速隔離型AD7606模塊為大家做個說明。
AD7606的原理圖下載:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=97547 。
76.3.1 AD7606硬件接口
V7板子上AD7606模塊的插座的原理圖如下:
實際對應開發板的位置如下:
為了方便大家更好的理解接線,下面是框圖:
模塊引腳說明:
- OS2 OS1 OS2 :
組合狀態選擇過采樣模式。
-
- 000表示無過采樣,最大200Ksps采樣速率。
- 001表示2倍過采樣, 也就是硬件內部采集2個樣本求平均。
- 010表示4倍過采樣, 也就是硬件內部采集4個樣本求平均。
- 011表示8倍過采樣, 也就是硬件內部采集8個樣本求平均。
- 100表示16倍過采樣, 也就是硬件內部采集16個樣本求平均。
- 101表示32倍過采樣, 也就是硬件內部采集32個樣本求平均。
- 110表示64倍過采樣, 也就是硬件內部采集64個樣本求平均。
過采樣倍率越高,ADC轉換時間越長,可得到的最大采樣頻率就越低。
- CVA,CVB :
啟動AD轉換的控制信號。CVA決定1-4通道,CVB決定5-8通道。2個信號可以錯開短暫的時間。一般情況可以將CVA,CVB並聯在一起。
- RAGE :
量程范圍選擇。0表示正負5V, 1表示正負10V。
- RD :
讀信號。
- RST :
復位信號。
- BUSY :
忙信號。
- CS :
片選信號。
- FRST :
第1個通道樣本的指示信號。【注,此引腳可以省略不使用】
- VIO :
通信接口電平。
- DB0-DB15 :
數據總線。
如果采用SPI接口方式,接線框圖如下:
76.3.2 AD7606模塊(通用版)
產品規格:
1、 16bit分辨率,內置基准,單5V供電。
2、 8路模擬輸入,阻抗1M歐姆。【無需負電源,無需前端模擬運放電路,可直接接傳感器輸出】
3、 輸入范圍可以選擇正負5V或者正負10V,可通過IO控制量程。
4、 最大采樣頻率 200Ksps,支持8檔過采樣設置(可以有效降低抖動)。
5、 通信接口支持SPI或16位總線方式(也支持8位總線,一般用的比較少),接口IO電平可以是5V或3.3V。
重要提示:
1、 AD7606的配置很簡單,它沒有內部寄存器。量程范圍和過采樣參數是通過外部IO控制的。采樣速率由MCU或DSP提供的脈沖頻率控制。
2、 AD7606必須使用單5V供電。
3、 AD7606和MCU之間的通信接口電平由VIO(VDRIVE)引腳控制。也就是說VIO必須接單片機的電源,可以是3.3V也可以是5V。
產品效果:
8080或者SPI接口方式選擇
出廠的AD7606模塊缺省是8080並行接口,如果用SPI接口模式,需要修改R1、R2電阻配置。
並口模式跳線:R1 懸空(不貼),R2貼10K電阻。
SPI接口模式跳線:R1 貼10K電阻,R2 懸空(不貼)。
76.3.3 AD7606模塊(屏蔽版)
屏蔽版主要是為了更好的應對復雜的電磁工作,軟件代碼與非屏蔽版是一樣的:
76.3.4 AD7606模塊(磁耦高速隔離)
該款ADC模塊采用磁耦隔離技術隔離SPI通信接口,采用DC-DC隔離電源模塊隔離供電電源。高速SPI接口,ADC主芯片采用AD7606芯片。8通道200KHz采樣。量程和濾波設置通過短路焊點設置。
產品規格
模擬通道 : 8路同步采集。
采樣頻率 : 最大200KHz。
ADC分辨率 : 16bit。
輸入量程 : 正負5V或正負10V (通過焊點切換)。
濾波設置 : 0 - 64 共7級硬件均值濾波。
供電電壓 : 5.0V, 耗電最大50mA。
通信接口 : SPI,最大時鍾頻率 16MHz。
接口電平 : 3.3V 或 5V (3.3V時,耗電15mA)。
產品特點
1、電源隔離,隔離電壓1500V。
2、SPI通信接口隔離,高速磁耦隔離技術。
3、短路點切換量程和過采樣(濾波)參數。
4、體積小,2.0mm間距排針,節約主板面積。
產品效果:
引腳定義和接線圖:
76.4 AD7606關鍵知識點整理(重要)
驅動AD7606需要對下面這些知識點有個認識。
76.4.1 AD7606基礎信息
- 支持8通道同步采樣,每個通道最高200Ksps,16bit分辨率。
- 真雙極模擬輸入范圍:±10V、±5V。
- 5V單模擬電源,VDRIVER支持2.3V到5V。
- 完全集成的數據采集解決方案:
- 模擬輸入鉗位保護,可以耐受±16.5V的電壓。
- 具有1MΩ模擬輸入阻抗的輸入緩沖器。
- 二階抗混疊模擬濾波器。
- 片內精密基准電壓及緩沖。
- 通過數字濾波器,提供過采樣功能。
- 靈活的並行/串行即可,支持SPI/QSPI/MICROWIRE/DSP等。
- 性能
- 模擬輸入通道提供7KV ESD。
- 95.5dB SNR,-107dB THD,±0.5 LSB INL,±0.5 LSB DNL。
- 低功耗:100mW。
- 待機功耗:25mW。
76.4.2 AD7606常用引腳的作用
AD7606的封裝形式:
這里把常用的幾個引腳做個說明:
- AVcc
模擬電源電壓,4.75V到5.25V。這是內部前端放大器和ADC內核的電源電壓。應將這些電壓引腳去偶接AGND。
- AGND
模擬地,這些引腳是AD7606上所有模擬電路的接地基准點。所有模擬輸入信號和外部基准信號都應參考這些引腳。
- OS2 OS1 OS2 :
組合狀態選擇過采樣模式。
-
- 000表示無過采樣,最大200Ksps采樣速率。
- 001表示2倍過采樣, 也就是硬件內部采集2個樣本求平均。
- 010表示4倍過采樣, 也就是硬件內部采集4個樣本求平均。
- 011表示8倍過采樣, 也就是硬件內部采集8個樣本求平均。
- 100表示16倍過采樣, 也就是硬件內部采集16個樣本求平均。
- 101表示32倍過采樣, 也就是硬件內部采集32個樣本求平均。
- 110表示64倍過采樣, 也就是硬件內部采集64個樣本求平均。
過采樣倍率越高,ADC轉換時間越長,可得到的最大采樣頻率就越低。
- CONVSTA,CONVSTB :
啟動AD轉換的控制信號。CONVSTA決定1-4通道,CONVSTB決定5-8通道。2個信號可以錯開短暫的時間。一般情況可以將CVA,CVB並聯在一起。
- RAGE :
量程范圍選擇。0表示正負5V, 1表示正負10V.
- RD /SCL:
讀信號,低電平有效。
- RESET
復位信號。
- BUSY :
CONVST A和CONVST B均達到上升沿后,此引腳變為邏輯高電平,表示轉換過程已經開始,BUSY輸出保持高電平,直到所有通道的轉換過程完成為止。BUSY下降沿表示轉換數據正被鎖存至輸出數據寄存器,此時用戶就可以讀取數據。
- CS :
片選信號,低電平有效。
- FRST :
第1個通道樣本的指示信號。【注,此引腳可以省略不使用】
- VDriver:
通信接口電平。
- DB0-DB15 :
數據總線。
- REF SELECT
內部/外部基准電壓選擇。如果設置此引腳設為邏輯高電平,使用內部基准電壓。如果此引腳設為邏輯低電平,則內部基准電壓禁止,必須將外部基准電壓加到REFIN/REFOUT引腳。
- REFIN/REFOUT
基准電壓輸入(REFIN)/基准電壓輸出(REFOUT)引腳,如果REF SELECT引腳設置為邏輯高電平,此引腳將提供2.5V片內基准電壓供外部使用。或者可以將REF SELECT引腳設置為邏輯低電平將禁止用內部基准電壓。
- V1到V8
模擬輸入,此引腳為單端模擬輸入,此通道的模擬輸入范圍由RANGE引腳決定。
- V1GND到V8GND
模擬輸入接地引腳,這些引腳與模擬輸入引腳V1到V8對應,所有模擬輸入AGND引腳都應連接到系統的AGND平面。
76.4.3 AD7606輸出電壓計算公式
AD7606的計算公式如下:
采用二進制補碼(其實就是16bit有符號數,將轉換結果定義為int16_t即可),因為AD7606支持正負壓采集。
- VIN
AD7606采集到的電壓值范圍-32768到32767。
- REF
一般使用內部基准,即2.5V。
76.4.4 AD7606時序圖
了解時序參數是驅動AD7606能否成功的關鍵,我們這里對幾個重要的參數做個說明。
1、AD7606的CONVST轉換時序(轉換之后讀取數據):
- t5
CONVST A和CONVST B上升沿之間最大允許的延遲時間。一般我們是用一根控制線同時控制CONVST A和CONVST B,因此可以不用管這個時間。
- tCYCLE
並行模式,轉換后並讀取數據的最大值是5us,即最高支持的時鍾速度是20MHz及其以上。
- tCONV
轉換時間。
- t3
最短的CONVST A/B電平脈沖,最小值25ns。
- t4
BUSY下降沿到CS下降沿設置時間,最小值0ns,所以可以忽略。
2、AD7606的並行驅動模式有兩種時序圖,一個是獨立的CS片選和RD讀信號時序圖:
- t8
CS到RD的設置時間,最小值是0ns,可以忽略。
- t10
RD讀信號的低電平脈沖寬度,通信電壓不同,時間不同。對於STM32來說,FMC通信電平一般是3.3V,即最小值21ns。
- t11
RD高電平脈沖寬度,最小值15ns。
- t9
CS到RD保持時間,最小值0ns,可以忽略。
- 13到t17
這幾個參數了解下即可:
3、另一個是CS片選和RD相連的方式:
這個時序里面最重要的是t12。
- t12
CS和RD的高電平脈沖寬度,最小值22ns。
第2個和第3個時序圖的主要區別是連續讀取8路數據時,一個CS信號是全程低電平,另一個CS信號是與RD信號同步,每讀取完一路,拉高一次。
76.4.5 AD7606的過采樣
使用過采樣可以改善SNR信噪比。SNR性能隨着過采樣倍率提高而改善,具體參數如下:
通過這個表,我們可以方便的了解不同過采樣下的信噪比,3dB帶寬時的頻率和最高支持的采樣率。
注意正確的理解過采樣,比如我們設置是1Ksps采樣率,64倍過采樣。意思是指每次采樣,AD7606會采樣64次數據並求平均,相當於AD7606以64Ksps進行采樣的,只是將每64個采樣點的值做了平均,用戶得到的值就是平均后的數值。因此,如果使用AD7606最高的200Ksps采樣率,就不可以使用過采樣了。
76.5 AD7606的FMC接口硬件設計
FMC硬件接口涉及到的知識點稍多,下面逐一為大家做個說明。
76.5.1 FMC的塊區分配
FMC總線可操作的地址范圍0x60000000到0xDFFFFFFF,具體的框圖如下:
從上面的框圖可以看出,NOR/PSRAM/SRAM塊區有4個片選NE1,NE2,NE3和NE4,但由於引腳復用,部分片選對應的引腳要用於其他功能,而且要控制的總線外設較多,導致片選不夠用。因此需要增加譯碼器。
76.5.2 譯碼器及其地址計算
有了前面的認識之后再來看下面的譯碼器電路:
SN74LVC1G139APWR是雙2-4線地址譯碼器,也就是帶了兩個譯碼器。原理圖上僅用了一個。下面是139的真值表和引腳功能:
通過上面的原理圖和真值表就比較好理解了,真值表的輸出是由片選FMC_NE1和地址線FMC_A10、FMC_A11控制。
FMC_NE1 輸出低電平:
- FMC_A11(B),FMC_A10(A) = 00時,1Y0輸出的低電平,選擇的是OLED。
- FMC_A11(B),FMC_A10(A) = 01時,1Y1輸出的低電平,選擇的是74HC574。
- FMC_A11(B),FMC_A10(A) = 10時,1Y2輸出的低電平,選擇的是DM9000。
- FMC_A11(B),FMC_A10(A) = 11時,1Y3輸出的低電平,選擇的是AD7606。
然后我們再計算譯碼器的地址,注意,這里地址的計算都是按照FMC的32bit訪問模式計算的,因為我們的V7程序中是將NE1對應的FMC配置為32bit模式了。
具體FMC的32bit訪問模式,16bit訪問模式和8bit訪問模式的區別在第47章的2.4小節有詳細講解。
32bit模式下,我們計算A10和A11的時候,實際上需要按HADDR12和HADDR13計算的。
如果來算NE1 + HADDR12 + HADDR13的四種組合地址就是如下:
NE1 + HADDR13 + HADDR12 = 0x60000000 + 0<<13 + 0<<12 = 0x60000000
NE1 + HADDR13 + HADDR12 = 0x60000000 + 0<<13 + 1<<12 = 0x60001000
NE1 + HADDR13 + HADDR12 = 0x60000000 + 1<<13 + 0<<12 = 0x60002000
NE1 + HADDR13 + HADDR12 = 0x60000000 + 1<<13 + 1<<12 = 0x60003000
這樣一來,原理圖里面給的地址就對應上了。同理如果配置為16位模式和8位模式,大家應該也都會計算了。
76.6 AD7606的FMC接口驅動設計
AD7606的程序驅動框架設計如下:
有了這個框圖,程序設計就比較好理解了。
76.6.1 第1步,AD7606整體驅動框架設計
主要實現了兩種采集方式:
(1)軟件定時獲取方式,適合低速查詢獲取。
(2)FIFO工作模式,適合8路實時采集,支持最高采樣率200Ksps。
- 方案一:軟件定時獲取方式代碼框架:
可以在硬件定時器中斷服務程序或者軟件定時器里面實現。
定時器中斷ISR: { 中斷入口; 讀取8個通道的采樣結果保存到RAM; ----> 讀取的是上次的采集結果,對於連續采集來說,是沒有關系的 啟動下次ADC采集;(翻轉CVA和CVB) 中斷返回; }
定時器的頻率就是ADC采樣頻率。這種模式可以不連接BUSY口線。
- 方案二:FIFO工作模式框架:
配置CVA、CVB引腳為PWM輸出模式,周期設置為需要的采樣頻率,之后MCU將產生周期非常穩定的AD轉換信號
將BUSY口線設置為中斷下降沿觸發模式;
外部中斷ISR:
{
中斷入口;
讀取8個通道的采樣結果保存到RAM;
}
- 方案1和方案2的差異
(1)方案1 可以少用 BUSY口線,但是其他中斷服務程序或者主程序臨時關閉全局中斷時,可能導致ADC轉換周期存在輕微抖動。
(2)方案2 可以確保采集時鍾的穩定性,因為它是MCU硬件產生的,但是需要多接一根BUSY口線。
76.6.2 第2步,AD7606所涉及到的GPIO配置
這里需要把用到的GPIO時鍾、FMC時鍾、GPIO引腳和復用配置好即可:
/* ********************************************************************************************************* * 函 數 名: AD7606_CtrlLinesConfig * 功能說明: 配置GPIO口線,FMC管腳設置為復用功能 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ /* 安富萊STM32-H7開發板接線方法:4片74HC574掛在FMC 32位總線上。1個地址端口可以擴展出32個IO PD0/FMC_D2 PD1/FMC_D3 PD4/FMC_NOE ---- 讀控制信號,OE = Output Enable , N 表示低有效 PD5/FMC_NWE -XX- 寫控制信號,AD7606 只有讀,無寫信號 PD8/FMC_D13 PD9/FMC_D14 PD10/FMC_D15 PD14/FMC_D0 PD15/FMC_D1 PE7/FMC_D4 PE8/FMC_D5 PE9/FMC_D6 PE10/FMC_D7 PE11/FMC_D8 PE12/FMC_D9 PE13/FMC_D10 PE14/FMC_D11 PE15/FMC_D12 PG0/FMC_A10 --- 和主片選FMC_NE2一起譯碼 PG1/FMC_A11 --- 和主片選FMC_NE2一起譯碼 PD7/FMC_NE1 --- 主片選(OLED, 74HC574, DM9000, AD7606) +-------------------+------------------+ + 32-bits Mode: D31-D16 + +-------------------+------------------+ | PH8 <-> FMC_D16 | PI0 <-> FMC_D24 | | PH9 <-> FMC_D17 | PI1 <-> FMC_D25 | | PH10 <-> FMC_D18 | PI2 <-> FMC_D26 | | PH11 <-> FMC_D19 | PI3 <-> FMC_D27 | | PH12 <-> FMC_D20 | PI6 <-> FMC_D28 | | PH13 <-> FMC_D21 | PI7 <-> FMC_D29 | | PH14 <-> FMC_D22 | PI9 <-> FMC_D30 | | PH15 <-> FMC_D23 | PI10 <-> FMC_D31 | +------------------+-------------------+ */ /* 控制AD7606參數的其他IO分配在擴展的74HC574上 X13 - AD7606_OS0 X14 - AD7606_OS1 X15 - AD7606_OS2 X24 - AD7606_RESET X25 - AD7606_RAGE PE5 - AD7606_BUSY */ static void AD7606_CtrlLinesConfig(void) { /* bsp_fm_io 已配置fmc,bsp_InitExtIO(); 此處可以不必重復配置 */ GPIO_InitTypeDef gpio_init_structure; /* 使能 GPIO時鍾 */ __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOI_CLK_ENABLE(); /* 使能FMC時鍾 */ __HAL_RCC_FMC_CLK_ENABLE(); /* 設置 GPIOD 相關的IO為復用推挽輸出 */ gpio_init_structure.Mode = GPIO_MODE_AF_PP; gpio_init_structure.Pull = GPIO_PULLUP; gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; gpio_init_structure.Alternate = GPIO_AF12_FMC; /* 配置GPIOD */ gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15; HAL_GPIO_Init(GPIOD, &gpio_init_structure); /* 配置GPIOE */ gpio_init_structure.Pin = 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; HAL_GPIO_Init(GPIOE, &gpio_init_structure); /* 配置GPIOG */ gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1; HAL_GPIO_Init(GPIOG, &gpio_init_structure); /* 配置GPIOH */ gpio_init_structure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; HAL_GPIO_Init(GPIOH, &gpio_init_structure); /* 配置GPIOI */ gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10; HAL_GPIO_Init(GPIOI, &gpio_init_structure); /* 配置BUSY引腳,默認是普通IO狀態 */ { GPIO_InitTypeDef GPIO_InitStructure; __HAL_RCC_SYSCFG_CLK_ENABLE(); BUSY_RCC_GPIO_CLK_ENABLE(); /* 打開GPIO時鍾 */ /* BUSY信號,使用的PE5,用於轉換完畢檢測 */ GPIO_InitStructure.Mode = GPIO_MODE_INPUT; /* 設置推挽輸出 */ GPIO_InitStructure.Pull = GPIO_NOPULL; /* 無上拉下拉 */ GPIO_InitStructure.Pin = BUSY_PIN; HAL_GPIO_Init(BUSY_GPIO, &GPIO_InitStructure); } /* CONVST 啟動ADC轉換的GPIO = PC6 */ { GPIO_InitTypeDef GPIO_InitStructure; CONVST_RCC_GPIO_CLK_ENABLE(); /* 配置PC6 */ GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; /* 設置推挽輸出 */ GPIO_InitStructure.Pull = GPIO_NOPULL; /* 上下拉電阻不使能 */ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM; /* GPIO速度等級 */ GPIO_InitStructure.Pin = CONVST_PIN; HAL_GPIO_Init(CONVST_GPIO, &GPIO_InitStructure); } }
這里重點注意AD7606_CONVST和AD7606_BUSY引腳,上電后的默認配置是普通IO。另外還有過采樣的3個引腳,量程配置的1個引腳和復位控制的1個引腳,均通過V7板子的擴展IO實現:
/* 設置過采樣的IO, 在擴展的74HC574上 */ #define OS0_1() HC574_SetPin(AD7606_OS0, 1) #define OS0_0() HC574_SetPin(AD7606_OS0, 0) #define OS1_1() HC574_SetPin(AD7606_OS1, 1) #define OS1_0() HC574_SetPin(AD7606_OS1, 0) #define OS2_1() HC574_SetPin(AD7606_OS2, 1) #define OS2_0() HC574_SetPin(AD7606_OS2, 0) /* 設置輸入量程的GPIO, 在擴展的74HC574上 */ #define RANGE_1() HC574_SetPin(AD7606_RANGE, 1) #define RANGE_0() HC574_SetPin(AD7606_RANGE, 0) /* AD7606復位口線, 在擴展的74HC574上 */ #define RESET_1() HC574_SetPin(AD7606_RESET, 1) #define RESET_0() HC574_SetPin(AD7606_RESET, 0)
76.6.3 第3步,FMC的時鍾源選擇
使用FMC可以選擇如下幾種時鍾源HCLK3,PLL1Q,PLL2R和PER_CK:
我們這里直接使用HCLK3,配置STM32H7的主頻為400MHz的時候,HCLK3輸出的200MHz,這個速度是FMC支持的最高時鍾,正好用於這里:
76.6.4 第4步,FMC的時序配置(重要)
由於操作AD7606僅需要讀操作,而且使用的是FMC總線的Mode_A,那么僅需按照如下時序圖配置好即可:
根據這個時序圖,重點配置好ADDSET地址建立時間和DATAST數據建立時間即可。
- DATAST(DataSetupTime,數據建立時間)
DATAST實際上對應的就是76.4.4小節里面的t10 。RD讀信號的低電平脈沖寬度,通信電壓不同,時間不同,對於STM32來說,FMC通信電平一般是3.3V,即最小值21ns。
- ADDST(AddressSetupTime,地址建立時間)
DATAST實際上對應的就是76.4.4小節里面的t11 或者t12。
-
- 如果采用CS(NEx)片選和RD(NOE)讀信號獨立方式,對應的時間最小15ns,即t11 。
- 如果采用CS(NEx)片選和RD(NOE)讀信號並聯方式,對應的時間最小22ns,即t12 。
我們這里將t12作為最小值更合理,因為CS(NEx)片選信號,每讀取完畢一路,拉高一次。
有了這些認識后,再來看FMC的時序配置就比較好理解了:
1. /* 2. ****************************************************************************************************** 3. * 函 數 名: AD7606_FSMCConfig 4. * 功能說明: 配置FSMC並口訪問時序 5. * 形 參: 無 6. * 返 回 值: 無 7. ****************************************************************************************************** 8. */ 9. static void AD7606_FSMCConfig(void) 10. { 11. /* 12. DM9000,擴展IO,OLED和AD7606公用一個FMC配置,如果都開啟,請以FMC速度最慢的為准。 13. 從而保證所有外設都可以正常工作。 14. */ 15. SRAM_HandleTypeDef hsram = {0}; 16. FMC_NORSRAM_TimingTypeDef SRAM_Timing = {0}; 17. 18. /* 19. AD7606規格書要求(3.3V時,通信電平Vdriver):RD讀信號低電平脈沖寬度最短21ns,對應DataSetupTime 20. CS片選和RD讀信號獨立方式的高電平脈沖最短寬度15ns。 21. CS片選和RD讀信號並聯方式的高電平脈沖最短寬度22ns。 22. 這里將22ns作為最小值更合理些,對應FMC的AddressSetupTime。 23. 24. 5-x-5-x-x-x : RD高持續25ns, 低電平持續25ns. 讀取8路樣本數據到內存差不多就是400ns。 25. */ 26. hsram.Instance = FMC_NORSRAM_DEVICE; 27. hsram.Extended = FMC_NORSRAM_EXTENDED_DEVICE; 28. 29. /* FMC使用的HCLK3,主頻200MHz,1個FMC時鍾周期就是5ns */ 30. SRAM_Timing.AddressSetupTime = 5; /* 5*5ns=25ns,地址建立時間,范圍0 -15個FMC時鍾周期個數 */ 31. SRAM_Timing.AddressHoldTime = 2; /* 地址保持時間,配置為模式A時,用不到此參數 范圍1 -15個 32. 時鍾周期個數 */ 33. SRAM_Timing.DataSetupTime = 5; /* 5*5ns=25ns,數據建立時間,范圍1 -255個時鍾周期個數 */ 34. SRAM_Timing.BusTurnAroundDuration = 1; /* 此配置用不到這個參數 */ 35. SRAM_Timing.CLKDivision = 2; /* 此配置用不到這個參數 */ 36. SRAM_Timing.DataLatency = 2; /* 此配置用不到這個參數 */ 37. SRAM_Timing.AccessMode = FMC_ACCESS_MODE_A; /* 配置為模式A */ 38. hsram.Init.NSBank = FMC_NORSRAM_BANK1; /* 使用的BANK1,即使用的片選 39. FMC_NE1 */ 40. hsram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; /* 禁止地址數據復用 */ 41. hsram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; /* 存儲器類型SRAM */ 42. hsram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_32; /* 32位總線寬度 */ 43. hsram.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE; /* 關閉突發模式 */ 44. hsram.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; /* 用於設置等待信號的極性,關閉突 45. 發模式,此參數無效 */ 46. hsram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; /* 關閉突發模式,此參數無效 */ 47. hsram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; /* 用於使能或者禁止寫保護 */ 48. hsram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; /* 關閉突發模式,此參數無效 */ 49. hsram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; /* 禁止擴展模式 */ 50. hsram.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE; /* 用於異步傳輸期間,使能或者禁止 51. 等待信號,這里選擇關閉 */ 52. hsram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE; /* 禁止寫突發 */ 53. hsram.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY; /* 僅同步模式才做時鍾輸出 */ 54. hsram.Init.WriteFifo = FMC_WRITE_FIFO_ENABLE; /* 使能寫FIFO */ 55. 56. /* 初始化SRAM控制器 */ 57. if (HAL_SRAM_Init(&hsram, &SRAM_Timing, &SRAM_Timing) != HAL_OK) 58. { 59. /* 初始化錯誤 */ 60. Error_Handler(__FILE__, __LINE__); 61. } 62. }
這里把幾個關鍵的地方闡釋下:
- 第15- 16行,對作為局部變量的HAL庫結構體做初始化,防止不確定值配置時出問題。
- 第30行,地址建立時間,對於AD7606來說,這個地方最小值22ns。保險起見,這里取值5個FMC時鍾周期,即25ns。
- 第31行,地址保持時間,對於FMC模式A來說,此參數用不到。
- 第33行,數據建立時間,對於AD7606來說,這個地方最小值是21ns,保險起見,這里取值5個FMC時鍾周期,即25ns。
- 第34 – 36行,當前配置用不到這三個參數。
- 第38行,使用的BANK1,即使用的片選FMC_NE1。
76.6.5 第5步,FMC的MPU配置
實際測試發現,使能FMC_NE1所管理的存儲區的Cache功能后,會出現擴展IO的NE片選和NWE信號輸出2次的問題。經過各種Cache方式配置、FMC帶寬配置、操作FMC時的數據位寬設置,發現禁止了Cache功能就正常了,也就是說,設置FMC_NE1所管理的存儲區MPU屬性為Device或者Strongly Ordered即可。
/* 配置FMC擴展IO的MPU屬性為Device或者Strongly Ordered */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x60000000; MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER1; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct);
MPU配置中直接從FMC_NE1的首地址開始配置,設置了64KB空間的屬性。將FMC_NE1通過譯碼器所管理的所有設備地址全部設置為此配置:
76.6.6 第6步,AD7606的軟件定時器讀取數據(方案一)
AD7606的軟件定時器讀取方式比較簡單,周期性調用下面兩個函數即可:
AD7606_ReadNowAdc(); /* 讀取采樣結果 */ AD7606_StartConvst(); /* 啟動下次轉換 */
函數AD7606_ReadNowAdc的實現如下:
/* AD7606 FSMC總線地址,只能讀,無需寫 */ #define AD7606_RESULT() *(__IO uint16_t *)0x60003000 void AD7606_ReadNowAdc(void) { g_tAD7606.sNowAdc[0] = AD7606_RESULT(); /* 讀第1路樣本 */ g_tAD7606.sNowAdc[1] = AD7606_RESULT(); /* 讀第2路樣本 */ g_tAD7606.sNowAdc[2] = AD7606_RESULT(); /* 讀第3路樣本 */ g_tAD7606.sNowAdc[3] = AD7606_RESULT(); /* 讀第4路樣本 */ g_tAD7606.sNowAdc[4] = AD7606_RESULT(); /* 讀第5路樣本 */ g_tAD7606.sNowAdc[5] = AD7606_RESULT(); /* 讀第6路樣本 */ g_tAD7606.sNowAdc[6] = AD7606_RESULT(); /* 讀第7路樣本 */ g_tAD7606.sNowAdc[7] = AD7606_RESULT(); /* 讀第8路樣本 */ AD7606_SEGGER_RTTOUT(); }
啟動ADC轉換的函數實現如下:
/* ********************************************************************************************************* * 函 數 名: AD7606_StartConvst * 功能說明: 啟動1次ADC轉換 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void AD7606_StartConvst(void) { /* page 7: CONVST 高電平脈沖寬度和低電平脈沖寬度最短 25ns */ /* CONVST平時為高 */ CONVST_0(); CONVST_0(); CONVST_0(); CONVST_1(); }
76.6.7 第7步,AD7606的FIFO方式實時讀取數據(方案二)
通過下面的框圖可以對AD7606的FIFO方式有個整體認識:
- 啟動采集函數AD7606_StartRecord
這個函數的主要作用是配置TIM8的CH1 PWM輸出並使能BUSY引腳的EXTI中斷。
/* ********************************************************************************************************* * 函 數 名: AD7606_StartRecord * 功能說明: 開始采集 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void AD7606_StartRecord(uint32_t _ulFreq) { AD7606_StopRecord(); AD7606_Reset(); /* 復位硬件 */ AD7606_StartConvst(); /* 啟動采樣,避免第1組數據全0的問題 */ g_tAdcFifo.usRead = 0; /* 必須在開啟定時器之前清0 */ g_tAdcFifo.usWrite = 0; g_tAdcFifo.usCount = 0; g_tAdcFifo.ucFull = 0; AD7606_EnterAutoMode(_ulFreq); } /* ********************************************************************************************************* * 函 數 名: AD7606_EnterAutoMode * 功能說明: 配置硬件工作在自動采集模式,結果存儲在FIFO緩沖區。 * 形 參: _ulFreq : 采樣頻率,單位Hz, 1k,2k,5k,10k,20K,50k,100k,200k * 返 回 值: 無 ********************************************************************************************************* */ void AD7606_EnterAutoMode(uint32_t _ulFreq) { /* 配置PC6為TIM8_CH1功能,輸出占空比50%的方波 */ bsp_SetTIMOutPWM(CONVST_GPIO, CONVST_PIN, CONVST_TIMX, CONVST_TIMCH, _ulFreq, 5000); /* 配置PE5, BUSY 作為中斷輸入口,下降沿觸發 */ { GPIO_InitTypeDef GPIO_InitStructure; CONVST_RCC_GPIO_CLK_ENABLE(); /* 打開GPIO時鍾 */ __HAL_RCC_SYSCFG_CLK_ENABLE(); GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING; /* 中斷下降沿觸發 */ GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Pin = BUSY_PIN; HAL_GPIO_Init(BUSY_GPIO, &GPIO_InitStructure); HAL_NVIC_SetPriority(BUSY_IRQn, 2, 0); HAL_NVIC_EnableIRQ(BUSY_IRQn); } }
- AD7606轉換完畢后,中斷服務程序的處理。
下面這幾個函數的調用關系是
-
- EXTI9_5_IRQHandler調用HAL_GPIO_EXTI_IRQHandler。
- HAL_GPIO_EXTI_IRQHandler調用HAL_GPIO_EXTI_Callback。
- HAL_GPIO_EXTI_Callback調用AD7606_ISR。
- AD7606_ISR調用AD7606_ReadNowAdc。
/* ********************************************************************************************************* * 函 數 名: EXTI9_5_IRQHandler * 功能說明: 外部中斷服務程序。 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void EXTI9_5_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(BUSY_PIN); } /* ********************************************************************************************************* * 函 數 名: EXTI9_5_IRQHandler * 功能說明: 外部中斷服務程序入口, AD7606_BUSY 下降沿中斷觸發 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == BUSY_PIN) { AD7606_ISR(); } } /* ********************************************************************************************************* * 函 數 名: AD7606_ISR * 功能說明: 定時采集中斷服務程序 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void AD7606_ISR(void) { uint8_t i; AD7606_ReadNowAdc(); for (i = 0; i < 8; i++) { g_tAdcFifo.sBuf[g_tAdcFifo.usWrite] = g_tAD7606.sNowAdc[i]; if (++g_tAdcFifo.usWrite >= ADC_FIFO_SIZE) { g_tAdcFifo.usWrite = 0; } if (g_tAdcFifo.usCount < ADC_FIFO_SIZE) { g_tAdcFifo.usCount++; } else { g_tAdcFifo.ucFull = 1; /* FIFO 滿,主程序來不及處理數據 */ } } } /* ********************************************************************************************************* * 函 數 名: AD7606_ReadNowAdc * 功能說明: 讀取8路采樣結果。結果存儲在全局變量 g_tAD7606 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void AD7606_ReadNowAdc(void) { g_tAD7606.sNowAdc[0] = AD7606_RESULT(); /* 讀第1路樣本 */ g_tAD7606.sNowAdc[1] = AD7606_RESULT(); /* 讀第2路樣本 */ g_tAD7606.sNowAdc[2] = AD7606_RESULT(); /* 讀第3路樣本 */ g_tAD7606.sNowAdc[3] = AD7606_RESULT(); /* 讀第4路樣本 */ g_tAD7606.sNowAdc[4] = AD7606_RESULT(); /* 讀第5路樣本 */ g_tAD7606.sNowAdc[5] = AD7606_RESULT(); /* 讀第6路樣本 */ g_tAD7606.sNowAdc[6] = AD7606_RESULT(); /* 讀第7路樣本 */ g_tAD7606.sNowAdc[7] = AD7606_RESULT(); /* 讀第8路樣本 */ AD7606_SEGGER_RTTOUT(); }
這里的FIFO比較好理解,與前面按鍵FIFO章節的實現是一樣的,詳情可重溫下按鍵FIFO的實現。
76.6.8 第8步,AD7606的雙緩沖方式存儲思路
為了方便大家實時處理采集的數據,專門預留了一個弱定義函數AD7606_SEGGER_RTTOUT,方便大家將采集函數存儲到雙緩沖里面,這個函數是在中斷服務程序里面調用的。
/* ********************************************************************************************************* * 函 數 名: AD7606_ReadNowAdc * 功能說明: 讀取8路采樣結果。結果存儲在全局變量 g_tAD7606 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ /* 弱定義,方便用戶將采集的結果實時輸出 */ __weak void AD7606_SEGGER_RTTOUT(void) { } void AD7606_ReadNowAdc(void) { g_tAD7606.sNowAdc[0] = AD7606_RESULT(); /* 讀第1路樣本 */ g_tAD7606.sNowAdc[1] = AD7606_RESULT(); /* 讀第2路樣本 */ g_tAD7606.sNowAdc[2] = AD7606_RESULT(); /* 讀第3路樣本 */ g_tAD7606.sNowAdc[3] = AD7606_RESULT(); /* 讀第4路樣本 */ g_tAD7606.sNowAdc[4] = AD7606_RESULT(); /* 讀第5路樣本 */ g_tAD7606.sNowAdc[5] = AD7606_RESULT(); /* 讀第6路樣本 */ g_tAD7606.sNowAdc[6] = AD7606_RESULT(); /* 讀第7路樣本 */ g_tAD7606.sNowAdc[7] = AD7606_RESULT(); /* 讀第8路樣本 */ AD7606_SEGGER_RTTOUT(); }
本章是將此函數用於實時采集數據並輸出到J-Scope。
76.6.9 第9步,AD7606過采樣設置
AD7606的過采樣實現比較簡單,通過IO引腳就可以控制,支持2倍,4倍,8倍,16倍,32倍和64倍過采樣設置。
/* ********************************************************************************************************* * 函 數 名: AD7606_SetOS * 功能說明: 配置AD7606數字濾波器,也就設置過采樣倍率。 * 通過設置 AD7606_OS0、OS1、OS2口線的電平組合狀態決定過采樣倍率。 * 啟動AD轉換之后,AD7606內部自動實現剩余樣本的采集,然后求平均值輸出。 * * 過采樣倍率越高,轉換時間越長。 * 0、無過采樣時,AD轉換時間 = 3.45us - 4.15us * 1、2倍過采樣時 = 7.87us - 9.1us * 2、4倍過采樣時 = 16.05us - 18.8us * 3、8倍過采樣時 = 33us - 39us * 4、16倍過采樣時 = 66us - 78us * 5、32倍過采樣時 = 133us - 158us * 6、64倍過采樣時 = 257us - 315us * * 形 參: _ucOS : 過采樣倍率, 0 - 6 * 返 回 值: 無 ********************************************************************************************************* */ void AD7606_SetOS(uint8_t _ucOS) { g_tAD7606.ucOS = _ucOS; switch (_ucOS) { case AD_OS_X2: OS2_0(); OS1_0(); OS0_1(); break; case AD_OS_X4: OS2_0(); OS1_1(); OS0_0(); break; case AD_OS_X8: OS2_0(); OS1_1(); OS0_1(); break; case AD_OS_X16: OS2_1(); OS1_0(); OS0_0(); break; case AD_OS_X32: OS2_1(); OS1_0(); OS0_1(); break; case AD_OS_X64: OS2_1(); OS1_1(); OS0_0(); break; case AD_OS_NO: default: g_tAD7606.ucOS = AD_OS_NO; OS2_0(); OS1_0(); OS0_0(); break; } }
76.6.10 第10步,AD7606量程設置
AD7606支持兩種量程,±5V和±10V,實現代碼如下:
/* ********************************************************************************************************* * 函 數 名: AD7606_SetInputRange * 功能說明: 配置AD7606模擬信號輸入量程。 * 形 參: _ucRange : 0 表示正負5V 1表示正負10V * 返 回 值: 無 ********************************************************************************************************* */ void AD7606_SetInputRange(uint8_t _ucRange) { if (_ucRange == 0) { g_tAD7606.ucRange = 0; RANGE_0(); /* 設置為正負5V */ } else { g_tAD7606.ucRange = 1; RANGE_1(); /* 設置為正負10V */ } }
76.6.11 第11步,操作數據位寬注意事項
在bsp_fmc_ad7606.c文件開頭有個宏定義
#define AD7606_RESULT() *(__IO uint16_t *)0x60003000
特別注意,這里是要操作地址0x60003000上的16位數據空間,即做了一個強制轉換uint16_t *。
76.7 AD7606板級支持包(bsp_fmc_ad7606.c)
AD7606驅動文件bsp_fmc_ad7606.c主要實現了如下幾個API供用戶調用:
- bsp_InitAD7606
- AD7606_SetOS
- AD7606_SetInputRange
- AD7606_Reset
- AD7606_StartConvst
- AD7606_ReadNowAdc
- AD7606_EnterAutoMode
- AD7606_StartRecord
- AD7606_StopRecord
- AD7606_FifoNewData
- AD7606_ReadFifo
- AD7606_FifoFull
76.7.1 函數bsp_InitAD7606
函數原型:
void bsp_InitAD7606(void)
函數描述:
主要用於AD7606的初始化。
76.7.2 函數AD7606_SetOS
函數原型:
void AD7606_SetOS(uint8_t _ucOS)
函數描述:
此函數用於配置AD7606數字濾波器,也就設置過采樣倍率。通過設置 AD7606_OS0、OS1、OS2口線的電平組合狀態決定過采樣倍率。啟動AD轉換之后,AD7606內部自動實現剩余樣本的采集,然后求平均值輸出。
過采樣倍率越高,轉換時間越長。
無過采樣時,AD轉換時間 = 3.45us - 4.15us。
2倍過采樣時 = 7.87us - 9.1us。
4倍過采樣時 = 16.05us - 18.8us。
8倍過采樣時 = 33us - 39us。
16倍過采樣時 = 66us - 78us。
32倍過采樣時 = 133us - 158us。
64倍過采樣時 = 257us - 315us。
函數參數:
- 第1個參數為范圍0 – 6,分別對應無過采樣,2倍過采樣,4倍過采樣,8倍過采樣,16倍過采樣,32倍過采樣和64倍過采樣。
76.7.3 函數AD7606_SetInputRange
函數原型:
void AD7606_SetInputRange(uint8_t _ucRange)
函數描述:
配置AD7606模擬信號輸入量程。
函數參數:
- 第1個參數為0 表示正負5V ,1表示正負10V。
76.7.4 函數AD7606_Reset
函數原型:
void AD7606_Reset(void)
函數描述:
此函數用於硬件復位AD7606,復位之后恢復到正常工作狀態。
76.7.5 函數AD7606_StartConvst
函數原型:
void AD7606_StartConvst(void)
函數描述:
此函數用於啟動1次ADC轉換。
76.7.6 函數AD7606_ReadNowAdc
函數原型:
void AD7606_ReadNowAdc(void)
函數描述:
此函數用於讀取8路采樣結果,結果存儲在全局變量 g_tAD7606。
76.7.7 函數AD7606_EnterAutoMode
函數原型:
void AD7606_EnterAutoMode(uint32_t _ulFreq)
函數描述:
此函數用於配置硬件工作在自動采集模式,結果存儲在FIFO緩沖區。一般不單獨調用,函數AD7606_StartRecord會調用。
函數參數:
- 第1個參數是采樣頻率,范圍1-200KHz,單位Hz。
76.7.8 函數AD7606_StartRecord
函數原型:
void AD7606_StartRecord(uint32_t _ulFreq)
函數描述:
用於啟動采集。
函數參數:
- 第1個參數是采樣頻率,范圍1-200KHz,單位Hz。
76.7.9 函數AD7606_StopRecord
函數原型:
void AD7606_StopRecord(void)
函數描述:
此函數用於停止采集定時器。函數AD7606_StartRecord和AD7606_StopRecord是配套的。
76.7.10 函數AD7606_FifoNewData
函數原型:
uint8_t AD7606_HasNewData(void)
函數描述:
此函數用於判斷FIFO中是否有新數據。
函數參數:
- 返回值,1 表示有,0表示暫無數據。
76.7.11 函數AD7606_ReadFifo
函數原型:
uint8_t AD7606_ReadFifo(uint16_t *_usReadAdc)
函數描述:
此函數用於從FIFO中讀取一個ADC值。
函數參數:
- 第1個參數是存放ADC結果的變量指針。
- 返回值,1 表示OK,0表示暫無數據。
76.7.12 函數AD7606_FifoFull
函數原型:
uint8_t AD7606_FifoFull(void)
函數描述:
此函數用於判斷FIFO是否滿。
函數參數:
- 返回值,1 表示滿,0表示未滿。
76.8 J-Scope實時展示AD7606采集數據說明
J-Scope專題教程(實時展示要用J-Scope的RTT模式),本章配套例子也做了支持:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=86881 。
看完專題教程,基本就會操作了,這里有三點注意事項需要大家提前有個了解。另外,推薦使用MDK版工程做測試J-Scope,IAR版容易測試不正常。
76.8.1 J-Scope閃退問題解決辦法
如下界面,不要點擊選擇按鈕,閃退就是因為點擊了這個選擇按鈕。
直接手動填寫型號即可,比如STM32H743XI,STM32F429BI,STM32F407IG,STM32F103ZE等。
76.8.2 J-Scope多通道傳輸實現
J-Scope的多通道傳輸配置好函數SEGGER_RTT_ConfigUpBuffer即可,主要是通過第2個參數實現的。
/* 配置通道1,上行配置 默認情況下,J-Scope僅顯示1個通道。 上傳1個通道的波形,配置第2個參數為JScope_i2 上傳2個通道的波形,配置第2個參數為JScope_i2i2 上傳3個通道的波形,配置第2個參數為JScope_i2i2i2 上傳4個通道的波形,配置第2個參數為JScope_i2i2i2i2 上傳5個通道的波形,配置第2個參數為JScope_i2i2i2i2i2 上傳6個通道的波形,配置第2個參數為JScope_i2i2i2i2i2i2 上傳7個通道的波形,配置第2個參數為JScope_i2i2i2i2i2i2i2 上傳8個通道的波形,配置第2個參數為JScope_i2i2i2i2i2i2i2i2 */ SEGGER_RTT_ConfigUpBuffer(1, "JScope_i2", buf, 20480, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
使用函數SEGGER_RTT_Write上傳數據時,要跟配置的通道數匹配,比如配置的三個通道,就需要調用三次函數:
SEGGER_RTT_Write(1, &(g_tAD7606.sNowAdc[0]), 2); SEGGER_RTT_Write(1, &(g_tAD7606.sNowAdc[1]), 2); SEGGER_RTT_Write(1, &(g_tAD7606.sNowAdc[2]), 2);
多路效果:
76.8.3 J-Scope帶寬問題
普通的JLINK時鍾速度8 - 12MHz時, J-Scope的速度基本可以達到500KB/S(注意,單位是字節)AD7606的最高采樣率是200Ksps,16bit,那么一路采集就有400KB/S的速速,所以要根據設置的采樣率設置要顯示的J-Scope通道數,如果超出了最高通信速度,波形顯示會混亂。
200Ksps時,實時顯示1路
100Ksps時,實時顯示2路
50Ksps時, 實時顯示4路
25Ksps時, 實時顯示8路
實際速度以底欄的展示為准,如果與設置的速度差異較大,說明傳輸異常了。
76.9 AD7606驅動移植和使用
AD7606移植步驟如下:
- 第1步:復制bsp_fmc_ad7606.c和bsp_fmc_ad7606.h到自己的工程目錄,並添加到工程里面。
- 第2步:根據使用的CONVST引腳,BUSY引腳,過采樣引腳,量程控制引腳,復位引腳,修改bsp_fmc_ad7606.c開頭的宏定義。
這里要特別注意過采樣引腳,量程控制引腳和復位引腳是采用的擴展IO,需要大家根據自己的情況修改。
/* CONVST 啟動ADC轉換的GPIO = PC6 */ #define CONVST_RCC_GPIO_CLK_ENABLE __HAL_RCC_GPIOC_CLK_ENABLE #define CONVST_TIM8_CLK_DISABLE __HAL_RCC_TIM8_CLK_DISABLE #define CONVST_GPIO GPIOC #define CONVST_PIN GPIO_PIN_6 #define CONVST_TIMX TIM8 #define CONVST_TIMCH 1 /* BUSY 轉換完畢信號 = PE5 */ #define BUSY_RCC_GPIO_CLK_ENABLE __HAL_RCC_GPIOE_CLK_ENABLE #define BUSY_GPIO GPIOE #define BUSY_PIN GPIO_PIN_5 #define BUSY_IRQn EXTI9_5_IRQn #define BUSY_IRQHandler EXTI9_5_IRQHandler /* 設置過采樣的IO, 在擴展的74HC574上 */ #define OS0_1() HC574_SetPin(AD7606_OS0, 1) #define OS0_0() HC574_SetPin(AD7606_OS0, 0) #define OS1_1() HC574_SetPin(AD7606_OS1, 1) #define OS1_0() HC574_SetPin(AD7606_OS1, 0) #define OS2_1() HC574_SetPin(AD7606_OS2, 1) #define OS2_0() HC574_SetPin(AD7606_OS2, 0) /* 啟動AD轉換的GPIO : PC6 */ #define CONVST_1() CONVST_GPIO->BSRR = CONVST_PIN #define CONVST_0() CONVST_GPIO->BSRR = ((uint32_t)CONVST_PIN << 16U) /* 設置輸入量程的GPIO, 在擴展的74HC574上 */ #define RANGE_1() HC574_SetPin(AD7606_RANGE, 1) #define RANGE_0() HC574_SetPin(AD7606_RANGE, 0) /* AD7606復位口線, 在擴展的74HC574上 */ #define RESET_1() HC574_SetPin(AD7606_RESET, 1) #define RESET_0() HC574_SetPin(AD7606_RESET, 0)
- 第3步:根據具體用到的FMC引腳,修改函數AD7606_CtrlLinesConfig里面做的IO配置。
- 第4步:根據使用的FMC BANK,修改函數AD7606_FSMCConfig里面的BANK配置,這點非常容易疏忽。
- 第5步:注意MPU配置,詳情見本章77.7.5小節。
- 第6步:初始化AD7606。
bsp_InitAD7606(); /* 配置AD7606所用的GPIO */
- 第7步:AD7606驅動主要用到HAL庫的FMC驅動文件,簡單省事些可以添加所有HAL庫C源文件進來。
- 第8步:應用方法看本章節配套例子即可。
76.10 實驗例程設計框架
通過程序設計框架,讓大家先對配套例程有一個全面的認識,然后再理解細節,本次實驗例程的設計框架如下:
第1階段,上電啟動階段:
- 這部分在第14章進行了詳細說明。
第2階段,進入main函數:
- 第1部分,硬件初始化,主要是MPU,Cache,HAL庫,系統時鍾,滴答定時器和LED。
- 第2部分,應用程序設計部分,測試AD7606的兩種采集方案。
76.11 實驗例程說明(MDK)
配套例子:
V7-056_AD7606的FMC總線驅動方式實現(8通道同步采樣, 16bit, 正負10V)
實驗目的:
- 學習AD7606的FMC驅動方式實現。
重要提示:
- 板子上電后,默認是軟件定時采集,0.5秒一次,適合串口展示數據。
- 如果需要使用J-Scope實時展示采集的波形效果,需要按下K2按鍵切換到FIFO模式。
- 如果使用的JLINK速度不夠快,導致J-Scope無法最高速度實時上傳,可以使用搖桿上下鍵設置過采樣來降低上傳速度。
- 默認情況下,程序僅上傳了AD7606通道1采集的數據。
- 串口數據展示推薦使用SecureCRT,因為數據展示做了特別處理,方便采集數據在串口軟件同一個位置不斷刷新。
實驗內容:
1、AD7606的FMC驅動做了兩種采集方式
(1)軟件定時獲取方式,適合低速查詢獲取。
(2)FIFO工作模式,適合8路實時采集,支持最高采樣率200Ksps。
2、數據展示方式:
(1)軟件查詢方式,數據通過串口打印輸出。
(2)FIFO工作模式,數據通過J-Scope實時輸出。
(3)J-Scope的實時輸出方法請看V7板子用戶手冊對應的AD7606章節。
3、將模擬輸入接地時,采樣值是0左右。
4、模擬輸入端懸空時,采樣值在某個范圍浮動(這是正常的,這是AD7606內部輸入電阻導致的浮動電壓)。
5、出廠的AD7606模塊缺省是8080 並行接口。如果用SPI接口模式,需要修改 R1 R2電阻配置。
6、配置CVA CVB 引腳為PWM輸出模式,周期設置為需要的采樣頻率,之后MCU將產生周期非常穩定的AD轉換信號。
實驗操作:
- 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
- K1鍵 : 切換量程(5V或10V)。
- K2鍵 : 進入FIFO工作模式。
- K3鍵 : 進入軟件定時采集模式。
- 搖桿上下鍵 : 調節過采樣參數。
上電后串口打印的信息:
波特率 115200,數據位 8,奇偶校驗位無,停止位 1。
J-Scope波形效果:
模塊插入位置:
程序設計:
系統棧大小分配:
RAM空間用的DTCM:
硬件外設初始化
硬件外設的初始化是在 bsp.c 文件實現:
/* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只需要調用一次 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) { /* 配置MPU */ MPU_Config(); /* 使能L1 Cache */ CPU_CACHE_Enable(); /* STM32H7xx HAL 庫初始化,此時系統用的還是H7自帶的64MHz,HSI時鍾: - 調用函數HAL_InitTick,初始化滴答時鍾中斷1ms。 - 設置NVIV優先級分組為4。 */ HAL_Init(); /* 配置系統時鍾到400MHz - 切換使用HSE。 - 此函數會更新全局變量SystemCoreClock,並重新配置HAL_InitTick。 */ SystemClock_Config(); /* Event Recorder: - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。 - 默認不開啟,如果要使能此選項,務必看V7開發板用戶手冊第xx章 */ #if Enable_EventRecorder == 1 /* 初始化EventRecorder並開啟 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); #endif bsp_InitDWT(); /* 初始化DWT時鍾周期計數器 */ bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */ bsp_InitTimer(); /* 初始化滴答定時器 */ bsp_InitLPUart(); /* 初始化串口 */ bsp_InitExtIO(); /* 初始化FMC總線74HC574擴展IO. 必須在 bsp_InitLed()前執行 */ bsp_InitLed(); /* 初始化LED */ bsp_InitExtSDRAM(); /* 初始化SDRAM */ /* 針對不同的應用程序,添加需要的底層驅動模塊初始化函數 */ bsp_InitAD7606(); /* 配置AD7606所用的GPIO */ }
MPU配置和Cache配置:
數據Cache和指令Cache都開啟。配置了AXI SRAM區(本例子未用到AXI SRAM)和FMC的擴展IO區。
/* ********************************************************************************************************* * 函 數 名: MPU_Config * 功能說明: 配置MPU * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void MPU_Config( void ) { MPU_Region_InitTypeDef MPU_InitStruct; /* 禁止 MPU */ HAL_MPU_Disable(); /* 配置AXI SRAM的MPU屬性為Write back, Read allocate,Write allocate */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x24000000; MPU_InitStruct.Size = MPU_REGION_SIZE_512KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER0; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); /* 配置FMC擴展IO的MPU屬性為Device或者Strongly Ordered */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x60000000; MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER1; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); /*使能 MPU */ HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); } /* ********************************************************************************************************* * 函 數 名: CPU_CACHE_Enable * 功能說明: 使能L1 Cache * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void CPU_CACHE_Enable(void) { /* 使能 I-Cache */ SCB_EnableICache(); /* 使能 D-Cache */ SCB_EnableDCache(); }
每10ms調用一次按鍵處理:
按鍵處理是在滴答定時器中斷里面實現,每10ms執行一次檢測。
/* ********************************************************************************************************* * 函 數 名: bsp_RunPer10ms * 功能說明: 該函數每隔10ms被Systick中斷調用1次。詳見 bsp_timer.c的定時中斷服務程序。一些處理時間要求 * 不嚴格的任務可以放在此函數。比如:按鍵掃描、蜂鳴器鳴叫控制等。 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_RunPer10ms(void) { bsp_KeyScan10ms(); }
主功能:
主程序實現如下操作:
- 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
- K1鍵 : 切換量程(5V或10V)。
- K2鍵 : 進入FIFO工作模式。
- K3鍵 : 進入軟件定時采集模式。
- 搖桿上下鍵 : 調節過采樣參數。
/* ********************************************************************************************************* * 函 數 名: main * 功能說明: c程序入口 * 形 參: 無 * 返 回 值: 錯誤代碼(無需處理) ********************************************************************************************************* */ int main(void) { bsp_Init(); /* 硬件初始化 */ PrintfLogo(); /* 打印例程名稱和版本等信息 */ DemoFmcAD7606(); /* AD7606測試 */ } /* ********************************************************************************************************* * 函 數 名: DemoFmcAD7606 * 功能說明: AD7606測試 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void DemoFmcAD7606(void) { uint8_t ucKeyCode; uint8_t ucRefresh = 0; uint8_t ucFifoMode; sfDispMenu(); /* 打印命令提示 */ ucFifoMode = 0; /* AD7606進入普通工作模式 */ ucRefresh = 0; /* 數據在串口刷新的標志 */ AD7606_SetOS(AD_OS_NO); /* 無過采樣 */ AD7606_SetInputRange(1); /* 0表示輸入量程為正負5V, 1表示正負10V */ AD7606_StartConvst(); /* 啟動1次轉換 */ bsp_StartAutoTimer(0, 500); /* 啟動1個500ms的自動重裝的定時器 */ bsp_StartAutoTimer(3, 200); /* 啟動1個200ms的自動重裝的定時器 */ /* 配置通道1,上行配置 默認情況下,J-Scope僅顯示1個通道。 上傳1個通道的波形,配置第2個參數為JScope_i2 上傳2個通道的波形,配置第2個參數為JScope_i2i2 上傳3個通道的波形,配置第2個參數為JScope_i2i2i2 上傳4個通道的波形,配置第2個參數為JScope_i2i2i2i2 上傳5個通道的波形,配置第2個參數為JScope_i2i2i2i2i2 上傳6個通道的波形,配置第2個參數為JScope_i2i2i2i2i2i2 上傳7個通道的波形,配置第2個參數為JScope_i2i2i2i2i2i2i2 上傳8個通道的波形,配置第2個參數為JScope_i2i2i2i2i2i2i2i2 */ SEGGER_RTT_ConfigUpBuffer(1, "JScope_i2", buf, 20480, SEGGER_RTT_MODE_NO_BLOCK_SKIP); while(1) { bsp_Idle(); /* 這個函數在bsp.c文件。用戶可以修改這個函數實現CPU休眠和喂狗 */ /* 判斷定時器超時時間 */ if (bsp_CheckTimer(3)) { /* 每隔100ms 進來一次 */ bsp_LedToggle(2); } if (ucRefresh == 1) { ucRefresh = 0; /* 處理數據 */ AD7606_Mak(); /* 打印ADC采樣結果 */ AD7606_Disp(); } if (ucFifoMode == 0) /* AD7606 普通工作模式 */ { if (bsp_CheckTimer(0)) { /* 每隔500ms 進來一次. 由軟件啟動轉換 */ AD7606_ReadNowAdc(); /* 讀取采樣結果 */ AD7606_StartConvst(); /* 啟動下次轉換 */ ucRefresh = 1; /* 刷新顯示 */ } } else { /* 在FIFO工作模式,bsp_AD7606自動進行采集,數據存儲在FIFO緩沖區。 結果可以通過下面的函數讀取: uint8_t AD7606_ReadFifo(uint16_t *_usReadAdc) 大家可以將數據保存到SD卡,或者保存到外部SRAM。 本例未對FIFO中的數據進行處理,進行打印當前最新的樣本值和J-Scope的實時輸出展示。 如果主程序不能及時讀取FIFO數據,那么 AD7606_FifoFull() 將返回真。 8通道200K采樣時,數據傳輸率 = 200 000 * 2 * 8 = 3.2MB/S */ if (bsp_CheckTimer(0)) { ucRefresh = 1; /* 刷新顯示 */ } } /* 按鍵檢測由后台systick中斷服務程序實現,我們只需要調用bsp_GetKey讀取鍵值即可。這個函數不會 等待按鍵按下,這樣我們可以在while循環內做其他的事情 */ ucKeyCode = bsp_GetKey(); /* 讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */ if (ucKeyCode != KEY_NONE) { switch (ucKeyCode) { case KEY_DOWN_K1: /* K1鍵按下 切換量程 */ if (g_tAD7606.ucRange == 0) { AD7606_SetInputRange(1); } else { AD7606_SetInputRange(0); } ucRefresh = 1; break; case KEY_DOWN_K2: /* K2鍵按下 */ ucFifoMode = 1; /* AD7606進入FIFO工作模式 */ g_tAD7606.ucOS = 1; /* 無過采樣 */ AD7606_StartRecord(AD7606_SampleFreq[g_tAD7606.ucOS]); /* 啟動100kHz采樣速率 */ AD7606_SetOS(g_tAD7606.ucOS); /* 設置無過采樣 */ printf("\33[%dA", (int)1); /* 光標上移n行 */ printf("AD7606進入FIFO工作模式 (200KHz 8通道同步采集)...\r\n"); break; case KEY_DOWN_K3: /* K3鍵按下 */ AD7606_StopRecord(); /* 停止記錄 */ ucFifoMode = 0; /* AD7606進入普通工作模式 */ g_tAD7606.ucOS = 0; /* 無過采樣 */ AD7606_SetOS(g_tAD7606.ucOS); printf("\33[%dA", (int)1); /* 光標上移n行 */ printf("AD7606進入普通工作模式(0.5s定時8通道同步采集)...\r\n"); break; case JOY_DOWN_U: /* 搖桿UP鍵按下 */ if (g_tAD7606.ucOS < 6) { g_tAD7606.ucOS++; } AD7606_SetOS(g_tAD7606.ucOS); /* 如果是FIFO模式,*/ if(ucFifoMode == 1) { /* 啟動當前過采樣下最高速度 */ AD7606_StartRecord(AD7606_SampleFreq[g_tAD7606.ucOS]); } ucRefresh = 1; break; case JOY_DOWN_D: /* 搖桿DOWN鍵按下 */ if (g_tAD7606.ucOS > 0) { g_tAD7606.ucOS--; } AD7606_SetOS(g_tAD7606.ucOS); ucRefresh = 1; /* 如果是FIFO模式,*/ if(ucFifoMode == 1) { /* 啟動當前過采樣下最高速度 */ AD7606_StartRecord(AD7606_SampleFreq[g_tAD7606.ucOS]); } break; default: /* 其他的鍵值不處理 */ break; } } } }
76.12 實驗例程說明(IAR)
配套例子:
V7-056_AD7606的FMC總線驅動方式實現(8通道同步采樣, 16bit, 正負10V)
實驗目的:
- 學習AD7606的FMC驅動方式實現。
重要提示:
- 板子上電后,默認是軟件定時采集,0.5秒一次,適合串口展示數據。
- 如果需要使用J-Scope實時展示采集的波形效果,需要按下K2按鍵切換到FIFO模式。
- 如果使用的JLINK速度不夠快,導致J-Scope無法最高速度實時上傳,可以使用搖桿上下鍵設置過采樣來降低上傳速度。
- 默認情況下,程序僅上傳了AD7606通道1采集的數據。
- 串口數據展示推薦使用SecureCRT,因為數據展示做了特別處理,方便采集數據在串口軟件同一個位置不斷刷新。
實驗內容:
1、AD7606的FMC驅動做了兩種采集方式
(1)軟件定時獲取方式,適合低速查詢獲取。
(2)FIFO工作模式,適合8路實時采集,支持最高采樣率200Ksps。
2、數據展示方式:
(1)軟件查詢方式,數據通過串口打印輸出。
(2)FIFO工作模式,數據通過J-Scope實時輸出。
(3)J-Scope的實時輸出方法請看V7板子用戶手冊對應的AD7606章節。
3、將模擬輸入接地時,采樣值是0左右。
4、模擬輸入端懸空時,采樣值在某個范圍浮動(這是正常的,這是AD7606內部輸入電阻導致的浮動電壓)。
5、出廠的AD7606模塊缺省是8080 並行接口。如果用SPI接口模式,需要修改 R1 R2電阻配置。
6、配置CVA CVB 引腳為PWM輸出模式,周期設置為需要的采樣頻率,之后MCU將產生周期非常穩定的AD轉換信號。
實驗操作:
- 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
- K1鍵 : 切換量程(5V或10V)。
- K2鍵 : 進入FIFO工作模式。
- K3鍵 : 進入軟件定時采集模式。
- 搖桿上下鍵 : 調節過采樣參數。
上電后串口打印的信息:
波特率 115200,數據位 8,奇偶校驗位無,停止位 1。
J-Scope波形效果:
模塊插入位置:
程序設計:
系統棧大小分配:
RAM空間用的DTCM:
硬件外設初始化
硬件外設的初始化是在 bsp.c 文件實現:
/* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只需要調用一次 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) { /* 配置MPU */ MPU_Config(); /* 使能L1 Cache */ CPU_CACHE_Enable(); /* STM32H7xx HAL 庫初始化,此時系統用的還是H7自帶的64MHz,HSI時鍾: - 調用函數HAL_InitTick,初始化滴答時鍾中斷1ms。 - 設置NVIV優先級分組為4。 */ HAL_Init(); /* 配置系統時鍾到400MHz - 切換使用HSE。 - 此函數會更新全局變量SystemCoreClock,並重新配置HAL_InitTick。 */ SystemClock_Config(); /* Event Recorder: - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。 - 默認不開啟,如果要使能此選項,務必看V7開發板用戶手冊第xx章 */ #if Enable_EventRecorder == 1 /* 初始化EventRecorder並開啟 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); #endif bsp_InitDWT(); /* 初始化DWT時鍾周期計數器 */ bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */ bsp_InitTimer(); /* 初始化滴答定時器 */ bsp_InitLPUart(); /* 初始化串口 */ bsp_InitExtIO(); /* 初始化FMC總線74HC574擴展IO. 必須在 bsp_InitLed()前執行 */ bsp_InitLed(); /* 初始化LED */ bsp_InitExtSDRAM(); /* 初始化SDRAM */ /* 針對不同的應用程序,添加需要的底層驅動模塊初始化函數 */ bsp_InitAD7606(); /* 配置AD7606所用的GPIO */ }
MPU配置和Cache配置:
數據Cache和指令Cache都開啟。配置了AXI SRAM區(本例子未用到AXI SRAM)和FMC的擴展IO區。
/* ********************************************************************************************************* * 函 數 名: MPU_Config * 功能說明: 配置MPU * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void MPU_Config( void ) { MPU_Region_InitTypeDef MPU_InitStruct; /* 禁止 MPU */ HAL_MPU_Disable(); /* 配置AXI SRAM的MPU屬性為Write back, Read allocate,Write allocate */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x24000000; MPU_InitStruct.Size = MPU_REGION_SIZE_512KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER0; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); /* 配置FMC擴展IO的MPU屬性為Device或者Strongly Ordered */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x60000000; MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER1; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); /*使能 MPU */ HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); } /* ********************************************************************************************************* * 函 數 名: CPU_CACHE_Enable * 功能說明: 使能L1 Cache * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void CPU_CACHE_Enable(void) { /* 使能 I-Cache */ SCB_EnableICache(); /* 使能 D-Cache */ SCB_EnableDCache(); }
每10ms調用一次按鍵處理:
按鍵處理是在滴答定時器中斷里面實現,每10ms執行一次檢測。
/* ********************************************************************************************************* * 函 數 名: bsp_RunPer10ms * 功能說明: 該函數每隔10ms被Systick中斷調用1次。詳見 bsp_timer.c的定時中斷服務程序。一些處理時間要求 * 不嚴格的任務可以放在此函數。比如:按鍵掃描、蜂鳴器鳴叫控制等。 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_RunPer10ms(void) { bsp_KeyScan10ms(); }
主功能:
主程序實現如下操作:
- 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
- K1鍵 : 切換量程(5V或10V)。
- K2鍵 : 進入FIFO工作模式。
- K3鍵 : 進入軟件定時采集模式。
- 搖桿上下鍵 : 調節過采樣參數。
/* ********************************************************************************************************* * 函 數 名: main * 功能說明: c程序入口 * 形 參: 無 * 返 回 值: 錯誤代碼(無需處理) ********************************************************************************************************* */ int main(void) { bsp_Init(); /* 硬件初始化 */ PrintfLogo(); /* 打印例程名稱和版本等信息 */ DemoFmcAD7606(); /* AD7606測試 */ } /* ********************************************************************************************************* * 函 數 名: DemoFmcAD7606 * 功能說明: AD7606測試 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void DemoFmcAD7606(void) { uint8_t ucKeyCode; uint8_t ucRefresh = 0; uint8_t ucFifoMode; sfDispMenu(); /* 打印命令提示 */ ucFifoMode = 0; /* AD7606進入普通工作模式 */ ucRefresh = 0; /* 數據在串口刷新的標志 */ AD7606_SetOS(AD_OS_NO); /* 無過采樣 */ AD7606_SetInputRange(1); /* 0表示輸入量程為正負5V, 1表示正負10V */ AD7606_StartConvst(); /* 啟動1次轉換 */ bsp_StartAutoTimer(0, 500); /* 啟動1個500ms的自動重裝的定時器 */ bsp_StartAutoTimer(3, 200); /* 啟動1個200ms的自動重裝的定時器 */ /* 配置通道1,上行配置 默認情況下,J-Scope僅顯示1個通道。 上傳1個通道的波形,配置第2個參數為JScope_i2 上傳2個通道的波形,配置第2個參數為JScope_i2i2 上傳3個通道的波形,配置第2個參數為JScope_i2i2i2 上傳4個通道的波形,配置第2個參數為JScope_i2i2i2i2 上傳5個通道的波形,配置第2個參數為JScope_i2i2i2i2i2 上傳6個通道的波形,配置第2個參數為JScope_i2i2i2i2i2i2 上傳7個通道的波形,配置第2個參數為JScope_i2i2i2i2i2i2i2 上傳8個通道的波形,配置第2個參數為JScope_i2i2i2i2i2i2i2i2 */ SEGGER_RTT_ConfigUpBuffer(1, "JScope_i2", buf, 20480, SEGGER_RTT_MODE_NO_BLOCK_SKIP); while(1) { bsp_Idle(); /* 這個函數在bsp.c文件。用戶可以修改這個函數實現CPU休眠和喂狗 */ /* 判斷定時器超時時間 */ if (bsp_CheckTimer(3)) { /* 每隔100ms 進來一次 */ bsp_LedToggle(2); } if (ucRefresh == 1) { ucRefresh = 0; /* 處理數據 */ AD7606_Mak(); /* 打印ADC采樣結果 */ AD7606_Disp(); } if (ucFifoMode == 0) /* AD7606 普通工作模式 */ { if (bsp_CheckTimer(0)) { /* 每隔500ms 進來一次. 由軟件啟動轉換 */ AD7606_ReadNowAdc(); /* 讀取采樣結果 */ AD7606_StartConvst(); /* 啟動下次轉換 */ ucRefresh = 1; /* 刷新顯示 */ } } else { /* 在FIFO工作模式,bsp_AD7606自動進行采集,數據存儲在FIFO緩沖區。 結果可以通過下面的函數讀取: uint8_t AD7606_ReadFifo(uint16_t *_usReadAdc) 大家可以將數據保存到SD卡,或者保存到外部SRAM。 本例未對FIFO中的數據進行處理,進行打印當前最新的樣本值和J-Scope的實時輸出展示。 如果主程序不能及時讀取FIFO數據,那么 AD7606_FifoFull() 將返回真。 8通道200K采樣時,數據傳輸率 = 200 000 * 2 * 8 = 3.2MB/S */ if (bsp_CheckTimer(0)) { ucRefresh = 1; /* 刷新顯示 */ } } /* 按鍵檢測由后台systick中斷服務程序實現,我們只需要調用bsp_GetKey讀取鍵值即可。這個函數不會 等待按鍵按下,這樣我們可以在while循環內做其他的事情 */ ucKeyCode = bsp_GetKey(); /* 讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */ if (ucKeyCode != KEY_NONE) { switch (ucKeyCode) { case KEY_DOWN_K1: /* K1鍵按下 切換量程 */ if (g_tAD7606.ucRange == 0) { AD7606_SetInputRange(1); } else { AD7606_SetInputRange(0); } ucRefresh = 1; break; case KEY_DOWN_K2: /* K2鍵按下 */ ucFifoMode = 1; /* AD7606進入FIFO工作模式 */ g_tAD7606.ucOS = 1; /* 無過采樣 */ AD7606_StartRecord(AD7606_SampleFreq[g_tAD7606.ucOS]); /* 啟動100kHz采樣速率 */ AD7606_SetOS(g_tAD7606.ucOS); /* 設置無過采樣 */ printf("\33[%dA", (int)1); /* 光標上移n行 */ printf("AD7606進入FIFO工作模式 (200KHz 8通道同步采集)...\r\n"); break; case KEY_DOWN_K3: /* K3鍵按下 */ AD7606_StopRecord(); /* 停止記錄 */ ucFifoMode = 0; /* AD7606進入普通工作模式 */ g_tAD7606.ucOS = 0; /* 無過采樣 */ AD7606_SetOS(g_tAD7606.ucOS); printf("\33[%dA", (int)1); /* 光標上移n行 */ printf("AD7606進入普通工作模式(0.5s定時8通道同步采集)...\r\n"); break; case JOY_DOWN_U: /* 搖桿UP鍵按下 */ if (g_tAD7606.ucOS < 6) { g_tAD7606.ucOS++; } AD7606_SetOS(g_tAD7606.ucOS); /* 如果是FIFO模式,*/ if(ucFifoMode == 1) { /* 啟動當前過采樣下最高速度 */ AD7606_StartRecord(AD7606_SampleFreq[g_tAD7606.ucOS]); } ucRefresh = 1; break; case JOY_DOWN_D: /* 搖桿DOWN鍵按下 */ if (g_tAD7606.ucOS > 0) { g_tAD7606.ucOS--; } AD7606_SetOS(g_tAD7606.ucOS); ucRefresh = 1; /* 如果是FIFO模式,*/ if(ucFifoMode == 1) { /* 啟動當前過采樣下最高速度 */ AD7606_StartRecord(AD7606_SampleFreq[g_tAD7606.ucOS]); } break; default: /* 其他的鍵值不處理 */ break; } } }
76.13 總結
本章節涉及到的知識點非常多,實戰性較強,需要大家稍花點精力去研究。