luat_lib_gpio.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /*
  2. @module gpio
  3. @summary GPIO操作
  4. @catalog 外设API
  5. @version 1.0
  6. @date 2020.03.30
  7. @demo gpio
  8. @video https://www.bilibili.com/video/BV1hr4y1p7dt
  9. @tag LUAT_USE_GPIO
  10. */
  11. #include "luat_base.h"
  12. #include "luat_gpio.h"
  13. #include "luat_malloc.h"
  14. #include "luat_mcu.h"
  15. #include "luat_msgbus.h"
  16. #include <math.h>
  17. #define LUAT_LOG_TAG "gpio"
  18. #include "luat_log.h"
  19. // 若bsp没有定义最大PIN编号, 那么默认给个128吧
  20. #ifndef LUAT_GPIO_PIN_MAX
  21. #define LUAT_GPIO_PIN_MAX (128)
  22. #endif
  23. static int l_gpio_set(lua_State *L);
  24. static int l_gpio_get(lua_State *L);
  25. static int l_gpio_close(lua_State *L);
  26. int l_gpio_handler(lua_State *L, void* ptr) ;
  27. typedef struct gpio_ctx
  28. {
  29. int lua_ref; // irq下的回调函数
  30. uint32_t latest_tick; // 防抖功能的最后tick数
  31. uint16_t conf_tick; // 防抖设置的超时tick数
  32. }gpio_ctx_t;
  33. // 保存中断回调的数组
  34. static gpio_ctx_t gpios[LUAT_GPIO_PIN_MAX] __attribute__((aligned (16)));
  35. static uint32_t default_gpio_pull = Luat_GPIO_DEFAULT;
  36. // 记录GPIO电平,仅OUTPUT时可用
  37. static uint8_t gpio_out_levels[LUAT_GPIO_PIN_MAX / 8] __attribute__((aligned (16)));
  38. static uint8_t gpio_bit_get(int pin) {
  39. if (pin < 0 || pin >= LUAT_GPIO_PIN_MAX)
  40. return 0;
  41. return (gpio_out_levels[pin/8] >> (pin%8)) & 0x01;
  42. }
  43. static void gpio_bit_set(int pin, uint8_t value) {
  44. if (pin < 0 || pin >= LUAT_GPIO_PIN_MAX)
  45. return;
  46. uint8_t val = (gpio_out_levels[pin/8] >> (pin%8)) & 0x01;
  47. if (val == value)
  48. return; // 不变呀
  49. if (value == 0) {
  50. gpio_out_levels[pin/8] -= (1 << (pin%8));
  51. }
  52. else {
  53. gpio_out_levels[pin/8] += (1 << (pin%8));
  54. }
  55. }
  56. int luat_gpio_irq_default(int pin, void* args) {
  57. rtos_msg_t msg = {0};
  58. if (pin < 0 || pin >= Luat_GPIO_MAX_ID) {
  59. return 0;
  60. }
  61. if (pin < LUAT_GPIO_PIN_MAX && gpios[pin].conf_tick > 0) {
  62. uint32_t ticks = (uint32_t)luat_mcu_ticks();
  63. uint32_t diff = (ticks > gpios[pin].latest_tick) ? (ticks - gpios[pin].latest_tick) : (gpios[pin].latest_tick - ticks);
  64. if (diff >= gpios[pin].conf_tick) {
  65. gpios[pin].latest_tick = ticks;
  66. }
  67. else {
  68. // 防抖生效, 直接返回
  69. return 0;
  70. }
  71. }
  72. msg.handler = l_gpio_handler;
  73. msg.ptr = NULL;
  74. msg.arg1 = pin;
  75. msg.arg2 = (int)args;
  76. return luat_msgbus_put(&msg, 0);
  77. }
  78. int l_gpio_handler(lua_State *L, void* ptr) {
  79. // 给 sys.publish方法发送数据
  80. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  81. int pin = msg->arg1;
  82. if (pin < 0 || pin >= LUAT_GPIO_PIN_MAX)
  83. return 0;
  84. if (gpios[pin].lua_ref == 0)
  85. return 0;
  86. lua_geti(L, LUA_REGISTRYINDEX, gpios[pin].lua_ref);
  87. if (!lua_isnil(L, -1)) {
  88. lua_pushinteger(L, msg->arg2);
  89. lua_call(L, 1, 0);
  90. }
  91. return 0;
  92. }
  93. /*
  94. 设置管脚功能
  95. @api gpio.setup(pin, mode, pull, irq)
  96. @int pin 针脚编号,必须是数值
  97. @any mode 输入输出模式:<br>数字0/1代表输出模式<br>nil代表输入模式<br>function代表中断模式
  98. @int pull 上拉下列模式, 可以是gpio.PULLUP 或 gpio.PULLDOWN, 需要根据实际硬件选用
  99. @int irq 默认gpio.BOTH。中断触发模式<br>上升沿gpio.RISING<br>下降沿gpio.FALLING<br>上升和下降都要gpio.BOTH
  100. @return any 输出模式返回设置电平的闭包, 输入模式和中断模式返回获取电平的闭包
  101. @usage
  102. -- 设置gpio17为输入
  103. gpio.setup(17, nil)
  104. -- 设置gpio17为输出
  105. gpio.setup(17, 0)
  106. -- 设置gpio27为中断
  107. gpio.setup(27, function(val) print("IRQ_27",val) end, gpio.PULLUP)
  108. */
  109. static int l_gpio_setup(lua_State *L) {
  110. luat_gpio_t conf;
  111. conf.pin = luaL_checkinteger(L, 1);
  112. //conf->mode = luaL_checkinteger(L, 2);
  113. conf.lua_ref = 0;
  114. conf.irq = 0;
  115. if (lua_isfunction(L, 2)) {
  116. conf.mode = Luat_GPIO_IRQ;
  117. lua_pushvalue(L, 2);
  118. conf.lua_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  119. conf.irq = luaL_optinteger(L, 4, Luat_GPIO_BOTH);
  120. }
  121. else if (lua_isinteger(L, 2)) {
  122. conf.mode = Luat_GPIO_OUTPUT;
  123. conf.irq = luaL_checkinteger(L, 2) == 0 ? 0 : 1; // 重用irq当初始值用
  124. }
  125. else {
  126. conf.mode = Luat_GPIO_INPUT;
  127. }
  128. conf.pull = luaL_optinteger(L, 3, default_gpio_pull);
  129. conf.irq_cb = 0;
  130. int re = luat_gpio_setup(&conf);
  131. if (re != 0) {
  132. LLOGW("gpio setup fail pin=%d", conf.pin);
  133. return 0;
  134. }
  135. if (conf.mode == Luat_GPIO_IRQ) {
  136. if (gpios[conf.pin].lua_ref && gpios[conf.pin].lua_ref != conf.lua_ref) {
  137. luaL_unref(L, LUA_REGISTRYINDEX, gpios[conf.pin].lua_ref);
  138. gpios[conf.pin].lua_ref = conf.lua_ref;
  139. }
  140. gpios[conf.pin].lua_ref = conf.lua_ref;
  141. }
  142. else if (conf.mode == Luat_GPIO_OUTPUT) {
  143. luat_gpio_set(conf.pin, conf.irq); // irq被重用为OUTPUT的初始值
  144. }
  145. // 生成闭包
  146. lua_settop(L, 1);
  147. if (conf.mode == Luat_GPIO_OUTPUT) {
  148. lua_pushcclosure(L, l_gpio_set, 1);
  149. }
  150. else {
  151. lua_pushcclosure(L, l_gpio_get, 1);
  152. }
  153. return 1;
  154. }
  155. /*
  156. 设置管脚电平
  157. @api gpio.set(pin, value)
  158. @int pin 针脚编号,必须是数值
  159. @int value 电平, 可以是 高电平gpio.HIGH, 低电平gpio.LOW, 或者直接写数值1或0
  160. @return nil 无返回值
  161. @usage
  162. -- 设置gpio17为低电平
  163. gpio.set(17, 0)
  164. */
  165. static int l_gpio_set(lua_State *L) {
  166. int pin = 0;
  167. int value = 0;
  168. if (lua_isinteger(L, lua_upvalueindex(1))) {
  169. pin = lua_tointeger(L, lua_upvalueindex(1));
  170. value = luaL_checkinteger(L, 1);
  171. }
  172. else {
  173. pin = luaL_checkinteger(L, 1);
  174. value = luaL_checkinteger(L, 2);
  175. }
  176. luat_gpio_set(pin, value);
  177. gpio_bit_set(pin, (uint8_t)value);
  178. return 0;
  179. }
  180. /*
  181. 获取管脚电平
  182. @api gpio.get(pin)
  183. @int pin 针脚编号,必须是数值
  184. @return value 电平, 高电平gpio.HIGH, 低电平gpio.LOW, 对应数值1和0
  185. @usage
  186. -- 获取gpio17的当前电平
  187. gpio.get(17)
  188. */
  189. static int l_gpio_get(lua_State *L) {
  190. if (lua_isinteger(L, lua_upvalueindex(1)))
  191. lua_pushinteger(L, luat_gpio_get(luaL_checkinteger(L, lua_upvalueindex(1))) & 0x01 ? 1 : 0);
  192. else
  193. lua_pushinteger(L, luat_gpio_get(luaL_checkinteger(L, 1)) & 0x01 ? 1 : 0);
  194. return 1;
  195. }
  196. /*
  197. 关闭管脚功能(高阻输入态),关掉中断
  198. @api gpio.close(pin)
  199. @int pin 针脚编号,必须是数值
  200. @return nil 无返回值,总是执行成功
  201. @usage
  202. -- 关闭gpio17
  203. gpio.close(17)
  204. */
  205. static int l_gpio_close(lua_State *L) {
  206. int pin = luaL_checkinteger(L, 1);
  207. if (pin < 0 || pin >= LUAT_GPIO_PIN_MAX)
  208. return 0;
  209. luat_gpio_close(pin);
  210. if (gpios[pin].lua_ref) {
  211. luaL_unref(L, LUA_REGISTRYINDEX, gpios[pin].lua_ref);
  212. gpios[pin].lua_ref = 0;
  213. }
  214. return 0;
  215. }
  216. /*
  217. 设置GPIO脚的默认上拉/下拉设置, 默认是平台自定义(一般为开漏).
  218. @api gpio.setDefaultPull(val)
  219. @int val 0平台自定义,1上拉, 2下拉
  220. @return boolean 传值正确返回true,否则返回false
  221. @usage
  222. -- 设置gpio.setup的pull默认值为上拉
  223. gpio.setDefaultPull(1)
  224. */
  225. static int l_gpio_set_default_pull(lua_State *L) {
  226. int value = luaL_checkinteger(L, 1);
  227. if (value >= 0 && value <= 2) {
  228. default_gpio_pull = value;
  229. lua_pushboolean(L, 1);
  230. }
  231. else {
  232. lua_pushboolean(L, 0);
  233. }
  234. return 1;
  235. }
  236. /*
  237. 变换GPIO脚输出电平,仅输出模式可用
  238. @api gpio.toggle(pin)
  239. @int 管脚的GPIO号
  240. @return nil 无返回值
  241. @usage
  242. -- 本API于 2022.05.17 添加
  243. -- 假设GPIO16上有LED, 每500ms切换一次开关
  244. gpio.setup(16, 0)
  245. sys.timerLoopStart(function()
  246. gpio.toggle(16)
  247. end, 500)
  248. */
  249. static int l_gpio_toggle(lua_State *L) {
  250. int pin = 0;
  251. if (lua_isinteger(L, lua_upvalueindex(1)))
  252. pin = lua_tointeger(L, lua_upvalueindex(1));
  253. else
  254. pin = luaL_checkinteger(L, 1);
  255. if (pin < 0 || pin >= LUAT_GPIO_PIN_MAX) {
  256. LLOGW("pin id out of range (0-127)");
  257. return 0;
  258. }
  259. uint8_t value = gpio_bit_get(pin);
  260. luat_gpio_set(pin, value == 0 ? Luat_GPIO_HIGH : Luat_GPIO_LOW);
  261. gpio_bit_set(pin, value == 0 ? 1 : 0);
  262. return 0;
  263. }
  264. /*
  265. 在同一个GPIO输出一组脉冲, 注意, len的单位是bit, 高位在前.
  266. @api gpio.pulse(pin,level,len,delay)
  267. @int gpio号
  268. @int/string 数值或者字符串.
  269. @int len 长度 单位是bit, 高位在前.
  270. @int delay 延迟,当前无固定时间单位
  271. @return nil 无返回值
  272. @usage
  273. -- 通过PB06脚输出输出8个电平变化.
  274. gpio.pulse(pin.PB06,0xA9, 8, 0)
  275. */
  276. static int l_gpio_pulse(lua_State *L) {
  277. int pin,delay = 0;
  278. char tmp;
  279. size_t len;
  280. char* level = NULL;
  281. if (lua_isinteger(L, lua_upvalueindex(1))){
  282. pin = lua_tointeger(L, lua_upvalueindex(1));
  283. if (lua_isinteger(L, 1)){
  284. tmp = (char)luaL_checkinteger(L, 1);
  285. level = &tmp;
  286. }else if (lua_isstring(L, 1)){
  287. level = (char*)luaL_checklstring(L, 1, &len);
  288. }
  289. len = luaL_checkinteger(L, 2);
  290. delay = luaL_checkinteger(L, 3);
  291. }else{
  292. pin = luaL_checkinteger(L, 1);
  293. if (lua_isinteger(L, 2)){
  294. tmp = (char)luaL_checkinteger(L, 2);
  295. level = &tmp;
  296. }else if (lua_isstring(L, 2)){
  297. level = (char*)luaL_checklstring(L, 2, &len);
  298. }
  299. len = luaL_checkinteger(L, 3);
  300. delay = luaL_checkinteger(L, 4);
  301. }
  302. if (pin < 0 || pin >= LUAT_GPIO_PIN_MAX) {
  303. LLOGD("pin id out of range (0-127)");
  304. return 0;
  305. }
  306. luat_gpio_pulse(pin,(uint8_t*)level,len,delay);
  307. return 0;
  308. }
  309. /*
  310. 防抖设置, 根据硬件ticks进行防抖
  311. @api gpio.debounce(pin, ms)
  312. @int gpio号, 0~127, 与硬件相关
  313. @int 防抖时长,单位毫秒, 最大 65555 ms, 设置为0则关闭
  314. @return nil 无返回值
  315. @usage
  316. -- 本API与2022.06.22可用
  317. -- 开启防抖
  318. gpio.debounce(7, 100) -- 若芯片执行pin库, 可用pin.PA7代替数字7
  319. -- 关闭防抖
  320. gpio.debounce(7, 0)
  321. */
  322. static int l_gpio_debounce(lua_State *L) {
  323. uint8_t pin = luaL_checkinteger(L, 1);
  324. uint16_t time = luaL_checkinteger(L, 2);
  325. if (pin >= LUAT_GPIO_PIN_MAX) {
  326. LLOGW("MUST pin < 128");
  327. return 0;
  328. }
  329. gpios[pin].conf_tick = time;
  330. gpios[pin].latest_tick = 0;
  331. return 0;
  332. }
  333. #include "rotable2.h"
  334. static const rotable_Reg_t reg_gpio[] =
  335. {
  336. { "setup" , ROREG_FUNC(l_gpio_setup )},
  337. { "set" , ROREG_FUNC(l_gpio_set)},
  338. { "get" , ROREG_FUNC(l_gpio_get)},
  339. { "close" , ROREG_FUNC(l_gpio_close)},
  340. { "toggle", ROREG_FUNC(l_gpio_toggle)},
  341. { "debounce", ROREG_FUNC(l_gpio_debounce)},
  342. { "pulse", ROREG_FUNC(l_gpio_pulse)},
  343. { "setDefaultPull", ROREG_FUNC(l_gpio_set_default_pull)},
  344. //@const LOW number 低电平
  345. { "LOW", ROREG_INT(Luat_GPIO_LOW)},
  346. //@const HIGH number 高电平
  347. { "HIGH", ROREG_INT(Luat_GPIO_HIGH)},
  348. //@const OUTPUT number 输出模式
  349. { "OUTPUT", ROREG_INT(Luat_GPIO_OUTPUT)},
  350. //@const INPUT number 输入模式
  351. { "INPUT", ROREG_INT(Luat_GPIO_INPUT)},
  352. //@const IRQ number 中断模式
  353. { "IRQ", ROREG_INT(Luat_GPIO_IRQ)},
  354. //@const PULLUP number 上拉
  355. { "PULLUP", ROREG_INT(Luat_GPIO_PULLUP)},
  356. //@const PULLDOWN number 下拉
  357. { "PULLDOWN", ROREG_INT(Luat_GPIO_PULLDOWN)},
  358. //@const RISING number 上升沿触发
  359. { "RISING", ROREG_INT(Luat_GPIO_RISING)},
  360. //@const FALLING number 下降沿触发
  361. { "FALLING", ROREG_INT(Luat_GPIO_FALLING)},
  362. //@const BOTH number 双向触发,部分设备支持
  363. { "BOTH", ROREG_INT(Luat_GPIO_BOTH)},
  364. //@const HIGH_IRQ number 高电平触发,部分设备支持
  365. { "HIGH_IRQ", ROREG_INT(Luat_GPIO_HIGH_IRQ)},
  366. //@const LOW_IRQ number 低电平触发,部分设备支持
  367. { "LOW_IRQ", ROREG_INT(Luat_GPIO_LOW_IRQ)},
  368. { NULL, ROREG_INT(0) }
  369. };
  370. LUAMOD_API int luaopen_gpio( lua_State *L ) {
  371. memset(gpios, 0, sizeof(gpio_ctx_t) * LUAT_GPIO_PIN_MAX);
  372. luat_newlib2(L, reg_gpio);
  373. return 1;
  374. }
  375. // -------------------- 一些辅助函数
  376. void luat_gpio_mode(int pin, int mode, int pull, int initOutput) {
  377. if (pin == 255) return;
  378. luat_gpio_t conf = {0};
  379. conf.pin = pin;
  380. conf.mode = mode == Luat_GPIO_INPUT ? Luat_GPIO_INPUT : Luat_GPIO_OUTPUT; // 只能是输入/输出, 不能是中断.
  381. conf.pull = pull;
  382. conf.irq = initOutput;
  383. conf.lua_ref = 0;
  384. conf.irq_cb = 0;
  385. luat_gpio_setup(&conf);
  386. if (conf.mode == Luat_GPIO_OUTPUT)
  387. luat_gpio_set(pin, initOutput);
  388. }
  389. #ifndef LUAT_COMPILER_NOWEAK
  390. void LUAT_WEAK luat_gpio_pulse(int pin, uint8_t *level, uint16_t len, uint16_t delay_ns) {
  391. }
  392. #endif