你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

介绍AXI quad SPI 使用方法

[复制链接]
gaosmile 发布时间:2020-11-16 20:09
初识AXI quad SPI; O* E8 s$ q$ U6 |8 ^3 \1 N
微信图片_20201116195853.png

自《PG153 AXI Quad SPI v3.2》

支持:

  • Legacy Mode
  • standard mode: 准SPI通常就称SPI,它是一种串行外设接口规范,有4根通信脚:SCK (时钟), CS(片选), MOSI(主出从入), MISO(主入从出)。
  • Dual/Quad SPI Mode:
    2 u, q! Y) a/ {
微信图片_20201116195857.png
AXI Quad SPI 模式

在标准模式下,支持高达32个从站,这是非常灵活的指标。本文对于手册中的详细技术细节不做过多阐述,有兴趣的自行深入阅读研究。

该SPI IP能干神马呢?

完成如下这样一个应用场景:

微信图片_20201116195900.png
SPI IP访问多从SPI芯片

所需要实现的需求用例为:

微信图片_20201116195904.png
本文实现用例描述
  • 利用AXI quad SPI 实现SPI外设控制器
  • 实现SPI外设控制器驱动
  • 实现多SPI从设备挂载在SPI总线
  • 实现用户空间访问多从SPI物理从设备
    7 ~6 F. g; J5 A9 K6 e" q

从软件分层的视角来看,上述的需求需要实现下面的访问层级:

微信图片_20201116195908.png
PS/PL软硬件层次架构图

为什么要研究这个呢?实际用ZYNQ芯片做产品时,很有可能外部有多个SPI从设备芯片需要利用Linux访问,你或许会说ZYNQ的PS端不是自带了两个SPI控制器吗?但有时候项目中这两个SPI对应的引脚可能用做其他用途了,而一个复杂的项目中又不得不使用多个SPI从设备芯片时,本文所讨论的话题就能很好的解决这样的需求场景了。通过本文,你会发现,原来ZYNQ的SPI IP是如此灵活好用!

本文目的实战描述,如何一步一步从PL端设计:

  • block design
  • 约束
  • 综合
  • 导出
    ) A+ `) O% I1 c1 i  I) J

乃至PS端:

  • SPI驱动配置
  • 设备树修改
  • 系统编译部署
  • 设备驱动测试- E& [+ W- m5 L4 }: }

按照这个流程,那么第一步需要设计PL端与PS端的配置,且看:

AXI Quad SPI 之配置

从IP catalog中按下图从ip库中添加如下IP:

  • ZYNQ7 processing System
  • AXI interconnect
  • AXI Quad SPI(可根据需要添加多个)
  • Processing System Reset(添加ZYNQ7 processing System 点自动连线会自动添加,当然也可以手动添加)
  • Concat( @0 v: {) [: d! V' p/ \4 k
微信图片_20201116195911.png
Block设计图: M/ R7 q7 O8 i; |( L+ a

使能ZYNQ7 processing System的时钟PL Fabric clocks,用以驱动PL端的IP:

微信图片_20201116195914.png
PL Fabric clocks设置

使能M AXI GP0接口如下:

微信图片_20201116195916.png
M AXI GP0
设置

双击AXI interconnect,设置2主1从:

微信图片_20201116195920.png
AXI interconnect
设置

双击axi_quad_spi_0设置如下,设置4个从设备(最多可支持32个从设备,PS端内置的SPI控制器1个最多支持3个从设备,从这一点可看出该IP的灵活性

微信图片_20201116195924.png
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时钟等
  • ......
    5 g7 |  D. M4 `6 K% y- t3 R4 o3 L

至于这些怎么配置,比较常见这里就不赘述了。

对于AXI quad SPI外设还有一个很重要的配置,就是其地址范围:

微信图片_20201116195927.png
AXI quad SPI
地址设置

该地址最终将导出到设备树描述文件,用于SPI控制器驱动访问,从而让SPI控制器驱动得以与该IP通过AXI总线进行通信。

导出硬件文件

点击open elaborated design ,然后打开io ports进行管脚分配,这需要根据各自的硬件实际情况进行设置,比如我是这样设置的:

