合宙Air105|fatfs| io操作(扩展)|SPI|可调功放|I2C|SPI|toHex()|os.remove|LuatOS-SOC接口|官方demo|学习(15-1):fatfs文件系统

该文详细介绍了如何在Air105开发板上使用LuatOS操作系统,通过SPI接口与SD卡进行通信,进行fatfs文件系统的挂载、读写和管理。内容包括SPI配置、SD卡模块的接线、文件操作如打开、读写、移动句柄等,并提供了相关错误排查和示例代码。
摘要由CSDN通过智能技术生成

基础资料

基于Air105开发板:Air105 - LuatOS 文档

上手:开发上手 - LuatOS 文档

探讨重点

官方LuatOS-SOC接口fatfs的demo测试。

扩展阅读:

合宙Air105|fs| io操作(扩展)|io.SEEK_END|io.SEEK_SET|io.SEEK_CUR|LuatOS-SOC接口|官方demo|学习(15-2):fs - 文件系统额外操作_打酱油的工程师的博客-CSDN博客

合宙Air103|SDIO (扩展) |LuatOS-SOC接口|官方demo|学习(15-3):SDIO - 文件读写操作_打酱油的工程师的博客-CSDN博客

合宙Air105|SFUD库|FS|SPI FLASH|W25QXX |LuatOS-SOC接口|官方demo|学习(15-4):SFUD库操作-外置flash_打酱油的工程师的博客-CSDN博客

参考博文:

合宙Air105|摄像头|capture|SPI|Serial 串口|TFTLCD|Micro SD卡|GC032A|USB转TTL|官方demo|学习(2-1):摄像头camera-capture_合宙air105的摄像头_打酱油的工程师的博客-CSDN博客

硬件准备

Air105开发板1块,面包板1块, SPI/SDIO接口SD卡模块(SPI/SDIO) 1个,。

https://i-blog.csdnimg.cn/blog_migrate/ad178b2a0bfc019ca782afbe70ba8923.png

Air105开发板

Micro SD卡读写模块未适配:

需采用:SPI/SDIO双功能版本读写模块

SD卡容量应小玉16G,实测>16G时读写会出现问题。

接线方式:

--[[

接线要求:

SPI 使用常规4线接法

Air105开发板         TF模块

PB3                  CS

PB2(SPI2_CLK)        CLK

PB4(SPI2_MISO)       MOSI

PB5(SPI2_MISO)       MISO

3.3V                 VCC

GND                  GND

]]

接线示例:

Demo执行后SD卡内生成文件:

 

 Demo代码解析及注释:

-- LuaTools需要PROJECT和VERSION这两个信息

PROJECT = "fatfs"

VERSION = "1.0.0"



-- sys库是标配

_G.sys = require("sys")



