Browse Source

add:非则塞的SPI和I2C传输接口

alienwalker 3 years ago
parent
commit
998cfa4bdd

+ 3 - 0
luat/include/luat_i2c.h

@@ -20,4 +20,7 @@ int luat_i2c_recv(int id, int addr, void* buff, size_t len);
 int luat_i2c_write_reg(int id, int addr, int reg, uint16_t value, uint8_t stop);
 int luat_i2c_write_reg(int id, int addr, int reg, uint16_t value, uint8_t stop);
 int luat_i2c_read_reg(int id, int addr, int reg, uint16_t* value);
 int luat_i2c_read_reg(int id, int addr, int reg, uint16_t* value);
 
 
+int luat_i2c_transfer(int id, int addr, uint8_t *reg, size_t reg_len, uint8_t *buff, size_t len);
+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);
+
 #endif
 #endif

+ 1 - 0
luat/include/luat_irq.h

@@ -11,4 +11,5 @@ int luat_irq_uart_cb(int uartid, void* args);
 
 
 int luat_irq_spi_cb(int id);
 int luat_irq_spi_cb(int id);
 
 
+int32_t luat_irq_hardware_cb_handler(void *pdata, void *param);
 #endif
 #endif

+ 3 - 0
luat/include/luat_spi.h

@@ -77,6 +77,9 @@ int luat_spi_recv(int spi_id, char* recv_buf, size_t length);
 //发SPI数据,返回发送字节数
 //发SPI数据,返回发送字节数
 int luat_spi_send(int spi_id, const char* send_buf, size_t length);
 int luat_spi_send(int spi_id, const char* send_buf, size_t length);
 
 
+//非阻塞SPI收发数据
+int luat_spi_no_block_transfer(int spi_id, uint8_t *tx_buff, uint8_t *rx_buff, size_t len, void *CB, void *pParam);
+
 // 初始化总线
 // 初始化总线
 int luat_spi_bus_setup(luat_spi_device_t* spi_dev);
 int luat_spi_bus_setup(luat_spi_device_t* spi_dev);
 // 初始化设备
 // 初始化设备

+ 26 - 0
luat/modules/luat_irq.c

@@ -27,3 +27,29 @@ int luat_irq_uart_cb(int id, void* args) {
 
 
 int luat_irq_spi_cb(int id);
 int luat_irq_spi_cb(int id);
 
 
+static int luat_irq_topic_cb_handler(lua_State *L, void* ptr) {
+    rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
+    lua_getglobal(L, "sys_pub");
+    if (lua_isfunction(L, -1)) {
+        lua_pushstring(L, msg->ptr);
+        lua_pushinteger(L, msg->arg1);
+        lua_pushboolean(L, !msg->arg2);
+        lua_pushinteger(L, msg->arg2);
+        lua_call(L, 4, 0);
+    }
+    luat_heap_free(msg->ptr);
+    return 0;
+}
+
+//pdata 为 result << 16 | device_id, result 为0 则表示成功,其他失败
+//param 为回调topic
+int32_t luat_irq_hardware_cb_handler(void *pdata, void *param)
+{
+    rtos_msg_t msg;
+    msg.handler = luat_irq_topic_cb_handler;
+    msg.ptr = param;
+    msg.arg1 = (uint32_t)pdata & 0x0000ffff;
+    msg.arg2 = !((uint32_t)pdata >> 16);
+    luat_msgbus_put(&msg, 0);
+    return 0;
+}

+ 69 - 1
luat/modules/luat_lib_i2c.c

@@ -13,6 +13,7 @@
 #include "luat_i2c.h"
 #include "luat_i2c.h"
 #include "luat_gpio.h"
 #include "luat_gpio.h"
 #include "luat_zbuff.h"
 #include "luat_zbuff.h"
+#include "luat_irq.h"
 #define LUAT_LOG_TAG "i2c"
 #define LUAT_LOG_TAG "i2c"
 #include "luat_log.h"
 #include "luat_log.h"
 
 
@@ -659,6 +660,11 @@ int LUAT_WEAK luat_i2c_transfer(int id, int addr, uint8_t *reg, size_t reg_len,
     return luat_i2c_recv(id, addr, buff, len);
     return luat_i2c_recv(id, addr, buff, len);
 }
 }
 
 