微信图片_20201116195940.png
管脚约束设置
  • 电平标准
  • 是否上拉
  • 驱动能力
  • .....
    5 b9 X. m5 ?6 V9 [1 H7 ?1 r

然后点击Run synthesis进行综合,成功之后点击生成bit stream。再点击export hardware,得到.hdf文件,这个文件用于构建内核。

微信图片_20201116195944.png
导出硬件描述文件

将得到的硬件描述hdf文件以及bitstream文件拷贝至内核编译文件夹下:

微信图片_20201116195948.png
硬件描述及bit文件配置编译内核

运行命令读取硬件描述文件:

petalinux-config --get-hw-description ../base.sdk
, x3 @" ?# {  L' y; V

注:这里将hdf文件以及.bit文件放置在petalinux编译路径的上级目录的base.sdk,根据习惯可自行设置,只有上述命令传入的路径正确即可。

等待一段时间后,可得到一个配置界面,用于配置内核源、u-boot源、Image 等配置。

微信图片_20201116195952.png
petalinux-config

根据实际情况配置好后,退出配置并保存配置。使用过的会比较熟悉,这里不赘述了。

配置设备树

编辑用户设备树文件,用户设备树文件在下面路径中:

./project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
  e7 e& \' p8 g  N# c

配置设备树如下:

/include/ "system-conf.dtsi"/ ?; b0 ]2 q; G& V
/ {- \# i+ S  l& E  f

  v( x5 W$ \1 I. K' `};
* z; m- l8 w7 s) k  F) Z& D' [. O- x! n+ K, j5 c
&axi_quad_spi_0 {8 a1 g1 q1 M# U& P! D; X# l7 j8 _
    status = "okay";
9 D0 K0 P3 _3 w' c  A# ?: M    clock-names = "axi_clk", "axi4_clk", "spi_clk";
8 k* q9 f8 q/ e! Z    clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>;
, K) t- u9 Y' j9 o1 ]8 N- g    spi0_dev_0@0 {  o  ]! S+ f( [2 W; c& U
        compatible = "spidev";( @3 u& k2 ]/ G0 O1 F$ y2 A1 \
        reg = <0>;
, {; G2 P, w$ t+ V. L        spi-max-frequency = <500000>;2 W- ^7 Y3 u" B: q% w( E- e# ?
        #address-cells = <1>;/ o3 n+ e4 _- j" I, Y+ V  M
        #size-cells = <1>;
) ?, b. h; n9 r; B* d    };* ?) C# [% `2 j# h1 C: {$ V

. v2 X' Q2 K" O( c  \& C) H    spi0_dev_1@1 {) b& q& m" h. t2 H
        compatible = "spidev";
% g5 h" a5 G; d' l$ e) Q        reg = <1>;' n) _6 [" e5 u3 ]( m
        spi-max-frequency = <500000>;3 V; o# ~5 ?2 U9 ^5 j4 g8 l% R
        #address-cells = <1>;+ ^5 g" F0 {. `. u* _' q5 Z6 Y/ h$ I
        #size-cells = <1>;
$ V; d1 @% ]5 C9 {0 w& O9 g1 p0 L8 w    };9 }3 b( x! k+ l) r- ^4 y+ s' E
    spi0_dev_2@2 {
' g  o& y2 P) v, J! B9 w8 d; u% ^        compatible = "spidev";4 t  P& k; u; s$ A4 }: a
        reg = <2>;7 J" e, }: u/ @
        spi-max-frequency = <500000>;
4 J8 W3 H- Q3 q$ f, c        #address-cells = <1>;
. _9 R* p. e1 K2 p: y* k( v7 J: u        #size-cells = <1>;3 {+ B2 {, D& Q9 v) P6 H2 u
    };; s, L3 Q  {& Q+ X2 m
    spi0_dev_3@3 {
3 O2 Q6 t8 s; A- k+ ~6 U+ m9 G1 O        compatible = "spidev";" I' T7 B% x8 v$ s% B* Z
        reg = <3>;8 A) i) Q- b. w% w
        spi-max-frequency = <500000>;4 K& f5 P9 w0 D3 g8 y& g
        #address-cells = <1>;- `/ g- b1 u2 e* S! g% a
        #size-cells = <1>;/ q! }* Z$ d6 O& D
    };        
