搜索
bottom↓
12
返回列表 发新帖
楼主: sunnydragon

【开源】万能 SPI Flash 驱动库 SFUD 正式发布

  [复制链接]

出0入0汤圆

发表于 2016-9-17 10:55:31 | 显示全部楼层
强人开源代码不错,值得学习一下,谢谢分享!

出0入0汤圆

发表于 2016-9-25 16:44:39 | 显示全部楼层
感谢楼主的开源

出0入0汤圆

发表于 2016-9-26 22:39:25 | 显示全部楼层
SPI——Flash驱动

出0入0汤圆

发表于 2016-9-28 11:06:40 | 显示全部楼层
楼主你好,我移植了你的代码到RT THREAD,SPI FLASH挂载在/目录下,SPI FLASH创建了/SD目录,SD卡挂载在/SD下,第一次启动后都可以正常挂载,第二次后发现/SD目录丢失,请问SPI FLASH每次初始化后都清除一次FLASH吗?

出0入198汤圆

 楼主| 发表于 2016-9-29 08:03:16 | 显示全部楼层
coolhorse 发表于 2016-9-28 11:06
楼主你好,我移植了你的代码到RT THREAD,SPI FLASH挂载在/目录下,SPI FLASH创建了/SD目录,SD卡挂载在/SD ...

是不是用最新源码测试的?当时一楼位置源码存在一个“采用 SFDP 参数在某些条件下,擦除命令选择不合适的问题”,后来修复了。

你可以在 GitHub : https://github.com/armink/SFUD 下载最新源码,并更换核心源码再试试。有结果了再跟帖留言。

出0入198汤圆

 楼主| 发表于 2016-9-29 08:31:07 | 显示全部楼层
coolhorse 发表于 2016-9-28 11:06
楼主你好,我移植了你的代码到RT THREAD,SPI FLASH挂载在/目录下,SPI FLASH创建了/SD目录,SD卡挂载在/SD ...

SFUD 本身只是驱动库,所有具体操作都要听从于上层应用的安排,所以它自己初始化时候是不会执行擦除的操作。

你这个现象倒是让我想到了,之前由于 EasyFlash 的 Log 功能还没有与 SPI Flash 对接好,所以当 EasyFlash 在 使用 SFUD 作为底层驱动时,Log 功能每次初始化在初始化过程中都会错误的擦除部分 Flash 区域。

不过这个 Bug 也很快修复了,如果使用了 EasyFlash ,建议也对其源码进行更新。

出0入0汤圆

发表于 2016-9-29 08:52:06 | 显示全部楼层
不错,支持楼主

出0入17汤圆

发表于 2016-9-29 09:07:05 | 显示全部楼层
赞一个,回头移植到ebox上,不知道可行不

出0入17汤圆

发表于 2016-9-29 09:07:46 | 显示全部楼层
赞一个,回头移植到ebox上不知道可行不

出0入0汤圆

发表于 2016-9-29 09:11:30 | 显示全部楼层
问题解决了,是我驱动写错了,现在上传文件系统驱动

出0入0汤圆

发表于 2016-9-29 09:13:25 | 显示全部楼层
#include <rtthread.h>
#include <drivers/spi.h>
#include <sfud.h>

struct spi_flash_device
{
    struct rt_device flash_device;
       
        const sfud_flash  *flash;
    struct rt_device_blk_geometry   geometry;
};

static struct spi_flash_device  spi_flash_device;


/* RT-Thread device interface */
static rt_err_t sfud_flash_init(rt_device_t dev)
{
    return RT_EOK;
}

static rt_err_t sfud_flash_open(rt_device_t dev, rt_uint16_t oflag)
{
        struct spi_flash_device *aa = (struct spi_flash_device *)dev;
        const sfud_flash *flash = aa->flash;
       
    return RT_EOK;
}

static rt_err_t sfud_flash_close(rt_device_t dev)
{
    return RT_EOK;
}

static rt_err_t sfud_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args)
{
    RT_ASSERT(dev != RT_NULL);

    if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
    {
        struct rt_device_blk_geometry *geometry;

        geometry = (struct rt_device_blk_geometry *)args;
        if (geometry == RT_NULL) return -RT_ERROR;

        geometry->bytes_per_sector = spi_flash_device.geometry.bytes_per_sector;
        geometry->sector_count = spi_flash_device.geometry.sector_count;
        geometry->block_size = spi_flash_device.geometry.block_size;
    }

    return RT_EOK;
}

static rt_size_t sfud_flash_read(rt_device_t dev,
                                   rt_off_t pos,
                                   void* buffer,
                                   rt_size_t size)
{
        struct spi_flash_device *aa = (struct spi_flash_device *)dev;
        const sfud_flash *flash = aa->flash;
        sfud_read(flash, pos*spi_flash_device.geometry.bytes_per_sector, size*spi_flash_device.geometry.bytes_per_sector, buffer);
       
    return size;
}