sys.taskInit(function()

    --sys.wait(1000) -- 启动延时

    local spiId = 2

    local result = spi.setup(

        spiId,--串口id

        255, -- 不使用默认CS脚

        0,--CPHA

        0,--CPOL

        8,--数据宽度

        400*1000  -- 初始化时使用较低的频率

    )

    local TF_CS = pin.PB3

    --设置管脚功能,数字0/1代表输出模式,设置 pin.PB3为输出模式,

    gpio.setup(TF_CS, 1)

    --fatfs.debug(1) -- 若挂载失败,可以尝试打开调试信息,查找原因

    -- 提醒, 若TF/SD模块带电平转换, 通常不支持10M以上的波特率!!

    fatfs.mount("SD", spiId, TF_CS, 24000000)

    local data, err = fatfs.getfree("SD")

    --getfree所获得的数据 table包含的内容有

    -- total_sectors 总扇区数量

    -- free_sectors 空闲扇区数量

    -- total_kb 总字节数,单位kb

    -- free_kb 空闲字节数, 单位kb

    -- 注意,当前扇区大小固定在512字节

    if data then

        log.info("fatfs", "getfree", json.encode(data))

    else

        log.info("fatfs", "err", err)

    end



    -- 重新设置spi,使用更高速率

    -- spi.close(0)

    -- sys.wait(100)

    -- spi.setup(spiId, 255, 0, 0, 8, 24*1000*1000)



    -- #################################################

    -- 文件操作测试



    --[[io模块是lua原生模块,LuatOS增加了一些API

-- 请配合os模块一起使用



-- 只读模式, 打开文件

local fd = io.open("/xxx.txt", "rb")

-- 读写默认,打开文件

local fd = io.open("/xxx.txt", "wb")

-- 写入文件,且截断为0字节

local fd = io.open("/xxx.txt", "wb+")

-- 追加模式

local fd = io.open("/xxx.txt", "a")



-- 若文件打开成功, fd不为nil,否则就是失败了

-- 注意, 刷机时所添加的文件, 均在 /luadb 目录下, 只读

if fd then

  -- 读取指定字节数,如果数据不足,就只返回实际长度的数据

  local data = fd:read(12)

  -- 按行读取

  local line = fd:read("*l")

  -- 全部读取

  local line = fd:read("*a")



  -- 数据写入, 仅w或a模式可调用

  -- 数据需要是字符串, lua的字符串是带长度的,可以包含任何二进制数据

  fd:write("xxxx")

  -- 以下是写入0x12, 0x13

  fd:write(string.char(0x12, 0x13))



  -- 移动句柄,绝对坐标

  fd:seek(1024, io.SEEK_SET)

  -- 移动句柄,相对坐标

  fd:seek(1024, io.SEEK_CUR)

  -- 移动句柄,反向绝对坐标,从文件结尾往文件头部算

  fd:seek(124, io.SEEK_END)



  -- 执行完操作后,一定要关掉文件

  fd:close()]]

    -- #################################################

    local f = io.open("/sd/boottime", "rb")

    local c = 0

    if f then

        local data = f:read("*a")

        --[[string.toHex(str, separator)

将字符串转成HEX

参数

传入值类型

解释

string

需要转换的字符串

string

分隔符, 默认为””

返回值

返回值类型

解释

string

HEX字符串

number

HEX字符串的长度

返回值例如:I/user.fs data    8       38            2

                             原始值    HEX字符串    字符串长度

]]

        log.info("fs", "data", data, data:toHex())

        --C为上一次程序写入文件的已重启次数

        c = tonumber(data)

        f:close()

    end

    --输出已重启次数

    log.info("fs", "boot count", c)

    --本次值+1

    c = c + 1

    f = io.open("/sd/boottime", "wb")

    if f ~= nil then

        log.info("fs", "write c to file", c, tostring(c))

        --将更新后的重启次数c值转化为string后写入文件

        f:write(tostring(c))

        f:close()

    else

        log.warn("sdio", "mount not good?!")

    end

    if fs then

        --打印根分区的信息

        log.info("fsstat", fs.fsstat("/"))

        log.info("fsstat", fs.fsstat("/sd"))

    end



    -- 测试一下追加, fix in 2021.12.21

    --os.remove (filename)删除指定名字的文件(在 POSIX 系统上可以是一个空目录)

    --如果函数失败,返回 nil 加一个错误描述串及出错码。

    os.remove("/sd/test_a")

    sys.wait(50)

    f = io.open("/sd/test_a", "w") --写入模式

    if f then

        f:write("ABC")

        f:close()

    end

    f = io.open("/sd/test_a", "a+")  --追加模式

    if f then

        f:write("def")

        f:close()

    end

    f = io.open("/sd/test_a", "r")  --读取模式

    if  f then

        local data = f:read("*a")

        log.info("data", data, data == "ABCdef")

        f:close()

    end



    -- 测试一下按行读取, fix in 2022-01-16

    --写入3行数据

    f = io.open("/sd/testline", "w")

    if f then

        f:write("abc\n")

        f:write("123\n")

        f:write("wendal\n")

        f:close()

    end

    sys.wait(100)

    --f:read每次读取1行

    --而io.readFile(path)  读取整个文件,请注意内存消耗

    f = io.open("/sd/testline", "r")

    if f then

        log.info("sdio", "line1", f:read("*l"))

        log.info("sdio", "line2", f:read("*l"))

        log.info("sdio", "line3", f:read("*l"))

        f:close()

    end



    -- #################################################



end)



