【ZYNQ實戰】利用AXI Quad SPI快速打通Linux至PL端SPI從設備

關注、星標嵌入式客棧,精彩及時送達

[導讀] 前面寫過篇介紹ZYNQ基本情況的文章,今天來肝一篇實戰文章介紹AXI quad SPI 使用方法,如果你正使用ZYNQ的這個IP,希望對你有所幫助。

初識AXI quad SPI

自《PG153 AXI Quad SPI v3.2》

支持:

  • Legacy Mode

  • standard mode: 準SPI通常就稱SPI,它是一種串行外設接口規範,有4根通信腳:SCK (時鐘), CS(片選), MOSI(主出從入), MISO(主入從出)。

  • Dual/Quad SPI Mode:

AXI Quad SPI 模式

在標準模式下,支持高達32個從站,這是非常靈活的指標。本文對於手冊中的詳細技術細節不做過多闡述,有興趣的自行深入閱讀研究。

該SPI IP能幹神馬呢?

完成如下這樣一個應用場景:

SPI IP訪問多從SPI芯片

所需要實現的需求用例爲:

本文實現用例描述

  • 利用AXI quad SPI 實現SPI外設控制器

  • 實現SPI外設控制器驅動

  • 實現多SPI從設備掛載在SPI總線

  • 實現用戶空間訪問多從SPI物理從設備

從軟件分層的視角來看,上述的需求需要實現下面的訪問層級:

PS/PL軟硬件層次架構圖

爲什麼要研究這個呢?實際用ZYNQ芯片做產品時,很有可能外部有多個SPI從設備芯片需要利用Linux訪問,你或許會說ZYNQ的PS端不是自帶了兩個SPI控制器嗎?但有時候項目中這兩個SPI對應的引腳可能用做其他用途了,而一個複雜的項目中又不得不使用多個SPI從設備芯片時,本文所討論的話題就能很好的解決這樣的需求場景了。通過本文,你會發現,原來ZYNQ的SPI IP是如此靈活好用!

本文目的實戰描述,如何一步一步從PL端設計:

  • block design

  • 約束

  • 綜合

  • 導出

乃至PS端:

  • SPI驅動配置

  • 設備樹修改

  • 系統編譯部署

  • 設備驅動測試

按照這個流程,那麼第一步需要設計PL端與PS端的配置,且看:

AXI Quad SPI 之配置

從IP catalog中按下圖從ip庫中添加如下IP:

  • ZYNQ7 processing System

  • AXI interconnect

  • AXI Quad SPI(可根據需要添加多個)

  • Processing System Reset(添加ZYNQ7 processing System 點自動連線會自動添加,當然也可以手動添加)

  • Concat

Block設計圖

使能ZYNQ7 processing System的時鐘PL Fabric clocks,用以驅動PL端的IP:

PL Fabric clocks設置

使能M AXI GP0接口如下:

M AXI GP0設置

雙擊AXI interconnect,設置2主1從:

AXI interconnect設置

