未经允许,本文禁止转载

目录

简介

AXI Quad SPI IP设置

寄存器说明

AXI Quad SPI支持的通用命令

读flash id

读flash 数据

擦除扇区

写flash 数据

注意事项


简介

本文简要介绍xilinx 7系的AXI quad spi IP核的使用,主要用于读写boot用的flash(n25q128为例)做在线升级用。本文会略去很多细节,主要是因为我也没有搞得很懂,其次是很多细节可以在其他博客找到介绍。目前为止,我只尝试了使用axi lite接口配置寄存器,对flash读id,读数据,擦除扇区,写数据。后期会学习如何对flash进行分区管理,做升级备份以及针对不同flash加入quad的读写命令提高速率。

串行flash通常指spi flash,有standard,dual,quad三种,flash的操作就是发送命令,发送地址(可选),写数据/读数据(可选)。各种模式间的区分主要在于传输数据在数据线上的分布。这里我描述不清楚,细节暂且略过。    

AXI Quad SPI IP设置

手册pg153介绍了该ip的寄存器含义,在第五章节Example Programming Sequence介绍了几种flash操作方式的寄存器写顺序。IP配置中,XIP(eXecute In Place)即芯片内执行,指应用程序可以直接在flash闪存内运行,就是说提供一个memory map的操作接口让CPU直接访问地址,就像访问内存一样,而不是发送flash的cmd命令,相当于是flash里再集成了一个控制器,把读地址命令转换为各种读时序。注意XIP只能读flash。这里我用不上不勾选。勾选performance Mode就能有AXI4接口支持突发,目前也不需要。配置IP为quad模式,只有1个slave设备,设备类型是混合的,支持winbond,micron,spansion,macronix共有的命令。如果勾选Micron,就能支持micron的特殊命令,否则发送它的特殊命令,IPISR状态寄存器就会报command error。FIFO深度只有16和256两种选择。STARTUP原语勾选上后指SPI的clk就会从FPGA专用的CCLK引脚输出时钟。

axi lite和spi的时钟频率在手册上有说明。spi_clk是操作flash clk的2倍,这个频率也要受到flash器件的约束。STARTUP_IO不用接,SPI_IO输出后用IOBUF引出到inout管脚即可,也可以自己写三态控制,spi_io0_t = 1时输出高阻。

寄存器说明

寄存器说明在pg153的第二章节Register Space。主要寄存器如下。

该IP的操作原理就是,先配置SPI为master,配置相位/极性,复位fifo,禁止传输;再把命令和数据写到SPI_DTR寄存器里,再使能设备片选,使能传输,关闭片选,关闭传输;从SPI_DRR里读取出数据(可选)。此外可以配置中断,选择使能哪些中断,再打开全局中断使能,传输完后查询IPISR就知道当前传输有没有错误。

40h:复位寄存器,写0xa复位整个IP,自动解复位。

60h:控制寄存器,控制SPI的工作方式。

64h:状态寄存器,查看fifo是否空满,用来判断是否传输结束。

68h:发送fifo,往里面写数据,写满了会覆盖。所以不要写满。

6ch:接收fifo,接收满了会自动丢弃后续数据。

70h:片选,写0就表示0设备的cs拉低,某个设备片选结束后,写一个没有用的设备拉高cs。

74h:发送fifo里有多少个数据。比如值5,表示里面有6个数据待发送。

78h:接收fifo里有多少个数据。比如值5,表示里面有6个数据还没有读走。

AXI Quad SPI支持的通用命令

查看flash手册可以发送,应该绝大多数flash都支持下命的这些命令。尤其是02/06/9f/d8,这也是我目前成功应用过的命令。

读flash id

读flash id和普通读操作没有区别,先配置SPI,禁止发送,就是发送读cmd(9f),再写几个dummy(假的,没有意义的数据)用于交换数据出来,使能片选,使能发送,关闭片选,禁止发送,读数据。对应的手册描述如下所述。

