air101#

本章介绍LuatOS的sfud库使用方式

简介#

SFUD 是一款开源的串行 SPI Flash 通用驱动库,LuatOS中集成了该库,可以调用sfud的api实现对各类SPI Flash的读写操作

硬件准备#

  • air101开发板

  • SPI FLASH,这里使用W25Q128

接线示意

        SPI_CS/GPIO20    -----  CS
        SPI_MISO/GPIO19  -----  DO
        SPI_MOSI/GPIO21  -----  DI
air101  SPI_CLK/GPIO18   -----  CLK   SPI_FLASH
        3.3V             -----  VCC
        GND              -----  GND

软件部分#

接口文档可参考:sfud库

初始化sfud#

使用SPI ID初始化#

代码如下

local spiID, csPin = 0, 20
local initRes = sfud.init(spiID, csPin, 20 * 1000 * 1000)
if initRes == false then
    log.error(PROJECT .. ".init", "ERROR")
    return
end

使用SPI DEVICE初始化#

代码如下

local spiID, csPin = 0, 20
-- 最后一个参数工作模式选择半双工
local spiFlash = spi.deviceSetup(spiID, csPin, 0, 0, 8, 20 * 1000 * 1000, spi.MSB, 1, 0)
local initRes = sfud.init(spiFlash)
if initRes == false then
    log.error(PROJECT .. ".init", "ERROR")
    return
end

初始化过程会有类似如下日志输出

D/sfud Start initialize Serial Flash Universal Driver(SFUD) V1.1.0. 
D/sfud You can get the latest version on https://github.com/armink/SFUD . 
D/sfud The flash device manufacturer ID is 0xEF, memory type ID is 0x40, capacity ID is 0x18. 
D/sfud Check SFDP header is OK. The reversion is V1.5, NPN is 0. 
D/sfud Check JEDEC basic flash parameter header is OK. The table id is 0, reversion is V1.5, length is 16, parameter table pointer is 0x000080. 
D/sfud JEDEC basic flash parameter table info: 
D/sfud MSB-LSB  3    2    1    0 
D/sfud [0001] 0xFF 0xF9 0x20 0xE5 
D/sfud [0002] 0x07 0xFF 0xFF 0xFF 
D/sfud [0003] 0x6B 0x08 0xEB 0x44 
D/sfud [0004] 0xBB 0x42 0x3B 0x08 
D/sfud [0005] 0xFF 0xFF 0xFF 0xFE 
D/sfud [0006] 0x00 0x00 0xFF 0xFF 
D/sfud [0007] 0xEB 0x40 0xFF 0xFF 
D/sfud [0008] 0x52 0x0F 0x20 0x0C 
D/sfud [0009] 0x00 0x00 0xD8 0x10 
D/sfud 4 KB Erase is supported throughout the device. Command is 0x20. 
D/sfud Write granularity is 64 bytes or larger. 
D/sfud Target flash status register is non-volatile. 
D/sfud 3-Byte only addressing. 
D/sfud Capacity is 16777216 Bytes. 
D/sfud Flash device supports 4KB block erase. Command is 0x20. 
D/sfud Flash device supports 32KB block erase. Command is 0x52. 
D/sfud Flash device supports 64KB block erase. Command is 0xD8. 
D/sfud Find a Winbond flash chip. Size is 16777216 bytes. 
D/sfud Flash device reset success. 
D/sfud LuatOS-sfud flash device is initialize success. 

获取flash设备信息表#

初始化sfud成功后,需要获取flash设备信息表,这也是一个抽象的flash对象,在后续的读写中需要传递这个flash对象

代码如下

local sfudDevice = sfud.getDeviceTable()

读写Flash#

成功初始化sfud之后,我们有两种方式对Flash进行读写,一种是直接对Flash的特定地址进行读写数据,一种是将挂载sfud lfs文件系统,然后使用Lua io api对挂载位置进行读写

直接对特定地址进行读写#

代码如下

-- 向地址1024写入字符串
local data = "LuatOS"
log.info(PROJECT .. ".write", sfud.writ(sfudDevice, 1024, data))
log.info(PROJECT .. ".read", sfud.read(sfudDevice,1024, string.len(data)))

日志如下

I/user.sfud.write 0
I/user.sfud.read LuatOS

挂载sfud lfs文件系统#

代码如下

log.info(PROJECT .. ".mount", sfud.moun(sfudDevice, "/sfud"))
log.info(PROJECT .. ".fsstat", fs.fsstat("/sfud"))

日志如下

D/sfud lfs_mount 0
I/user.sfud.mount true
I/user.sfud.fsstat true 4096 5 4096 lfs

可以看到,/sfud挂载点 的Flash容量为 4096*4096/1024/1024 = 16MB

之后就可以使用Lua中的io api在/sfud下进行读写操作了

我们可以创建一个文件写入再读出

代码如下

local writeFile = io.open("/sfud/test.txt", "w")
if writeFile then
    writeFile:write("LuatOS")
    writeFile:close()
else
    log.error(PROJECT .. ".writeFile", "文件创建失败")
    return
end

local readFile = io.open("/sfud/test.txt", "r")
    if readFile then
    local res = readFile:read("*all")
    readFile:close()
    log.info(PROJECT .. ".readFile", res)
else
    log.error(tag .. ".readFile", "文件不存在或文件输入格式不正确")
    return
end

日志如下

-- 可以正常读出我们之前写入的内容
I/user.sfud.readFile LuatOS

完整代码#

PROJECT = "sfud"
VERSION = "1.0.0"

sys = require("sys")

USE_SPIID_INIT = true
MOUNT_FLASH = true

local function test()
    local spiID, csPin = 0, 20
    if USE_SPIID_INIT == true then
        -- 使用SPI ID初始化
        local initRes = sfud.init(spiID, csPin, 20 * 1000 * 1000)
        if initRes == false then
            log.error(PROJECT .. ".init", "ERROR")
            return
        end
    else
        -- 使用SPI DEVICE初始化
        -- 最后一个参数工作模式选择半双工
        local spiFlash = spi.deviceSetup(spiID, csPin, 0, 0, 8, 20 * 1000 * 1000, spi.MSB, 1, 0)
        local initRes = sfud.init(spiFlash)
        if initRes == false then
            log.error(PROJECT .. ".init", "ERROR")
            return
        end
    end

    local sfudDevice = sfud.getDeviceTable()

    if MOUNT_FLASH == false then
        -- 向地址1024写入字符串
        local data = "LuatOS"
        log.info(PROJECT .. ".write", sfud.write(sfudDevice, 1024, data))
        log.info(PROJECT .. ".read", sfud.read(sfudDevice, 1024, string.len(data)))
    else
        log.info(PROJECT .. ".mount", sfud.mount(sfudDevice, "/sfud"))
        log.info(PROJECT .. ".fsstat", fs.fsstat("/sfud"))

        local writeFile = io.open("/sfud/test.txt", "w")
        if writeFile then
            writeFile:write("LuatOS")
            writeFile:close()
        else
            log.error(PROJECT .. ".writeFile", "文件创建失败")
            return
        end

        local readFile = io.open("/sfud/test.txt", "r")
        if readFile then
            local res = readFile:read("a")
            readFile:close()
            log.info(PROJECT .. ".readFile", res)
        else
            log.error(tag .. ".readFile", "文件不存在或文件输入格式不正确")
            return
        end
    end
end

sys.taskInit(test)

sys.run()