Просмотр исходного кода

add: 添加读写spi flash的sfd库

Wendal Chen 4 лет назад
Родитель
Сommit
40cb2ad473
4 измененных файлов с 314 добавлено и 0 удалено
  1. 2 0
      luat/include/luat_base.h
  2. 20 0
      luat/include/luat_sfd.h
  3. 166 0
      luat/modules/luat_lib_sfd.c
  4. 126 0
      luat/modules/luat_sfd.c

+ 2 - 0
luat/include/luat_base.h

@@ -107,6 +107,8 @@ LUAMOD_API int luaopen_dbg( lua_State *L );
 /** 加载zbuff库, 可选,平台无关*/
 LUAMOD_API int luaopen_zbuff( lua_State *L );
 
+LUAMOD_API int luaopen_sfd( lua_State *L );
+
 /** sprintf需要支持longlong值的打印, 提供平台无关的实现*/
 int l_sprintf(char *buf, size_t size, const char *fmt, ...);
 

+ 20 - 0
luat/include/luat_sfd.h

@@ -0,0 +1,20 @@
+
+#include "luat_base.h"
+
+typedef struct sfd_w25q {
+    int spi_id;
+    int spi_cs;
+    size_t sector_size;
+    size_t sector_count;
+    size_t erase_size;
+    char chip_id[8];
+} sfd_w25q_t;
+
+typedef struct sdf_opts {
+    int (*initialize) (void* userdata);
+	int (*status) (void* userdata);
+	int (*read) (void* userdata, char* buff, size_t offset, size_t len);
+	int (*write) (void* userdata, const char* buff, size_t offset, size_t len);
+	int (*erase) (void* userdata, size_t sector, size_t count);
+	int (*ioctl) (void* userdata, size_t cmd, void* buff);
+}sdf_opts_t;

+ 166 - 0
luat/modules/luat_lib_sfd.c

