跳转至

SD卡

一、SD 卡以及 SDIO 概述

1、SD 卡

1.1 SD 卡简介

  • 定义:SD 卡(Secure Digital Card)是一种基于半导体快闪记忆器的新一代记忆设备,被广泛用于便携式设备中存储数据。
  • 特点:高存储容量、快速数据传输速度、体积小、重量轻、安全性高(支持数据加密)。

1.2 SD 卡类型与规格

  • 标准 SD 卡:原始 SD 卡规格。
  • miniSD 卡:缩小版的 SD 卡。
  • microSD 卡(又称 TF 卡):最小的 SD 卡规格,常用于智能手机和微型设备。

1.3 SD 卡工作原理

  • 文件系统:通常使用 FAT 文件系统(如 FAT16、FAT32)。
  • 通信协议:基于 SPI 或 SD 总线协议进行数据传输。

2、SDIO 协议介绍

2.1 定义

SDIO(Secure Digital Input and Output)是基于 SD 卡接口的新型接口标准。它不仅保持了与 SD 卡的兼容性,还扩展了连接其他外设的能力。

2.2 工作原理

SDIO 接口基于 SD 卡通信协议进行扩展。主机通过 SDIO 接口发送命令和数据到连接的设备,设备也可以向主机发送响应和数据。这种双向通信能力使得 SDIO 接口在多种应用场景中表现出色。

2.3 优势

  • 高速数据传输:支持高速数据传输,提高设备性能和响应速度。
  • 低功耗:在保持高性能的同时,实现了低功耗设计,延长了设备的电池寿命。

二、演示功能概述

本 demo 展示了如何在基于 Air8101 开发板上,通过 Luat 脚本使用 FATFS 文件系统库对 SD/TF 卡进行基本的文件操作。在 demo 中介绍 SDIO 初始化,fatfs 文件系统的挂载,获取可用 sd 卡空间,查看文件系统状态,还有一些文件操作测试:读取文件、写入文件、文件追加测试、按行读取测试。最后会测试通过 http 直接下载一个文件到 sd 卡中。

三、准备硬件环境

1. Air8101 开发板准备环境:

“古人云:‘工欲善其事,必先利其器。’在深入介绍本功能示例之前,我们首先需要确保以下硬件环境的准备工作已经完成。”

在我们 Air8101 开发板上已经集成了 SD 卡卡座:

参考:硬件环境清单,准备以及组装好硬件环境。

注意:

(1)用 B10 开发板的时候,SD 3.3V 需要和 SWD 3.3V 短接。

(2)B11 以及后续的开发板,不需要短接

2. SD 卡:

可淘宝上自行选择购买。

四、准备软件环境

“凡事预则立,不预则废。”在详细阐述本功能示例之前,我们需先精心筹备好以下软件环境。

1. 烧录工具 Luatools

2. 内核固件文件(底层 core 固件文件):点击获取底层固件

3. LuatOS 需要的脚本和资源文件:https://gitee.com/openLuat/LuatOS-Air8101/tree/master/demo/sdCard

4. lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;

准备好软件环境之后,接下来查看如何烧录项目文件到 Air8101 开发板 - luatos@air8101 - 合宙文档中心,将本篇文章中演示使用的项目文件烧录到 Air8101 开发板中。

五、SD 卡软硬件参考

5.1 API 接口介绍

本教程使用 api 接口为:

https://docs.openluat.com/air8101/luatos/api/core/fatfs/

https://docs.openluat.com/air8101/luatos/api/core/fs/

https://docs.openluat.com/air8101/luatos/api/core/io/

注意:

1. luatos 的 api 接口是通用的。

2. 通常只使用 fatfs.mount 挂载 tf/sd 卡,其他操作走 io 库就可以了。

3. 挂载成 fatfs 后,可以通过 fs.fsstat 来获取文件系统信息,或 fs.fsize 来获取文件大小。

5.2 SDIO 硬件设计

SDIO 硬件设计参考电路:

六、代码示例介绍

6.1 软件代码介绍

代码中有详细的注释,可以用来参考:

-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "fatfs"
VERSION = "1.0.0"

-- sys库是标配
_G.sys = require("sys")
_G.sysplus = require("sysplus")

--[[
注意:B10开发板需要SD_3.3V和SWD3.3V短接
]]