static rt_size_t sfud_flash_write(rt_device_t dev,
                                    rt_off_t pos,
                                    const void* buffer,
                                    rt_size_t size)
{
        rt_size_t i = 0;
    rt_size_t block = size;
    const uint8_t * ptr = buffer;
        struct spi_flash_device *aa = (struct spi_flash_device *)dev;
        const sfud_flash *flash = aa->flash;

        while(block--)
    {
        sfud_erase_write(flash,(pos + i)*spi_flash_device.geometry.bytes_per_sector,spi_flash_device.geometry.bytes_per_sector,ptr);
                //w25qxx_page_write((pos + i)*spi_flash_device.geometry.bytes_per_sector,ptr);
        ptr += spi_flash_device.geometry.bytes_per_sector;
        i++;
    }
       
    return size;
}

rt_err_t sfudxx_init(const char * flash_device_name)
{
    /* init flash */
        sfud_init();
        spi_flash_device.flash = sfud_get_device_table() + 0;
       
        spi_flash_device.geometry.bytes_per_sector = spi_flash_device.flash->chip.erase_gran;
    spi_flash_device.geometry.block_size = spi_flash_device.flash->chip.erase_gran;
        spi_flash_device.geometry.sector_count = spi_flash_device.flash->chip.capacity / spi_flash_device.geometry.bytes_per_sector;
    /* register device */
    spi_flash_device.flash_device.type    = RT_Device_Class_Block;
    spi_flash_device.flash_device.init    = sfud_flash_init;
    spi_flash_device.flash_device.open    = sfud_flash_open;
    spi_flash_device.flash_device.close   = sfud_flash_close;
    spi_flash_device.flash_device.read    = sfud_flash_read;
    spi_flash_device.flash_device.write   = sfud_flash_write;
    spi_flash_device.flash_device.control = sfud_flash_control;
    /* no private */
    spi_flash_device.flash_device.user_data = RT_NULL;

    rt_device_register(&spi_flash_device.flash_device, flash_device_name,
                       RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);

    return RT_EOK;
}

出0入0汤圆

发表于 2016-9-29 09:14:41 | 显示全部楼层
#include <sfud.h>
#include <stdarg.h>
#include <rtthread.h>
#include <drivers/spi.h>

typedef struct {
    struct rt_semaphore lock;
        struct rt_spi_device * rt_spi_device;
} spi_user_data, *spi_user_data_t;

static spi_user_data spi2 = { .rt_spi_device = 0 };

static char log_buf[256];

void sfud_log_debug(const char *file, const long line, const char *format, ...);


static void spi_lock(const sfud_spi *spi) {
    spi_user_data_t spi_dev = (spi_user_data_t) spi->user_data;

    rt_sem_take(&spi_dev->lock, RT_WAITING_FOREVER);
}

static void spi_unlock(const sfud_spi *spi) {
    spi_user_data_t spi_dev = (spi_user_data_t) spi->user_data;

    rt_sem_release(&spi_dev->lock);
}

static void retry_delay_ms(void) {
    /* millisecond delay */
    rt_tick_from_millisecond(1);
}

static void retry_delay_100us(void) {
    /* 100 microsecond delay */
    rt_thread_delay((RT_TICK_PER_SECOND * 1 + 9999) / 10000);
}

/**
* SPI write data then read data
*/
static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
        size_t read_size) {
                       
        struct rt_spi_device * rt_spi_device;
    sfud_err result = SFUD_SUCCESS;
       
    spi_user_data_t spi_dev = (spi_user_data_t) spi->user_data;

    rt_spi_send_then_recv(spi_dev->rt_spi_device, write_buf,write_size, read_buf, read_size);

    return result;
}



sfud_err sfud_spi_port_init(sfud_flash *flash) {
        sfud_err result = SFUD_SUCCESS;
    struct rt_spi_device * rt_spi_device;
       
        rt_spi_device = (struct rt_spi_device *)rt_device_find("spi20");
        if(rt_spi_device == RT_NULL)
    {
        rt_kprintf("spi device %s not found!\r\n", "spi20");
        return -RT_ENOSYS;
    }
    spi2.rt_spi_device = rt_spi_device;

    /* config spi */
    {
        struct rt_spi_configuration cfg;
        cfg.data_width = 8;
        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
        cfg.max_hz = 50 * 1000 * 1000; /* 50M */
        rt_spi_configure(spi2.rt_spi_device, &cfg);
    }
       
        flash->spi.wr = spi_write_read;
        flash->spi.lock = spi_lock;
        flash->spi.unlock = spi_unlock;
        flash->spi.user_data = &spi2;
        /* 100 microsecond delay */
        flash->retry.delay = retry_delay_100us;
        /* 60 seconds timeout */
        flash->retry.times = 60 * 10000;

        rt_sem_init(&spi2.lock, "spi2 lock", 1, RT_IPC_FLAG_PRIO);

    return result;
}

/**
* This function is print debug info.
*
* @param file the file which has call this function
* @param line the line number which has call this function
* @param format output format
* @param ... args
*/
void sfud_log_debug(const char *file, const long line, const char *format, ...) {
    va_list args;

    /* args point to the first variable parameter */
    va_start(args, format);
    rt_kprintf("[SFUD](%s:%ld) ", file, line);
    /* must use vprintf to print */
    vsnprintf(log_buf, sizeof(log_buf), format, args);
    rt_kprintf("%s\n", log_buf);
    va_end(args);
}

