| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934 |
- /*
- @module i2c
- @summary I2C操作
- @version 1.0
- @date 2020.03.30
- @demo i2c
- @tag LUAT_USE_I2C
- */
- #include "luat_base.h"
- #include "luat_log.h"
- #include "luat_timer.h"
- #include "luat_mem.h"
- #include "luat_i2c.h"
- #include "luat_gpio.h"
- #include "luat_zbuff.h"
- #include "luat_irq.h"
- #define LUAT_LOG_TAG "i2c"
- #include "luat_log.h"
- void i2c_soft_start(luat_ei2c_t *ei2c)
- {
- luat_gpio_mode(ei2c->sda, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, 1);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->scl, Luat_GPIO_HIGH);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->sda, Luat_GPIO_LOW);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->scl, Luat_GPIO_LOW);
- luat_timer_us_delay(ei2c->udelay);
- }
- static void i2c_soft_stop(luat_ei2c_t *ei2c)
- {
- luat_gpio_mode(ei2c->sda, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, 1);
- luat_gpio_set(ei2c->scl, Luat_GPIO_LOW);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->sda, Luat_GPIO_LOW);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->scl, Luat_GPIO_HIGH);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->sda, Luat_GPIO_HIGH);
- luat_timer_us_delay(ei2c->udelay);
- }
- static unsigned char i2c_soft_wait_ack(luat_ei2c_t *ei2c)
- {
- luat_gpio_set(ei2c->sda, Luat_GPIO_HIGH);
- luat_gpio_mode(ei2c->sda, Luat_GPIO_INPUT, Luat_GPIO_PULLUP, 1);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->scl, Luat_GPIO_HIGH);
- luat_timer_us_delay(ei2c->udelay * 3);
- int max_wait_time = 3000;
- while (max_wait_time--)
- {
- if (luat_gpio_get(ei2c->sda) == Luat_GPIO_LOW)
- {
- luat_gpio_set(ei2c->scl, Luat_GPIO_LOW);
- return 1;
- }
- luat_timer_us_delay(1);
- }
- i2c_soft_stop(ei2c);
- return 0;
- }
- static void i2c_soft_send_ack(luat_ei2c_t *ei2c)
- {
- luat_gpio_mode(ei2c->sda, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, 0);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->scl, Luat_GPIO_HIGH);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->scl, Luat_GPIO_LOW);
- }
- static void i2c_soft_send_noack(luat_ei2c_t *ei2c)
- {
- luat_gpio_mode(ei2c->sda, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, 1);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->scl, Luat_GPIO_HIGH);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->scl, Luat_GPIO_LOW);
- }
- static void i2c_soft_send_byte(luat_ei2c_t *ei2c, unsigned char data)
- {
- unsigned char i = 8;
- luat_gpio_mode(ei2c->sda, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, 0);
- while (i--)
- {
- luat_gpio_set(ei2c->scl, Luat_GPIO_LOW);
- luat_timer_us_delay(ei2c->udelay * 2);
- if (data & 0x80)
- {
- luat_gpio_set(ei2c->sda, Luat_GPIO_HIGH);
- }
- else
- {
- luat_gpio_set(ei2c->sda, Luat_GPIO_LOW);
- }
- luat_timer_us_delay(ei2c->udelay);
- data <<= 1;
- luat_gpio_set(ei2c->scl, Luat_GPIO_HIGH);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->scl, Luat_GPIO_LOW);
- luat_timer_us_delay(ei2c->udelay);
- }
- }
- static char i2c_soft_recv_byte(luat_ei2c_t *ei2c)
- {
- unsigned char i = 8;
- unsigned char data = 0;
- luat_gpio_set(ei2c->sda, Luat_GPIO_HIGH);
- luat_gpio_mode(ei2c->sda, Luat_GPIO_INPUT, Luat_GPIO_PULLUP, 1);
- while (i--)
- {
- data <<= 1;
- luat_gpio_set(ei2c->scl, Luat_GPIO_LOW);
- luat_timer_us_delay(ei2c->udelay);
- luat_gpio_set(ei2c->scl, Luat_GPIO_HIGH);
- luat_timer_us_delay(ei2c->udelay);
- if (luat_gpio_get(ei2c->sda))
- data |= 0x01;
- }
- luat_gpio_set(ei2c->scl, Luat_GPIO_LOW);
- return (data);
- }
- LUAT_WEAK int i2c_soft_recv(luat_ei2c_t *ei2c, unsigned char addr, char *buff, size_t len)
- {
- size_t i;
- i2c_soft_start(ei2c);
- i2c_soft_send_byte(ei2c, (addr << 1) + 1);
- if (!i2c_soft_wait_ack(ei2c))
- {
- i2c_soft_stop(ei2c);
- return -1;
- }
- luat_timer_us_delay(ei2c->udelay * 10);
- for (i = 0; i < len; i++)
- {
- *buff++ = i2c_soft_recv_byte(ei2c);
- if (i < (len - 1))
- i2c_soft_send_ack(ei2c);
- }
- i2c_soft_send_noack(ei2c);
- i2c_soft_stop(ei2c);
- return 0;
- }
- LUAT_WEAK int i2c_soft_send(luat_ei2c_t *ei2c, unsigned char addr, char *data, size_t len, uint8_t stop)
- {
- size_t i;
- i2c_soft_start(ei2c);
- i2c_soft_send_byte(ei2c, addr << 1);
- if (!i2c_soft_wait_ack(ei2c))
- {
- i2c_soft_stop(ei2c);
- return -1;
- }
- for (i = 0; i < len; i++)
- {
- i2c_soft_send_byte(ei2c, data[i]);
- if (!i2c_soft_wait_ack(ei2c))
- {
- i2c_soft_stop(ei2c);
- return -1;
- }
- }
- if (stop){
- i2c_soft_stop(ei2c);
- }
- return 0;
- }
- /*
- i2c编号是否存在
- @api i2c.exist(id)
- @int 设备id, 例如i2c1的id为1, i2c2的id为2
- @return bool 存在就返回true,否则返回false
- @usage
- -- 检查i2c1是否存在
- if i2c.exist(1) then
- log.info("存在 i2c1")
- end
- */
- static int l_i2c_exist(lua_State *L)
- {
- int re = luat_i2c_exist(luaL_checkinteger(L, 1));
- lua_pushboolean(L, re == 0 ? 0 : 1);
- return 1;
- }
- LUAT_WEAK int luat_i2c_set_polling_mode(int id, uint8_t on_off){
- return -1;
- }
- /*
- i2c初始化
- @api i2c.setup(id, speed, pullup)
- @int 设备id, 例如i2c1的id为1, i2c2的id为2
- @int I2C速度, 例如i2c.FAST
- @bool 是否使用轮询模式,true是,false不是。默认状态具体平台决定,除非使用中有问题,否则留空!!!
- @return int 成功就返回1,否则返回0
- @usage
- -- 初始化i2c1
- i2c.setup(1, i2c.FAST) -- id正确就一定成功
- -- 如需判断i2c id是否合法, 请使用 i2c.exist 函数
- */
- static int l_i2c_setup(lua_State *L)
- {
- if (lua_isuserdata(L, 1)) {
- LLOGD("软件i2c不需要再执行i2c.setup");
- lua_pushinteger(L, 1);
- return 1;
- }
- int re = luat_i2c_setup(luaL_checkinteger(L, 1), luaL_optinteger(L, 2, 0));
- if (lua_isboolean(L, 3) && lua_toboolean(L, 3)) {
- luat_i2c_set_polling_mode(luaL_checkinteger(L, 1), lua_toboolean(L, 3));
- }
- lua_pushinteger(L, re == 0 ? 1 : 0);
- return 1;
- }
- LUAT_WEAK int i2c_soft_setup(luat_ei2c_t *ei2c){
- luat_gpio_mode(ei2c->scl, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, 1);
- luat_gpio_mode(ei2c->sda, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, 1);
- i2c_soft_stop(ei2c);
- return 0;
- }
- LUAT_WEAK int i2c_soft_close(luat_ei2c_t *ei2c){
- luat_gpio_close(ei2c->scl);
- luat_gpio_close(ei2c->sda);
- return 0;
- }
- /*
- 新建一个软件i2c对象
- @api i2c.createSoft(scl,sda,delay)
- @int i2c SCL引脚编号(GPIO编号)
- @int i2c SDA引脚编号(GPIO编号)
- @int 每个操作的延时, 单位us, 默认5
- @return 软件I2C对象 可当作i2c的id使用
- @usage
- -- 注意!这个接口是软件模拟i2c,速度可能会比硬件的慢
- -- 不需要调用i2c.close接口
- -- 初始化软件i2c
- local softI2C = i2c.createSoft(1, 2, 5)
- i2c.send(softI2C, 0x5C, string.char(0x0F, 0x2F))
- -- 注意, 第3个参数是 2023.06.19 添加的delay
- -- 通过调整delay参数的值, 可增加或降低I2C的速度
- */
- static int l_i2c_soft(lua_State *L)
- {
- luat_ei2c_t *ei2c = (luat_ei2c_t *)lua_newuserdata(L, sizeof(luat_ei2c_t));
- ei2c->scl = luaL_checkinteger(L, 1);
- ei2c->sda = luaL_checkinteger(L, 2);
- if (lua_isinteger(L, 3)) {
- ei2c->udelay = luaL_checkinteger(L, 3);
- if (ei2c->udelay < 1)
- ei2c->udelay = 1;
- }
- else {
- ei2c->udelay = 5;
- }
- i2c_soft_setup(ei2c);
- luaL_setmetatable(L, LUAT_EI2C_TYPE);
- return 1;
- }
- /*
- i2c发送数据
- @api i2c.send(id, addr, data,stop)
- @int 设备id, 例如i2c1的id为1, i2c2的id为2
- @int I2C子设备的地址, 7位地址
- @integer/string/table 待发送的数据,自适应参数类型
- @integer 可选参数 是否发送停止位 1发送 0不发送 默认发送(105不支持)
- @return true/false 发送是否成功
- @usage
- -- 往i2c0发送1个字节的数据
- i2c.send(0, 0x68, 0x75)
- -- 往i2c1发送2个字节的数据
- i2c.send(1, 0x5C, string.char(0x0F, 0x2F))
- i2c.send(1, 0x5C, {0x0F, 0x2F})
- */
- static int l_i2c_send(lua_State *L)
- {
- int id = 0;
- if (!lua_isuserdata(L, 1))
- {
- id = luaL_checkinteger(L, 1);
- }
- int addr = luaL_checkinteger(L, 2);
- size_t len = 0;
- int result = 0;
- int stop = luaL_optnumber(L, 4 , 1);
- if (lua_isinteger(L, 3))
- {
- char buff = (char)luaL_checkinteger(L, 3);
- if (lua_isuserdata(L, 1))
- {
- luat_ei2c_t *ei2c = toei2c(L);
- result = i2c_soft_send(ei2c, addr, &buff, 1,stop);
- }
- else
- {
- result = luat_i2c_send(id, addr, &buff, 1,stop);
- }
- // luat_heap_free(buff);
- }
- else if (lua_isstring(L, 3))
- {
- const char *buff = luaL_checklstring(L, 3, &len);
- if (lua_isuserdata(L, 1))
- {
- luat_ei2c_t *ei2c = toei2c(L);
- result = i2c_soft_send(ei2c, addr, (char *)buff, len,stop);
- }
- else
- {
- result = luat_i2c_send(id, addr, (char *)buff, len,stop);
- }
- }
- else if (lua_istable(L, 3))
- {
- const int len = lua_rawlen(L, 3); //返回数组的长度
- char *buff = (char *)luat_heap_malloc(len);
- for (size_t i = 0; i < len; i++)
- {
- lua_rawgeti(L, 3, 1 + i);
- buff[i] = (char)lua_tointeger(L, -1);
- lua_pop(L, 1); //将刚刚获取的元素值从栈中弹出
- }
- if (lua_isuserdata(L, 1))
- {
- luat_ei2c_t *ei2c = toei2c(L);
- result = i2c_soft_send(ei2c, addr, buff, len,stop);
- }
- else
- {
- result = luat_i2c_send(id, addr, buff, len,stop);
- }
- luat_heap_free(buff);
- }
- else
- {
- if (lua_isuserdata(L, 1))
- {
- luat_ei2c_t *ei2c = toei2c(L);
- result = i2c_soft_send(ei2c, addr, NULL, 0,stop);
- }
- else
- {
- result = luat_i2c_send(id, addr, NULL, 0,stop);
- }
- }
- lua_pushboolean(L, result == 0);
- return 1;
- }
- /*
- i2c接收数据
- @api i2c.recv(id, addr, len)
- @int 设备id, 例如i2c1的id为1, i2c2的id为2
- @int I2C子设备的地址, 7位地址
- @int 接收数据的长度
- @return string 收到的数据
- @usage
- -- 从i2c1读取2个字节的数据
- local data = i2c.recv(1, 0x5C, 2)
- */
- static int l_i2c_recv(lua_State *L)
- {
- int id = 0;
- if (!lua_isuserdata(L, 1))
- {
- id = luaL_checkinteger(L, 1);
- }
- int addr = luaL_checkinteger(L, 2);
- int len = luaL_checkinteger(L, 3);
- char *buff = (char *)luat_heap_malloc(len);
- int result;
- if (lua_isuserdata(L, 1))
- {
- luat_ei2c_t *ei2c = toei2c(L);
- result = i2c_soft_recv(ei2c, addr, buff, len);
- }
- else
- {
- result = luat_i2c_recv(id, addr, buff, len);
- }
- if (result != 0)
- { //如果返回值不为0,说明收失败了
- len = 0;
- LLOGD("i2c receive result %d", result);
- }
- lua_pushlstring(L, buff, len);
- luat_heap_free(buff);
- return 1;
- }
- /*
- i2c写寄存器数据
- @api i2c.writeReg(id, addr, reg, data,stop)
- @int 设备id, 例如i2c1的id为1, i2c2的id为2
- @int I2C子设备的地址, 7位地址
- @int 寄存器地址
- @string 待发送的数据
- @integer 可选参数 是否发送停止位 1发送 0不发送 默认发送(105不支持)
- @return true/false 发送是否成功
- @usage
- -- 从i2c1的地址为0x5C的设备的寄存器0x01写入2个字节的数据
- i2c.writeReg(1, 0x5C, 0x01, string.char(0x00, 0xF2))
- */
- static int l_i2c_write_reg(lua_State *L)
- {
- int id = 0;
- if (!lua_isuserdata(L, 1))
- {
- id = luaL_checkinteger(L, 1);
- }
- int addr = luaL_checkinteger(L, 2);
- int reg = luaL_checkinteger(L, 3);
- size_t len;
- const char *lb = luaL_checklstring(L, 4, &len);
- int stop = luaL_optnumber(L, 5 , 1);
- char *buff = (char *)luat_heap_malloc(len + 1);
- *buff = (char)reg;
- memcpy(buff + 1, lb, len);
- int result;
- if (lua_isuserdata(L, 1))
- {
- luat_ei2c_t *ei2c = toei2c(L);
- result = i2c_soft_send(ei2c, addr, buff, len + 1,stop);
- }
- else
- {
- result = luat_i2c_send(id, addr, buff, len + 1,stop);
- }
- luat_heap_free(buff);
- lua_pushboolean(L, result == 0);
- return 1;
- }
- /*
- i2c读寄存器数据
- @api i2c.readReg(id, addr, reg, len)
- @int 设备id, 例如i2c1的id为1, i2c2的id为2
- @int I2C子设备的地址, 7位地址
- @int 寄存器地址
- @int 待接收的数据长度
- @integer 可选参数 是否发送停止位 1发送 0不发送 默认发送(105不支持)
- @return string 收到的数据
- @usage
- -- 从i2c1的地址为0x5C的设备的寄存器0x01读出2个字节的数据
- i2c.readReg(1, 0x5C, 0x01, 2)
- */
- static int l_i2c_read_reg(lua_State *L)
- {
- int id = 0;
- if (!lua_isuserdata(L, 1))
- {
- id = luaL_checkinteger(L, 1);
- }
- int addr = luaL_checkinteger(L, 2);
- int reg = luaL_checkinteger(L, 3);
- int len = luaL_checkinteger(L, 4);
- int stop = luaL_optnumber(L, 5 , 0);
- char temp = (char)reg;
- int result;
- if (lua_isuserdata(L, 1))
- {
- luat_ei2c_t *ei2c = toei2c(L);
- result = i2c_soft_send(ei2c, addr, &temp, 1,stop);
- }
- else
- {
- result = luat_i2c_send(id, addr, &temp, 1,stop);
- }
- if (result != 0)
- { //如果返回值不为0,说明收失败了
- LLOGD("i2c send result %d", result);
- lua_pushlstring(L, NULL, 0);
- return 1;
- }
- char *buff = (char *)luat_heap_malloc(sizeof(char) * len);
- if (lua_isuserdata(L, 1))
- {
- luat_ei2c_t *ei2c = toei2c(L);
- result = i2c_soft_recv(ei2c, addr, buff, len);
- }
- else
- {
- result = luat_i2c_recv(id, addr, buff, len);
- }
- if (result != 0)
- { //如果返回值不为0,说明收失败了
- len = 0;
- LLOGD("i2c receive result %d", result);
- }
- lua_pushlstring(L, buff, len);
- luat_heap_free(buff);
- return 1;
- }
- /*
- 关闭i2c设备
- @api i2c.close(id)
- @int 设备id, 例如i2c1的id为1, i2c2的id为2
- @return nil 无返回值
- @usage
- -- 关闭i2c1
- i2c.close(1)
- */
- static int l_i2c_close(lua_State *L)
- {
- int id = luaL_checkinteger(L, 1);
- luat_i2c_close(id);
- return 0;
- }
- /*
- 从i2c总线读取DHT12的温湿度数据
- @api i2c.readDHT12(id)
- @int 设备id, 例如i2c1的id为1, i2c2的id为2
- @int DHT12的设备地址,默认0x5C
- @return boolean 读取成功返回true,否则返回false
- @return int 湿度值,单位0.1%, 例如 591 代表 59.1%
- @return int 温度值,单位0.1摄氏度, 例如 292 代表 29.2摄氏度
- @usage
- -- 从i2c0读取DHT12
- i2c.setup(0)
- local re, H, T = i2c.readDHT12(0)
- if re then
- log.info("dht12", H, T)
- end
- */
- static int l_i2c_readDHT12(lua_State *L)
- {
- int id = 0;
- if (!lua_isuserdata(L, 1))
- {
- id = luaL_checkinteger(L, 1);
- }
- int addr = luaL_optinteger(L, 2, 0x5C);
- char buff[5] = {0};
- char temp = 0x00;
- int result = -1;
- if (lua_isuserdata(L, 1))
- {
- luat_ei2c_t *ei2c = toei2c(L);
- result = i2c_soft_send(ei2c, addr, &temp, 1,1);
- }
- else
- {
- result = luat_i2c_send(id, addr, &temp, 1,1);
- }
- if (result != 0)
- {
- LLOGD("DHT12 i2c bus write fail");
- lua_pushboolean(L, 0);
- return 1;
- }
- if (lua_isuserdata(L, 1))
- {
- luat_ei2c_t *ei2c = toei2c(L);
- result = i2c_soft_recv(ei2c, addr, buff, 5);
- }
- else
- {
- result = luat_i2c_recv(id, addr, buff, 5);
- }
- if (result != 0)
- {
- lua_pushboolean(L, 0);
- return 1;
- }
- else
- {
- if (buff[0] == 0 && buff[1] == 0 && buff[2] == 0 && buff[3] == 0 && buff[4] == 0)
- {
- LLOGD("DHT12 DATA emtry");
- lua_pushboolean(L, 0);
- return 1;
- }
- // 检查crc值
- LLOGD("DHT12 DATA %02X%02X%02X%02X%02X", buff[0], buff[1], buff[2], buff[3], buff[4]);
- uint8_t crc_act = (uint8_t)buff[0] + (uint8_t)buff[1] + (uint8_t)buff[2] + (uint8_t)buff[3];
- uint8_t crc_exp = (uint8_t)buff[4];
- if (crc_act != crc_exp)
- {
- LLOGD("DATA12 DATA crc not ok");
- lua_pushboolean(L, 0);
- return 1;
- }
- lua_pushboolean(L, 1);
- lua_pushinteger(L, (uint8_t)buff[0] * 10 + (uint8_t)buff[1]);
- if (((uint8_t)buff[2]) > 127)
- lua_pushinteger(L, ((uint8_t)buff[2] - 128) * -10 + (uint8_t)buff[3]);
- else
- lua_pushinteger(L, (uint8_t)buff[2] * 10 + (uint8_t)buff[3]);
- return 3;
- }
- }
- /*
- 从i2c总线读取DHT30的温湿度数据(由"好奇星"贡献)
- @api i2c.readSHT30(id,addr)
- @int 设备id, 例如i2c1的id为1, i2c2的id为2
- @int 设备addr,SHT30的设备地址,默认0x44 bit7
- @return boolean 读取成功返回true,否则返回false
- @return int 湿度值,单位0.1%, 例如 591 代表 59.1%
- @return int 温度值,单位0.1摄氏度, 例如 292 代表 29.2摄氏度
- @usage
- -- 从i2c0读取SHT30
- i2c.setup(0)
- local re, H, T = i2c.readSHT30(0)
- if re then
- log.info("sht30", H, T)
- end
- */
- static int l_i2c_readSHT30(lua_State *L)
- {
- char buff[7] = {0x2c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00};
- float temp = 0x00;
- float hum = 0x00;
- int result = -1;
- int addr = luaL_optinteger(L, 2, 0x44);
- if (lua_isuserdata(L, 1))
- {
- luat_ei2c_t *ei2c = toei2c(L);
- i2c_soft_send(ei2c, addr, buff, 2,1);
- luat_timer_mdelay(13);
- result = i2c_soft_recv(ei2c, addr, buff, 6);
- }
- else
- {
- int id = luaL_optinteger(L, 1, 0);
- luat_i2c_send(id, addr, buff, 2, 1);
- luat_timer_mdelay(1);
- result = luat_i2c_recv(id, addr, buff, 6);
- }
- if (result != 0)
- {
- lua_pushboolean(L, 0);
- return 1;
- }
- else
- {
- if (buff[0] == 0 && buff[1] == 0 && buff[2] == 0 && buff[3] == 0 && buff[4] == 0)
- {
- LLOGD("SHT30 DATA emtry");
- lua_pushboolean(L, 0);
- return 1;
- }
- // 检查crc值
- // LLOGD("SHT30 DATA %02X %02X %02X %02X %02X %02X", buff[0], buff[1], buff[2], buff[3], buff[4], buff[5]);
- temp = ((((buff[0] * 256) + buff[1]) * 175) / 6553.5) - 450;
- hum = ((((buff[3] * 256) + buff[4]) * 100) / 6553.5);
- // LLOGD("\r\n SHT30 %d deg %d Hum ", temp, hum);
- // 跳过CRC
- // uint8_t crc_act = (uint8_t)buff[0] + (uint8_t)buff[1] + (uint8_t)buff[2] + (uint8_t)buff [3];
- // uint8_t crc_exp = (uint8_t)buff[4];
- // if (crc_act != crc_exp) {
- // LLOGD("DATA12 DATA crc not ok");
- // lua_pushboolean(L, 0);
- // return 1;
- // }
- // Convert the data
- lua_pushboolean(L, 1);
- lua_pushinteger(L, (int)hum);
- lua_pushinteger(L, (int)temp);
- return 3;
- // 华氏度
- // fTemp = (cTemp * 1.8) + 32;
- }
- }
- #ifndef LUAT_COMPILER_NOWEAK
- LUAT_WEAK int luat_i2c_transfer(int id, int addr, uint8_t *reg, size_t reg_len, uint8_t *buff, size_t len)
- {
- int result;
- result = luat_i2c_send(id, addr, reg, reg_len, 0);
- if (result != 0) return-1;
- return luat_i2c_recv(id, addr, buff, len);
- }
- LUAT_WEAK int luat_i2c_no_block_transfer(int id, int addr, uint8_t is_read, uint8_t *reg, size_t reg_len, uint8_t *buff, size_t len, uint16_t Toms, void *CB, void *pParam)
- {
- return -1;
- }
- #endif
- /**
- i2c通用传输,包括发送N字节,发送N字节+接收N字节,接收N字节三种功能,在发送转接收过程中发送reStart信号,解决类似mlx90614必须带restart信号,但是又不能用i2c.send来控制的,比如air105
- @api i2c.transfer(id, addr, txBuff, rxBuff, rxLen)
- @int 设备id, 例如i2c1的id为1, i2c2的id为2
- @int I2C子设备的地址, 7位地址
- @integer/string/zbuff 待发送的数据,自适应参数类型,如果为nil,则不发送数据
- @zbuff 待接收数据的zbuff 如果不用zbuff,则接收数据将在return返回
- @int 需要接收的数据长度,如果为0或nil,则不接收数据
- @return boolean true/false 发送是否成功
- @return string or nil 如果参数5是interger,则返回接收到的数据
- @usage
- local result, _ = i2c.transfer(0, 0x11, txbuff, rxbuff, 1)
- local result, _ = i2c.transfer(0, 0x11, txbuff, nil, 0) --只发送txbuff里的数据,不接收数据,典型应用就是写寄存器了,这里寄存器地址和值都放在了txbuff里
- local result, _ = i2c.transfer(0, 0x11, "\x01\x02\x03", nil, 1) --发送0x01, 0x02,0x03,不接收数据,如果是eeprom,就是往0x01的地址写02和03,或者往0x0102的地址写03,看具体芯片了
- local result, rxdata = i2c.transfer(0, 0x11, "\x01\x02", nil, 1) --发送0x01, 0x02,然后接收1个字节,典型应用就是eeprom
- local result, rxdata = i2c.transfer(0, 0x11, 0x00, nil, 1) --发送0x00,然后接收1个字节,典型应用各种传感器
- */
- static int l_i2c_transfer(lua_State *L)
- {
- int addr = luaL_checkinteger(L, 2);
- size_t tx_len = 0;
- size_t rx_len = 0;
- int result = -1;
- uint8_t temp[1];
- uint8_t *tx_buff = NULL;
- uint8_t *rx_buff = NULL;
- uint8_t tx_heap_flag = 0;
- if (lua_isnil(L, 3)) {
- tx_len = 0;
- }
- else if (lua_isinteger(L, 3)) {
- temp[0] = luaL_checkinteger(L, 3);
- tx_buff = temp;
- tx_len = 1;
- }
- else if (lua_isstring(L, 3)) {
- tx_buff = (uint8_t*)luaL_checklstring(L, 3, &tx_len);
- }
- else if (lua_istable(L, 3)) {
- const int tx_len = lua_rawlen(L, 3); //返回数组的长度
- tx_buff = (uint8_t *)luat_heap_malloc(tx_len);
- tx_heap_flag = 1;
- for (size_t i = 0; i < tx_len; i++)
- {
- lua_rawgeti(L, 3, 1 + i);
- tx_buff[i] = (char)lua_tointeger(L, -1);
- lua_pop(L, 1); //将刚刚获取的元素值从栈中弹出
- }
- }
- else {
- luat_zbuff_t *buff = ((luat_zbuff_t *)luaL_checkudata(L, 3, LUAT_ZBUFF_TYPE));
- tx_buff = buff->addr;
- tx_len = buff->used;
- }
- luat_zbuff_t *rbuff = ((luat_zbuff_t *)luaL_testudata(L, 4, LUAT_ZBUFF_TYPE));
- if (lua_isnil(L, 5)) {
- rx_len = 0;
- }
- else if (lua_isinteger(L, 5)) {
- rx_len = luaL_checkinteger(L, 5);
- if (rx_len) {
- if (!rbuff) {
- rx_buff = luat_heap_malloc(rx_len);
- }
- else {
- if ((rbuff->used + rx_len) > rbuff->len) {
- __zbuff_resize(rbuff, rbuff->len + rx_len);
- }
- rx_buff = rbuff->addr + rbuff->used;
- }
- }
- }
- int id = 0;
- if (!lua_isuserdata(L, 1)) {
- id = luaL_checkinteger(L, 1);
- if (rx_buff && rx_len) {
- result = luat_i2c_transfer(id, addr, tx_buff, tx_len, rx_buff, rx_len);
- } else {
- result = luat_i2c_transfer(id, addr, NULL, 0, tx_buff, tx_len);
- }
- }else if (lua_isuserdata(L, 1)){
- luat_ei2c_t *ei2c = toei2c(L);
- if (tx_buff && tx_len) {
- result = i2c_soft_send(ei2c, addr, (char*)tx_buff, tx_len,0);
- }
- result = i2c_soft_recv(ei2c, addr, (char*)rx_buff, rx_len);
- }
- if (tx_heap_flag) {
- luat_heap_free(tx_buff);
- }
- lua_pushboolean(L, !result);
- if (rx_buff && rx_len) {
- if (rbuff) {
- rbuff->used += rx_len;
- lua_pushnil(L);
- } else {
- lua_pushlstring(L, (const char *)rx_buff, rx_len);
- luat_heap_free(rx_buff);
- }
- } else {
- lua_pushnil(L);
- }
- return 2;
- }
- /**
- i2c非阻塞通用传输,类似transfer,但是不会等到I2C传输完成才返回,调用本函数会立刻返回,I2C传输完成后,通过消息回调
- @api i2c.xfer(id, addr, txBuff, rxBuff, rxLen, transfer_done_topic, timeout)
- @int 设备id, 例如i2c1的id为1, i2c2的id为2
- @int I2C子设备的地址, 7位地址
- @zbuff 待发送的数据,由于用的非阻塞模型,为保证动态数据的有效性,只能使用zbuff,发送的数据从zbuff.addr开始,长度为zbuff.used
- @zbuff 待接收数据的zbuff,如果为nil,则忽略后面参数, 不接收数据。接收的数据会放在zbuff.addr开始的位置,会覆盖掉之前的数据,注意zhuff的预留空间要足够
- @int 需要接收的数据长度,如果为0或nil,则不接收数据
- @string 传输完成后回调的消息
- @int 超时时间,如果填nil,则为100ms
- @return boolean true/false 本次传输是否正确启动,true,启动,false,有错误无法启动。传输完成会发布消息transfer_done_topic和boolean型结果
- @usage
- local result = i2c.xfer(0, 0x11, txbuff, rxbuff, 1, "I2CDONE") if result then result, i2c_id, succ, error_code = sys.waitUntil("I2CDONE") end if not result or not succ then log.info("i2c fail, error code", error_code) else log.info("i2c ok") end
- */
- static int l_i2c_no_block_transfer(lua_State *L)
- {
- size_t topic_len = 0;
- const char *topic = luaL_checklstring(L, 6, &topic_len);
- int id = luaL_checkinteger(L, 1);
- int addr = luaL_checkinteger(L, 2);
- size_t tx_len = 0;
- size_t rx_len = 0;
- int result = -1;
- uint8_t *tx_buff = NULL;
- uint8_t *rx_buff = NULL;
- luat_zbuff_t *buff = ((luat_zbuff_t *)luaL_testudata(L, 3, LUAT_ZBUFF_TYPE));
- if (buff) {
- tx_buff = buff->addr;
- tx_len = buff->used;
- }
- luat_zbuff_t *rbuff = ((luat_zbuff_t *)luaL_testudata(L, 4, LUAT_ZBUFF_TYPE));
- if (lua_isinteger(L, 5) && rbuff) {
- rx_len = luaL_checkinteger(L, 5);
- rx_buff = rbuff->addr;
- rbuff->used = rx_len;
- }
- uint32_t timeout = luaL_optinteger(L, 7, 100);
- char *cb_topic = luat_heap_malloc(topic_len + 1);
- memcpy(cb_topic, topic, topic_len);
- cb_topic[topic_len] = 0;
- if (rx_buff && rx_len) {
- result = luat_i2c_no_block_transfer(id, addr, 1, tx_buff, tx_len, rx_buff, rx_len, timeout, luat_irq_hardware_cb_handler, cb_topic);
- } else {
- result = luat_i2c_no_block_transfer(id, addr, 0, NULL, 0, tx_buff, tx_len, timeout, luat_irq_hardware_cb_handler, cb_topic);
- }
- if (result) {
- luat_heap_free(cb_topic);
- }
- lua_pushboolean(L, !result);
- return 1;
- }
- /**
- 扫描i2c设备
- @api i2c.scan(id,speed)
- @int 设备id, 例如i2c1的id为1, i2c2的id为2
- @int 速度, 可选i2c.SLOW i2c.FAST i2c.PLUS i2c.HSMODE 默认为i2c.SLOW,如探测不到则修改此项
- @return nil 当前无返回值
- @usage
- -- 本函数于2023.07.04添加
- -- 这个函数的主要目标是为了在开发期扫描i2c设备
- -- 有些BSP在指定addr无响应时会输出日志,导致输出会被打乱
- i2c.scan()
- */
- #if defined(LUA_USE_WINDOWS) || defined(LUA_USE_LINUX) || defined(LUA_USE_MACOS)
- static int l_i2c_scan(lua_State *L) {
- return 0;
- }
- #else
- #include "i2c_utils.h"
- static int l_i2c_scan(lua_State *L) {
- int id = luaL_optinteger(L, 1, 0);
- i2c_init(id,luaL_optinteger(L, 2, 0));
- i2c_scan();
- return 0;
- }
- #endif
- #include "rotable2.h"
- static const rotable_Reg_t reg_i2c[] =
- {
- { "exist", ROREG_FUNC(l_i2c_exist)},
- { "setup", ROREG_FUNC(l_i2c_setup)},
- { "createSoft", ROREG_FUNC(l_i2c_soft)},
- #ifdef __F1C100S__
- #else
- { "send", ROREG_FUNC(l_i2c_send)},
- { "recv", ROREG_FUNC(l_i2c_recv)},
- #endif
- { "transfer", ROREG_FUNC(l_i2c_transfer)},
- { "writeReg", ROREG_FUNC(l_i2c_write_reg)},
- { "readReg", ROREG_FUNC(l_i2c_read_reg)},
- { "close", ROREG_FUNC(l_i2c_close)},
- { "readDHT12", ROREG_FUNC(l_i2c_readDHT12)},
- { "readSHT30", ROREG_FUNC(l_i2c_readSHT30)},
- { "xfer", ROREG_FUNC(l_i2c_no_block_transfer)},
-
- { "scan", ROREG_FUNC(l_i2c_scan)},
-
- { "HSMODE", ROREG_INT(I2C_SPEED_HSMODE)},
- { "PLUS", ROREG_INT(I2C_SPEED_PLUS)},
- //@const FAST number 高速
- { "FAST", ROREG_INT(I2C_SPEED_FAST)},
- //@const SLOW number 低速
- { "SLOW", ROREG_INT(I2C_SPEED_SLOW)},
- { NULL, ROREG_INT(0) }
- };
- LUAMOD_API int luaopen_i2c(lua_State *L)
- {
- luat_newlib2(L, reg_i2c);
- luaL_newmetatable(L, LUAT_EI2C_TYPE);
- lua_pop(L, 1);
- return 1;
- }
|