具体代码如下所示。dummy的个数是可以自己控制的,要读多少数据就写几个dummy数据进去。

  REG_W(pstDev, 0x80040, 0xa);       //Software Reset RegisterREG_W(pstDev, 0x80028, 0x00003fff);//使能所有中断REG_W(pstDev, 0x8001c, 0x80000000);//打开全局中断使能REG_W(pstDev, 0x80060, 0x000001e6);//复位tx rx fifo,REG_W(pstDev, 0x80060, 0x00000186);//解复位fifoREG_W(pstDev, 0x80068, 0x0000009f);//cmd = 9f,读flash idREG_W(pstDev, 0x80068, 0x00000000);//dummyREG_W(pstDev, 0x80068, 0x00000000);//dummyREG_W(pstDev, 0x80068, 0x00000000);//dummyREG_W(pstDev, 0x80068, 0x00000000);//dummyREG_W(pstDev, 0x80068, 0x00000000);//dummyREG_W(pstDev, 0x80068, 0x00000000);//dummyREG_W(pstDev, 0x80068, 0x00000000);//dummyREG_W(pstDev, 0x80068, 0x00000000);//dummyREG_W(pstDev, 0x80068, 0x00000000);//dummyREG_W(pstDev, 0x80068, 0x00000000);//dummyprintf("Reg[0x%04X] : 0x%08X\n", 0x80074, REG_R(pstDev, 0x80074));REG_W(pstDev, 0x80070, 0x00000000);//选择0通道csREG_W(pstDev, 0x80060, 0x00000086);//使能master,开始发数据REG_W(pstDev, 0x80070, 0x00000001);//选择0通道cs拉高REG_W(pstDev, 0x80060, 0x00000186);//禁止master speprintf("Reg[0x%04X] : 0x%08X\n", 0x80078, REG_R(pstDev, 0x80078));for(i=0;i<11;i++){printf("data = 0x%08X\n", REG_R(pstDev, 0x8006c));}printf("Reg[0x%04X] : 0x%08X\n", 0x80020, REG_R(pstDev, 0x80020));REG_W(pstDev, 0x80020, REG_R(pstDev, 0x80020));//clear

读flash 数据

手册描述和上面读id一致,只不过cmd = 03。并不是每次读需要复位0x40和设置中断。读数据时默认03命令后面需要3byte的addr,如果需要4byte的地址,命令根据flash不同会是不同的cmd,但一定不会是03。先发送高位地址。要注意,读回来的数据是4 + dummy 个数据。也就是说只要写一个数据到DTR里,就会有一个数据接收到写入DRR。所以读回来的数据会是FF FF FF FF xx xx......(真正数据)。要注意DRR fifo只有256深度,不要读太多数据。

  REG_W(pstDev, 0x80040, 0xa);       //Software Reset RegisterREG_W(pstDev, 0x80028, 0x00003fff);//使能所有中断REG_W(pstDev, 0x8001c, 0x80000000);//打开全局中断使能REG_W(pstDev, 0x80060, 0x000001e6);//复位tx rx fifo,REG_W(pstDev, 0x80060, 0x00000186);//解复位fifoREG_W(pstDev, 0x80068, 0x00000003);//cmd = 03,读flash data//write addrREG_W(pstDev, 0x80068, (nOffset>>16)&0xff);REG_W(pstDev, 0x80068, (nOffset>>8)&0xff);REG_W(pstDev, 0x80068, (nOffset&0xff));for(i=0;i<nCount;i++){REG_W(pstDev, 0x80068, 0);//dummy}REG_W(pstDev, 0x80070, 0x00000000);//选择0通道csREG_W(pstDev, 0x80060, 0x00000086);//使能master,开始发数据REG_W(pstDev, 0x80070, 0x00000001);//选择0通道cs拉高REG_W(pstDev, 0x80060, 0x00000186);//禁止master spefor(i=0;i<nCount+4;i++){printf("data = 0x%08X\n", REG_R(pstDev, 0x8006c));}printf("Reg[0x%04X] : 0x%08X\n", 0x80020, REG_R(pstDev, 0x80020));REG_W(pstDev, 0x80020, REG_R(pstDev, 0x80020));//clear