@@ -0,0 +1,166 @@
+/*
+@module  sfd
+@summary SPI FLASH操作库
+@version 1.0
+@date    2021.05.18
+*/
+#include "luat_base.h"
+#include "luat_spi.h"
+#include "luat_sfd.h"
+
+#define LUAT_LOG_SDF
+#include "luat_log.h"
+
+
+extern const sdf_opts_t sfd_w25q_opts;
+
+/*
+初始化spi flash
+@api    sfd.init(spi_id, spi_cs)
+@int  SPI总线的id
+@int  SPI FLASH的片选脚对应的GPIO
+@return userdata 成功返回一个数据结构,否则返回nil
+@usage
+local w25q = sfd.init(0, 17)
+if w25q then
+    log.info("sfd", "chip id", sfd.id(w25q):toHex())
+end
+*/
+static int l_sfd_init(lua_State *L) {
+    int spi_id = luaL_checkinteger(L, 1);
+    int spi_cs = luaL_checkinteger(L, 2);
+
+    sfd_w25q_t *w25q = (sfd_w25q_t *)lua_newuserdata(L, sizeof(sfd_w25q_t));
+    memset(w25q, 0, sizeof(sfd_w25q_t));
+    w25q->spi_id = spi_id;
+    w25q->spi_cs = spi_cs;
+
+    int re = sfd_w25q_opts.initialize(w25q);
+    if (re == 0) {
+        return 1;
+    }
+    return 0;
+}
+
+/*
+检查spi flash状态
+@api    sfd.status(w25q)
+@userdata  sfd.init返回的数据结构
+@return int 状态值,0 未初始化成功,1初始化成功且空闲,2正忙
+@usage
+local w25q = sfd.init(0, 17)
+if w25q then
+    log.info("sfd", "status", sfd.status(w25q))
+end
+*/
+static int l_sfd_status(lua_State *L) {
+    sfd_w25q_t *w25q = (sfd_w25q_t *) lua_touserdata(L, 1);
+    lua_pushinteger(L, sfd_w25q_opts.status(w25q));
+    return 1;
+}
+
+/*
+读取数据
+@api    sfd.read(w25q, offset, len)
+@userdata  sfd.init返回的数据结构
+@int    起始偏移量
+@int    读取长度,当前限制在256以内
+@return string 数据
+@usage
+local w25q = sfd.init(0, 17)
+if w25q then
+    log.info("sfd", "read", sfd.read(w25q, 0x100, 256))
+end
+*/
+static int l_sfd_read(lua_State *L) {
+    sfd_w25q_t *w25q = (sfd_w25q_t *) lua_touserdata(L, 1);
+    size_t offset = luaL_checkinteger(L, 2);
+    size_t len = luaL_checkinteger(L, 3);
+    luaL_Buffer buff;
+    luaL_buffinitsize(L, &buff, len);
+    sfd_w25q_opts.read(w25q, buff.b, offset, len);
+    luaL_pushresult(&buff);
+    return 1;
+}
+
+/*
+写入数据
+@api    sfd.write(w25q, offset, data)
+@userdata  sfd.init返回的数据结构
+@int    起始偏移量
+@string    需要写入的数据,当前支持256字节及以下
+@return boolean 成功返回true,失败返回false
+@usage
+local w25q = sfd.init(0, 17)
+if w25q then
+    log.info("sfd", "write", sfd.write(w25q, 0x100, "hi,luatos"))
+end
+*/
+static int l_sfd_write(lua_State *L) {
+    sfd_w25q_t *w25q = (sfd_w25q_t *) lua_touserdata(L, 1);
+    size_t offset = luaL_checkinteger(L,2);
+    size_t len = 0;
+    const char* buff = luaL_checklstring(L, 3, &len);
+    int re = sfd_w25q_opts.write(w25q, buff, offset, len);
+    lua_pushboolean(L, re == 0 ? 1 : 0);
+    return 1;
+}
+
+/*
+写入数据
+@api    sfd.erase(w25q, offset)
+@userdata  sfd.init返回的数据结构
+@int    起始偏移量
+@return boolean 成功返回true,失败返回false
+@usage
+local w25q = sfd.init(0, 17)
+if w25q then
+    log.info("sfd", "write", sfd.erase(w25q, 0x100))
+end
+*/
+static int l_sfd_erase(lua_State *L) {
+    sfd_w25q_t *w25q = (sfd_w25q_t *) lua_touserdata(L, 1);
+    size_t offset = luaL_checkinteger(L,2);
+    size_t len = luaL_checkinteger(L, 3);
+    int re = sfd_w25q_opts.erase(w25q, offset, len);
+    lua_pushboolean(L, re == 0 ? 1 : 0);
+    return 1;
+}
+
+static int l_sfd_ioctl(lua_State *L) {
+    return 0;
+}
+
+/*
+芯片唯一id
+@api    sfd.id(w25q)
+@userdata  sfd.init返回的数据结构
+@return string 8字节(64bit)的芯片id
+@usage
+local w25q = sfd.init(0, 17)
+if w25q then
+    log.info("sfd", "chip id", sfd.id(w25q))
+end
+*/
+static int l_sfd_id(lua_State *L) {
+    sfd_w25q_t *w25q = (sfd_w25q_t *) lua_touserdata(L, 1);
+    lua_pushlstring(L, w25q->chip_id, 8);
+    return 1;
+}
+
+#include "rotable.h"
+static const rotable_Reg reg_sfd[] =
+{
+    { "init" ,             l_sfd_init,           0},
+    { "status",            l_sfd_status,         0},
+    { "read",              l_sfd_read,           0},
+    { "write",             l_sfd_write,          0},
+    { "erase",             l_sfd_erase,          0},
+    { "ioctl",             l_sfd_ioctl,          0},
+    { "id",                l_sfd_id,             0},
+};
+
+LUAMOD_API int luaopen_sfd( lua_State *L ) {
+    luat_newlib(L, reg_sfd);
+    return 1;
+}

+ 126 - 0
luat/modules/luat_sfd.c