雙擊axi_quad_spi_0設置如下,設置4個從設備(最多可支持32個從設備,PS端內置的SPI控制器1個最多支持3個從設備,從這一點可看出該IP的靈活性

axi_quad_spi設置

同樣將axi_quad_spi_1設置爲2個從設備接口。

然後按照前面的連線圖,將各塊連接好,做過硬件的盆友會比較適應,這就像畫原理圖一樣,就將各IP建立了邏輯連接關係了。除此之外,對於一個ZYNQ的板子而言,你還需要做如下的PS端設置:

  • DDR RAM設置,根據自身的板子的內存芯片以及內存大小進行設置

  • Peripheral IO外設設置,比如SD卡,UART,QUAD SPI Flash,erthernet等

  • clock時鐘系統設置,根據板子的情況進行設置CPU、DDR時鐘頻率、IO時鐘等

  • ......

至於這些怎麼配置,比較常見這裏就不贅述了。

對於AXI quad SPI外設還有一個很重要的配置,就是其地址範圍:

AXI quad SPI地址設置

該地址最終將導出到設備樹描述文件,用於SPI控制器驅動訪問,從而讓SPI控制器驅動得以與該IP通過AXI總線進行通信。

導出硬件文件

點擊open elaborated design ,然後打開io ports進行管腳分配,這需要根據各自的硬件實際情況進行設置,比如我是這樣設置的:

管腳約束設置
  • 電平標準

  • 是否上拉

  • 驅動能力

  • .....

然後點擊Run synthesis進行綜合,成功之後點擊生成bit stream。再點擊export hardware,得到.hdf文件,這個文件用於構建內核。

導出硬件描述文件

將得到的硬件描述hdf文件以及bitstream文件拷貝至內核編譯文件夾下:

硬件描述及bit文件

配置編譯內核

運行命令讀取硬件描述文件:

petalinux-config --get-hw-description ../base.sdk

注:這裏將hdf文件以及.bit文件放置在petalinux編譯路徑的上級目錄的base.sdk,根據習慣可自行設置,只有上述命令傳入的路徑正確即可。

等待一段時間後,可得到一個配置界面,用於配置內核源、u-boot源、Image 等配置。

petalinux-config

根據實際情況配置好後,退出配置並保存配置。使用過的會比較熟悉,這裏不贅述了。

配置設備樹

編輯用戶設備樹文件,用戶設備樹文件在下面路徑中:

./project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi

配置設備樹如下:

/include/ "system-conf.dtsi"
/ {

};

&axi_quad_spi_0 {
    status = "okay";
    clock-names = "axi_clk", "axi4_clk", "spi_clk";
    clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>; 
    spi0_dev_0@0 {
        compatible = "spidev";
        reg = <0>;
        spi-max-frequency = <500000>;
        #address-cells = <1>;
        #size-cells = <1>;
    };

    spi0_dev_1@1 {
        compatible = "spidev";
        reg = <1>;
        spi-max-frequency = <500000>;
        #address-cells = <1>;
        #size-cells = <1>;
    };
    spi0_dev_2@2 {
        compatible = "spidev";
        reg = <2>;
        spi-max-frequency = <500000>;
        #address-cells = <1>;
        #size-cells = <1>;
    };
    spi0_dev_3@3 {
        compatible = "spidev";
        reg = <3>;
        spi-max-frequency = <500000>;
        #address-cells = <1>;
        #size-cells = <1>;
    };        
}; 

&axi_quad_spi_1 {
    status = "okay";
    clock-names = "axi_clk", "axi4_clk", "spi_clk";
    clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>; 
    spi1_dev_0@0 {
        compatible = "spidev";
        reg = <0>;
        spi-max-frequency = <500000>;
        #address-cells = <1>;
        #size-cells = <1>;
    };
    
    spi1_dev_1@1 {
        compatible = "spidev";
        reg = <1>;
        spi-max-frequency = <500000>;
        #address-cells = <1>;
        #size-cells = <1>;
    }; 
}; 

這裏直接使用內置spidev兼容從設備驅動,當然如果需要自己定義一個SPI設備驅動也是非常容易的,但是對於大部分普通的SPI從芯片而言直接使用spidev設備驅動即可,只需要在讀寫時按照芯片手冊協議進行訪問即可。

配置內核

運行下面命令進行內核配置:

petalinux-config -c kernel  

內核配置

對於本應用而言,需要配置SPI驅動:

Device Drivers  --->
     +-SPI support--->     

配置如下:

SPI控制器及設備驅動配置

這裏調試中遇到一個奇怪的問題,CONFIG_SUSPEND需要禁止,否則控制器驅動加載不成功,目前還沒有深入研究爲什麼不成功,猜想可能是主控制器驅動關於SUSPEND功能還不支持或者有bug,如果有哪位大神知道怎麼解決請求留言指點。

Power management options  --->
     Suspend to RAM and standby

功能管理配置

退出並保存配置,然後運行下面命令編譯系統:

petalinux-build

等待編譯成功後,運行下面命令將bitstream文件包進BOOT.bin中。

petalipackage --boot --fsbl ./images/linux/zynq_fsbl.elf --fpga ../base.sdk/design_1_wrapper.bit --u-boot    --force

將得到下面的輸出信息,表示操作成功:

INFO: File in BOOT BIN: "/home/zynq/ALINX/spi_ip/ax_peta/images/linux/zynq_fsbl.elf"
INFO: File in BOOT BIN: "/home/zynq/ALINX/spi_ip/base.sdk/design_1_wrapper.bit"
INFO: File in BOOT BIN: "/home/zynq/ALINX/spi_ip/ax_peta/images/linux/u-boot.elf"
INFO: Generating zynq binary package BOOT.BIN...
INFO: Binary is ready.
WARNING: Unable to access the TFTPBOOT folder /tftpboot!!!
WARNING: Skip file copy to TFTPBOOT folder!!!

注:/home/zynq/ALINX/spi_ip/ax_peta 是本文工程的目錄

測試SPI從設備

編寫驅動測試程序,代碼如下:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
    int fd;
    int len;
    unsigned char buf[10];
    unsigned char tmp;

    /* 驗證輸入參數個數 */
    if(3 != argc)
    {
        printf("none para\n");
        return -1;
    }

    /* 打開輸入的設備文件, 獲取文件句柄 */
    fd = open(argv[1], O_RDWR);
    if(fd < 0)
    {
        /* 打開文件失敗 */
        printf("Can't open file %s\r\n", argv[1]);
        return -1;
    }

    int i = 0;
    int j = 0;
    len =strlen(argv[2]);
    for(i=0;i<len;i++)
    {
        if(argv[2][i]>='0' && argv[2][i]<='9')
        {
            tmp = argv[2][i] - '0';
        }
        else if(argv[2][i]>='a' && argv[2][i]<='f')
        {
            tmp = argv[2][i] - 'a'+10;
        }
        else if(argv[2][i]>='A' && argv[2][i]<='F')
        {
            tmp = argv[2][i] - 'A'+10;
        }
        else
        {
            printf("Invalid input parameters \r\n");
            return -1;
        }
        if(i%2==0)
           buf[j] = tmp<<4;
        else
        {
            buf[j] += tmp;
            j++;
        }
    }
    len = j;
    printf("Test wr:");
    for(i=0;i<len;i++)
        printf(" %x",buf[i]);
    
    write(fd, &buf[0], len);
    printf("\n");
    /* 操作結束後關閉文件 */
    close(fd);
    return 0;
}