/**
* This function is print routine info.
*
* @param format output format
* @param ... args
*/
void sfud_log_info(const char *format, ...) {
    va_list args;

    /* args point to the first variable parameter */
    va_start(args, format);
    rt_kprintf("[SFUD]");
    /* must use vprintf to print */
    vsnprintf(log_buf, sizeof(log_buf), format, args);
    rt_kprintf("%s\n", log_buf);
    va_end(args);
}

出0入0汤圆

发表于 2016-9-29 09:22:23 | 显示全部楼层
测试两款芯片:N25Q032A13ESE40F(支持SFUD)  SST25VF032B(不支持SFUD) 通过,  SST26VF032B (支持SFUD)不通过,奇怪[SFUD](..\..\components\drivers\spi\sfud\src\sfud.c:78) Start initialize Serial Flash Universal Driver(SFUD) V0.08.25.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud.c:712) The flash device manufacturer ID is 0xBF, memory type ID is 0x26, capacity ID is 0x42.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:134) Check SFDP header is OK. The reversion is V1.6, NPN is 2.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:175) Check JEDEC basic flash parameter header is OK. The table id is 0, reversion is V1.6, length is 16, parameter table pointer is[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:205) JEDEC basic flash parameter table info:
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:206) MSB-LSB  3    2    1    0
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:208) [0001] 0xFF 0xF1 0x20 0xFD
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:208) [0002] 0x01 0xFF 0xFF 0xFF
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:208) [0003] 0x6B 0x08 0xEB 0x44
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:208) [0004] 0xBB 0x80 0x3B 0x08
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:208) [0005] 0xFF 0xFF 0xFF 0xFE
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:208) [0006] 0xFF 0x00 0xFF 0xFF
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:208) [0007] 0x0B 0x44 0xFF 0xFF
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:208) [0008] 0xD8 0x0D 0x20 0x0C
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:208) [0009] 0xD8 0x10 0xD8 0x0F
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:217) 4 KB Erase is supported throughout the device. Command is 0x20.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:236) Write granularity is 64 bytes or larger.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:252) Block Protect bits in device's status register are solely volatile.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:262) Flash device requires instruction 06h as the write enable prior to performing a volatile write to the status register.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:273) 3-Byte only addressing.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:307) Capacity is 4194304 Bytes.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:313) Flash device supports 4KB block erase. Command is 0x20.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:313) Flash device supports 8KB block erase. Command is 0xD8.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:313) Flash device supports 32KB block erase. Command is 0xD8.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud_sfdp.c:313) Flash device supports 64KB block erase. Command is 0xD8.
[SFUD]Find a SST flash chip. Size is 4194304 bytes.
[SFUD](..\..\components\drivers\spi\sfud\src\sfud.c:687) Flash device reset success.
[SFUD]XXXX flash device is initialize success.

出0入198汤圆

 楼主| 发表于 2016-9-29 09:23:02 | 显示全部楼层
coolhorse 发表于 2016-9-29 09:11
问题解决了,是我驱动写错了,现在上传文件系统驱动

解决完成就好,不过还是建议定期关注项目首页,及时采用最新源码。

出0入198汤圆

 楼主| 发表于 2016-9-29 09:23:56 | 显示全部楼层
coolhorse 发表于 2016-9-29 09:14
#include
#include
#include

多谢分享哈~~

出0入198汤圆

 楼主| 发表于 2016-9-29 09:26:05 | 显示全部楼层
coolhorse 发表于 2016-9-29 09:22
测试两款芯片:N25Q032A13ESE40F(支持SFUD)  SST25VF032B(不支持SFUD) 通过,  SST26VF032B (支持SFUD)不 ...

SST26VF032B (支持SFUD)不通过,具体是什么现象?

出0入198汤圆

 楼主| 发表于 2016-9-29 09:38:26 | 显示全部楼层
coolhorse 发表于 2016-9-29 09:22
测试两款芯片:N25Q032A13ESE40F(支持SFUD)  SST25VF032B(不支持SFUD) 通过,  SST26VF032B (支持SFUD)不 ...


你的括号里面写的 “支持 SFUD” 或 “不支持SFUD”,应该指的是 SFDP 参数表吧。SFUD 是万能 SPI Flash 驱动库的名称,两个单词差一个字母

出0入0汤圆

发表于 2016-9-29 09:39:29 | 显示全部楼层
好东西,顶上

出0入0汤圆

发表于 2016-9-29 10:18:10 | 显示全部楼层
是的,不好意思啊,支持 SFUD” 或 “不支持SFUD”,指的是 SFDP 参数表,SST26VF032B支持参数表的,上面打印的就是SST26VF032B的信息,但是用上面的文件系统驱动,文件系统无法初始化成功,估计是SFDP写保护问题,无法执行写操作,楼主你帮我找找问题吧,我这里有SST26VF032B样品,要不要寄给你

出0入198汤圆

 楼主| 发表于 2016-9-29 10:49:54 | 显示全部楼层
coolhorse 发表于 2016-9-29 10:18
是的,不好意思啊,支持 SFUD” 或 “不支持SFUD”,指的是 SFDP 参数表,SST26VF032B支持参数表的,上面打 ...

你用用 RT-Thread Demo 里面那个 sf 命令测试下这个 Flash 试试,命令教程在这里:https://github.com/armink/SFUD/tree/master/demo/stm32f2xx_rtt#111-flash-操作命令

先定位下问题,确实不好找,你再寄给我样品,不过要等国庆以后才能帮你测试了。

