Air201-LuatOS-如何使用SPI读写外部Flash
一、SPI 概述
SPI(Serial Peripheral Interface)是一种同步串行通信协议,广泛应用于微控制器和外围设备之间的数据传输。它由摩托罗拉公司开发,具有全双工通信能力,即可以同时进行数据的发送和接收。 SPI 通信通常涉及四条信号线:
- MOSI(Master Out Slave In):主设备发送数据,外设接收数据。
- MISO(Master In Slave Out):外设发送数据,主设备接收数据。
- SCLK(Serial Clock):由主设备生成的时钟信号,用于同步数据传输。
- CS/SS(Chip/Slave Select):选择特定的从设备进行通信。
SPI 的优点包括简单的硬件连接、高速数据传输和全双工通信。其缺点是通常需要更多的引脚,尤其是在多个从设备的情况下,每个从设备需要一个独立的 CS 引脚。此外,SPI 没有标准化的协议层,因此设备间的兼容性需要仔细管理。
二、演示功能概述
本文通过 Air201+ 扩展板读写外部flash来演示 SPI 的使用
三、准备硬件环境
3.1 Air201 模组
使用 Air201 开发套件,如下图所示:
淘宝购买链接:Air201 开发套件淘宝购买链接 ;
此开发套件的详细使用说明参考:Air201 产品手册 中的 Air201 硬件手册 和 Air201 的 LuatOS 快速入门。
3.2 SIM 卡
请准备一张可正常上网的 SIM 卡,该卡可以是物联网卡或您的个人手机卡。
特别提醒:请确保 SIM 卡未欠费且网络功能正常,以便顺利进行后续操作。
3.3 PC 电脑
WIN10以及以上版本的WINDOWS系统。
3.4 数据通信线
USB 数据线(其一端为 Type-C 接口,用于连接 Air201)。
3.5 BTB 扩展板
3.6 FLASH 模块
本文采用 W25Q 系列 spi flash
四、准备软件环境
4.1 下载调试工具
使用说明参考:Luatools 下载和详细使用
4.2 源码及固件
- Air201 模组使用固件:core/LuatOS-SoC_V1004_Air201.soc,本 demo 使用的固件版本是:LuatOS-SoC_V1004_Air201.soc
- 本教程使用的 demo:https://gitee.com/openLuat/LuatOS-Air201/tree/master/demo/spi
- 源码和固件已打包,如下所示:
注:缩包中 core 文件夹存放固件,code 文件夹存放 demo
五、软硬件资料
5.1 API 接口介绍
本教程使用 api 接口为:https://docs.openluat.com/air201/luatos/api/core/spi/
5.2 硬件安装与连接
5.2.1 SPI 管脚定义
SPI 管脚定义请参考 Air201 产品手册 中的 Air201 硬件资料 中的 Air201 硬件说明 中的 BTB 扩展接口的 SPI 接口说明
5.2.2 实物连接图
Air201 通过 FPC 线连接 BTB 扩展板,BTB 扩展板再连接 FLASH 模块,接线如下所示:
BTB 扩展板 | FLASH 模块 |
---|---|
cam_reclk | DO |
cam_sck | CLK |
I2C1_SCL | DI |
I2C1_SDA | CS |
+3.3V | VCC |
GND | GND |
完整接线如下图所示:
六、代码示例介绍
6.1 程序流程图
6.2 代码介绍
6.2.1 初始化配置
SPI使用的是SPI0,CS使用的GPIO8,在进行SPI通信之前,需要使用spi.setup()接口对SPI0接口进行配置,同时将GPIO8配置为输出模式,用于控制CS信号。在初始化阶段,通常会将CS(GPIO8)拉高,表示当前没有选中任何从设备。如下代码所示:
--spi编号,请按实际情况修改!
local spiId = 0
--cs脚,请按需修改!
local cs = 8
local cspin = gpio.setup(cs, 1)
local result = spi.setup(
spiId,--串口id
nil,
0,--CPHA
0,--CPOL
8,--数据宽度
100000--,--频率
-- spi.MSB,--高低位顺序 可选,默认高位在前
-- spi.master,--主模式 可选,默认主
-- spi.full--全双工 可选,默认全双工
)
6.2.2 CS 信号的操作
在SPI通信过程中,CS信号的操作是关键的一步,它决定了哪个从设备会被选中进行通信。 1. 选中从设备: 在主设备准备与某个特定的从设备通信之前,它会先将对应的CS信号线(在这里是GPIO8)拉低。这表示选中了该从设备,使其准备好接收或发送数据。 2. 数据传输: 一旦CS信号被拉低,主设备和被选中的从设备之间就可以开始数据传输了。这包括发送和接收数据帧,具体取决于通信协议和数据的方向。 3. 结束通信: 数据传输完成后,主设备会将CS信号再次拉高,表示结束与当前从设备的通信。此时,该从设备将不再参与SPI总线上的数据传输,直到下一次被选中。
如下代码所示,收发数据前先使用cspin(0)将CS信号拉低,数据传输完成后使用cspin(1)将CS信号再拉高。
--收发数据
local function sendRecv(data,len)
local r = ""
cspin(0)
if data then spi.send(spiId,data) end
if len then r = spi.recv(spiId,len) end
cspin(1)
return r
end
6.2.3 向 FLASH 写入数据
查看 W25QX 系列 FLASH 模块数据手册的命令集,先写使能命令 0x06,再写页数据到地址 0x000001
local data = "123456"
--enable write
sendRecv(string.char(0x06))
--写页数据到地址0x000001
sendRecv(string.char(0x02,0x00,0x00,0x01)..data)
log.info("spi","write",data)
6.2.4 从 FLASH 读取数据
查看 W25QX 系列 FLASH 模块数据手册的命令集,使用 0x03 命令,读取 0x000001 地址的数据,完成操作后关闭 SPI
--读数据
local r = sendRecv(string.char(0x03,0x00,0x00,0x01),data:len())
log.info("spi","read",r)
--disable write
sendRecv(string.char(0x04))
spi.close(spiId)
6.3 完整程序清单
注:完整复制后保存为 main.lua,可直接使用
-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "w25q_spi_demo"
VERSION = "1.0.1"
sys = require("sys")
--spi编号,请按实际情况修改!
local spiId = 0
--cs脚,请按需修改!
local cs = 8
local cspin = gpio.setup(cs, 1)
--收发数据
local function sendRecv(data,len)
local r = ""
cspin(0)
if data then spi.send(spiId,data) end
if len then r = spi.recv(spiId,len) end
cspin(1)
return r
end
sys.taskInit(function()
local result = spi.setup(
spiId,--串口id
nil,
0,--CPHA
0,--CPOL
8,--数据宽度
100000--,--频率
-- spi.MSB,--高低位顺序 可选,默认高位在前
-- spi.master,--主模式 可选,默认主
-- spi.full--全双工 可选,默认全双工
)
print("open",result)
if result ~= 0 then--返回值为0,表示打开成功
print("spi open error",result)
return
end
--检查芯片型号
local chip = sendRecv(string.char(0x9f),3)
if chip == string.char(0xef,0x60,0x17) then
log.info("spi", "chip id read ok 0xef,0x60,0x17")
else
log.info("spi", "chip id read error")
for i=1,#chip do
print(chip:byte(i))
end
return
end
local data = "123456"
--enable write
sendRecv(string.char(0x06))
--写页数据到地址0x000001
sendRecv(string.char(0x02,0x00,0x00,0x01)..data)
log.info("spi","write",data)
sys.wait(500)--等写入操作完成
--读数据
local r = sendRecv(string.char(0x03,0x00,0x00,0x01),data:len())
log.info("spi","read",r)
--disable write
sendRecv(string.char(0x04))
spi.close(spiId)
end)
-- 结尾总是这一句哦
sys.run()
6.4 运行结果展示
七、总结
至此,我们已经使用 Air201 的 SPI 接口成功完成了对 W25Q64 Flash 存储器的读写操作。本教程的目的是展示如何使用 Air201 连接和操作 SPI 外设,而不局限于使用 Flash 存储器。这一过程为您提供了一个清晰的示范,帮助您理解和应用 SPI 接口的使用方法。