-- 特别提醒, 由于FAT32是DOS时代的产物, 文件名超过8个字节是需要额外支持的(需要更大的ROM)
-- 例如 /sd/boottime 是合法文件名, 而/sd/boot_time就不是合法文件名, 需要启用长文件名支持.

--网络任务
-- 联网函数, 可自行删减
-- sys.taskInit(function()
--     -----------------------------
--     -- 统一联网函数, 可自行删减
--     ----------------------------
--     if wlan and wlan.connect then
--         -- wifi 联网, Air8101系列均支持
--         local ssid = "Xiaomi 15"
--         local password = "wsh123456"
--         log.info("wifi", ssid, password)
--         wlan.init()
--         wlan.connect(ssid, password, 1)
--         --等待WIFI联网结果,WIFI联网成功后,内核固件会产生一个"IP_READY"消息
--         local result, data = sys.waitUntil("IP_READY")
--         log.info("wlan", "IP_READY", result, data)
--     end
--     log.info("已联网")
--     sys.publish("net_ready")
-- end)

-- spi_id,pin_cs
**local** **function** **fatfs_spi_pin**()
    **return** 0, 3, fatfs.SDIO
**end**

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


    **local** spi_id, pin_cs,tp = fatfs_spi_pin()
    fatfs.mount(tp or fatfs.SPI, "/sd", spi_id, pin_cs, 24 * 1000 * 1000) --挂载fatfs

    **local** data, err = fatfs.getfree("/sd")  --获取可用空间信息
    **if** data **then**
        log.info("fatfs", "getfree", json.encode(data))
    **else**
        log.info("fatfs", "err", err)
    **end**

    -- #################################################
    -- 文件操作测试
    -- #################################################
    **local** f = io.open("/sd/boottime", "rb") --
    **local** c = 0
    **if** f **then**
        **local** data = f:read("*a")
        log.info("fs", "data", data, data:toHex())
        c = tonumber(data)
        f:close()
    **end**
    log.info("fs", "boot count", c)
    **if** c == **nil** **then**
        c = 0
    **end**
    c = c + 1
    f = io.open("/sd/boottime", "wb")
    **if** f ~= **nil** **then**
        log.info("fs", "write c to file", c, tostring(c))
        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"))  --打印sd卡文件系统分区信息
    **end**

    -- 测试一下追加, fix in 2021.12.21
    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
    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 = 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**)


-- 按需打印
-- code 响应值, 若大于等于 100 为服务器响应, 小于的均为错误代码
-- headers是个table, 一般作为调试数据存在
-- body是字符串. 注意lua的字符串是带长度的byte[]/char*, 是可以包含不可见字符的
-- http下载文件到sd卡功能演示任务
-- sys.taskInit(function()
--     sys.waitUntil("net_ready") -- 等联网
--     sys.wait(5000)
--     log.info("测试http下载文件到sd卡中")
--     local code, headers, body = http.request("GET", "http://airtest.openluat.com:2900/download/12345.txt", {}, "",{ dst = "/sd/test.txt" }).wait()
--     log.info("http.get", code, headers, body)
--     log.info("text size", fs.fsize("/sd/test.txt"))
-- end)

-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!

6.2 效果展示

通过日志可以查看到 sd 卡已经挂载成功,并且打印了可用空间大小和文件系统的信息,文件系统操作的操作也都成功。

可以看到通过 http 下载到 sd 操作成功,读取的文件大小也与实际大小相符。

sd 卡通过读卡器接入电脑上查看相关文件。

七、总结

至此,我们已使用 Air8101 开发板的 SDIO 接口完成了对 SD 卡挂载 fatfs、以及对 sd 卡中文件读写操作。

八、常见问题

1. 为什么 air8101 不能识别新购买的 sd 卡:

文件系为 FAT32 格式(windows、linux 都可以正常识别),所以非 FAT 格式的 SD 卡会挂载失败,而无法正常识别。

2. SD 卡的读写路径是什么?

SD 卡文件访问通过路径前加上"/sd",如果 sd 卡中有一个文件 test.txt ,那这个文件的路径就是"/sd/test.txt"。

3. http 下载的文件可以直接保存到 sd 卡里吗?

支持,http.request 接口支持直接下载到文件系统中,下载到 sd 卡中的时候只需要注意路径设置。参考 demo 中注释掉的部分。