-- 用户代码已结束---------------------------------------------

-- 结尾总是这一句

sys.run()

-- sys.run()之后后面不要加任何语句!!!!!

LOG文件解析:

[2023-02-08 22:00:08.526] no bl encrypt

[2023-02-08 22:00:08.526] main 672:bootloader build release Jan  1 2023 16:21:12!

[2023-02-08 22:00:08.526] Jump_AppRun 76:jump to 0x01010400 !

[2023-02-08 22:00:08.526] main 188:APP Build release Jan  1 2023 16:20:44!

[2023-02-08 22:00:08.526] I/main LuatOS@AIR105 base 22.12 bsp V0013 32bit

[2023-02-08 22:00:08.526] I/main ROM Build: Jan  1 2023 16:20:52

[2023-02-08 22:00:08.531] D/main loadlibs luavm 204792 15376 15376

[2023-02-08 22:00:08.531] D/main loadlibs sys   397480 51032 51616

初始化提示:SPI_ID为2,片选端口为:GPIO19 SPI2_CSN

初始化使用较低频率:

local result = spi.setup(

        spiId,--串口id

        255, -- 不使用默认CS脚

        0,--CPHA

        0,--CPOL

        8,--数据宽度

        400*1000  -- 初始化时使用较低的频率

    )

挂载:

fatfs.mount(mount_point, spiid_or_spidevice, spi_cs, spi_speed)

挂载fatfs

参数

传入值类型

解释

string

fatfs挂载点, 通常填””或者”SD”, 底层会映射到vfs的 /sd 路径

int

传入spi device指针,或者spi的id

int

片选脚的GPIO 号, 若前一个参数传的是spi device,这个参数就不需要传

int

SPI最高速度,默认10M, 若前2个参数传的是spi device,这个参数就不需要传

返回值

返回值类型

解释

bool

成功返回true, 否则返回nil或者false

string

失败的原因

[2023-02-08 22:00:08.532] D/fatfs init sdcard at spi=2 cs=19 

初始化:正常

[2023-02-08 22:00:08.606] SDHC_SpiInitCard 684:sdcard init OK OCR:0xc0ff8000!

[2023-02-08 22:00:08.606] I/user.fatfs   getfree

    --getfree所获得的数据 table包含的内容有

    -- total_sectors 总扇区数量

    -- free_sectors 空闲扇区数量

    -- total_kb 总字节数,单位kb

    -- free_kb 空闲字节数, 单位kb

    -- 注意,当前扇区大小固定在512字节

         {"free_kb":15458224,"total_sectors":30916576,"free_sectors":30916448,"total_kb":15458288}

[2023-02-08 22:00:08.606] I/user.fs       data 8       38    2

[2023-02-08 22:00:08.606] I/user.fs       boot count      8

--将更新后的重启次数c值转化为string后写入文件

[2023-02-08 22:00:08.611] I/user.fs       write c to file   9       9

-- 打印当前分区的信息("/"),例如lfs代表littlefs

[2023-02-08 22:00:08.637] I/user.fsstat true 128  2       4096         lfs

-- -- 打印根分区的信息("/sd"),例如fatfs

[2023-02-08 22:00:08.637] I/user.fsstat true 1932286  1932278  16    fatfs

--读取数据data的内容,与文件内容相同(True))

[2023-02-08 22:00:08.729] I/user.data  ABCdef    true

[2023-02-08 22:00:08.837] I/user.sdio   line1 abc

[2023-02-08 22:00:08.837] I/user.sdio   line2 123

[2023-02-08 22:00:08.837] I/user.sdio   line3 wendal

PS: io - io操作(扩展)

已适配 Air101/Air103 Air105 ESP32C3 Air780

备注

本页文档由这个文件自动生成。如有错误,请提交issue或帮忙修改后pr,谢谢!

小技巧

本库有专属demo点此链接查看io的demo例子

示例

-- io模块是lua原生模块,LuatOS增加了一些API
-- 请配合os模块一起使用
 