出0入0汤圆

发表于 2016-9-29 10:55:41 | 显示全部楼层
非常感谢楼主分享!!!

出0入198汤圆

 楼主| 发表于 2016-9-29 11:09:27 | 显示全部楼层
本帖最后由 sunnydragon 于 2016-9-29 11:11 编辑
coolhorse 发表于 2016-9-29 10:18
是的,不好意思啊,支持 SFUD” 或 “不支持SFUD”,指的是 SFDP 参数表,SST26VF032B支持参数表的,上面打 ...


对了,SST 的 Flash 是不是上电都默认是写保护的?我记得我测试 SST25 的时候就有这个问题, 同时 SST25 写数据还是很奇葩的 AAI 模式,所以我针对 支持 AAI 模式的 Flash 在初始化时,做了去除写保护处理,如图:



所以 SST26 系列,你可以这样尝试,两种方法:

第一种:使用 RT-Thread  Demo 可以使用我提供的
  1. flash_status <read|write> <device_index> [<1:volatile|0:non-volatile> <status>]
复制代码

命令,在 MSH 终端中输入:
  1. flash_status write 1 0
复制代码
,再进行写数据试试。

第二种:执行完 sfud_err sfud_init(void) 后,再增加  sfud_write_status(flash, true, 0x00); 代码,保证 Flash 被去除写保护

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入8汤圆

发表于 2016-9-29 15:18:40 来自手机 | 显示全部楼层
好牛逼的样子

出0入0汤圆

发表于 2016-10-8 21:42:17 来自手机 | 显示全部楼层
支持,经常用到华邦的芯片。

出0入0汤圆

发表于 2016-10-9 08:24:46 | 显示全部楼层
不错,严重支持,有空我来试试。

出0入198汤圆

 楼主| 发表于 2016-10-10 21:26:13 | 显示全部楼层
coolhorse 发表于 2016-9-29 10:18
是的,不好意思啊,支持 SFUD” 或 “不支持SFUD”,指的是 SFDP 参数表,SST26VF032B支持参数表的,上面打 ...

SST26VF032B 无法执行写操作的问题解决了吗?跟大家分享下进展吧。

出0入0汤圆

发表于 2016-10-11 17:12:39 | 显示全部楼层
我已经用在了项目上,FLASH是WINBOND的 W25Q64FV

因为SFUD的软件做得非常好,所以几乎没有啥移植工作,直接用就好了。实在是非常优秀的开源项目,感谢 sunnydragon

使用后有一些建议:

1、建议将 chip erase 这个函数开放出来。目前是包含在 sfud_erase 这个函数里面,通过判断起始地址为0和大小是flash的大小时就擦除整个芯片。这样感觉还不够方便。
2、在将 SFUD_DEBUG_MODE 宏定义关掉的时候,还有一个npn的变量的警告,作为一个强迫症患者,建议这个也可以顺手修改掉。
3、在说明文档中提到的那些flash型号,并没有更新到最新的代码列表中。建议增加进去。
4、建议增加更详细的函数应用说明,比如sfud_erase函数,擦除是按照地址和大小来的,实际擦除的是地址为起始,地址+大小为结束的范围,以擦除block为单位的擦除。

出0入0汤圆

发表于 2016-10-11 17:41:52 | 显示全部楼层
感谢楼主的开源

出0入0汤圆

发表于 2016-10-11 17:45:06 | 显示全部楼层
mark                  

出0入76汤圆

发表于 2016-10-11 18:14:37 | 显示全部楼层
非常感谢楼主分享, 这个真心不错

出0入198汤圆

 楼主| 发表于 2016-10-11 21:19:04 | 显示全部楼层
FireHe 发表于 2016-10-11 17:12
我已经用在了项目上,FLASH是WINBOND的 W25Q64FV

因为SFUD的软件做得非常好,所以几乎没有啥移植工作,直 ...

多谢你的反馈,写的非常仔细认真,我来逐条回复下:

1、这点我确实也感觉到了,大概一个月前把全片擦除 API:sfud_chip_erase 加入进去了。以后可以常去 GitHub ,关注项目进展哈:lol:} ;(建议点击 GitHub 项目右上角的 watch 按钮,这样项目有更新会邮件通知你)

2、已修改,详见 GitHub 最新代码;

3、这点没有搞太明白,是说代码中的 SFUD_FLASH_CHIP_TABLE 没有包含支持 SFDP 参数表的 Flash 芯片吗?

4、刚才也对文档做了更新,在这里: https://www.zybuluo.com/armink/note/363414 ,你看下还有没有要完善的。没问题的话,我就推送至 GitHub 了。

还有其他建议或想法也欢迎随时反馈。

出30入0汤圆

发表于 2016-10-11 23:04:49 | 显示全部楼层
有见楼主发精品了,谢谢!

出0入0汤圆

发表于 2016-10-11 23:15:28 | 显示全部楼层
sunnydragon 发表于 2016-10-11 21:19
多谢你的反馈,写的非常仔细认真,我来逐条回复下:

1、这点我确实也感觉到了,大概一个月前把全片擦除  ...

第三点说的是,在说明文档 readme.md 中,有提到很多型号,但在代码的数组列表里面并没有这些型号。用户在用的时候,还需要自己再增加,比如我用的W25Q64FV。如果sunnydragon 已经做过测试了,建议把列表直接完善了。

