luat_lib_mcu.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. @module mcu
  3. @summary 封装mcu一些特殊操作
  4. @version core V0007
  5. @date 2021.08.18
  6. @tag LUAT_USE_MCU
  7. */
  8. #include "luat_base.h"
  9. #include "luat_mcu.h"
  10. #include "luat_zbuff.h"
  11. #include "luat_spi.h"
  12. #define LUAT_LOG_TAG "mcu"
  13. #include "luat_log.h"
  14. /*
  15. 设置主频,单位MHZ
  16. @api mcu.setClk(mhz)
  17. @int 主频,根据设备的不同有不同的有效值,请查阅手册
  18. @return bool 成功返回true,否则返回false
  19. @usage
  20. -- 请注意,主频与外设主频有关联性, 例如主频2M时SPI的最高只能1M
  21. -- 设置到80MHZ
  22. mcu.setClk(80)
  23. sys.wait(1000)
  24. -- 设置到240MHZ
  25. mcu.setClk(240)
  26. sys.wait(1000)
  27. -- 设置到2MHZ
  28. mcu.setClk(2)
  29. sys.wait(1000)
  30. */
  31. static int l_mcu_set_clk(lua_State* L) {
  32. int ret = luat_mcu_set_clk((size_t)luaL_checkinteger(L, 1));
  33. lua_pushboolean(L, ret == 0 ? 1 : 0);
  34. return 1;
  35. }
  36. /*
  37. 获取主频,单位MHZ
  38. @api mcu.getClk()
  39. @return int 若失败返回-1,否则返回主频数值,若等于0,可能处于32k晶振的省电模式
  40. @usage
  41. local mhz = mcu.getClk()
  42. print("Boom", mhz)
  43. */
  44. static int l_mcu_get_clk(lua_State* L) {
  45. int mhz = luat_mcu_get_clk();
  46. lua_pushinteger(L, mhz);
  47. return 1;
  48. }
  49. /*
  50. 获取设备唯一id. 注意,可能包含不可见字符,如需查看建议toHex()后打印
  51. @api mcu.unique_id()
  52. @return string 设备唯一id.若不支持, 会返回空字符串.
  53. @usage
  54. local unique_id = mcu.unique_id()
  55. print("unique_id", unique_id)
  56. */
  57. static int l_mcu_unique_id(lua_State* L) {
  58. size_t len = 0;
  59. const char* id = luat_mcu_unique_id(&len);
  60. lua_pushlstring(L, id, len);
  61. return 1;
  62. }
  63. /*
  64. 获取启动后的tick数,注意会出现溢出会出现负数
  65. @api mcu.ticks()
  66. @return int 当前tick值
  67. @usage
  68. local tick = mcu.ticks()
  69. print("ticks", tick)
  70. */
  71. static int l_mcu_ticks(lua_State* L) {
  72. long tick = luat_mcu_ticks();
  73. lua_pushinteger(L, tick);
  74. return 1;
  75. }
  76. /*
  77. 获取每秒的tick数量
  78. @api mcu.hz()
  79. @return int 每秒的tick数量,通常为1000
  80. @usage
  81. local hz = mcu.hz()
  82. print("mcu.hz", hz)
  83. */
  84. static int l_mcu_hz(lua_State* L) {
  85. uint32_t hz = luat_mcu_hz();
  86. lua_pushinteger(L, hz);
  87. return 1;
  88. }
  89. /*
  90. 读写mcu的32bit寄存器或者ram,谨慎使用写功能,请熟悉mcu的寄存器使用方法后再使用
  91. @api mcu.reg32(address, value, mask)
  92. @int 寄存器或者ram地址
  93. @int 写入的值,如果没有,则直接返回当前值
  94. @int 位掩码,可以对特定几个位置的bit做修改, 默认0xffffffff,修改全部32bit
  95. @return int 返回当前寄存的值
  96. @usage
  97. local value = mcu.reg32(0x2009FFFC, 0x01, 0x01) --对0x2009FFFC地址上的值,修改bit0为1
  98. */
  99. static int l_mcu_reg32(lua_State* L) {
  100. volatile uint32_t *address = (uint32_t *)(luaL_checkinteger(L, 1) & 0xfffffffc);
  101. if (lua_isinteger(L, 2)) {
  102. volatile uint32_t value = lua_tointeger(L, 2);
  103. volatile uint32_t mask = luaL_optinteger(L, 3, 0xffffffff);
  104. volatile uint32_t org = *address;
  105. *address = (org & ~mask)| (value & mask);
  106. lua_pushinteger(L, *address);
  107. } else {
  108. lua_pushinteger(L, *address);
  109. }
  110. return 1;
  111. }
  112. /*
  113. 转换10进制数为16进制字符串输出
  114. @api mcu.x32(value)
  115. @int 需要转换的值
  116. @return string 16进制字符串
  117. @usage
  118. local value = mcu.x32(0x2009FFFC) --输出"0x2009fffc"
  119. */
  120. static int l_mcu_x32(lua_State* L) {
  121. uint32_t value = luaL_checkinteger(L, 1);
  122. char c[16];
  123. sprintf_(c, "0x%x", value);
  124. lua_pushstring(L, c);
  125. return 1;
  126. }
  127. // #ifdef __LUATOS_TICK_64BIT__
  128. /*
  129. 获取启动后的高精度tick,如果支持bit64库,可以直接输出转换好的bit64结构
  130. @api mcu.tick64()
  131. @boolean 是否输出bit64结构,true是,其他都是false,留空也是false,用于兼容旧的demo
  132. @return string 当前tick值,8个字节的uint64,如果支持64bit库,同时要求输出64bit结构的话,会输出9字节的string
  133. @return int 1us有几个tick,0表示未知
  134. @usage
  135. local tick_str, tick_per = mcu.tick64()
  136. print("ticks", tick_str, tick_per)
  137. */
  138. static int l_mcu_hw_tick64(lua_State* L) {
  139. uint64_t tick = luat_mcu_tick64();
  140. uint32_t us_period = luat_mcu_us_period();
  141. #ifdef LUAT_USE_BIT64
  142. if (lua_isboolean(L, 1) && lua_toboolean(L, 1))
  143. {
  144. uint8_t data[9] = {0};
  145. memcpy(data, &tick, 8);
  146. lua_pushlstring(L, (const char*)data, 9);
  147. }
  148. else
  149. {
  150. lua_pushlstring(L, (const char*)&tick, 8);
  151. }
  152. #else
  153. lua_pushlstring(L, (const char*)&tick, 8);
  154. #endif
  155. lua_pushinteger(L, us_period);
  156. return 2;
  157. }
  158. /*
  159. 计算2个64bit tick的差值
  160. @api mcu.dtick64(tick1, tick2, check_value)
  161. @string 64bit的string
  162. @string 64bit的string
  163. @int 参考值,可选项,如果为0,则返回结果中第一个项目为true
  164. @return boolean 与参考值比较,如果大于等于为true,反之为false
  165. @return int 差值tick1 - tick2,如果超过了0x7fffffff,结果可能是错的
  166. @usage
  167. local result, diff_tick = mcu.dtick64(tick1, tick2)
  168. print("ticks", result, diff_tick)
  169. */
  170. static int l_mcu_hw_diff_tick64(lua_State* L) {
  171. uint64_t tick1, tick2;
  172. int64_t diff;
  173. int check_value = 0;
  174. size_t len1;
  175. const char *data1 = luaL_checklstring(L, 1, &len1);
  176. size_t len2;
  177. const char *data2 = luaL_checklstring(L, 2, &len2);
  178. check_value = luaL_optinteger(L, 3, 0);
  179. memcpy(&tick1, data1, len1);
  180. memcpy(&tick2, data2, len2);
  181. diff = tick1 - tick2;
  182. lua_pushboolean(L, (diff >= (int64_t)check_value)?1:0);
  183. lua_pushinteger(L, diff);
  184. return 2;
  185. }
  186. /*
  187. 选择时钟源,当前仅air105支持
  188. @api mcu.setXTAL(source_main, source_32k, delay)
  189. @boolean 高速时钟是否使用外部时钟源,如果为空则不改变
  190. @boolean 低速32K是否使用外部时钟源,如果为空则不改变
  191. @int PLL稳定时间,在切换高速时钟的时候,根据硬件环境,需要delay一段时间等待PLL稳定,默认是1200,建议不小于1024
  192. @usage
  193. mcu.setXTAL(true, true, 1248) --高速时钟使用外部时钟,低速32K使用外部晶振, delay1248
  194. */
  195. static int l_mcu_set_xtal(lua_State* L) {
  196. int source_main = 255;
  197. int source_32k = 255;
  198. int delay = luaL_optinteger(L, 3, 1200);
  199. if (lua_isboolean(L, 1)) {
  200. source_main = lua_toboolean(L, 1);
  201. }
  202. if (lua_isboolean(L, 2)) {
  203. source_32k = lua_toboolean(L, 2);
  204. }
  205. luat_mcu_set_clk_source(source_main, source_32k, delay);
  206. return 0;
  207. }
  208. // #endif
  209. LUAT_WEAK void luat_mcu_set_hardfault_mode(int mode) {;}
  210. /*
  211. mcu死机时处理模式,目前只有EC618平台适用
  212. @api mcu.hardfault(mode)
  213. @int 处理模式,0死机停机,1死机后重启,2死机后尽量将错误信息提交给外部工具后重启
  214. @usage
  215. mcu.hardfault(0) --死机后停机,一般用于调试状态
  216. mcu.hardfault(1) --死机后重启,一般用于正式产品
  217. mcu.hardfault(2) --死机后尽量将错误信息提交给外部工具后重启,一般用于压力测试或者正式产品
  218. */
  219. static int l_mcu_set_hardfault_mode(lua_State* L)
  220. {
  221. luat_mcu_set_hardfault_mode(luaL_optinteger(L, 1, 0));
  222. return 0;
  223. }
  224. LUAT_WEAK int luat_uart_pre_setup(int uart_id, uint8_t use_alt_type){return -1;}
  225. LUAT_WEAK int luat_i2c_set_iomux(int id, uint8_t value){return -1;}
  226. /*
  227. 在外设打开前,将外设IO复用到非默认配置上,目前只支持Air780E的部分外设复用到其他配置,这是一个临时接口,如果后续有更合适的api,本接口将不再更新
  228. @api mcu.iomux(type, channel, value)
  229. @int 外设类型,目前只有mcu.UART,mcu.I2C
  230. @int 总线序号,0~N,
  231. @int 新的配置,这个需要根据具体平台决定
  232. @usage
  233. mcu.iomux(mcu.UART, 2, 1) -- Air780E的UART2复用到gpio12和gpio13(Air780EG默认是这个复用,不要动)
  234. mcu.iomux(mcu.UART, 2, 2) -- Air780E的UART2复用到gpio6和gpio7
  235. mcu.iomux(mcu.I2C, 0, 1) -- Air780E的I2C0复用到gpio12和gpio13
  236. mcu.iomux(mcu.I2C, 0, 2) -- Air780E的I2C0复用到gpio16和gpio17
  237. mcu.iomux(mcu.I2C, 1, 1) -- Air780E的I2C1复用到gpio4和gpio5
  238. */
  239. static int l_mcu_iomux(lua_State* L)
  240. {
  241. int type = luaL_optinteger(L, 1, 0xff);
  242. int channel = luaL_optinteger(L, 2, 0xff);
  243. int value = luaL_optinteger(L, 3, 0);
  244. LLOGD("mcu iomux %d,%d,%d", type, channel, value);
  245. switch(type)
  246. {
  247. case LUAT_MCU_PERIPHERAL_UART:
  248. luat_uart_pre_setup(channel, value);
  249. break;
  250. case LUAT_MCU_PERIPHERAL_I2C:
  251. luat_i2c_set_iomux(channel, value);
  252. break;
  253. }
  254. return 0;
  255. }
  256. #include "rotable2.h"
  257. static const rotable_Reg_t reg_mcu[] =
  258. {
  259. { "setClk" , ROREG_FUNC(l_mcu_set_clk)},
  260. { "getClk", ROREG_FUNC(l_mcu_get_clk)},
  261. { "unique_id", ROREG_FUNC(l_mcu_unique_id)},
  262. { "ticks", ROREG_FUNC(l_mcu_ticks)},
  263. { "hz", ROREG_FUNC(l_mcu_hz)},
  264. { "reg32", ROREG_FUNC(l_mcu_reg32)},
  265. { "x32", ROREG_FUNC(l_mcu_x32)},
  266. // #ifdef __LUATOS_TICK_64BIT__
  267. { "tick64", ROREG_FUNC(l_mcu_hw_tick64)},
  268. { "dtick64", ROREG_FUNC(l_mcu_hw_diff_tick64)},
  269. { "setXTAL", ROREG_FUNC(l_mcu_set_xtal)},
  270. { "hardfault", ROREG_FUNC(l_mcu_set_hardfault_mode)},
  271. { "iomux", ROREG_FUNC(l_mcu_iomux)},
  272. // #endif
  273. //@const UART number 外设类型-串口
  274. { "UART", ROREG_INT(LUAT_MCU_PERIPHERAL_UART) },
  275. //@const I2C number 外设类型-I2C
  276. { "I2C", ROREG_INT(LUAT_MCU_PERIPHERAL_I2C) },
  277. //@const SPI number 外设类型-SPI
  278. { "SPI", ROREG_INT(LUAT_MCU_PERIPHERAL_SPI) },
  279. { NULL, ROREG_INT(0) }
  280. };
  281. LUAMOD_API int luaopen_mcu( lua_State *L ) {
  282. luat_newlib2(L, reg_mcu);
  283. return 1;
  284. }