+int LUAT_WEAK 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;
+}
+
 /**
 /**
 i2c通用传输,包括发送N字节,发送N字节+接收N字节,接收N字节三种功能,在发送转接收过程中发送reStart信号,解决类似mlx90614必须带restart信号,但是又不能用i2c.send来控制的,比如air105
 i2c通用传输,包括发送N字节,发送N字节+接收N字节,接收N字节三种功能,在发送转接收过程中发送reStart信号,解决类似mlx90614必须带restart信号,但是又不能用i2c.send来控制的,比如air105
 @api i2c.transfer(id, addr, txBuff, rxBuff, rxLen)
 @api i2c.transfer(id, addr, txBuff, rxBuff, rxLen)
@@ -681,7 +687,7 @@ static int l_i2c_transfer(lua_State *L)
 	int addr = luaL_checkinteger(L, 2);
 	int addr = luaL_checkinteger(L, 2);
 	size_t tx_len = 0;
 	size_t tx_len = 0;
 	size_t rx_len = 0;
 	size_t rx_len = 0;
-	int result = 0;
+	int result = -1;
 	uint8_t temp[1];
 	uint8_t temp[1];
 	uint8_t *tx_buff = NULL;
 	uint8_t *tx_buff = NULL;
 	uint8_t *rx_buff = NULL;
 	uint8_t *rx_buff = NULL;
@@ -764,6 +770,67 @@ static int l_i2c_transfer(lua_State *L)
 
 
 }
 }
 
 
+/**
+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);
+
+	uint32_t timeout = luaL_optinteger(L, 7, 100);
+	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;
+	if (lua_isnil(L, 3)) {
+		tx_len = 0;
+	}
+	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_isinteger(L, 5) && rbuff) {
+		rx_len = luaL_checkinteger(L, 5);
+		rx_buff = rbuff->addr;
+	}
+
+	int id = 0;
+	if (!lua_isuserdata(L, 1)) {
+		id = luaL_checkinteger(L, 1);
+		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;
+
+}
+
 #include "rotable2.h"
 #include "rotable2.h"
 static const rotable_Reg_t reg_i2c[] =
 static const rotable_Reg_t reg_i2c[] =
 {
 {
@@ -784,6 +851,7 @@ static const rotable_Reg_t reg_i2c[] =
     { "readDHT12",  ROREG_FUNC(l_i2c_readDHT12)},
     { "readDHT12",  ROREG_FUNC(l_i2c_readDHT12)},
     { "readSHT30",  ROREG_FUNC(l_i2c_readSHT30)},
     { "readSHT30",  ROREG_FUNC(l_i2c_readSHT30)},
 
 
+	{ "xfer",	ROREG_FUNC(l_i2c_no_block_transfer)},
     { "FAST",       ROREG_INT(1)},
     { "FAST",       ROREG_INT(1)},
     { "SLOW",       ROREG_INT(0)},
     { "SLOW",       ROREG_INT(0)},
 	{ NULL,         ROREG_INT(0) }
 	{ NULL,         ROREG_INT(0) }

+ 59 - 2
luat/modules/luat_lib_spi.c

@@ -15,7 +15,7 @@
 #include "luat_spi.h"
 #include "luat_spi.h"
 #include "luat_zbuff.h"
 #include "luat_zbuff.h"
 #include "luat_gpio.h"
 #include "luat_gpio.h"
-
+#include "luat_irq.h"
 #define LUAT_LOG_TAG "spi"
 #define LUAT_LOG_TAG "spi"
 
 
 #define META_SPI "SPI*"
 #define META_SPI "SPI*"
@@ -605,6 +605,63 @@ void luat_soft_spi_struct_init(lua_State *L) {
     lua_pop(L, 1);
     lua_pop(L, 1);
 }
 }
 
 
+
+int LUAT_WEAK luat_spi_no_block_transfer(int id, uint8_t *tx_buff, uint8_t *rx_buff, size_t len, void *CB, void *pParam)
+{
+    return -1;
+}
+
+/**
+非阻塞方式硬件SPI传输SPI数据,目的为了提高核心利用率。API直接返回是否启动传输,传输完成后通过topic回调,本API适合硬件SPI传输大量数据传输,外设功能(LCD SPI,W5500 SPI之类的)占据的SPI和软件SPI不能用,少量数据传输建议使用传统阻塞型API
+@api spi.xfer(id, txbuff, rxbuff, rx_len, transfer_done_topic)
+@userdata or int spi_device或者spi_id,注意,如果是spi_device,需要手动在传输完成后拉高cs!!!!!!
+@zbuff 待发送的数据,如果为nil,则只接收数据,由于用的非阻塞模型,为保证动态数据的有效性,只能使用zbuff,发送的数据从zbuff.addr
+@zbuff 接收数据,如果为nil,则只发送数据,由于用的非阻塞模型,为保证动态数据的有效性,只能使用zbuff,接收的数据从zbuff.addr开始存储
+@int 传输数据长度,特别说明 如果为半双工,先发后收,比如spi flash操作这种,则长度=发送字节+接收字节,注意上面发送和接收buff都要留足够的数据,后续接收数据处理需要跳过发送数据长度字节
+@string 传输完成后回调的topic
+@return boolean true/false 本次传输是否正确启动,true,启动,false,有错误无法启动。传输完成会发布消息transfer_done_topic和boolean型结果
+@usage
+local result = spi.xfer(spi.SPI_0, txbuff, rxbuff, 1024, "SPIDONE") if result then result, spi_id, succ, error_code = sys.waitUntil("SPIDONE") end if not result or not succ then log.info("spi fail, error code", error_code) else log.info("spi ok") end
+
+*/
+static int l_spi_no_block_transfer(lua_State *L)
+{
+	size_t topic_len = 0;
+	const char *topic = luaL_checklstring(L, 5, &topic_len);
+	size_t len = luaL_optinteger(L, 4, 0);
+
+	int result = -1;
+	uint8_t *tx_buff = NULL;
+	uint8_t *rx_buff = NULL;
+	luat_zbuff_t *txbuff = ((luat_zbuff_t *)luaL_testudata(L, 2, LUAT_ZBUFF_TYPE));
+	luat_zbuff_t *rxbuff = ((luat_zbuff_t *)luaL_testudata(L, 3, LUAT_ZBUFF_TYPE));
+	if ((!txbuff && !rxbuff) || !len) {
+		lua_pushboolean(L, 0);
+		return 1;
+	}
+	if (txbuff) tx_buff = txbuff->addr;
+	if (rxbuff) rx_buff = rxbuff->addr;
+
+	char *cb_topic = luat_heap_malloc(topic_len + 1);
+	memcpy(cb_topic, topic, topic_len);
+	cb_topic[topic_len] = 0;
+
+    if (lua_isinteger(L, 1)) {
+        int id = luaL_checkinteger(L, 1);
+        result = luat_spi_no_block_transfer(id, tx_buff, rx_buff, len, luat_irq_hardware_cb_handler, cb_topic);
+    }
+    else {
+    	luat_spi_device_t* spi_dev = (luat_spi_device_t*)lua_touserdata(L, 1);
+    	luat_spi_device_config(spi_dev);
+    	luat_gpio_set(spi_dev->spi_config.cs, 0);
+    	result = luat_spi_no_block_transfer(spi_dev->bus_id, tx_buff, rx_buff, len, luat_irq_hardware_cb_handler, cb_topic);
+    }
+    if (result) {
+    	luat_heap_free(cb_topic);
+    }
+	lua_pushboolean(L, !result);
+	return 1;
+}
 //------------------------------------------------------------------
 //------------------------------------------------------------------
 #include "rotable2.h"
 #include "rotable2.h"
 static const rotable_Reg_t reg_spi[] =
 static const rotable_Reg_t reg_spi[] =
@@ -618,7 +675,7 @@ static const rotable_Reg_t reg_spi[] =
     { "deviceSetup",      ROREG_FUNC(l_spi_device_setup)},
     { "deviceSetup",      ROREG_FUNC(l_spi_device_setup)},
     { "deviceTransfer",   ROREG_FUNC(l_spi_device_transfer)},
     { "deviceTransfer",   ROREG_FUNC(l_spi_device_transfer)},
     { "deviceSend",       ROREG_FUNC(l_spi_device_send)},
     { "deviceSend",       ROREG_FUNC(l_spi_device_send)},
-    
+	{ "xfer",   		  ROREG_FUNC(l_spi_no_block_transfer)},
     { "MSB",               ROREG_INT(1)},
     { "MSB",               ROREG_INT(1)},
     { "LSB",               ROREG_INT(0)},
     { "LSB",               ROREG_INT(0)},
     { "master",            ROREG_INT(1)},
     { "master",            ROREG_INT(1)},