其他的几点,我再去拜读最新版本代码去~~~

出0入4汤圆

发表于 2016-10-11 23:35:34 | 显示全部楼层
有没有 spi nandflash的 版本= =

出0入0汤圆

发表于 2016-10-11 23:40:23 | 显示全部楼层
好东西,顶起,再也不怕不兼容了

出0入198汤圆

 楼主| 发表于 2016-10-12 07:49:31 | 显示全部楼层
FireHe 发表于 2016-10-11 23:15
第三点说的是,在说明文档 readme.md 中,有提到很多型号,但在代码的数组列表里面并没有这些型号。用户 ...


我明白你的意思了,那可能是不是我文档中写的不够明确,SFUD_FLASH_CHIP_TABLE 数组里只包含了不支持 JEDEC SFDP 参数表的 Flash 芯片。

如果这块 Flash 芯片支持 JEDEC 的 SFDP 参数表,那么用户是不需要对这块 Flash 芯片做任何参数配置,只要开启了本库的 SFDP 模式(即打开 SFUD_USING_SFDP 宏定义),本库是可以自动读取存放在 Flash 芯片中的 SFDP 参数表,实现对 Flash 自动初始化,非常省事的。

出0入198汤圆

 楼主| 发表于 2016-10-12 08:00:49 | 显示全部楼层
huarana 发表于 2016-10-11 23:35
有没有 spi nandflash的 版本= =


暂时还没有,主要是 SPI 接口的 NandFlash 使用场景感觉太小,当时就没有开发。不过当时也做过部分调研,想要增加 SPI NandFlash 工作量也并不会很大。有没有兴趣我来协助你尝试下?

出0入4汤圆

发表于 2016-10-12 08:35:55 | 显示全部楼层
sunnydragon 发表于 2016-10-12 08:00
暂时还没有,主要是 SPI 接口的 NandFlash 使用场景感觉太小,当时就没有开发。不过当时也做过部分调研, ...

spi nand应用场景还是有的。

要求可靠性的场合下,tf卡 sd卡都不是好的解决方案。 而并口的nand对单片机要求又高了。

所以 spi nand就是最佳选择。然而使用起来发现磨损平衡和坏块管理比较麻烦。  目前我们的嵌入式工程师正在攻关这一块

出0入0汤圆

发表于 2016-10-12 09:04:55 | 显示全部楼层
huarana 发表于 2016-10-12 08:35
spi nand应用场景还是有的。

要求可靠性的场合下,tf卡 sd卡都不是好的解决方案。 而并口的nand对单片机 ...

eMMC 不就好了吗?

坏块管理和写平衡不是那么好做的。

出0入0汤圆

发表于 2016-10-12 09:05:57 | 显示全部楼层
谢谢分享! 学习下哈

出0入0汤圆

发表于 2016-10-12 09:13:48 | 显示全部楼层
sunnydragon 发表于 2016-10-12 07:49
我明白你的意思了,那可能是不是我文档中写的不够明确,SFUD_FLASH_CHIP_TABLE 数组里只包含了不支持 JED ...

原来是这样

刚刚看了代码,确实是有自动读取配置的部分,之前阅读不仔细,没看到这个。

所以如果FLASH是支持SFUD的话,那根本就不需要做数组的配置,直接就可以用啦?如果从应用逻辑上是兼容的话,不修改代码直接换芯片也是不影响的,是吗?

出0入4汤圆

发表于 2016-10-12 09:22:29 | 显示全部楼层
FireHe 发表于 2016-10-12 09:04
eMMC 不就好了吗?

坏块管理和写平衡不是那么好做的。

eMMC的话 体积大了,而且焊接是个麻烦,另外容量也太大了点。 对于100M-1G之间的需求来说不太好找。

出0入0汤圆

发表于 2016-10-12 09:45:07 | 显示全部楼层
对裸机系统有很大的帮助,试试移植楼主的代码。

出0入198汤圆

 楼主| 发表于 2016-10-12 11:51:53 | 显示全部楼层
huarana 发表于 2016-10-12 08:35
spi nand应用场景还是有的。

要求可靠性的场合下,tf卡 sd卡都不是好的解决方案。 而并口的nand对单片机 ...

只驱动 SPI Nand 读写,难度并不大,这会是 SFUD 的主要工作。

就像你说的难度更大的是如何做好 FTL ,这块学问还是挺深的。你们现在是自己在写 FTL 还是用现成的?

出0入198汤圆

 楼主| 发表于 2016-10-12 11:58:32 | 显示全部楼层
FireHe 发表于 2016-10-12 09:13
原来是这样

刚刚看了代码,确实是有自动读取配置的部分,之前阅读不仔细,没看到这个。


是的,如果你的 Flash 支持 SFDP 参数表,甚至可以把 SFUD_USING_FLASH_INFO_TABLE 宏定义关闭,SFUD_FLASH_CHIP_TABLE 这个数组的配置就不需要了,这样代码量还能再降低。

关于芯片更换问题,如果你换的芯片依然支持 JEDEC SFDP 参数表,那么肯定没有任何影响,所有代码都不用改。如果新换的 Flash 不支持 JEDEC SFDP 参数表,就需要开启 SFUD_USING_FLASH_INFO_TABLE ,手动在里面添加 Flash 芯片参数来使用。