擦除扇区

每个flash都有自己的扇区,页写参数,d8命令是擦除1个扇区,但扇区的大小是不一样大的。例如n25q128手册上描述:

可以看到,总共有16777216个字节,256个扇区(每个扇区64KB)有65536页(每页256字节)。所以执行一次擦除命令会擦除64KB的数据,把数据都写成0xFF,写数据只能把bit写成0。要注意的是,每一个擦除命令和写数据命令前都要有一个写使能命令(06)。擦除命令后面跟地址,就会擦除地址所在的地址对齐64KB。

测试代码为:

  REG_W(pstDev, 0x80040, 0xa);       //Software Reset RegisterREG_W(pstDev, 0x80060, 0x000001e6);//复位tx rx fifo,REG_W(pstDev, 0x80060, 0x00000186);//解复位fifoREG_W(pstDev, 0x80068, 0x00000006);//cmd = 06,写使能REG_W(pstDev, 0x80070, 0x00000000);//选择0通道csREG_W(pstDev, 0x80060, 0x00000086);//使能master,开始发数据REG_W(pstDev, 0x80070, 0x00000001);//选择0通道cs拉高REG_W(pstDev, 0x80060, 0x00000186);//禁止master speREG_W(pstDev, 0x80060, 0x000001e6);//复位tx rx fifo,REG_W(pstDev, 0x80060, 0x00000186);//解复位fifoREG_W(pstDev, 0x80068, 0x000000d8);//cmd = d8,擦除扇区。//write addrREG_W(pstDev, 0x80068, (nOffset>>16)&0xff);REG_W(pstDev, 0x80068, (nOffset>>8)&0xff);REG_W(pstDev, 0x80068, (nOffset&0xff));REG_W(pstDev, 0x80070, 0x00000000);//选择0通道csREG_W(pstDev, 0x80060, 0x00000086);//使能master,开始发数据REG_W(pstDev, 0x80070, 0x00000001);//选择0通道cs拉高REG_W(pstDev, 0x80060, 0x00000186);//禁止master spe

写flash 数据

和擦除扇区是类似的,写使能,写命令,写地址,写数据。

要注意写FIFO也只有256字节深度,虽然页写是256字节。页写的意思,写命令后面最多跟这么多个数据,多余的数据就重复写入了。所以可以从0开始写128个,再从128写128个字节。

测试代码如下:

  REG_W(pstDev, 0x80040, 0xa);       //Software Reset RegisterREG_W(pstDev, 0x80060, 0x000001e6);//复位tx rx fifo,REG_W(pstDev, 0x80060, 0x00000186);//解复位fifoREG_W(pstDev, 0x80068, 0x00000006);//cmd = 06,写使能REG_W(pstDev, 0x80070, 0x00000000);//选择0通道csREG_W(pstDev, 0x80060, 0x00000086);//使能master,开始发数据REG_W(pstDev, 0x80070, 0x00000001);//选择0通道cs拉高REG_W(pstDev, 0x80060, 0x00000186);//禁止master speREG_W(pstDev, 0x80060, 0x000001e6);//复位tx rx fifo,REG_W(pstDev, 0x80060, 0x00000186);//解复位fifoREG_W(pstDev, 0x80068, 0x00000002);//cmd = 02 页写,256字节每页//write addrREG_W(pstDev, 0x80068, (nOffset>>16)&0xff);REG_W(pstDev, 0x80068, (nOffset>>8)&0xff);REG_W(pstDev, 0x80068, (nOffset&0xff));for(i=0;i<128;i++){REG_W(pstDev, 0x80068, i);//固定写入递增的数据}REG_W(pstDev, 0x80070, 0x00000000);//选择0通道csREG_W(pstDev, 0x80060, 0x00000086);//使能master,开始发数据REG_W(pstDev, 0x80070, 0x00000001);//选择0通道cs拉高REG_W(pstDev, 0x80060, 0x00000186);//禁止master spe

