Samsung s3c6410/s3c2416 的SPI接口調試 (2011-06-14 22:33)

參考資料:

  • 6410手冊/2416手冊
  • Kernel部分驅動代碼
作者:agan
聯繫郵箱 [email protected]
racer.blog.chinaunix.net
轉載須註明出處!

 


  SPI接口簡述

  SPI是 Serial Peripheral Interface(串型外部接口)的縮寫。SPI接口有4根PIN腳,分別是:
          * SPICLK     : 用於傳輸數據的同步時鐘
          * SPIMISO    : 用於主模式下的輸入,或從模式下的輸出信號線
          * SPIMOSI    : 用於主模式下的輸出,或從模式下的輸入信號線
          * PSS        : 用於從設備的片選信號,低有效

   SPI 通信兩端各自扮演主設備(Master)和從設備(Slave)的角色。主設備在移位寄存器進行傳輸時(SPIMISO/SPIMOSI上面有信號時),提供SPICLK時鐘作爲對方同步和採樣的依據,同時在傳輸的過程中,PSS要一直被Master拉底。傳輸完成,PSS拉高,SPICLK信號消失。具體傳輸時序,請瀏覽後續的“傳輸時序”章節。

   SPI接口有點類似於UART接口,他們通常都用於滿足一些低速傳輸的需求,比如通信量小的控制數據傳輸/或者接入一些低速的輸入設備(鼠標/鍵盤/觸摸屏)等等。他們之間的主要區別如下:
        * SPI靠SPICLK作爲傳輸同步信號,因此它走的是串性同步傳輸信號。
        * UART是通用異步串性傳輸信號的縮寫,他的PIN定義中沒有時鐘信號,通信兩端靠約定好的波特率,以及數據格式中的開始位/停止位/校驗位來構造和解析數據。
        因爲UART是異步傳輸,所以他還有RTX/CTS之類的PIN腳用於數據碼流控制,現在大部分的UART控制器都支持硬件流控,這樣就簡化了這種老式數據傳輸方式的軟件設計複雜度。

    SPI傳輸時序

    在SPI控制器的寄存器佈局中,通常都有2個配置: CPOL (Polarity:極性) 和 CPHA (PHASE: 相位).
    CPOL 控制傳輸過程中SPICLK是高有效還是低有效, CPHA控制的是在對應的極性中,哪一個SPICLK EDGE進行數據同步,哪一個EDGE進行數據採集。
    這裏的說的比較抽象,讀者可以參考SPI傳輸時序圖 。


    寄存器佈局
    對比6410和2416的寄存器手冊,發現他們的寄存器佈局是一樣的,由此判斷他們芯片內部用的可能是同一種SPI控制器
    只不過6410有兩個SPI總線,2416只有一個。

    寄存器CH_CFG
        SW_RST    : SW reset   
        軟件復位,這非常重要。 6410的SPI驅動通常會頻繁的reset SPI控制器,reset通常發生在一次批量數據的傳輸之後(批量是指小於FIFO大小64字節的傳輸)下一次傳輸之前。
        每次reset過後,大部分寄存器的值都需要重新配置。這一點區別於我們通常對其他芯片的理解,其他芯片通常都只需要在init/probe之類的函數內reset和配置寄存器一次即可。
        CPOL/CPHA
        選擇傳輸時序,請查看前面的"SPI傳輸時序"章節。傳輸時許取決於SPI對端從設備的輸入時序,查閱對端從設備的手冊,它需要什麼輸入時序這裏就選擇輸出怎樣的時序。
        RxChOn/TxChOn
        讀寫通道的開關。6410 kernel的驅動經常會開關RxChOn/TxChOn,目的可能是隻在需要傳輸時打開,不需要就關閉,避免信號干擾產生垃圾數據。或者是錯誤處理:在出錯時先關掉傳輸通道,再清空2個64字節的FIFO.

    寄存器Clk_CFG
        用於配置SPI的輸入時鐘和輸出時鐘:
        ClkSel   
         這個跟具體的硬件有關,具體到2416, PCLK/EPLL都是通路。

        Prescaler Value
        分頻參數,是通過始終輸入,產生始終輸出SPICLK的一個計算分母,計算公式:HS_SPI clock-out = Clock source / ( 2 x (Prescaler value +1))。
             
        具體怎麼配置?先查看你的SPI掛接設備他需要多大的輸入時鐘頻率,再看看你的SPI控制器有哪些時鐘輸入,然後根據公式一算便知。

    寄存器MODE_CFG
        用於配置傳輸方式,以及每個方式所對應的一些配置參數:
        先說一下2416 SPI的傳輸方式。 SPI有傳輸和接收移位寄存器HS_SPI_TX_DATA/HS_SPI_RX_DATA。不管你是使用的哪種傳輸方式,所有的傳輸出口都是HS_SPI_TX_DATA,所有的接收入口都是HS_SPI_RX_DATA. 這兩個寄存器對應兩個FIFO,每個FIFO64字節,兩個寄存器就相當於兩個FIFO的棧頂指針。

        * 輪訓: 靠HS_SPI_STATUS寄存器的RxFifoLvl判斷RxFIFO內是否有數據,有多少字節的數據。靠同一個寄存器的TxFifoLvl位來判斷TxFifo內是否還有數據,用以判斷剛纔的TX動作是否成功完成。輪訓同一個寄存器的其他位可獲知傳輸過程中是否有錯誤發生。

        * 中斷方式: 設置當前寄存器(MODE_CFG)的RxTrigger位,用以表明在RxFifo中的數據堆積了多少字節後,產生一箇中斷。TxTrigger同理。Trailing Count爲用以配置在多少個時鐘週期後(從最後一次寫入RxFifo開始計時),產生一箇中斷。Trailing Count用以讓用戶獲取RxFifo中小於Trigger字節的數據。       
       
        * DMA模式:DMA的介入點,只是從系統內存中拷貝批量數據到移位傳輸的出口地址,或是從移位接收的入口地址批量拷貝數據到系統內存中。注意,要配置DMA模塊,在涉及SPI移位寄存器這一邊的地址,在DMA過程中不能遞增。

        當然,以上方式也不是互相排斥的。6410的driver就是用了DMA做爲用戶內存與移位寄存器之間的傳輸方式,使用中斷方式作爲傳輸等待/傳輸錯誤的捕獲方式,使用輪訓來判斷錯誤處理函數中FIFO是否已經清空。

    寄存器Slave_slection_reg
        用於配置怎樣產生PSS信號,就是對Slave端的片選信號。
        6410的驅動中,一直使用手動方式控制片選信號。   

        這裏再說清楚信號之間的一個疑惑。PSS/CLK同時存在(CLK有信號並且PSS拉低),不管數據線上有沒有信號,SPI主從設備都會採樣,也就是你的TxFifo/RxFifo就可能產生數據。
        如果PSS/CLK信號都用手動控制,那肯定會產生垃圾數據,因爲在你從你產生PSS/CLK信號到你往SPIMOSI/SPIMISO上讀寫數據這段時間內,肯定會有間隔時間(即使只有幾個時鐘週期),在這段間隔時間內,FIFO可能早就被垃圾數據填滿了。
        幸好硬件設計可能想到了這點,這裏的PSS信號手動控制,的確是讓用戶手動拉高拉低PSS信號。但是SPI_CLK信號,卻是硬件自動調製的。
        前面CLK_CFG:ENCLK信號,並不是控制CLK信號的輸出通斷,它只是控制CLK輸入輸出/以及分頻參數是否有效。
        真正的SPICLK輸出信號,是靠移位寄存器自動控制的:發送移位寄存器開始傳輸時,就按照你所配置的CPOL+CPHA時序打開SPICLK信號。
        那麼SPICLK在何時關閉?Master向Slave發送命令後,通常還要等待Slave返回的數據,返回數據長度不同,SPICLK的長度就不同,那麼SPICLK該在什麼時候關閉?
        這時寄存器Packet_Count_reg閃亮登場!這裏一個Packet的長度,應該是你前面配置的8/16/32寬度。這個寄存器告訴接收移位寄存器,這次傳輸在收到X個Packet後,關閉SPICLK.
        如果Packet Count過大,則SPICLK可能長時間有效,如果PacketCount過小,則能截斷對方發送的數據。

        總而言之,SPI的4根線,只有PSS是軟件程序控制,其他SPICLK/SPIMOSI/SPIMISO是根據你的配置,硬件自動調製的。

    寄存器HS_SPI_INT_EN
        中斷使能寄存器,用於控制讓什麼情況產生中斷。


    寄存器HS_SPI_STATUS
        很重要的狀態寄存器。

    接收移位寄存器HS_SPI_RX_DATA       
    發送移位寄存器HS_SPI_TX_DATA

        數據傳輸接收的唯一接口,請看上面的“傳輸方式”介紹。

    接受包計數寄存器Packet_Count_reg
        用於控制SPINCLK何時消失,請看上面的“傳輸方式”介紹。

    清除狀態寄存器Pending_clr_reg
        用於清除狀態寄存器,通常這樣使用:
        writel(readl(sspi->regs + SAMSPI_PENDING_CLR), sspi->regs + SAMSPI_PENDING_CLR);
        即,哪個沒清清哪個!

    SWAP_CFG/FB_Clk_sel
        這兩個的意思不明,只能根據字面意思猜測。
        6410的driver給的都是默認值。



    調試筆記

        * CPOL的實際情況,可能與手冊中寫的相反。即CPOL=0,實際輸出了低有效CLK;CPOL=1,實際上輸出了高有效CLK。
        * HS_SPI_STATUS:TX_done,這一位實際情況與手冊描述不符。實際情況中,完全讓人搞不懂,6410的driver中也沒有使用這一位。
        * 2416 kernel自帶的SPI driver,掛在系統spi_dev結構下,就是一個字符設備,用於訪問一些通用的外設,沒有錯誤處理,只能讀或者寫,不能處理外設的先寫後讀協議,只適合用於調試目的,不適合驅動外設。
        * 6410 kernel自帶的SPI driver,掛在系統的構架下,實現了一個SPI的MASTER。筆者研究的ads7846 ADC的現成驅動,可直接配合使用。

發佈了18 篇原創文章 · 獲贊 10 · 訪問量 32萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章