出0入8汤圆

发表于 2016-10-12 17:20:00 | 显示全部楼层
真不错,关注下啊~~

出0入198汤圆

 楼主| 发表于 2016-10-13 21:11:06 | 显示全部楼层
FireHe 发表于 2016-10-12 09:13
原来是这样

刚刚看了代码,确实是有自动读取配置的部分,之前阅读不仔细,没看到这个。


新改的文档看了吗?  https://www.zybuluo.com/armink/note/363414

出0入0汤圆

发表于 2016-10-14 01:04:43 | 显示全部楼层
sunnydragon 发表于 2016-10-13 21:11
新改的文档看了吗?  https://www.zybuluo.com/armink/note/363414

看啦

新的文档详细很多。很多细节都讲清楚了。这样更容易上手了

不过有一个地方我没看明白

sfud_write_status 这个函数,有一个 is_volatile 参数,这个具体是什么意义?


从这个函数也引发了一个思考。FLASH的写保护,目前默认是初始化就关闭的。从SPI FALSH的角度来说,这样是否存在数据风险?是否考虑这个开放一个接口出来给客户控制?

因为很多用SPI FLASH的用户,是只读的应用。并不需要写操作。

还有一个问题,兼容SFDP 标准的FLASH,对用户来说,主要区别就在于block的大小不同吧?(目前我用的好像都是一样的)这个是否也考虑做一个接口,给用户层调用,知道当前用的FLASH的最小擦除单位是多少,从而正确处理数据读写。

出0入198汤圆

 楼主| 发表于 2016-10-14 08:30:23 | 显示全部楼层
FireHe 发表于 2016-10-14 01:04
看啦

新的文档详细很多。很多细节都讲清楚了。这样更容易上手了

1、is_volatile 的参数含义为该状态写入以后是否需要设置为易闪失的,即设置完的状态掉电后保不保存,true 则不保存。这块你觉得在文档中需要怎么完善下才更好的理解?

2、Flash 写保护是这样的,可以全片也保护,也可以按照扇区写保护,不同的芯片,按照扇区保护的命令、数据差异非常大,所以这也是我一直没法统一的一个原因,最后就提供 sfud_write_status  方法还有 flash->spi.wr 方法给上层用户,用户自己参考芯片手册进行设置更为灵活。

3、初始化成功后 在 flash->chip 结构体中存放的芯片所有参数

  1. /* flash chip information */
  2. typedef struct {
  3.     char *name;                                  /**< flash chip name */
  4.     uint8_t mf_id;                               /**< manufacturer ID */
  5.     uint8_t type_id;                             /**< memory type ID */
  6.     uint8_t capacity_id;                         /**< capacity ID */
  7.     uint32_t capacity;                           /**< flash capacity (bytes) */
  8.     uint16_t write_mode;                         /**< write mode  @see sfud_write_mode */
  9.     uint32_t erase_gran;                         /**< erase granularity (bytes) */
  10.     uint8_t erase_gran_cmd;                      /**< erase granularity size block command */
  11. } sfud_flash_chip;
复制代码


如果芯片支持 SFDP ,还可以通过 flash->sfdp 看到更加全面的参数信息

  1. /**
  2. * the SFDP (Serial Flash Discoverable Parameters) parameter info which used on this library
  3. */
  4. typedef struct {
  5.     bool available;                              /**< available when read SFDP OK */
  6.     uint8_t major_rev;                           /**< SFDP Major Revision */
  7.     uint8_t minor_rev;                           /**< SFDP Minor Revision */
  8.     uint16_t write_gran;                         /**< write granularity (bytes) */
  9.     uint8_t erase_4k;                            /**< 4 kilobyte erase is supported throughout the device */
  10.     uint8_t erase_4k_cmd;                        /**< 4 Kilobyte erase command */
  11.     bool sr_is_non_vola;                         /**< status register is supports non-volatile */
  12.     uint8_t vola_sr_we_cmd;                      /**< volatile status register write enable command */
  13.     bool addr_3_byte;                            /**< supports 3-Byte addressing */
  14.     bool addr_4_byte;                            /**< supports 4-Byte addressing */
  15.     uint32_t capacity;                           /**< flash capacity (bytes) */
  16.     struct {
  17.         uint32_t size;                           /**< erase sector size (bytes). 0x00: not available */
  18.         uint8_t cmd;                             /**< erase command */
  19.     } eraser[SFUD_SFDP_ERASE_TYPE_MAX_NUM];      /**< supported eraser types table */
  20.     //TODO lots of fast read-related stuff (like modes supported and number of wait states/dummy cycles needed in each)
  21. } sfud_sfdp, *sfud_sfdp_t;
复制代码


不过这块可能需要文档描述下, 否则大家都不知道

出0入0汤圆

发表于 2016-10-14 10:12:22 | 显示全部楼层
sunnydragon 发表于 2016-10-14 08:30
1、is_volatile 的参数含义为该状态写入以后是否需要设置为易闪失的,即设置完的状态掉电后保不保存,tru ...

1、哦,那个状态是可以保存在FLASH里面,掉电不丢失的。是吧?也可以写寄存器的方式,但掉电就会丢失?嗯,如果是这样,这个描述应该是要针对状态寄存器的。开始我还以为是针对整个FLASH的

