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 复制代码
相关推荐
A小辣椒11 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒15 小时前
TShark:基础知识
linux
AlfredZhao17 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao1 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5202 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩2 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言