• <li id="00i08"><input id="00i08"></input></li>
  • <sup id="00i08"><tbody id="00i08"></tbody></sup>
    <abbr id="00i08"></abbr>
  • 新聞中心

    EEPW首頁 > 嵌入式系統 > 設計應用 > FPGA:SPI接口

    FPGA:SPI接口

    作者: 時間:2024-01-04 來源:EEPW編譯 收藏

    SPI可以用作和其他芯片之間簡單有效的通信方式。

    本文引用地址:http://www.czjhyjcfj.com/article/202401/454461.htm

    SPI 1 - 什么是SPI?

    SPI是一個簡單的接口,允許一個芯片與一個或多個其他芯片進行通信。

    它看起來如何?

    讓我們從一個簡單的例子開始,其中只有兩個芯片必須一起通信。

    SPI 需要在兩個芯片之間使用 4 根線。

    如您所見,這些電線被稱為 SCK、MOSI、MISO 和 SSEL,其中一個芯片是“主芯片”,另一個芯片是“從芯片”。

    SPI基礎知識

    基本上:

    1. 它是同步的。

    2. 它是全雙工串行。

    3. 它不是即插即用的。

    4. 有一個(也只有一個)主站和一個或多個(或多個)從站。

    更多細節:

    1. 同步:時鐘由主機生成。

    2. 全雙工串行:數據被串行化,在每個時鐘周期內向每個方向傳輸一位數據,因此使用兩條數據線(MOSI 和 MISO)。

    3. 非即插即用:主站和從站事先知道通信的細節(位順序、交換的數據字長度等)。

    4. 一個主站:從站不能發起通信,只有主站可以。從屬設備傾聽并做出回應。

    簡單轉移

    假設主站和從站需要 8 位數據傳輸,首先傳輸 MSB。
    以下是單個 8 位數據傳輸的樣子。

    MOSI線是“主輸出”,而MISO是“從輸出”。 由于SPI是全雙工的,兩條線同時切換,從主到從,從從到主,從到主。

    更多細節:

    1. 主站下拉 SSEL 以向從站指示通信正在啟動(SSEL 處于低電平有效狀態)。

    2. 主機切換時鐘八次,并在其 MOSI 線路上發送 8 個數據位。同時,它從MISO線路上的從站接收8個數據位。

    3. 主站向上拉 SSEL 以指示傳輸已結束。

    如果主服務器有多個 8 位數據要發送/接收,則它只能在發送/接收完成后繼續發送/接收并取消置位 SSEL。

    多個從站

    SPI主機可以通過兩種方式與多個從機通信:并行連接大多數信號并添加SSEL線,或者通過鏈接從機。

    使用多 SSEL 線路技術時,一次只能激活一條 SSEL 線路,并且未選擇的從站不得驅動 MISO 線路。

    它有多快?

    SPI可以輕松實現幾Mbps(兆比特/秒)。 這意味著它可以用于未壓縮的音頻或壓縮的視頻。

    SPI 2 - 簡單的實現

    ARM 處理器

    為了有機會測試我們新獲得的 SPI 知識,我們使用了 Saxo-L 板。 它有一個 ARM7 處理器 (LPC2138) 和一個 Cyclone (EP1C3),通過 SPI 總線連接。

    ARM 用作 SPI 主機,而 用作 SPI 從機。 Saxo-L ARM 處理器實際上有兩個 SPI 接口,一個稱為 SPI0,另一個更高級的稱為 SPI1/SSP。 它們都同樣易于使用。我們在 Saxo-L 上使用 SPI1/SSP,因為它已預先接線在電路板上。

    SPI 主機 - C ARM 代碼

    使用 SSP 只需初始化幾個寄存器,然后寫入/讀取數據以自動發送/接收。

    void main(void)
    {
     // initialize SSP
     SSP0CPSR = 0x02;  // SSP max speed
     SSP0CR0 = 0x07;  // SSP max speed, 8 bits
     SSP0CR1 = 0x02;  // SSP master mode
     PINSEL1 = 0x2A8;  // SSP mode for pins P0.17 to P0.20

     while(1)
     {
       // send two bytes
       SSP0DR = 0x55;  // one nice thing about the SSP is that it has a 8-words deep FIFO
       SSP0DR = 0x54;  // so here we write the data to be sent without worrying

       // now wait until both bytes are sent
       while(!(SSP0SR & 0x01));

       // now we can read the two bytes received... and do anything with them
       int data1 = SSP0DR;
       int data2 = SSP0DR;
       // ...
     }
    }

    SPI 從機 - HDL FPGA 代碼

    現在是FPGA中的SPI從機。

    由于SPI總線通常比FPGA工作時鐘速度慢得多,因此我們選擇使用FPGA時鐘對SPI總線進行過采樣。 這使得從機代碼稍微復雜一些,但其優點是SPI邏輯在FPGA時鐘域中運行,這將使以后的工作變得更容易。

    首先是模塊聲明。

    module SPI_slave(clk, SCK, MOSI, MISO, SSEL, LED);
    input clk;
    input SCK, SSEL, MOSI;
    output MISO;
    output LED;

    請注意,我們有“clk”(FPGA 時鐘)和一個 LED 輸出......一個不錯的小調試工具。 “clk”需要比 SPI 總線更快。Saxo-L 的默認時鐘為 24MHz,在這里工作正常。

    我們使用 FPGA 時鐘和移位寄存器對 SPI 信號(SCK、SSEL 和 MOSI)進行采樣/同步。

    // sync SCK to the FPGA clock using a 3-bits shift register
    reg [2:0] SCKr;  
    always @(posedge clk) SCKr <= {SCKr[1:0], SCK};
    wire SCK_risingedge = (SCKr[2:1]==2'b01);  // now we can detect SCK rising edges
    wire SCK_fallingedge = (SCKr[2:1]==2'b10);  // and falling edges
    // same thing for SSEL
    reg [2:0] SSELr;  
    always @(posedge clk) SSELr <= {SSELr[1:0], SSEL};
    wire SSEL_active = ~SSELr[1];  // SSEL is active low
    wire SSEL_startmessage = (SSELr[2:1]==2'b10);  // message starts at falling edge
    wire SSEL_endmessage = (SSELr[2:1]==2'b01);  // message stops at rising edge
    // and for MOSI
    reg [1:0] MOSIr;  
    always @(posedge clk) MOSIr <= {MOSIr[0], MOSI};
    wire MOSI_data = MOSIr[1];

    現在,從 SPI 總線接收數據很容易。

    // we handle SPI in 8-bits format, so we need a 3 bits counter to count the bits as they come in
    reg [2:0] bitcnt;reg byte_received;  // high when a byte has been received
    reg [7:0] byte_data_received;
    always @(posedge clk)begin
     if(~SSEL_active)
       bitcnt <= 3'b000;  else
     if(SCK_risingedge)  begin
       bitcnt <= bitcnt + 3'b001;

       // implement a shift-left register (since we receive the data MSB first)
       byte_data_received <= {byte_data_received[6:0], MOSI_data};  end
       end
       always @(posedge clk) byte_received <= SSEL_active && SCK_risingedge && (bitcnt==3'b111);
    // we use the LSB of the data received to control an LEDreg LED;
    always @(posedge clk) if(byte_received) LED <= byte_data_received[0];

    最后是傳動部分。

    reg [7:0] byte_data_sent;
    reg [7:0] cnt;
    always @(posedge clk) if(SSEL_startmessage) cnt<=cnt+8'h1;  // count the messages
    always @(posedge clk)if(SSEL_active)begin
     if(SSEL_startmessage)
       byte_data_sent <= cnt;  // first byte sent in a message is the message count  else
     if(SCK_fallingedge)  begin
       if(bitcnt==3'b000)
         byte_data_sent <= 8'h00;  // after that, we send 0s    else
         byte_data_sent <= {byte_data_sent[6:0], 1'b0};  
         end
         end
         assign MISO = byte_data_sent[7];  // send MSB first
    // we assume that there is only one slave on the SPI bus
    // so we don't bother with a tri-state buffer for MISO
    // otherwise we would need to tri-state MISO when SSEL is inactiveendmodule

    我們已經在 ARM 和 FPGA 之間建立了通信!

    運行代碼

    當我們逐步執行 ARM 代碼時,我們可以看到 LED 的狀態發生變化,以及 FPGA 返回的數據。

    現在讓我們看看我們是否可以用SPI做一些有用的事情。

    SPI 3 - 應用

    LCD接口

    由于我們已經知道如何驅動圖形 LCD 面板,尤其是在文本模式下,讓我們嘗試從 LPC 中寫出文本

    從FPGA的角度來看,LCD控制器使用幾個blockram來保存字體,字符顯示等... 因此,我們只需要確保SPI數據進入模塊即可。
    從ARM的角度來看,將數據發送到LCD模塊的功能稱為“SSP_WriteBlock”。

    // function used to write in the LCD blockrams
    void SSP_WriteBlock(char* ob, int len, int addr);

    void LCD_PutString(char* s, int x, int y)
    {
     // the blockram that holds the characters starts at address 0, and have 80 characters per line
     SSP_WriteBlock(s, strlen(s), x+y*80);
    }

    void main(void)
    {
     SSP_init();

     LCD_PutString("Hello world!", 0, 0);
     LCD_PutString("FPGA4FUN.COM - where FPGAs are fun.", 4, 3);

     LCD_PutString("Char set:", 0, 7);
     int i; for(i=0; i<128; i++) LCD_PutChar(i, i, 8);

     LCD_Cursor_off();
    }

    使用 LCD 控制器配置 FPGA 并運行 ARM 代碼后,我們得到以下結果:



    關鍵詞: FPGA SPI接口

    評論


    相關推薦

    技術專區

    關閉
    主站蜘蛛池模板: 雅江县| 濮阳市| 射洪县| 西华县| 盐源县| 湖北省| 镶黄旗| 南康市| 永清县| 论坛| 灌云县| 泗阳县| 荆门市| 洪湖市| 兴文县| 青神县| 和田县| 阜康市| 溆浦县| 文水县| 青海省| 武穴市| 隆安县| 平陆县| 织金县| 滦平县| 襄城县| 南部县| 连江县| 苍梧县| 栾城县| 玛纳斯县| 丰镇市| 政和县| 修水县| 黄平县| 西华县| 夏河县| 勃利县| 彝良县| 柯坪县|