Closed wendal closed 4 years ago
硬件: w60x, Lua虚拟机专属内存64k
上述代码在uart数据量小的时候正常.
以300字节每次, 100ms为间隔, 即可触发异常,提示无法not enough memory for buffer allocation
异常所致代码在 lauxlib.c
static void *resizebox (lua_State *L, int idx, size_t newsize) {
void *ud;
lua_Alloc allocf = lua_getallocf(L, &ud);
UBox *box = (UBox *)lua_touserdata(L, idx);
void *temp = allocf(ud, box->box, box->bsize, newsize);
if (temp == NULL && newsize > 0) { /* allocation error? */
lua_gc(L, LUA_GCCOLLECT, 0);
}
if (temp == NULL && newsize > 0) { /* allocation error? */
resizebox(L, idx, 0); /* free buffer */
luaL_error(L, "not enough memory for buffer allocation");
}
box->box = temp;
box->bsize = newsize;
return temp;
}
代码的风格是LuaTask 2.x, 即合宙Air202/Air80x/Air72x的Luat的写法.
从语法和代码逻辑上看, 是合法的代码:
有uart数据进入事,压入缓存队列, 发布消息 监听消息, 将缓存队列合并为字符串, 写入uart
luat_uart_rtt的当前实现是这样的:
其中一个已知限制(或者叫问题), 如果uart有大量数据输入, 不断触发uart中断, lua线程无法启动, 最终消息队列塞满. 直至uart数据输入减慢, lua线程才有机会复活.
对原始代码的改造:
function(uid, length)
--table.insert(recvBuff[uid], uart.read(uid, length or 1024))
--sys.timerStart(sys.publish, 50, 'UART_RECV_WAIT_', uid)
uart.write(uid, uart.read(uid, length or 1024))
end
读取数据并马上回写, 能在原报错条件下正常运行.
还有个地方是
local function read(uid)
local s = table.concat(recvBuff[uid])
recvBuff[uid] = {}
uart.write(uartid,s)
end
写入1kb数据, 会起码使用2kb的内存. 这写法在Air202/Air72x系列是没问题的, 它们内存都在1mb以上, 有足够的内存空间, 但对于w60x来说就是太奢侈的写法.
还有一个疑惑, 如果能支持 uart.write(uartid, recvBuff[uid])
即uart.write直接传入table, 也许能解决, 待验证.
测试中还发现一个问题,如果一次发送数据超过1k,间隔过小会出现抛出总线异常。看代码好像是串口回调导致的。一会贴详情。
发送1k数据,间隔300ms会出现如下警告,系统会陷入假死,过一段时间重启
W/luat.msgbus: msgbus is FULL!!!! W/luat.msgbus: msgbus is FULL!!!! W/UART: Warning: There is no enough buffer for saving data, please increase the RT_SERIAL_RB_BUFSZ option. W/luat.msgbus: msgbus is FULL!!!!
看来得改成缓存区才行
原因有两个:
先把原始代码贴上