rt-thread之w25q128驱动编写记录(未使用sfud通用串行库)

本文档详细描述了如何使用自定义方式初始化SPI1硬件驱动,以及针对W25Q128闪存的接口函数,包括设备ID验证、通信操作和数据擦写/读取等,展示了SPI配置和设备测试过程。
摘要由CSDN通过智能技术生成

前言

  1. 未使用sfud的方式,自己编写驱动的方式记录
  2. 使用的是spi1

硬件驱动IO初始化

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-3-31     shchl   first version
 */
#include "board.h"

void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
#ifdef BSP_USING_SPI1
    if (hspi->Instance == SPI1) {
        __HAL_RCC_SPI1_CLK_ENABLE();
        __HAL_RCC_GPIOB_CLK_ENABLE();
        /**SPI1 GPIO Configuration
        PB3     ------> SPI1_SCK
        PB4     ------> SPI1_MISO
        PB5     ------> SPI1_MOSI
        */
        GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
        return;
    }
#endif

}

w25q128

头文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-3-31     shchl   first version
 */

#ifndef EXAMPLE_W25Q128_FLASH_W25Q128_H
#define EXAMPLE_W25Q128_FLASH_W25Q128_H

#include "board.h"

#define W25Q128_DEVICE_ID 0x6817  /*根据实际情况(厂商的ID可能不是EF开头)*/

#define W25Q128_CS_PIN GET_PIN(B,14)
#define W25Q128_SPI_NO "spi10"

void w25q128_init(const char *bus_name, const char *dev_no);


uint16_t w25q128_read_deviceID();

uint32_t w25q128_read_JEDECID();

uint8_t w25q128_read_status_reg1();

uint8_t w25q128_read_status_reg2();


rt_err_t w25q128_device_check();

rt_err_t w25q128_write_enable();

rt_err_t w25q128_write_disable();

void w25q128_erase_4k(uint32_t addr);

void w25q128_erase_32k(uint32_t addr);

void w25q128_erase_63k(uint32_t addr);

rt_err_t w25q128_write_page(uint32_t addr, uint8_t *buf, uint16_t len);

rt_err_t w25q128_read_data(uint32_t addr, uint8_t *dst, uint16_t len);

rt_err_t w25q128_wake_up();

rt_err_t w25q128_power_down();

#endif //EXAMPLE_W25Q128_FLASH_W25Q128_H

源文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-3-31     shchl   first version
 */

#include "Flash_W25Q128.h"

#define DBG_ENABLE
#define DBG_TAG "w25q128"
#ifndef APP_LOG_LVL
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL APP_LOG_LVL
#endif

#include "rtdbg.h"

struct rt_spi_device *spi_device = RT_NULL;


void w25q128_init(const char *bus_name, const char *dev_no) {
    spi_device = (struct rt_spi_device *) rt_malloc(sizeof(struct rt_spi_device));
    if (!spi_device) {
        LOG_E("Failed to malloc the spi device.");
        return;
    }
    if (RT_EOK != rt_spi_bus_attach_device_cspin(spi_device, dev_no, bus_name, W25Q128_CS_PIN, RT_NULL)) {
        LOG_E("Failed to attach the spi device.");
        return;
    }
    /*spi 配置*/
    struct rt_spi_configuration spi_conf;
    {
        spi_conf.mode = RT_SPI_MASTER | RT_SPI_MSB | RT_SPI_MODE_0;
        spi_conf.data_width = 8;
        spi_conf.max_hz = 40 * 1000 * 1000;
        rt_spi_configure(spi_device, &spi_conf);
    }
    /*设备校验*/
    if (w25q128_device_check() != RT_EOK) {
        LOG_E("w25q128 device id is different set(%#x)", W25Q128_DEVICE_ID);
    }


}


static rt_err_t w25q128_tx_rx(uint8_t *send, uint16_t send_len, uint8_t *rec, uint16_t rec_len) {
    if (send && rec) {
        return rt_spi_send_then_recv(spi_device, send, send_len, rec, rec_len);
    } else if (send) {
        return rt_spi_send(spi_device, (const void *) send, send_len) == send_len ? RT_EOK : RT_EIO;
    }
    return rt_spi_recv(spi_device, rec, rec_len) == rec_len ? RT_EOK : RT_EIO;
}

static rt_err_t w25q128_tx_tx(uint8_t *cmd, uint16_t cmd_len, uint8_t *data, uint16_t data_len) {

    return rt_spi_send_then_send(spi_device, cmd, cmd_len, data, data_len);
}

uint16_t w25q128_read_deviceID() {
    uint8_t cmd[4] = {0x90, 00, 00, 00};
    uint8_t rec[2];
    if (w25q128_tx_rx(cmd, 4, rec, 2) != RT_EOK) return 0;
    return (uint16_t) (rec[0] << 8 | rec[1]);
}

