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 复制代码
相关推荐
无垠的广袤1 小时前
【“星睿O6”AI PC开发套件评测】基于 OpenClaw 的物体识别
linux·人工智能·opencv·摄像头·openclaw
我材不敲代码1 小时前
PyQt5入门教程——简单实现一个登录界面
linux·运维·服务器
s09071362 小时前
PetaLinux 文件系统目录详解:嵌入式 Linux 根文件系统各文件夹的作用与内容
linux·运维·服务器
曼岛_2 小时前
[网络安全]Linux权限维持-后门篇
linux·chrome·web安全
Fanfanaas2 小时前
Linux 系统编程 进程篇 (三)
linux·运维·服务器·c语言·单片机·学习
历程里程碑2 小时前
Linux 50 IP协议深度解析:从报头结构到子网划分与NAT
java·linux·开发语言·网络·c++·python·智能路由器
九天鸟2 小时前
ESXI里面虚拟机服务器始终保持免用户认证状态
linux·运维·centos
青城山下————2 小时前
CentOS 7 安装 Redis(使用默认 6379 端口)完整实践与踩坑总结
linux·redis·centos
王琦03182 小时前
第十一章 管理Linux软件包和进程
linux·运维·服务器