& {& o* O. n, R' ]/ x' e0 T) u};
+ m7 ]! U3 c, @; @9 {3 ~- J/ _8 k9 Z
&axi_quad_spi_1 {
, G9 M1 Q6 N$ V% k, V  [- U9 P    status = "okay";
- R' ?: p* T/ D( F% L6 @  N    clock-names = "axi_clk", "axi4_clk", "spi_clk";; v5 @4 X/ [* |! b; `
    clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>;
: d& y5 f; n( i4 x    spi1_dev_0@0 {  R  _6 V6 j5 O! H
        compatible = "spidev";
5 U8 m5 H2 Z# m/ r# A5 Y( U7 S        reg = <0>;
6 D. P8 O0 ]  z        spi-max-frequency = <500000>;2 Q$ z) m9 \4 |! M( A! ^7 R
        #address-cells = <1>;
  Q7 S/ x9 T2 b        #size-cells = <1>;3 T: [3 X3 |* B  F& Z: U  ^7 g
    };6 i3 w! V; a6 U2 j# H1 }9 M7 u
      a" V8 j. G* d+ V" A
    spi1_dev_1@1 {+ v/ s( R1 g1 N  `
        compatible = "spidev";5 C2 J4 x) i% |9 T# h
        reg = <1>;
( j6 X" |. H  u        spi-max-frequency = <500000>;
( e5 D4 N* K9 D6 R        #address-cells = <1>;
' F4 B& d3 u5 v: A; O9 X        #size-cells = <1>;
6 w' A3 z' p3 d    }; ' [* g) y/ N; }  e( S0 e
}; $ V! F( S. k" M  S

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

配置内核

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

petalinux-config -c kernel  
4 Z2 C1 M( q# |

6 M. E% h4 @: R& F' I
微信图片_20201116195955.png
内核配置( ~4 F& d4 @2 F1 U

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

Device Drivers  --->: y+ u/ [. C: C' g
     +-SPI support--->     ! I- O" y% G5 b: l& V9 q' Y

配置如下:

微信图片_20201116195958.png
SPI控制器及设备驱动配置

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

Power management options  --->( ]& t# ]7 h+ H' R' w
     Suspend to RAM and standby
微信图片_20201116200001.png
功能管理配置- X; v; A1 l# N

退出并保存配置,然后运行下面命令编译系统:

petalinux-build2 M' L8 ^/ ]5 \( ^: E* F

等待编译成功后,运行下面命令将bitstream文件包进BOOT.bin中。

petalipackage --boot --fsbl ./images/linux/zynq_fsbl.elf --fpga ../base.sdk/design_1_wrapper.bit --u-boot    --force& V. E/ H- C* [& V/ f6 o/ Q

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

INFO: File in BOOT BIN: "/home/zynq/ALINX/spi_ip/ax_peta/images/linux/zynq_fsbl.elf"
4 T1 G1 W- Y2 q9 U* }2 r( D+ @INFO: File in BOOT BIN: "/home/zynq/ALINX/spi_ip/base.sdk/design_1_wrapper.bit"4 q' {1 o" h- ]
INFO: File in BOOT BIN: "/home/zynq/ALINX/spi_ip/ax_peta/images/linux/u-boot.elf"
" w0 p$ n) G& K9 M0 X2 rINFO: Generating zynq binary package BOOT.BIN...
& k3 T" M- u9 ]2 H: AINFO: Binary is ready.7 m/ `. }, w! l/ g7 j2 a  T
WARNING: Unable to access the TFTPBOOT folder /tftpboot!!!
3 e9 U# Y2 _. T3 RWARNING: Skip file copy to TFTPBOOT folder!!!
5 q/ h+ J# d1 k. ?/ |7 h0 V* {

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

测试SPI从设备

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

#include <stdio.h>( P, h/ a& d! K- y5 l
#include <string.h>
3 J2 ]% x  d- d6 j4 n0 P6 Y2 j% y% X#include <unistd.h>5 f# R3 h; f) C/ ]
#include <fcntl.h>' B0 H* y) s. h9 o! ^. u! e5 o% r
$ Y, ^/ [& C3 T; j
int main(int argc, char **argv)6 \  G% a- P& \
{3 b. R; u9 \: Q0 W) r, v
    int fd;7 B8 A8 L$ ^! M3 W
    int len;
( \9 R  P2 x4 ]1 a3 g( F' X5 n    unsigned char buf[10];' C7 }2 t3 m4 Q
    unsigned char tmp;+ w0 s0 u+ w. @$ N

/ m; t" r; E( f    /* 验证输入参数个数 */
; n4 D" R. D% [    if(3 != argc)
3 F! |' w: N6 Q$ H/ r$ n    {+ I! P& U7 e8 T2 B& Z
        printf("none para\n");
. P# ]% V# _5 p        return -1;8 \/ l, ^: o+ G" R) n8 G
    }
! I% X3 p5 U4 n% n
% V! G2 p/ m. V3 z$ O. w9 b6 a    /* 打开输入的设备文件, 获取文件句柄 */
; H$ L* {; F7 D4 j    fd = open(argv[1], O_RDWR);
& Y% l5 q( V$ q# R  ]& o/ z0 v* n    if(fd < 0)
/ a$ c% D% n- w    {( a; t2 p4 p4 M. H$ E" e; h
        /* 打开文件失败 */1 Y  a$ V2 B/ ?; o8 K2 A
        printf("Can't open file %s\r\n", argv[1]);
. O; G7 V- b5 |% w3 c        return -1;
' p$ O  C4 Q& ]' P    }1 o/ r$ K5 N, }7 z$ z
3 s! ^/ k! p; \. K& d. V
    int i = 0;) U, f+ W; B0 h, r5 j$ X. x
    int j = 0;
3 x7 u4 e) c5 Y7 q    len =strlen(argv[2]);
1 G) k4 e  A: `& A0 Y    for(i=0;i<len;i++)
+ M. j: ~3 M" U* y/ Y! m    {8 ]5 h6 a$ V  U; ?
        if(argv[2]>='0' && argv[2]<='9')
! B0 n; _4 _0 p8 |; W+ W( D. G" y* W        {- R# _( Q+ I, R# a9 J
            tmp = argv[2] - '0';+ r* A, j6 s  l+ j0 z8 @" Y. O* X
        }! ^! z) F8 ]6 C
        else if(argv[2]>='a' && argv[2]<='f')
; e% k$ ^) I- w; _& S  p/ T        {) I5 ]1 I& W/ I! C
            tmp = argv[2] - 'a'+10;+ Y0 i( S% r$ B* e
        }
5 }: L; o; q  y9 R( c        else if(argv[2]>='A' && argv[2]<='F')
5 e/ T( b% ~: k5 F7 F, g        {/ z$ X' b- D% ^7 e$ B, y' O9 J0 s
            tmp = argv[2] - 'A'+10;
3 ?1 [3 v$ |* l  y) `/ z$ N0 h        }
3 F1 Y+ ~8 c+ y        else
6 y( s/ m1 _) q* m' E        {$ v7 |6 o# ]5 \8 A3 D1 H7 A% N
            printf("Invalid input parameters \r\n");
- p" ^5 i0 H7 T% F* e8 H8 }            return -1;, X9 O. r' @0 J5 O
        }, ]8 A/ s1 a2 f2 d( j, [% N0 |$ ?+ s
        if(i%2==0)5 t2 t. W8 Q0 C* R
           buf[j] = tmp<<4;
+ G( r3 r6 r, H) J* J        else6 x. O- k6 D( \
        {
: o/ \" X* ?1 l            buf[j] += tmp;, `: ~& }/ h$ u8 ?. \# D- k) _
            j++;
0 @; q0 x9 g' x* h; b, U! T2 d        }$ e+ F$ ?! W8 R) V; U
    }# J; h; {' b6 @0 Q: L* n9 z7 p) S
    len = j;7 c6 E" V" I; D5 Z) a% t/ h) h0 S
    printf("Test wr:");
) A$ l# N5 o6 E- J  q! S( {$ R" e    for(i=0;i<len;i++)
5 ]' c0 e, X5 T& ~! \0 }        printf(" %x",buf);
  I0 o; p- @- j   