远程升级

对于mcs,bin,bit,hex文件的区别,可以查看ug470 7 Series FPGAsConfiguration.      

简单说就是bit文件,bit没有反序(每个字节的bit反序),是二进制文件。bin文件没有bit反序,二进制文件。MCS bit反序了,是ASCII文件,带有地址和校验。对于我们升级来说,bin文件就可以了。FPGA升级时从0开始读数据从到同步头aa 99 55 66,就表示一个有效的配置文件开始了。如下所示。

ffff ffff ffff ffff ffff ffff ffff ffff
ffff ffff ffff ffff ffff ffff ffff ffff
0000 00bb 1122 0044 ffff ffff ffff ffff
aa99 5566 2000 0000 3003 e001 0000 026b
3000 8001 0000 0012 2000 0000 3002 2001
0000 0000 3002 0001 0000 0000 3000 8001
0000 0000 2000 0000 3000 8001 0000 0007

所以在线升级的简单设计就是拿到bin文件后,先根据bin文件大小擦除扇区,擦除每个扇区是是需要时间的,在手册里也有说明,擦除命令之间留出间隔即可,再从0开始直接写bin文件就可以了,写完后再读出校验。

后续会研究如何做备份,普通升级写镜像时只写user image区域,当启动时发现user image启动失败,会自动跳转factory image,保证有出厂镜像里有在线升级的代码,防止一次升级失败导致必须返厂使用JTAG的问题。

注意事项

如果使用JTAG to AXI Master,可以用JTAG去发送axi lite读写命令。

使用方法:

1.在bd中添加jtag to axi master ip,连接axi lite端口,配置address;

2.编译工程,下载。

3.先建立axi lite读写操作,再在vivado tcl console里执行,建立一次就可以了。

create_hw_axi_txn reset_qspi         [get_hw_axis hw_axi_1] -address 0x00000040 -data 0x0000000a -type write -force
create_hw_axi_txn rd_txn_lite_read_60 [get_hw_axis hw_axi_1] -address 00000060 -type read -force
run_hw_axi rd_txn_lite_read_74

我的测试是把xdma的bypas接口接到了SPI IP,访问寄存器时,会发现读写数据都在变化,增加操作寄存器之间的延时,增加一定时间,例如10us即可。

目前已验证A7上使用pcie xdma烧写bin文件到n25q128 flash,新bin能正常加载。驱动源码支持按文件大小擦除,逐页写入,支持读出校验。有需要可通过CSDN私信我,有偿提供技术支持,详解文章中未提及的部分编码细节。

本文是本人原创,禁止任何形式的转载。