2、写保护统一接口那这个确实没有太好的办法。不过,是否提供给客户一个变量来控制目前是否需要写入数据的需求?
     比如一个应用场景,客户用FLASH来存储字库,基本上是只读的。只有系统更新的时候才可能会刷新版本写进去。那正常启动的时候,应该就是只读的。在系统更新的时候,通过开放的专门函数来打开读保护,然后再写。这样是否会更安全?有没有这个必要?
     因为我之前用EEPROM的时候,发现在上电或掉电的瞬间,如果没有读保护,容易造成里面的内容被错误改写的情况。不知道SPI FLASH有没有这个问题。

3、我说的就是 erase_gran  这个参数啦。刚刚看了一下代码,这个没有封装起来的。用户层面可以直接读取。那就ok了。

出0入198汤圆

 楼主| 发表于 2016-10-14 13:26:47 | 显示全部楼层
FireHe 发表于 2016-10-14 10:12
1、哦,那个状态是可以保存在FLASH里面,掉电不丢失的。是吧?也可以写寄存器的方式,但掉电就会丢失?嗯 ...

1、就是这样的

2、当Flash 不使用时,打开写保护是最好的,避免的外部信号干扰对芯片造成影响。接下来,我打算独立出 Flash 全片写保护开启及关闭方法;增加空闲时自动开启写保护的宏定义,开启后必须先执行关闭写保护的方法后,才可以正确执行擦写操作,执行完擦写操作后将会自动对 Flash 开启写保护。另外,出于进一步提高可靠性的考虑,建议用户对关闭保护操作增加授权、校验操作,避免程序跑飞等其他异常场景导致 Flash 被错误的取消保护。

3、现在用户是可以通过 Flash 对象直接读取的。没有封装起来是什么意思,你的意思在写个方法来返回给用户吗?

出0入0汤圆

发表于 2016-10-14 18:12:49 | 显示全部楼层
sunnydragon 发表于 2016-10-14 13:26
1、就是这样的

2、当Flash 不使用时,打开写保护是最好的,避免的外部信号干扰对芯片造成影响。接下来, ...

这些计划完全满足我对这个优秀的开源项目的未来展望啦

   感谢 sunnydragon~~~

出0入0汤圆

发表于 2016-10-14 18:14:35 | 显示全部楼层
关于第三点,目前已经可以直接通过flash对象读取了。我之前没仔细看代码,不确认用户是否可见。后来确认了,目前是没有封装起来的。用户可见的,我个人的看法是没有必要再用函数返回了。用户直接调用这个就好了。

出0入17汤圆

发表于 2016-10-20 01:03:02 | 显示全部楼层
本帖最后由 shentqlf 于 2016-10-20 01:43 编辑

楼主我的代码上传下,ebox下支持了sfud,
支持软件SPI和硬件SPI。
支持单条总线挂载多个FLASH。(eBox底层有总裁,可以是总线上的器件使用不同的总线配置,避免读写相互间的串扰)
支持多条总线挂载多个FLASH。

map文件



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-10-20 10:06:39 | 显示全部楼层
感谢分享 !!!!!

出0入198汤圆

 楼主| 发表于 2016-10-20 13:40:16 | 显示全部楼层
