zynq裸机和linux spidev操作W25Q16

写使能

读取地址0x000051的值

发 03 00 00 51

收 0x74

BD

linux_spi_oled_system.tcl

注意事项:

Vivado 自动生成了两个未使用的片选信号。请在 system_wrapper.v 文件中删除与这两个片选相关的代码,以避免综合报错。

未使用的片选信号包括:

bash 复制代码
output SPI_0_0_ss1_o;
output SPI_0_0_ss2_o;

PIN.xdc

bash 复制代码
## SPI SCLK
set_property PACKAGE_PIN M15 [get_ports SPI_0_0_sck_io]
set_property IOSTANDARD LVCMOS33 [get_ports SPI_0_0_sck_io]

## SPI MOSI
set_property PACKAGE_PIN L16 [get_ports SPI_0_0_io0_io]
set_property IOSTANDARD LVCMOS33 [get_ports SPI_0_0_io0_io]

## SPI MISO 
set_property PACKAGE_PIN K14 [get_ports SPI_0_0_io1_io]
set_property IOSTANDARD LVCMOS33 [get_ports SPI_0_0_io1_io]

## SPI CS
set_property PACKAGE_PIN J14 [get_ports SPI_0_0_ss_io]
set_property IOSTANDARD LVCMOS33 [get_ports SPI_0_0_ss_io]