@@ -0,0 +1,126 @@
+
+#include "luat_base.h"
+#include "luat_spi.h"
+#include "luat_gpio.h"
+
+#include "luat_sfd.h"
+
+#define LUAT_LOG_TAG "sfd"
+#include "luat_log.h"
+
+#define CS_H(pin) luat_gpio_set(pin, 1)
+#define CS_L(pin) luat_gpio_set(pin, 0)
+
+// 针对W25Q的实现
+
+static int sfd_w25q_init (void* userdata);
+static int sfd_w25q_status (void* userdata);
+static int sfd_w25q_read (void* userdata, char* buff, size_t offset, size_t len);
+static int sfd_w25q_write (void* userdata, const char* buff, size_t offset, size_t len);
+static int sfd_w25q_erase (void* userdata, size_t offset, size_t len);
+static int sfd_w25q_ioctl (void* userdata, size_t cmd, void* buff);
+
+const sdf_opts_t sfd_w25q_opts = {
+    .initialize = sfd_w25q_init,
+    .status = sfd_w25q_status,
+    .read = sfd_w25q_read,
+    .write = sfd_w25q_write,
+    .erase = sfd_w25q_erase,
+    .ioctl = sfd_w25q_ioctl,
+};
+
+static int sfd_w25q_init (void* userdata) {
+    sfd_w25q_t *w25q = (sfd_w25q_t *)userdata;
+    uint8_t cmd = 0x9F;
+    // 发送CMD 9F, 读取容量信息
+    luat_gpio_set(w25q->spi_cs, 0);
+    luat_spi_send(w25q->spi_id, (const char*)&cmd, 1);
+    char buff[3] = {0};
+    luat_spi_recv(w25q->spi_id, buff, 3);
+    luat_gpio_set(w25q->spi_cs, 1);
+    if (buff[0] != 0x40) {
+        LLOGW("can't read spi flash: cmd 9F");
+        return -1;
+    }
+    LLOGD("spi flash %02X %02X %02X", buff[0], buff[1], buff[2]);
+    if (buff[1] == 0xEF) {
+        switch(buff[2]) {
+            case 0x13:
+                w25q->sector_count = 8*256;// w25q80, 8M
+                break;
+            case 0x14:
+                w25q->sector_count = 16*256;// w25q16, 16M
+                break;
+            case 0x15:
+                w25q->sector_count = 32*256;// w25q32, 32M
+                break;
+            case 0x16:
+                w25q->sector_count = 64*256;// w25q64, 64M
+                break;
+            case 0x17:
+                w25q->sector_count = 128*256;// w25q128, 128M
+                break;
+            case 0x18:
+                w25q->sector_count = 256*256;// w25q256, 256M
+                break;
+            case 0x19:
+                w25q->sector_count = 512*256;// w25q512, 512M
+                break;
+            default :
+                w25q->sector_count = 16*256;// 默认当16M吧
+                break;
+        }
+    }
+    else {
+        w25q->sector_count = 16*256;// 默认当16M吧
+    }
+    //w25q->flash_id[0] = buff[1];
+    //w25q->flash_id[1] = buff[2];
+
+    // 读设备唯一id
+    luat_gpio_set(w25q->spi_cs, 0);
+    const char* chip_id_cmd = {0x4B, 0x00, 0x00, 0x00, 0x00};
+    luat_spi_send(w25q->spi_id, chip_id_cmd, 5);
+    luat_spi_read(w25q->spi_id, w25q->chip_id, 8);
+    luat_gpio_set(w25q->spi_cs, 1);
+
+    return 0;
+}
+
+static int sfd_w25q_status (void* userdata) {
+    sfd_w25q_t *w25q = (sfd_w25q_t *)userdata;
+    return w25q->sector_count == 0 ? 0 : 1; // TODO 根据BUSY 状态返回
+}
+
+static int sfd_w25q_read (void* userdata, char* buff, size_t offset, size_t len) {
+    sfd_w25q_t *w25q = (sfd_w25q_t *)userdata;
+    char cmd[4] = {0x03, offset >> 16, (offset >> 8) & 0xFF, offset & 0xFF};
+    luat_gpio_set(w25q->spi_cs, 0);
+    luat_spi_send(w25q->spi_id, (const char*)&cmd, 4);
+    luat_spi_read(w25q->spi_id, buff, len);
+    luat_gpio_set(w25q->spi_cs, 1);
+    return 0;
+}
+
+static int sfd_w25q_write (void* userdata, const char* buff, size_t offset, size_t len) {
+    sfd_w25q_t *w25q = (sfd_w25q_t *)userdata;
+    char cmd[4] = {0x02, offset >> 16, (offset >> 8) & 0xFF, offset & 0xFF};
+    luat_gpio_set(w25q->spi_cs, 0);
+    luat_spi_send(w25q->spi_id, (const char*)&cmd, 4);
+    luat_spi_send(w25q->spi_id, buff, len);
+    luat_gpio_set(w25q->spi_cs, 1);
+    return 0;
+}
+
+static int sfd_w25q_erase (void* userdata, size_t offset, size_t len) {
+    sfd_w25q_t *w25q = (sfd_w25q_t *)userdata;
+    char cmd[4] = {0x20, offset >> 16, (offset >> 8) & 0xFF, offset & 0xFF};
+    luat_gpio_set(w25q->spi_cs, 0);
+    luat_spi_send(w25q->spi_id, (const char*)&cmd, 4);
+    luat_gpio_set(w25q->spi_cs, 1);
+    return 0;
+}
+
+static int sfd_w25q_ioctl (void* userdata, size_t cmd, void* buff) {
+    return -1;
+}