AXI Quad SPI读写Flash做远程升级相关推荐

  1. 【ZYNQ实战】利用AXI Quad SPI快速打通Linux至PL端SPI从设备

    关注.星标嵌入式客栈,精彩及时送达 [导读] 前面写过篇介绍ZYNQ基本情况的文章,今天来肝一篇实战文章介绍AXI quad SPI 使用方法,如果你正使用ZYNQ的这个IP,希望对你有所帮助. 初识 ...

  2. STM32笔记(十二)---SPI读写FLASH

    SPI读写FLASH 文章目录 SPI读写FLASH 一.SPI协议简介 1.1 SPI 物理层 1.2 协议层 1.2.1 SPI 基本通讯过程 1.2.2 通讯的起始和停止信号 1.2.3 数据有 ...

  3. AXI quad SPI没有输出

    AXI quad SPI没有输出(已解决) 在使用ZYNQ的AXI quad SPI时遇到以下问题: 使用loopback可以成功,但是使用示波器测量引脚却没有输出. 问题描述: 最近在用ZYNQ的A ...

  4. STM32F103学习笔记——SPI读写Flash(二)

      此系列文章是小白学习STM32的一些学习笔记.小白第一次写笔记文章,有不足或是错误之处,请多体谅和交流! 目录 1.软件设计流程 2.SPI初始化 3.SPI发送接收一字节函数编写 4.FLASH ...

  5. 《STM32从零开始学习历程》——SPI读写FLASH

    <STM32从零开始学习历程>@EnzoReventon SPI读写FLASH 相关链接: SPI物理层及FLASH芯片介绍 SPI协议层 SPI特性及架构 参考资料: [野火EmbedF ...

  6. STM32CUBEIDE之SPI读写FLASH进阶串行FLASH文件系统FatFs

    预备知识 >>W25Q128是16M spi flash,一共有256个block ,每个Block 64KB. >>一个Block可以分割为16个扇区(small secto ...

  7. STM32F103配合STM32CubeMX实现SPI读写flash

    本人采用的是正点原子的精英STM32F103开发板,其包含一块W25Q128型号的flash芯片.该flash与STM32F103的SPI2相连. 下面根据正点原子提供的开发指南文档,实现FreeRT ...

  8. STM32F429入门(二十一):SPI协议及SPI读写FLASH

    IIC主要用于通讯速率一般的场合,而SPI一般用于较高速的场合. 一.SPI协议简介 SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设 ...

  9. STM32 SPI读写FLASH

    文章目录 一.SPI协议 1.物理层 2.协议层 总体讲解 具体讲解 二.STM32 SPI外设 1.通讯引脚 2.时钟控制逻辑 3.数据控制 4.整体控制逻辑 三.通信过程 四.固件库编程 1.结构 ...

最新文章

  1. tensorflow object_detect 操作步骤
  2. 怎么证明会python_如何在python中验证SSL证书?
  3. 牛客题霸 NC1 大数加法
  4. 阿里云服务器下安装LAMP环境(CentOS Linux 6.3) 安装与配置 Apache 服务
  5. vmware 克隆后Linux没有eth网卡只有lo
  6. 提高python执行效率_提升Python程序运行效率的6个方法
  7. Android Studio显示行数
  8. 工作157:动态路由
  9. centos7的systemd命令对比
  10. 如何在Java中将毫秒转换为“ X分钟,x秒”?
  11. php仿金蝶电商ERP进销存系统多仓库版
  12. 关于配置移动硬盘上的Eclipse+mingw+qt4.5.3的问题解决!
  13. 数列求和再求极限问题
  14. pythonmsgbox怎么使用_详解MessageBox(),MsgBox函数的正确使用
  15. 百战归来再读书--一个程序员的2008年阅读书目
  16. DAYTIME(daytime可数吗)
  17. SAP message TK 248 solved
  18. Maya获取材质ShadingEngine信息
  19. lr0文法分析表示例_LR0分析表
  20. 简明易懂的JVM垃圾回收理解

热门文章

  1. 《Android 应用 之路》 MPAndroidChart~BubbleChart(气泡图) and RadarChart(雷达图)
  2. pytest parametrize 传参和启动pytest项目报错make sure your test modules/packages have valid Python names
  3. unity EZ Replay Manager 1.53
  4. html代码轮播图片错位,可拖动选项卡嵌套图片轮播时图片错位的问题
  5. 【译】迁移被废弃的Kotlin Android Extensions插件
  6. outlook服务器无法搜索邮件,outlook2010无法搜索解决方法
  7. 【我的DOT语言学习之旅】 学习DOT语言并使用Graphviz软件来打开.dot文件
  8. 移动硬盘提示需要格式化怎么办?数据可以恢复吗
  9. 经济管理专业必备的15种国内数据库推荐
  10. Day2多种抓包工具介绍以及使用封包监听工具找到挑战数据包实现发送数据包进行挑战