鐘芯片配置:SPI寄存器編程與PLL頻率規(guī)劃實(shí)戰(zhàn))
簡(jiǎn)介本資源是一套面向嵌入式工程師與硬件開發(fā)者的AD9517高性能時(shí)鐘芯片配置程序源碼包聚焦于解決多通道可編程時(shí)鐘發(fā)生器的寄存器初始化、SPI/I2C通信驅(qū)動(dòng)及動(dòng)態(tài)頻率配置等核心問題適用于雷達(dá)、通信基站、高速ADC/DAC同步等對(duì)時(shí)鐘精度與靈活性要求嚴(yán)苛的場(chǎng)景。壓縮包共含3個(gè)文件2個(gè)頭文件.h 1個(gè)C源文件.c總大小僅12KB結(jié)構(gòu)精煉頭文件定義了AD9517寄存器映射、配置結(jié)構(gòu)體及API函數(shù)原型C文件實(shí)現(xiàn)了底層寄存器寫入、PLL參數(shù)計(jì)算、輸出通道使能等關(guān)鍵驅(qū)動(dòng)邏輯代碼注釋清晰且貼近實(shí)際工程調(diào)用習(xí)慣。目前已有853人學(xué)習(xí)下載讀者可直接集成到嵌入式項(xiàng)目中快速完成芯片上電初始化、多路獨(dú)立時(shí)鐘輸出配置及運(yùn)行時(shí)動(dòng)態(tài)重配置顯著降低AD9517在Linux或裸機(jī)環(huán)境下的驅(qū)動(dòng)開發(fā)門檻。1. 為什么AD9517需要配置程序默認(rèn)狀態(tài)的真相1.1 一顆“功能齊全但默認(rèn)全關(guān)”的芯片做高速數(shù)據(jù)采集或者射頻系統(tǒng)的人對(duì)AD9517應(yīng)該都不陌生。一片芯片把PLL、內(nèi)部VCO、12路時(shí)鐘輸出和各種分頻器全集成在一起可以同時(shí)給ADC、DAC、FPGA、數(shù)字中頻模塊提供多路低抖動(dòng)時(shí)鐘板級(jí)時(shí)鐘樹一下子清爽很多。但用過它的人也都知道這顆芯片不是上電就能出時(shí)鐘的——它內(nèi)部每一路輸出、每一個(gè)分頻器、整個(gè)PLL環(huán)路全部靠SPI寄存器控制。默認(rèn)上電狀態(tài)下PLL沒有鎖定各路輸出驅(qū)動(dòng)基本處于關(guān)斷狀態(tài)你不在初始化階段跑一遍配置程序示波器探針往輸出腳上一搭就是一條直線啥都沒有。我把這個(gè)“配置程序”拆開看其實(shí)就三件事把目標(biāo)頻率方案翻譯成寄存器值按正確的時(shí)序把這些寄存器寫進(jìn)去再做回讀或狀態(tài)確認(rèn)保證芯片真的按預(yù)期工作。聽起來簡(jiǎn)單但坑都在細(xì)節(jié)里。比如24位SPI的幀格式、VCO校準(zhǔn)的觸發(fā)時(shí)機(jī)、分頻器改動(dòng)之后的同步操作任何一步錯(cuò)了表象都是同一個(gè)程序跑完了芯片沒輸出。1.2 配置程序在系統(tǒng)里的位置與職責(zé)AD9517這顆芯片的上游是參考時(shí)鐘源下游是ADC、DAC、FPGA這些需要時(shí)鐘的器件。配置程序就是夾在中間的那個(gè)“翻譯官”。在完整系統(tǒng)里它通常是MCU或者FPGA裸機(jī)程序里的一個(gè)驅(qū)動(dòng)模塊上電后先于業(yè)務(wù)邏輯執(zhí)行負(fù)責(zé)把AD9517帶到指定的工作狀態(tài)。職責(zé)邊界要分清楚配置程序只負(fù)責(zé)“讓AD9517按設(shè)計(jì)輸出正確的時(shí)鐘”不負(fù)責(zé)時(shí)鐘質(zhì)量。時(shí)鐘的抖動(dòng)、相位噪聲在原理圖階段就已經(jīng)由參考源、環(huán)路濾波器、電源設(shè)計(jì)這些決定了。配置程序的職責(zé)是把芯片內(nèi)部的分頻鏈路、PLL環(huán)路、輸出驅(qū)動(dòng)設(shè)置到設(shè)計(jì)值并且確認(rèn)芯片真的鎖定了。實(shí)際項(xiàng)目里很多人容易混淆這兩件事花大量時(shí)間在程序里調(diào)相位噪聲其實(shí)應(yīng)該回去查電源紋波和環(huán)路濾波器參數(shù)。還有一點(diǎn)容易被忽略AD9517有多個(gè)電源域不同電源域的上電順序、去耦電容的布局直接影響配置程序能不能正常工作。我調(diào)過的板子里就有因?yàn)橐宦份敵鲵?qū)動(dòng)電源沒貼好導(dǎo)致寄存器全配置成功、但某一路輸出就是沒有波形的案例。這個(gè)后面在調(diào)板記錄里會(huì)詳細(xì)講。2. 24位SPI與寄存器地圖動(dòng)手寫代碼前必須搞清的兩個(gè)基礎(chǔ)2.1 24位傳輸格式地址和數(shù)據(jù)怎么拼進(jìn)3個(gè)字節(jié)AD9517的SPI控制口是24位移位寄存器結(jié)構(gòu)一次完整傳輸就是24位。高位在前。這24位拆開看第一位是讀寫標(biāo)志接下來兩位是無關(guān)位可以填充0再接下來13位是寄存器地址最低8位是數(shù)據(jù)。很多第一次寫驅(qū)動(dòng)的人會(huì)想當(dāng)然地按字節(jié)去拼結(jié)果地址對(duì)不上。正確拼法是第一個(gè)字節(jié)的高位放讀寫標(biāo)志低5位放地址的A12到A8第二個(gè)字節(jié)放地址低8位第三個(gè)字節(jié)放數(shù)據(jù)。換算成代碼就是下面這樣我以STM32的HAL庫(kù)為例void ad9517_write_reg(uint16_t addr, uint8_t data) { uint8_t buf[3]; /* 24位幀: [RW][X][X][A12:A8] [A7:A0] [D7:D0] */ buf[0] ((addr 8) 0x1F); /* 寫操作RW0低5位是地址高段 */ buf[1] addr 0xFF; /* 地址低8位 */ buf[2] data; /* 數(shù)據(jù)8位 */ AD9517_CS_LOW(); HAL_SPI_Transmit(hspi2, buf, 3, 10); AD9517_CS_HIGH(); }這里有一個(gè)細(xì)節(jié)值得強(qiáng)調(diào)CSB引腳必須在整個(gè)24位傳輸期間保持低電平中途不能拉高。用STM32的硬件SPI時(shí)如果你只調(diào)HAL_SPI_TransmitCSB由GPIO手動(dòng)控制就天然滿足這個(gè)要求。但如果你用了硬件NSS模式一定要把NSS配置成軟件控制否則SPI外設(shè)會(huì)在每傳輸一個(gè)字節(jié)后自動(dòng)翻轉(zhuǎn)NSS把幀切碎寄存器根本寫不進(jìn)去。這是我見過的最常見的低級(jí)錯(cuò)誤。2.2 寄存器按功能分四大區(qū)AD9517的寄存器地圖在手冊(cè)里占了很大篇幅但按功能可以歸成四個(gè)區(qū)理解了這個(gè)框架看手冊(cè)就不暈了。第一個(gè)區(qū)是0x000附近的全局控制區(qū)包括SPI配置、軟復(fù)位、芯片狀態(tài)這些。第二個(gè)區(qū)是0x010到0x01F的PLL控制區(qū)R分頻器、N分頻器、電荷泵電流、預(yù)分頻器、VCO校準(zhǔn)和鎖定狀態(tài)都在這里。第三個(gè)區(qū)是0x100往后的通道分頻器區(qū)每路輸出對(duì)應(yīng)的分頻系數(shù)、分頻器使能、分頻器相位都在這一段。第四個(gè)區(qū)是0x1E0往后的輸出驅(qū)動(dòng)區(qū)配置各路輸出是LVPECL、LVDS還是CMOS以及輸出使能和電流幅度。功能區(qū)塊寄存器區(qū)段要關(guān)心的關(guān)鍵內(nèi)容全局控制0x000附近軟復(fù)位、SPI工作模式、狀態(tài)回讀PLL環(huán)路0x010~0x01FR、N分頻值、電荷泵電流、VCO校準(zhǔn)、鎖定檢測(cè)通道分頻0x100~0x1BF各路輸出分頻比、分頻器使能與同步輸出驅(qū)動(dòng)0x1E0~0x1FF輸出使能、電平標(biāo)準(zhǔn)、擺幅/電流檔位我一個(gè)項(xiàng)目做下來實(shí)際頻繁碰到的寄存器其實(shí)不超過20個(gè)。但是要注意AD9517有多個(gè)后綴版本個(gè)別寄存器位的定義可能略有差異寫代碼之前把手上那顆芯片對(duì)應(yīng)版本的數(shù)據(jù)手冊(cè)Register Map打出來對(duì)著表填值不要憑印象寫。2.3 軟復(fù)位是整個(gè)配置的第一步上電之后做任何配置之前強(qiáng)烈建議先執(zhí)行一次軟復(fù)位。AD9517的0x000寄存器里有一個(gè)軟復(fù)位位寫1觸發(fā)復(fù)位芯片內(nèi)部寄存器回到默認(rèn)狀態(tài)然后這個(gè)位會(huì)自動(dòng)清零。軟復(fù)位的意義在于如果芯片之前被配置過或者上一級(jí)系統(tǒng)做了熱重啟寄存器里殘留的狀態(tài)會(huì)干擾你的初始化尤其會(huì)影響PLL的VCO校準(zhǔn)結(jié)果。我習(xí)慣的軟復(fù)位代碼長(zhǎng)這樣static void ad9517_soft_reset(void) { ad9517_write_reg(0x000, 0x04); /* 觸發(fā)軟復(fù)位 */ HAL_Delay(1); ad9517_write_reg(0x000, 0x00); /* 復(fù)位位自清零這里再寫一次0確保狀態(tài)干凈 */ HAL_Delay(10); /* 給芯片足夠的復(fù)位時(shí)間 */ }這里的關(guān)鍵是軟復(fù)位之后必須延時(shí)。芯片內(nèi)部復(fù)位需要一點(diǎn)時(shí)間如果你緊接著就去寫PLL寄存器很可能寫了個(gè)寂寞后面PLL怎么都鎖不上。延時(shí)我一般給10毫秒以上足夠穩(wěn)妥。另外軟復(fù)位位觸發(fā)一次就夠了不要在初始化主流程里反復(fù)執(zhí)行否則會(huì)影響PLL的鎖定連續(xù)性。3. 從10MHz到1.6GHz頻率規(guī)劃與寄存器數(shù)值怎么算出來的3.1 PLL環(huán)路公式R、N、VCO配置程序里最核心的數(shù)學(xué)就是PLL的頻率公式。AD9517內(nèi)部PLL的結(jié)構(gòu)是參考輸入經(jīng)過可選的倍頻器和R分頻器得到鑒相頻率PFDPFD經(jīng)過N分頻器反饋到VCOVCO的輸出再分頻到各路輸出。整個(gè)鏈路用公式寫出來就是PFD REFIN × (參考倍頻器系數(shù)) / R VCO PFD × N 通道輸出頻率 VCO / 該通道分頻系數(shù)我這次項(xiàng)目的場(chǎng)景是10MHz參考輸入目標(biāo)VCO頻率1.6GHz。為了讓PFD高一些、改善帶內(nèi)相噪我把R分頻器設(shè)為1即PFD等于10MHz。接著算N1600MHz除以10MHzN等于160。N分頻器在這種芯片里是14位寬160這個(gè)值完全在范圍內(nèi)。這里有一個(gè)經(jīng)驗(yàn)之談VCO頻率不是隨便定的AD9517內(nèi)部VCO有明確的可調(diào)范圍我用的這顆是1.45GHz到1.8GHz左右。選VCO頻率時(shí)先保證落在芯片規(guī)格范圍內(nèi)再考慮輸出頻率往哪個(gè)方向分頻。如果系統(tǒng)需要的是低頻時(shí)鐘寧可讓VCO跑高一點(diǎn)再往下分頻也不要為了省分頻器把VCO壓到太低。VCO工作點(diǎn)偏低時(shí)芯片的相位噪聲性能和鎖定裕量都會(huì)變差。3.2 輸出分頻與驅(qū)動(dòng)類型選擇VCO定在1.6GHz之后各路輸出分頻就很好算了。需求里有一路200MHz給ADC那就用LVPECL輸出分頻系數(shù)8一路100MHz給FPGA用LVDS輸出分頻系數(shù)16還有一路100MHz單端時(shí)鐘給邏輯電路用CMOS輸出分頻系數(shù)16。AD9517的12路輸出不是完全一樣的兩路LVPECL、六路LVDS、四路CMOS每路輸出前面都有獨(dú)立的分頻器。分頻系數(shù)不是連續(xù)的1到32全都有而是支持1、2、3、4、5、6、8、10、12、16、20、24、32這些檔位。所以做頻率規(guī)劃的時(shí)候一定要先確認(rèn)輸出頻率除以VCO頻率之后得到的分頻系數(shù)在支持列表里。如果不在就得回頭調(diào)整VCO頻率或者接受一個(gè)略有偏差的輸出頻率。輸出驅(qū)動(dòng)類型的配置也要對(duì)應(yīng)上芯片的物理引腳。比如某個(gè)引腳在封裝上是LVDS輸出你就不可能在寄存器里把它配成LVPECL寄存器只是讓你在LVDS的幾個(gè)電流檔位和共模電平里做選擇。我見過有人對(duì)著手冊(cè)把LVPECL輸出當(dāng)LVDS來配結(jié)果輸出波形畸變嚴(yán)重還以為芯片壞了。3.3 用ADIsimClk生成寄存器表手算R和N沒問題但整個(gè)芯片幾十個(gè)寄存器的完整配置我不建議純手算。ADI官方有ADIsimClk這個(gè)評(píng)估軟件把參考頻率、目標(biāo)輸出頻率、輸出電平類型填進(jìn)去它能自動(dòng)算出所有寄存器值還能仿真抖動(dòng)性能。我的做法是先用ADIsimClk把頻率方案跑通生成寄存器列表然后人為檢查幾個(gè)關(guān)鍵位的數(shù)值是否符合預(yù)期再把這個(gè)列表轉(zhuǎn)化成代碼里的初始化表。這樣做的原因很實(shí)際。AD9517的寄存器里有些位的影響是非線性的比如電荷泵電流的設(shè)置會(huì)影響環(huán)路穩(wěn)定性輸出分頻器的同步模式影響各路輸出之間的相位關(guān)系這些靠手算很容易漏。ADIsimClk生成的表至少保證了一致性人工檢查時(shí)重點(diǎn)看R、N、VCO校準(zhǔn)、輸出使能這幾類關(guān)鍵寄存器就夠了。4. 配置程序?qū)崿F(xiàn)SPI驅(qū)動(dòng)、初始化表與回讀校驗(yàn)4.1 SPI讀寫函數(shù)底層驅(qū)動(dòng)就兩個(gè)函數(shù)一個(gè)寫寄存器一個(gè)讀寄存器。寫寄存器前面已經(jīng)給了讀寄存器是同樣構(gòu)造24位幀只是讀寫標(biāo)志位置1然后在SPI時(shí)鐘下從芯片的DOUT引腳把8位數(shù)據(jù)讀回來。uint8_t ad9517_read_reg(uint16_t addr) { uint8_t tx[3], rx[3]; tx[0] (1 7) | ((addr 8) 0x1F); /* 讀操作RW1 */ tx[1] addr 0xFF; tx[2] 0x00; /* 第3個(gè)字節(jié)只是用來產(chǎn)生時(shí)鐘 */ AD9517_CS_LOW(); HAL_SPI_TransmitReceive(hspi2, tx, rx, 3, 10); AD9517_CS_HIGH(); return rx[2]; /* 讀到的數(shù)據(jù)在rx[2] */ }讀操作的本質(zhì)是用SPI時(shí)鐘把芯片里的數(shù)據(jù)移位輸出。所以第三個(gè)字節(jié)你發(fā)什么無所謂純粹是為了提供時(shí)鐘沿。如果你的MCU用的是3線SPI模式注意這時(shí)SDIO引腳要切換到輸入方向或者直接用帶MOSI/MISO分開的4線模式。AD9517的SDO引腳是否啟用和上電時(shí)的引腳電平有關(guān)這個(gè)在硬件設(shè)計(jì)時(shí)就要定好軟件側(cè)要保證本文還有配套的精品資源點(diǎn)擊獲取