## DC
set_property PACKAGE_PIN N20 [get_ports {GPIO_EMIO_tri_io[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {GPIO_EMIO_tri_io[0]}]

## RES
set_property PACKAGE_PIN U19 [get_ports {GPIO_EMIO_tri_io[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {GPIO_EMIO_tri_io[1]}]

代码

裸机,驱动和应用是三个独立运行的例子

裸机

main.c

c 复制代码
#include "xparameters.h"
#include "xspips.h"
#include "xil_printf.h"
#include "sleep.h"

#define SPI_DEVICE_ID   XPAR_XSPIPS_0_DEVICE_ID

#define CS_ASSERT       0x00   // 片选引脚激活,低电平使能SPI设备通信
#define CS_RELEASE      0x0F   // 片选引脚释放,高电平禁用SPI设备通信

#define W25Q_WREN       0x06   // 写使能命令(Write Enable),允许写操作,必须在进行写操作之前先发送此命令
#define W25Q_RDSR       0x05   // 读取状态寄存器命令(Read Status Register),用来读取闪存的状态寄存器
#define W25Q_PP         0x02   // 页编程命令(Page Program),用于将数据写入闪存的指定页
#define W25Q_READ       0x03   // 读取数据命令(Read Data),用于从闪存中读取数据
#define W25Q_SE         0x20   // 扇区擦除命令(Sector Erase),用于擦除闪存中的指定扇区

#define SR_WIP  0x01

#define TEST_ADDR  0x000051
#define TEST_VALUE  0x74

static XSpiPs SpiInstance;

/*================ CS =================*/
static inline void cs_low() {
    XSpiPs_SetSlaveSelect(&SpiInstance, CS_ASSERT);
    usleep(2);
}
static inline void cs_high() {
    XSpiPs_SetSlaveSelect(&SpiInstance, CS_RELEASE);
    usleep(5);
}

/*================ SR =================*/
static u8 read_sr(void)
{
    u8 tx[2] = {W25Q_RDSR, 0};
    u8 rx[2] = {0};

    cs_low();
    XSpiPs_PolledTransfer(&SpiInstance, tx, rx, 2);
    cs_high();

    return rx[1];
}

static void wait_busy(void)
{
    while (read_sr() & SR_WIP) {
        usleep(100);
    }
}

/*================ WREN =================*/
static void write_enable(void)
{
    u8 cmd = W25Q_WREN;

    cs_low();
    XSpiPs_PolledTransfer(&SpiInstance, &cmd, NULL, 1);
    cs_high();
}

/*================ 擦除 =================*/
static void erase_sector(u32 addr)
{
    u8 tx[4];

    write_enable();

    tx[0] = W25Q_SE;
    tx[1] = (addr >> 16);
    tx[2] = (addr >> 8);
    tx[3] = addr;

    cs_low();
    XSpiPs_PolledTransfer(&SpiInstance, tx, NULL, 4);
    cs_high();

    wait_busy();
}

/*================ 写 =================*/
static void write_byte(u32 addr, u8 data)
{
    u8 tx[5];

    write_enable();

    tx[0] = W25Q_PP;
    tx[1] = (addr >> 16);
    tx[2] = (addr >> 8);
    tx[3] = addr;
    tx[4] = data;

    cs_low();
    XSpiPs_PolledTransfer(&SpiInstance, tx, NULL, 5);
    cs_high();

    wait_busy();
}

/*================ 读 =================*/
static u8 read_byte(u32 addr)
{
    u8 tx[5];
    u8 rx[5] = {0};

    tx[0] = W25Q_READ;
    tx[1] = (addr >> 16);
    tx[2] = (addr >> 8);
    tx[3] = addr;
    tx[4] = 0x00;

    cs_low();
    XSpiPs_PolledTransfer(&SpiInstance, tx, rx, 5);
    cs_high();

    return rx[4];
}

/*================ main =================*/
int main(void)
{
    XSpiPs_Config *cfg;
    u8 wr = TEST_VALUE;
    u8 rd;

    xil_printf("\r\n=== SPI WRITE+READ LOOP ===\r\n");

    cfg = XSpiPs_LookupConfig(SPI_DEVICE_ID);
    if (!cfg) return -1;

    if (XSpiPs_CfgInitialize(&SpiInstance, cfg, cfg->BaseAddress) != XST_SUCCESS)
        return -1;

    XSpiPs_SetOptions(&SpiInstance,
        XSPIPS_MASTER_OPTION |
        XSPIPS_FORCE_SSELECT_OPTION);

    XSpiPs_SetClkPrescaler(&SpiInstance, XSPIPS_CLK_PRESCALE_64);

    cs_high();
    usleep(1000);

    while (1)
    {
        xil_printf("\r\n--- cycle ---\r\n");

        /* 1. 擦 */
        xil_printf("erase...\r\n");
        erase_sector(TEST_ADDR);

        /* 2. 写 */
        xil_printf("write...\r\n");
        write_byte(TEST_ADDR, wr);

        while(1){

        	 /* 3. 读 */
        	        rd = read_byte(TEST_ADDR);

        	        xil_printf("WRITE=0x%02X READ=0x%02X %s\r\n",
        	                   wr, rd, (wr==rd)?"OK":"FAIL");

        	        sleep(1);

        }

    }
}

驱动

myw25q16.c

c 复制代码

应用

main.c

c 复制代码
相关推荐
donoot1 小时前
Linux系统下图书馆级电子书全自动标准化分类整理完整实施方案
大数据·linux·运维·电子书管理
Felix-lxd2 小时前
Ubuntu 22.04 配置 Nginx
linux·nginx·ubuntu
Tim_Van3 小时前
在 CentOS 7 中安装 Chromium 的完整步骤
linux·运维·chrome·centos
2023自学中4 小时前
C++ 内存追踪器
linux·c++
啵啵鱼爱吃小猫咪5 小时前
Ubuntu 20.04 + ROS Noetic 源码安装 libfranka 0.8.0 和 franka_ros 0.8.0 完整教程
linux·运维·ubuntu
ljs6482739516 小时前
Linux运维实操:vi编辑器永久配置静态IP(CentOS系列)
linux·运维·编辑器
dddwjzx6 小时前
嵌入式Linux C应用编程入门——高级I/O
linux·嵌入式
Waay8 小时前
Linux 三个核心环境变量配置文件、作用域、生效方式完整梳理
linux·运维·学习·云原生·容器
星空语8 小时前
音频001_Android+Linux车载/手机音频全链路分层架构图
android·linux·音视频
携程DBA8 小时前
数据库软限制相关研究
linux·mysql·性能