uint32_t w25q128_read_JEDECID() {
    uint8_t cmd[1] = {0x9f};
    uint8_t rec[3];
    if (w25q128_tx_rx(cmd, 1, rec, 3) != RT_EOK) return 0;
    return (uint32_t) (rec[0] << 16 | rec[1] << 8 | rec[2]);
}

static inline void w25q128_wait_busy() {
    while (w25q128_read_status_reg1() & 0x1) {
        rt_hw_us_delay(100);
    }
}

/**
 * @brief 读取状态寄存器 1
 * @return (S7--S0)
 */
uint8_t w25q128_read_status_reg1() {
    uint8_t cmd[1] = {0x05};
    uint8_t rec[1];
    return w25q128_tx_rx(cmd, 1, rec, 1) == RT_EOK ? rec[0] : UINT8_MAX;
}

/**
 * @brief 读取状态寄存器 2
 * @return (S15--S8)
 */
uint8_t w25q128_read_status_reg2() {
    uint8_t cmd[1] = {0x35};
    uint8_t rec[1];
    return w25q128_tx_rx(cmd, 1, rec, 1) == RT_EOK ? rec[0] : UINT8_MAX;
}


/**
 * @brief 写使能
 * @return
 */
rt_err_t w25q128_write_enable() {
    uint8_t cmd[1] = {0x06};
    return w25q128_tx_rx(cmd, 1, NULL, 0);

}

/**
 * @brief 写保护
 * @return
 */
rt_err_t w25q128_write_disable() {
    uint8_t cmd[1] = {0x04};
    return w25q128_tx_rx(cmd, 1, NULL, 0);
}

/**
 * 从掉电模式下唤醒
 * @return
 */
rt_err_t w25q128_wake_up() {
    uint8_t cmd[1] = {0xAB};
    return w25q128_tx_rx(cmd, 1, NULL, 0);
}

/**
 * 进入掉电模式
 * @return
 */
rt_err_t w25q128_power_down() {
    uint8_t cmd[1] = {0xB9};
    return w25q128_tx_rx(cmd, 1, NULL, 0);
}

rt_err_t w25q128_device_check() {

    return w25q128_read_deviceID() == W25Q128_DEVICE_ID ? RT_EOK : RT_ERROR;
}

static inline rt_err_t w25q128_erase(uint32_t addr, uint8_t cmd) {
    w25q128_write_enable();
    uint8_t page_wr[4] = {cmd, ((addr >> 16) & 0xFF), ((addr >> 8) & 0xFF), addr & 0xFF};
    return w25q128_tx_rx(page_wr, 4, NULL, 0);
}

void w25q128_erase_4k(uint32_t addr) {
    w25q128_erase(addr, 0x20);
    w25q128_wait_busy();

}

void w25q128_erase_32k(uint32_t addr) {
    w25q128_erase(addr, 0x52);
    w25q128_wait_busy();
}

void w25q128_erase_63k(uint32_t addr) {
    w25q128_erase(addr, 0xD8);
    w25q128_wait_busy();
}

rt_err_t w25q128_write_page(uint32_t addr, uint8_t *buf, uint16_t len) {
    /*写使能*/
    w25q128_write_enable();
    uint8_t page_wr[4] = {0x02, ((addr >> 16) & 0xFF), ((addr >> 8) & 0xFF), addr & 0xFF};
    if (w25q128_tx_tx(page_wr, 4, buf, len) != RT_EOK) return RT_ERROR;
    w25q128_wait_busy();
    return RT_EOK;
}

rt_err_t w25q128_read_data(uint32_t addr, uint8_t *dst, uint16_t len) {

    uint8_t rd[4] = {0x03, ((addr >> 16) & 0xFF), ((addr >> 8) & 0xFF), addr & 0xFF};
    return w25q128_tx_rx(rd, 4, dst, len);
}


#if 1

int w25q128_test() {
    w25q128_init("spi1", "spi10");
    if (!spi_device) {
        rt_kprintf("spi init err\r\n");

        return -1;
    }
//    w25q128_wake_up();
#define BUF_SZ sizeof(buf)/ sizeof(buf[0])
    uint8_t buf[10];
    for (int i = 0; i < BUF_SZ; ++i) {
        buf[i] = i * 5;
    }
    w25q128_erase_4k(0x0);
//    rt_thread_mdelay(20);
    if (w25q128_write_page(0x0, buf, BUF_SZ) == RT_EOK) {
        rt_kprintf("w25q128_write_page ok\r\n");
        rt_memset(buf, 0, BUF_SZ);
        rt_thread_mdelay(10);
        if (w25q128_read_data(0x0, buf, BUF_SZ) == RT_EOK) {

            rt_kprintf("read data from w25q128: ");
            for (int i = 0; i < BUF_SZ; ++i) {
                rt_kprintf("%d ", buf[i]);
            }
            rt_kprintf("\r\n");
        } else {
            rt_kprintf("w25q128 read data err\r\n");
        }

    } else {
        rt_kprintf("w25q128_write_page err\r\n");

    }

    return 0;
}


INIT_DEVICE_EXPORT(w25q128_test);


#endif
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

詩不诉卿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值