2 S" o2 U6 B; a6 ?8 O+ @, i* @1 `    write(fd, &buf[0], len);6 v/ u+ d7 @0 @) l1 Y2 ]+ N! C
    printf("\n");" f1 x' G+ q1 t7 h5 A1 G' I
    /* 操作结束后关闭文件 */$ E3 V3 W2 p1 b8 S" U
    close(fd);  ^  ^. Q4 t: ?9 v! P" t
    return 0;6 E6 Y2 i+ ^+ R% r; |4 s; }
}
7 i! O/ }5 I# L! T5 @

编译:

arm-linux-gnueabihf-gcc test.c -o test
. a9 t* R- u/ h

将编译所得的BOOT.BIN以及image.ub文件拷贝至制作好的SD的BOOT区,test文件拷贝至/home下。然后插上SD卡上电运行电路板:

登录控制台后,运行ls /dev查看spidev设备是否加载成功:

微信图片_20201116200005.png
spidev设备挂载情况

可见spedev1.0、spidev1.1以及spidev2.0--spidev2.3加载成功,与预期一样。

然后运行测试程序:

root@ax_peta:/run/media/mmcblk0p2/home#./test /dev/spidev1.0 78aa$ V! m8 i9 }# A# q
Test wr: 78 aa
+ z/ H2 L0 F; w! H( D% q

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

总结一下

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

  • CPOL/CPHA 组合四种模式设置
  • SPI通信速率设置
  • 从设备应用协议程序编写
  • AXI Quad SPI FIFO特性的深入应用
  • AXI Quad SPI 其他模式及细节研究等* H- r! x- K1 \. ?7 ]5 h

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


3 U- P* {# B! r0 e3 }2 t
收藏 评论0 发布时间:2020-11-16 20:09

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版