編譯:

arm-linux-gnueabihf-gcc test.c -o test

將編譯所得的BOOT.BIN以及image.ub文件拷貝至製作好的SD的BOOT區,test文件拷貝至/home下。然後插上SD卡上電運行電路板:

登錄控制檯後,運行ls /dev查看spidev設備是否加載成功:

spidev設備掛載情況

可見spedev1.0、spidev1.1以及spidev2.0--spidev2.3加載成功,與預期一樣。

然後運行測試程序:

root@ax_peta:/run/media/mmcblk0p2/home#./test /dev/spidev1.0 78aa
Test wr: 78 aa

用示波器或者邏輯分析儀觀察對應引腳,將出現正確的SPI通信波形。

總結一下

至此,就基本實現了從PS端Linux用戶空間訪問PL端的SPI從設備了。當然實際項目中還有很多細節需要進一步研究:

  • CPOL/CPHA 組合四種模式設置

  • SPI通信速率設置

  • 從設備應用協議程序編寫

  • AXI Quad SPI FIFO特性的深入應用

  • AXI Quad SPI 其他模式及細節研究等

對於這些更細節的內容,相信在將基本框架搭建成功後,只要深入細緻研究都不會有太大的難度。從本文可看出,ZYNQ之所以如此靈活好用,是其廠家或者第三方提供了大量成熟可供使用的IP以及配套的驅動程序。如有興趣嘗試用來開發項目,相信你會很快喜歡上這個體系的芯片,真的可以做到片上即可實現系統這一目標!

END

往期精彩推薦,點擊即可閱讀

▲Linux驅動相關專輯 

手把手教信號處理專輯

片機相關專輯

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章