完整教程下載下傳位址: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 總結
- 學習本章節前,務必優先學習第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采集的資料。
這裡将六種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相比,可以實作更高的分辨率或更小的裸片尺寸。
這裡将開發闆上的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間距排針,節約主機闆面積。
引腳定義和接線圖:
驅動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上所有模拟電路的接地基準點。所有模拟輸入信号和外部基準信号都應參考這些引腳。
- CONVSTA,CONVSTB :
啟動AD轉換的控制信号。CONVSTA決定1-4通道,CONVSTB決定5-8通道。2個信号可以錯開短暫的時間。一般情況可以将CVA,CVB并聯在一起。
量程範圍選擇。0表示正負5V, 1表示正負10V.
- RD /SCL:
讀信号,低電平有效。
- RESET
CONVST A和CONVST B均達到上升沿後,此引腳變為邏輯高電平,表示轉換過程已經開始,BUSY輸出保持高電平,直到所有通道的轉換過程完成為止。BUSY下降沿表示轉換資料正被鎖存至輸出資料寄存器,此時使用者就可以讀取資料。
片選信号,低電平有效。
- VDriver:
- 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采樣率,就不可以使用過采樣了。
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位模式,大家應該也都會計算了。
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
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
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
AD7606_StartConvst(void)
此函數用于啟動1次ADC轉換。
76.7.6 函數AD7606_ReadNowAdc
AD7606_ReadNowAdc(void)
此函數用于讀取8路采樣結果,結果存儲在全局變量 g_tAD7606。
76.7.7 函數AD7606_EnterAutoMode
AD7606_EnterAutoMode(uint32_t _ulFreq)
此函數用于配置硬體工作在自動采集模式,結果存儲在FIFO緩沖區。一般不單獨調用,函數AD7606_StartRecord會調用。
- 第1個參數是采樣頻率,範圍1-200KHz,機關Hz。
76.7.8 函數AD7606_StartRecord
void AD7606_StartRecord(uint32_t
_ulFreq)
用于啟動采集。
76.7.9 函數AD7606_StopRecord
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表示未滿。
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路
實際速度以底欄的展示為準,如果與設定的速度差異較大,說明傳輸異常了。
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驅動做了兩種采集方式
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)
/*
*********************************************************************************************************
* 函 數 名: 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_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();
}
/*
*********************************************************************************************************
* 函 數 名: bsp_RunPer10ms
* 功能說明: 該函數每隔10ms被Systick中斷調用1次。詳見 bsp_timer.c的定時中斷服務程式。一些處理時間要求
* 不嚴格的任務可以放在此函數。比如:按鍵掃描、蜂鳴器鳴叫控制等。
* 形 參: 無
* 返 回 值: 無
*********************************************************************************************************
*/
void bsp_RunPer10ms(void)
{
bsp_KeyScan10ms();
}
/*
*********************************************************************************************************
* 函 數 名: 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 總結
本章節涉及到的知識點非常多,實戰性較強,需要大家稍花點精力去研究。
微信公衆号:armfly_com
安富萊論壇:www.armbbs.cn
安富萊淘寶:https://armfly.taobao.com