-- 只读模式, 打开文件
local fd = io.open("/xxx.txt", "rb")
-- 读写默认,打开文件
local fd = io.open("/xxx.txt", "wb")
-- 写入文件,且截断为0字节
local fd = io.open("/xxx.txt", "wb+")
-- 追加模式
local fd = io.open("/xxx.txt", "a")
 
-- 若文件打开成功, fd不为nil,否则就是失败了
-- 注意, 刷机时所添加的文件, 均在 /luadb 目录下, 只读
if fd then
  -- 读取指定字节数,如果数据不足,就只返回实际长度的数据
  local data = fd:read(12)
  -- 按行读取
  local line = fd:read("*l")
  -- 全部读取
  local line = fd:read("*a")
 
  -- 数据写入, wa模式可调用
  -- 数据需要是字符串, lua的字符串是带长度的,可以包含任何二进制数据
  fd:write("xxxx") 
  -- 以下是写入0x12, 0x13
  fd:write(string.char(0x12, 0x13))
 
  -- 移动句柄,绝对坐标
  fd:seek(1024, io.SEEK_SET)
  -- 移动句柄,相对坐标
  fd:seek(1024, io.SEEK_CUR)
  -- 移动句柄,反向绝对坐标,从文件结尾往文件头部算
  fd:seek(124, io.SEEK_END)
 
  -- 执行完操作后,一定要关掉文件
  fd:close()
end

io.exists(path)

判断文件是否存在

参数

传入值类型

解释

string

文件路径

返回值

返回值类型

解释

bool

存在返回true,否则返回false

例子

log.info("io", "file exists", io.exists("/boottime"))

io.fileSize(path)

获取文件大小

参数

传入值类型

解释

string

文件路径

返回值

返回值类型

解释

int

文件数据,若文件不存在会返回nil

例子

local fsize = io.fileSize("/bootime")
if fsize and fsize > 1024 then
  log.info("io", "file size", fsize)
end

io.readFile(path)

读取整个文件,请注意内存消耗

参数

传入值类型

解释

string

文件路径

返回值

返回值类型

解释

string

文件数据,若文件不存在会返回nil

例子

local data = io.readFile("/bootime")

io.writeFile(path, data)

将数据写入文件

参数

传入值类型

解释

string

文件路径

string

数据

返回值

返回值类型

解释

boolean

成功返回true, 否则返回false

例子

io.writeFile("/bootime", "1")

io.fill(buff, offset, len)

读取文件并填充到zbuff内,但不移动指针位置

参数

传入值类型

解释

userdata

zbuff实体

int

写入的位置,默认是0

int

写入的长度,默认是zbuff的len减去offset

返回值

返回值类型

解释

boolean

成功返回true,否则返回false

int

返回实际读取到的长度,如果小于0也说明是读取失败了

例子

local buff = zbuff.create(1024)
local f = io.open("/sd/test.txt")
if f then
  f:fill(buff)
end

io.mkdir(path)

创建文件夹

参数

传入值类型

解释

string

需要建立的目录路径

返回值

返回值类型

解释

bool

成功与否

int

底层返回值

例子

local ret, errio = io.mkdir("/data/")
log.info("fs", "mkdir", ret, errio)

io.rmdir(path)

删除文件夹

参数

传入值类型

解释

string

需要移除的目录路径

返回值

返回值类型

解释

bool

成功与否

int

底层返回值

例子

local ret, errio = io.rmdir("/data/")
log.info("fs", "rmdir", ret, errio)

io.lsdir(path, len, offset)

列出目录下的文件

参数

传入值类型

解释

string

需要枚举的目录路径

int

最大长度, 默认10, 最高50

int

偏移量, 默认0, 当目录文件很多时分页查询用

返回值

返回值类型

解释

bool

成功与否

int

底层返回值

例子

local ret, data = io.lsdir("/data/", 10, 0)
if ret then
  log.info("fs", "lsdir", json.encode(data))
else
  log.info("fs", "lsdir", "fail", ret, data)
end

io.lsmount()

列出所有挂载点

参数

返回值

返回值类型

解释

table

挂载点列表

例子

local data = io.lsmount()
log.info("fs", "lsmount", json.encode(data))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

打酱油的工程师

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

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

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

打赏作者

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

抵扣说明:

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

余额充值