当前位置:   article > 正文

【ZYNQ实战】利用AXI Quad SPI快速打通Linux至PL端SPI从设备_zynq axi quad spi

zynq axi quad 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

配置设备树如下:

  1. /include/ "system-conf.dtsi"
  2. / {
  3. };
  4. &axi_quad_spi_0 {
  5.     status = "okay";
  6.     clock-names = "axi_clk""axi4_clk""spi_clk";
  7.     clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>; 
  8.     spi0_dev_0@0 {
  9.         compatible = "spidev";
  10.         reg = <0>;
  11.         spi-max-frequency = <500000>;
  12.         #address-cells = <1>;
  13.         #size-cells = <1>;
  14.     };
  15.     spi0_dev_1@1 {
  16.         compatible = "spidev";
  17.         reg = <1>;
  18.         spi-max-frequency = <500000>;
  19.         #address-cells = <1>;
  20.         #size-cells = <1>;
  21.     };
  22.     spi0_dev_2@2 {
  23.         compatible = "spidev";
  24.         reg = <2>;
  25.         spi-max-frequency = <500000>;
  26.         #address-cells = <1>;
  27.         #size-cells = <1>;
  28.     };
  29.     spi0_dev_3@3 {
  30.         compatible = "spidev";
  31.         reg = <3>;
  32.         spi-max-frequency = <500000>;
  33.         #address-cells = <1>;
  34.         #size-cells = <1>;
  35.     };        
  36. }; 
  37. &axi_quad_spi_1 {
  38.     status = "okay";
  39.     clock-names = "axi_clk""axi4_clk""spi_clk";
  40.     clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>; 
  41.     spi1_dev_0@0 {
  42.         compatible = "spidev";
  43.         reg = <0>;
  44.         spi-max-frequency = <500000>;
  45.         #address-cells = <1>;
  46.         #size-cells = <1>;
  47.     };
  48.     
  49.     spi1_dev_1@1 {
  50.         compatible = "spidev";
  51.         reg = <1>;
  52.         spi-max-frequency = <500000>;
  53.         #address-cells = <1>;
  54.         #size-cells = <1>;
  55.     }; 
  56. }; 

这里直接使用内置spidev兼容从设备驱动,当然如果需要自己定义一个SPI设备驱动也是非常容易的,但是对于大部分普通的SPI从芯片而言直接使用spidev设备驱动即可,只需要在读写时按照芯片手册协议进行访问即可。

配置内核

运行下面命令进行内核配置:

petalinux-config -c kernel  


内核配置

对于本应用而言,需要配置SPI驱动:

  1. Device Drivers  --->
  2.      +-SPI support--->     

配置如下:

SPI控制器及设备驱动配置

这里调试中遇到一个奇怪的问题,CONFIG_SUSPEND需要禁止,否则控制器驱动加载不成功,目前还没有深入研究为什么不成功,猜想可能是主控制器驱动关于SUSPEND功能还不支持或者有bug,如果有哪位大神知道怎么解决请求留言指点。

  1. Power management options  --->
  2.      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

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

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

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

测试SPI从设备

编写驱动测试程序,代码如下:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. int main(int argc, char **argv)
  6. {
  7.     int fd;
  8.     int len;
  9.     unsigned char buf[10];
  10.     unsigned char tmp;
  11.     /* 验证输入参数个数 */
  12.     if(3 != argc)
  13.     {
  14.         printf("none para\n");
  15.         return -1;
  16.     }
  17.     /* 打开输入的设备文件, 获取文件句柄 */
  18.     fd = open(argv[1], O_RDWR);
  19.     if(fd < 0)
  20.     {
  21.         /* 打开文件失败 */
  22.         printf("Can't open file %s\r\n", argv[1]);
  23.         return -1;
  24.     }
  25.     int i = 0;
  26.     int j = 0;
  27.     len =strlen(argv[2]);
  28.     for(i=0;i<len;i++)
  29.     {
  30.         if(argv[2][i]>='0' && argv[2][i]<='9')
  31.         {
  32.             tmp = argv[2][i] - '0';
  33.         }
  34.         else if(argv[2][i]>='a' && argv[2][i]<='f')
  35.         {
  36.             tmp = argv[2][i] - 'a'+10;
  37.         }
  38.         else if(argv[2][i]>='A' && argv[2][i]<='F')
  39.         {
  40.             tmp = argv[2][i] - 'A'+10;
  41.         }
  42.         else
  43.         {
  44.             printf("Invalid input parameters \r\n");
  45.             return -1;
  46.         }
  47.         if(i%2==0)
  48.            buf[j] = tmp<<4;
  49.         else
  50.         {
  51.             buf[j] += tmp;
  52.             j++;
  53.         }
  54.     }
  55.     len = j;
  56.     printf("Test wr:");
  57.     for(i=0;i<len;i++)
  58.         printf(" %x",buf[i]);
  59.     
  60.     write(fd, &buf[0], len);
  61.     printf("\n");
  62.     /* 操作结束后关闭文件 */
  63.     close(fd);
  64.     return 0;
  65. }

编译:

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加载成功,与预期一样。

然后运行测试程序:

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

用示波器或者逻辑分析仪观察对应引脚,将出现正确的SPI通信波形。

总结一下

至此,就基本实现了从PS端Linux用户空间访问PL端的SPI从设备了。当然实际项目中还有很多细节需要进一步研究:

  • CPOL/CPHA 组合四种模式设置

  • SPI通信速率设置

  • 从设备应用协议程序编写

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

  • AXI Quad SPI 其他模式及细节研究等

对于这些更细节的内容,相信在将基本框架搭建成功后,只要深入细致研究都不会有太大的难度。从本文可看出,ZYNQ之所以如此灵活好用,是其厂家或者第三方提供了大量成熟可供使用的IP以及配套的驱动程序。如有兴趣尝试用来开发项目,相信你会很快喜欢上这个体系的芯片,真的可以做到片上即可实现系统这一目标!

END

往期精彩推荐,点击即可阅读

▲Linux驱动相关专辑 

手把手教信号处理专辑

片机相关专辑

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号