shentqlf 发表于 2016-10-20 01:03
楼主我的代码上传下,ebox下支持了sfud,
支持软件SPI和硬件SPI。
支持单条总线挂载多个FLASH。(eBox底层 ...

多谢分享~

刚看了下,使用 ebox 来做为底层驱动确实简单了不多。。。

另外软件模拟 SPI 代码在哪里?

出0入17汤圆

发表于 2016-10-20 14:15:27 | 显示全部楼层
sunnydragon 发表于 2016-10-20 13:40
多谢分享~

刚看了下,使用 ebox 来做为底层驱动确实简单了不多。。。

也在里面呢啊。吧硬件SPI那部分屏蔽了,然后把软件SPI那些取消屏蔽就行了

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入198汤圆

 楼主| 发表于 2016-10-20 15:22:30 | 显示全部楼层
shentqlf 发表于 2016-10-20 14:15
也在里面呢啊。吧硬件SPI那部分屏蔽了,然后把软件SPI那些取消屏蔽就行了

...

这个注释我看到了,我指的是 SoftSpi 里具体的实现代码。

出0入0汤圆

发表于 2017-5-29 12:52:19 | 显示全部楼层
这两天一个新项目又用上了SFUD,真的非常好用,快速开发。再次感谢  sunnydragon

再反馈一个细节:

SUFD_INFO 这个输出没有用宏定义管理,建议在cfg里面增加一个。这样跟debug信息一样可以配置是否输出了。

出0入198汤圆

 楼主| 发表于 2017-5-30 18:25:24 | 显示全部楼层
FireHe 发表于 2017-5-29 12:52
这两天一个新项目又用上了SFUD,真的非常好用,快速开发。再次感谢  sunnydragon

再反馈一个细节:

什么场景下不需要 info 日志的输出呢?目前我们产品出货时,info 日志也是必须开启的。

出0入0汤圆

发表于 2017-5-31 09:54:52 | 显示全部楼层
sunnydragon 发表于 2017-5-30 18:25
什么场景下不需要 info 日志的输出呢?目前我们产品出货时,info 日志也是必须开启的。 ...

比如串口要用来作为其他用途的时候,这个跟调试的时候需要打印并不冲突

我是先将基础环境搭好,配置好硬件,测试好SFUD,看日志输出,初始化正常了。然后再开始调试其他部分。这个时候串口需要输出自定义帧跟PC通讯了。如果有日志输出,会造成干扰。

这个每个项目的需求不同,都是不一样的,能作为一个可选配置就最好啦

另外,我现在这个项目也用上了esaylogger    真的很好用

出0入198汤圆

 楼主| 发表于 2017-5-31 13:28:29 | 显示全部楼层
FireHe 发表于 2017-5-31 09:54
比如串口要用来作为其他用途的时候,这个跟调试的时候需要打印并不冲突

我是先将基础环境搭好,配置好硬 ...

好的,已经改好了。快从 GitHub: https://github.com/armink/SFUD 上下载下来试试吧,多谢你的反馈。

出0入0汤圆

发表于 2017-6-2 12:51:39 | 显示全部楼层
感谢楼主的开源

出0入0汤圆

发表于 2017-11-9 06:48:16 | 显示全部楼层
想把代码移植到freertos中,spi_lock可以用freertos中什么替代?

出0入0汤圆

发表于 2017-11-9 10:45:26 | 显示全部楼层
收藏收藏,马克一下!!

出0入198汤圆

 楼主| 发表于 2017-11-9 10:54:39 | 显示全部楼层
游在云间 发表于 2017-11-9 06:48
想把代码移植到freertos中,spi_lock可以用freertos中什么替代?

mutex or sem

出0入0汤圆

发表于 2017-11-9 21:35:07 | 显示全部楼层
不错 不错 , SPI  FATS 也是一个麻烦  扇区4K   那么最小的一个文件是4K 不然,就得读出来,再写,就麻烦了.

出0入0汤圆

发表于 2017-11-10 17:41:18 | 显示全部楼层
大神是不是参与写过rtthread?署名armink?

出0入0汤圆

发表于 2017-11-25 22:41:50 | 显示全部楼层
楼主,这个驱动怎么添加Dual SPI或者Quad SPI支持呢

出0入198汤圆

 楼主| 发表于 2017-11-27 08:24:34 | 显示全部楼层
擦鞋匠 发表于 2017-11-10 17:41
大神是不是参与写过rtthread?署名armink?

嗯,我也是 RT-Thread 开发者。

出0入198汤圆

 楼主| 发表于 2017-11-27 08:25:54 | 显示全部楼层
tianxiaoMCU 发表于 2017-11-25 22:41
楼主,这个驱动怎么添加Dual SPI或者Quad SPI支持呢


https://github.com/armink/SFUD/b ... sfud_port.c#L55-L67

这个文件里有详细的说明,底层 SPI 是不需要 SFUD 关注的。

出0入4汤圆

发表于 2017-12-9 17:35:25 | 显示全部楼层
这个很不错,可用在正在做的烧录器程序中。

出0入0汤圆

发表于 2017-12-11 20:09:38 | 显示全部楼层
楼主好东西,有没有各种EEPROM开源的?

出0入0汤圆

发表于 2018-11-9 11:21:47 | 显示全部楼层
测试了两天,发现一个问题,如果在SPI Flash忙碌时MCU发生复位,重启后初始化是不响应查询SFUD信息命令的,此时会报芯片不支持SFUD

出0入198汤圆

 楼主| 发表于 2018-11-9 18:25:55 | 显示全部楼层
q457344370 发表于 2018-11-9 11:21
测试了两天,发现一个问题,如果在SPI Flash忙碌时MCU发生复位,重启后初始化是不响应查询SFUD信息命令的, ...

确实会有这个可能呀,SPI 的时序对不上,你有什么解决方法没?

出0入0汤圆

发表于 2019-3-6 10:29:14 | 显示全部楼层
在使用SFUD驱动GD25S513MD发现了个两个问题,(SFUD模式)
1、GD25S513MD在出厂默认BP0~BP3为保护状态,此时编程和4K擦除都是不执行的
  1. /* I found when the flash write mode is supported AAI mode. The flash all blocks is protected,
  2.      * so need change the flash status to unprotected before write and erase operate. */
  3.     if(flash->chip.write_mode & SFUD_WM_AAI)
  4.     {
  5.         result = sfud_write_status(flash, true, 0x00);
  6.         if(result != SFUD_SUCCESS)
  7.         {
  8.             return result;
  9.         }
  10.     }
复制代码


2、GD25S513MD内部是封装了两个Die,可以通过Software Die Select (C2H)命令可以选择,
如果使用SFUD库的话,您那边有什么好的实现方法嘛

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入46汤圆

发表于 2019-3-6 13:24:31 | 显示全部楼层
感谢楼主的无私分享,果断收藏!

出0入0汤圆

发表于 2019-3-6 13:27:11 来自手机 | 显示全部楼层
谢谢分享,准备试试看

出0入0汤圆

发表于 2020-6-22 12:42:01 来自手机 | 显示全部楼层
感谢楼主开源分享!

出16170入6148汤圆

发表于 2020-6-23 16:18:41 | 显示全部楼层
谢谢分享
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-27 10:24

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表