Verilog sccb配置攝像頭


      之前參加學校的比賽曾經用過攝像頭,不過當時時間不多,配置攝像頭時直接用的是網上的sccb驅動,是大神crazybingo寫的那個,自行百度ov7670攝像頭徹底解讀便能找到,而此次由於項目要求要把攝像頭配置這一模塊獨立出來,需要把寄存器值寫進去然后再一個一個讀出來進行比對,那只好自己設計一個sccb驅動了。

     Sccb和i2c差別不大,具體可百度(話說都可以百度出來的話我還寫這個干嘛。。。),提供幾個我認為有用的鏈接吧, 零基礎sccb完全開發手冊    http://wenku.baidu.com/link?url=2EF9rOeVFaFDnJmuu31qbDF61rVDq00f_I1jImoy5k1pm63X8lejWNvTSMPOqrmXLP9V0XTjyY1qmk_s3yf7JPpkoP-uYBzdCnXTNUeJny7 ,基於FPGA的OV攝像頭初始化之SCCB協議的實現http://www.61ic.com/FPGA/Altera/201504/52884.html

      話說代碼不是最重要的,重要的是對協議的理解,所以我只是說一下我的設計思路,其實也是參考上面第二個鏈接設計的。

      由於個人不喜歡用那種通過將state加1來進行狀態轉換的用法,就像鏈接里面的那種,我喜歡的是那種滿足條件就跳轉,否則就維持的用法,比如,一個sccb的寫過程可以簡化為 開始 ---> 寫ID地址  --->  寫寄存器地址 ---> 寫數據 ---> 結束。這樣一個寫過程的狀態機就可以設計成 等待使能(WAIT_EN) -> START -> W_IDADDR -> W_SUBADDR -> W_DATA -> STOP。同樣讀過程狀態轉換為 等待使能(WAIT_EN) -> START -> W_IDADDR -> W_SUBADDR -> STOP -> START -> W_IDADDR -> R_DATA -> STOP 。可以看到上面兩個過程的中間有幾個狀態是重合的,由於讀寫在這些過程中要寫的數據都是一樣的,所以讀寫的過程可以共用這些狀態,兩個過程中不一樣的地方是讀過程在第一次stop之后又要開始Start進入第二相得讀操作,而寫操作不用,那就可以在STOP狀態的最后進行判斷下一狀態是應該跳到等待下一個使能,還是重新發start信號進行讀取寄存器值的操作(實際最后由於時序上的要求,我在STOP之后都是跳到等待使能的狀態重新把時鍾線和數據線都拉高,然后在WAIT_EN狀態進行判斷的,《由於我的讀/寫使能只拉高時鍾周期,而且控制模塊要受到我發出的讀/寫完畢信號后才發下一個使能,所以不存在此時恰好又收到一個使能信號而打斷讀過程的問題》),這樣,我就需要增加一個信號phase_flag來指示讀過程的第二段操作,即在寫寄存器地址W_SUBADDR狀態的最后判斷是否將此信號拉高在R_DATA狀態后再把它拉低,這樣在WAIT_EN狀態如果檢測到此信號為1則立刻跳到START進行讀過程的第二段操作。好了,整個狀態機的轉換就是下面這樣

 

代碼的話就是這樣:

 

 

 

  里面一些信號的意義

sccb_en: 讀/寫使能,維持一個時鍾周期,收到此信號執行一次讀/寫周期。

phase_flag: 上面已經說了。

w_flag: 一個sclk周期低電平的中間,也就是數據線sdat在此標志為高的時刻改變。如下,PERIOD與sclk頻率有關,如要以100kHz讀寫的話,一個周期為10us,模塊工作時鍾為50MHz,周期為20ns,則要計數的PERIOD=10000/20=500

 

  data_cnt: 讀/寫數據計數,從0到8共9個sclk周期,sclk就是時鍾線。在w_flag標志為高時加1。這樣要寫到sdat線上的數據就可以根據data_cnt的值來決定。

 

 

  注意,sdat是雙向口,用三態門來決定何時釋放總線。

 

  下面來看看modelsim的仿真圖

 

  這是仿真的第一個START 和W_IDADDR狀態,在sclk低電平的中間改變data_cnt加1,改變數據,sclk高低平期間保持穩定,仿真成功地發送了ID地址0x42。其中在data_cnt==8時,即第9個sclk周期釋放總線,讀取應答信號ack,所以sdat為高阻態。其實,這里的雙向口也可以仿真,模擬回復一個低電平的ack信號讓fpga讀取,不過之前有段時間一直在糾結雙向口該如何仿真的問題,其實如果在RTL圖里看過綜合出來的三態門,要仿真也是很簡單的,打算另外詳細說一下。

好了,不多說,上板驗證,上signaltap

 

  捕捉到的寫ID地址時的波形,sccb_en拉高一個周期高電平后,進入START狀態,sdat在sclk為高電平期間拉低,之后送ID地址0x42,注意data_cnt 為8時,sdat_en為低電平,說明此時fpga已釋放sdat的控制權,此時從機攝像頭把sdat拉低作為ack,可以看到在data_cnt為8期間sclk高電平之后sdat有一個時間很短的高電平,說明此時從機攝像頭在sclk高電平之后也釋放了對sdat的控制權,此時sdat由上拉電阻拉高為高電平。

 

    來個讀狀態,注意在data_cnt為8期間,此時應該由主控制器fpga發送一個高電平作為NA信號,最后是一個結束信號,sdat在sclk為高電平期間拉高。

 

      再來一張讀過程中一個stop信號后接一個start信號開始讀過程的第二段,注意sdat_en信號,此過程中主控制器FPGA不釋放sdat的控制權,sdat一個拉高的結束標志之后緊接着一個拉低的開始標志,而且要注意這期間sclk要一直為高,否則接下來的讀操作將會失敗。

——————————————————————————————————————————————————————————————————————————————

        好了,接下來就該說說調試過程中遇到的問題了。

        第一個就是上電階段由於系統時鍾還不穩定,不應該立刻啟動狀態機,不知道是不是這個原因,也不是很確定,看圖

 

 

      這個不是sccb驅動模塊里面的狀態機,而是給我送使能信號sccb_en的另一個模塊的狀態機,可以看到(延時讓我注釋掉了),它一上電就立刻跳轉,給我一個sccb_en的使能信號,結果就如上面捕捉到的波形,一下子來了一連串的sccb_en信號(正常情況下它在給我一個使能信號后要收到我發出的end信號后再發下一個使能),結果是在data_cnt為8時從機並沒有給回正確的ack(低電平),寫數據失敗。

      第二個還是要仔細看datasheet啊,

 

      總線釋放到下一個開始信號之間要間隔至少1.3us,fpga外部晶振50M,一個周期才20ns,之前就是在收到end信號后隔幾個時鍾就發下一個使能,才100多ns,結果老是寫不成功。。。。

      最后,說一個很郁悶的失誤,本來我們是打算用ov2640來調試的,結果死活找不到,只能用ov7670了,本來這沒什么的,但區別就在ov2640那個是內部自帶工作時鍾的,而ov7670則需要從xclk引腳輸入工作時鍾,結果我們沒有給它一個xclk就愣是在那調了好久說怎么捕捉到的波形時序是對的,攝像頭總是不應答呢,呃,不多說,最后還是潘哥提醒了才知道,估計潘哥特無語,慚愧,慚愧。。。。。

      好了,就這么多吧,挺簡單的一個協議,結果搞了好久,學藝不精啊。。。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM