这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 树莓派RP2040以SPI外设方式驱动W25Q128的问题

共1条 1/1 1 跳转至

树莓派RP2040以SPI外设方式驱动W25Q128的问题

专家
2026-05-16 21:32:55     打赏

之前使用SPI方式下,测试RP2040读取W25Q64模块,结果失败。换用W25Q128芯片搭建电路依旧失败。

1、电路连接

W25Q64.png


RP2040-W25Q64.png

2、代码如下:

from machine import Pin, SPI
import time
# === 配置 SPI 引脚 ===
# 使用 SPI0 外设,使用软件控制片选引脚(CS)
# 19 - TX MOSI
# 16 - RX MISO
# 18 - SCK
cs_pin = Pin(17, Pin.OUT)
cs_pin.value(1) # 初始状态设为高电平,即不选中设备
# 创建 SPI 实例
# 参数说明: id=1(使用SPI1), baudrate=5_000_000(时钟频率5MHz),
#          polarity=0, phase=0 (SPI模式0), firstbit=MSB
spi = SPI(0, baudrate=5000000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB)
# === W25Q64 常用指令 ===
CMD_WRITE_ENABLE     = 0x06   # 写使能
CMD_WRITE_DISABLE    = 0x04   # 写禁止
CMD_READ_STATUS_REG1 = 0x05   # 读状态寄存器1
CMD_READ_DATA        = 0x03   # 读数据
CMD_PAGE_PROGRAM     = 0x02   # 页编程(写数据)
CMD_SECTOR_ERASE     = 0x20   # 扇区擦除(4KB)
CMD_READ_JEDEC_ID    = 0x9F   # 读取JEDEC ID
# === 辅助函数 ===
def cs_low():
    cs_pin.value(0)
def cs_high():
    cs_pin.value(1)
def spi_wait_ready():
    """等待芯片内部操作完成,通过读取状态寄存器1的BUSY位(bit 0)"""
    cs_low()
    spi.write(bytes([CMD_READ_STATUS_REG1]))
    status = spi.read(1, 0xFF)[0]
    while status & 0x01:  # 判断最低位是否为1
        status = spi.read(1, 0xFF)[0]
        time.sleep_ms(1)
    cs_high()
def spi_flash_write_enable():
    """发送写使能命令"""
    cs_low()
    spi.write(bytes([CMD_WRITE_ENABLE]))
    cs_high()
# === 核心功能 ===
def read_jedec_id():
    """读取JEDEC ID (制造商和设备ID)"""
    cs_low()
    # 发送命令
    spi.write(bytes([CMD_READ_JEDEC_ID]))
    # 读取3个字节: Manufacturer ID, Memory Type, Capacity
    data = spi.read(3, 0xFF)
    cs_high()
    return data
def read_data(address, length):
    """从指定地址读取数据"""
    # 构建命令字节数组: 命令(0x03) + 3字节地址(MSB)
    cmd = bytearray(4)
    cmd[0] = CMD_READ_DATA
    cmd[1] = (address >> 16) & 0xFF
    cmd[2] = (address >> 8) & 0xFF
    cmd[3] = address & 0xFF
    
    cs_low()
    spi.write(cmd)
    data = spi.read(length, 0xFF)
    cs_high()
    return data
def write_page(address, data):
    """
    页写入函数。W25Q64每页256字节,写入前地址必须对齐到页边界。
    注意:写入前必须先擦除。
    """
    if len(data) > 256:
        raise ValueError("数据长度不能超过256字节")
    
    # 使能写操作
    spi_flash_write_enable()
    
    # 发送页编程命令
    cmd = bytearray(4)
    cmd[0] = CMD_PAGE_PROGRAM
    cmd[1] = (address >> 16) & 0xFF
    cmd[2] = (address >> 8) & 0xFF
    cmd[3] = address & 0xFF
    
    cs_low()
    spi.write(cmd)
    spi.write(data)
    cs_high()
    
    # 等待写入完成
    spi_wait_ready()
def sector_erase(address):
    """
    扇区擦除 (4KB)。地址可以是该扇区范围内的任意地址。
    """
    # 使能写操作
    spi_flash_write_enable()
    
    # 发送扇区擦除命令
    cmd = bytearray(4)
    cmd[0] = CMD_SECTOR_ERASE
    cmd[1] = (address >> 16) & 0xFF
    cmd[2] = (address >> 8) & 0xFF
    cmd[3] = address & 0xFF
    
    cs_low()
    spi.write(cmd)
    cs_high()
    
    # 等待擦除完成 (扇区擦除需要较长时间,约150-400ms)
    spi_wait_ready()
# === 主函数测试 ===
print("--- Test Start ---")
while True:
    jedec = read_jedec_id()
    if len(jedec) == 3:
        print(f"JEDEC ID: 0x{jedec[0]:02X}, 0x{jedec[1]:02X}, 0x{jedec[2]:02X}")
        # W25Q64 的典型ID是: Manufacturer=0xEF, Memory Type=0x40, Capacity=0x17
        if jedec[0] == 0xEF and jedec[1] == 0x40 and jedec[2] == 0x17:
            print("Chip ID 匹配 W25Q64.")
        else:
            print("Chip ID 错误! 检查连接......")
    else:
        print("读JEDEC ID.失败。")
        # 如果读取失败,停止执行
        raise SystemExit
    time.sleep(0.01)

运行结果:

w25q218_error.png

读不出来 。然后使用逻辑分析仪检测四个信号(CS,SCK,MOSI,MISO)

w25q218_error_signal.png

可以看到,在CS信号给出后,没有看到SCK、MOSI、MISO信号有任何变化。似乎是SPI没有工作啊。

对比用软件模拟操作的检测:

w25q218_ok_signal.png

明显不一样。是不是因为使用软件模拟彻底信号使用了GPIO17,与硬件SPI0 的预设引脚重复了?

将CS换到GPI20上,结果依旧读不出来。

忽然明白了。RP2040的SPI是可以使用几组引脚配置的。在没有致命的情况下,他也不知道使用那些引脚。所以是不是必须要预先指定呢,据此该SPI初始化代码为:

spi = SPI(0,  baudrate=5_000_000,  polarity=0, phase=0, sck=Pin(18), mosi=Pin(19),  miso=Pin(16))

果然,问题解决了。





关键词: 大懒猫的试用笔记     RP2040     W25Q128    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]