spi.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. // Module for interfacing with the SPI interface
  2. #include "module.h"
  3. #include "lauxlib.h"
  4. #include "platform.h"
  5. #include "driver/spi.h"
  6. #define SPI_HALFDUPLEX 0
  7. #define SPI_FULLDUPLEX 1
  8. static u8 spi_databits[NUM_SPI] = {0, 0};
  9. static u8 spi_duplex[NUM_SPI] = {SPI_HALFDUPLEX, SPI_HALFDUPLEX};
  10. // Lua: = spi.setup( id, mode, cpol, cpha, databits, clock_div, [duplex_mode] )
  11. static int spi_setup( lua_State *L )
  12. {
  13. int id = luaL_checkinteger( L, 1 );
  14. int mode = luaL_checkinteger( L, 2 );
  15. int cpol = luaL_checkinteger( L, 3 );
  16. int cpha = luaL_checkinteger( L, 4 );
  17. int databits = luaL_checkinteger( L, 5 );
  18. u32 clock_div = luaL_checkinteger( L, 6 );
  19. int duplex_mode = luaL_optinteger( L, 7, SPI_HALFDUPLEX );
  20. MOD_CHECK_ID( spi, id );
  21. if (mode != PLATFORM_SPI_SLAVE && mode != PLATFORM_SPI_MASTER) {
  22. return luaL_error( L, "wrong arg type" );
  23. }
  24. if (cpol != PLATFORM_SPI_CPOL_LOW && cpol != PLATFORM_SPI_CPOL_HIGH) {
  25. return luaL_error( L, "wrong arg type" );
  26. }
  27. if (cpha != PLATFORM_SPI_CPHA_LOW && cpha != PLATFORM_SPI_CPHA_HIGH) {
  28. return luaL_error( L, "wrong arg type" );
  29. }
  30. if (databits < 0 || databits > 32) {
  31. return luaL_error( L, "out of range" );
  32. }
  33. if (clock_div == 0) {
  34. // defaulting to 8 for backward compatibility
  35. clock_div = 8;
  36. }
  37. if (duplex_mode == SPI_HALFDUPLEX || duplex_mode == SPI_FULLDUPLEX)
  38. {
  39. spi_duplex[id] = duplex_mode;
  40. }
  41. else
  42. {
  43. return luaL_error( L, "out of range" );
  44. }
  45. spi_databits[id] = databits;
  46. u32 res = platform_spi_setup(id, mode, cpol, cpha, clock_div);
  47. lua_pushinteger( L, res );
  48. return 1;
  49. }
  50. // Half-duplex mode:
  51. // Lua: wrote = spi.send( id, data1, [data2], ..., [datan] )
  52. // Full-duplex mode:
  53. // Lua: wrote, [data1], ..., [datan] = spi.send_recv( id, data1, [data2], ..., [datan] )
  54. // data can be either a string, a table or an 8-bit number
  55. static int spi_send_recv( lua_State *L )
  56. {
  57. unsigned id = luaL_checkinteger( L, 1 );
  58. const char *pdata;
  59. size_t datalen, i;
  60. u32 numdata;
  61. u32 wrote = 0;
  62. int pushed = 1;
  63. unsigned argn, tos;
  64. u8 recv = spi_duplex[id] == SPI_FULLDUPLEX ? 1 : 0;
  65. MOD_CHECK_ID( spi, id );
  66. if( (tos = lua_gettop( L )) < 2 )
  67. return luaL_error( L, "wrong arg type" );
  68. // prepare first returned item 'wrote' - value is yet unknown
  69. // position on stack is tos+1
  70. lua_pushinteger( L, 0 );
  71. for( argn = 2; argn <= tos; argn ++ )
  72. {
  73. // *** Send integer value and return received data as integer ***
  74. // lua_isnumber() would silently convert a string of digits to an integer
  75. // whereas here strings are handled separately.
  76. if( lua_type( L, argn ) == LUA_TNUMBER )
  77. {
  78. numdata = luaL_checkinteger( L, argn );
  79. if (recv > 0)
  80. {
  81. lua_pushinteger( L, platform_spi_send_recv( id, spi_databits[id], numdata ) );
  82. pushed ++;
  83. }
  84. else
  85. {
  86. platform_spi_send( id, spi_databits[id], numdata );
  87. }
  88. wrote ++;
  89. }
  90. // *** Send table elements and return received data items as a table ***
  91. else if( lua_istable( L, argn ) )
  92. {
  93. datalen = lua_objlen( L, argn );
  94. if (recv > 0 && datalen > 0) {
  95. // create a table for the received data
  96. lua_createtable( L, datalen, 0 );
  97. pushed ++;
  98. }
  99. for( i = 0; i < datalen; i ++ )
  100. {
  101. lua_rawgeti( L, argn, i + 1 );
  102. numdata = luaL_checkinteger( L, -1 );
  103. lua_pop( L, 1 );
  104. if (recv > 0) {
  105. lua_pushinteger( L, platform_spi_send_recv( id, spi_databits[id], numdata ) );
  106. lua_rawseti( L, -2, i + 1 );
  107. }
  108. else
  109. {
  110. platform_spi_send( id, spi_databits[id], numdata );
  111. }
  112. }
  113. wrote += i;
  114. if( i < datalen )
  115. break;
  116. }
  117. // *** Send characters of a string and return received data items as string ***
  118. else
  119. {
  120. luaL_Buffer b;
  121. pdata = luaL_checklstring( L, argn, &datalen );
  122. if (recv > 0) {
  123. luaL_buffinit( L, &b );
  124. }
  125. for( i = 0; i < datalen; i ++ )
  126. {
  127. if (recv > 0)
  128. {
  129. luaL_addchar( &b, (char)platform_spi_send_recv( id, spi_databits[id], pdata[ i ] ) );
  130. }
  131. else
  132. {
  133. platform_spi_send( id, spi_databits[id], pdata[ i ] );
  134. }
  135. }
  136. if (recv > 0 && datalen > 0) {
  137. luaL_pushresult( &b );
  138. pushed ++;
  139. }
  140. wrote += i;
  141. if( i < datalen )
  142. break;
  143. }
  144. }
  145. // update item 'wrote' on stack
  146. lua_pushinteger( L, wrote );
  147. lua_replace( L, tos+1 );
  148. return pushed;
  149. }
  150. // Lua: read = spi.recv( id, size, [default data] )
  151. static int spi_recv( lua_State *L )
  152. {
  153. int id = luaL_checkinteger( L, 1 );
  154. int size = luaL_checkinteger( L, 2 ), i;
  155. int def = luaL_optinteger( L, 3, 0xffffffff );
  156. luaL_Buffer b;
  157. MOD_CHECK_ID( spi, id );
  158. if (size == 0) {
  159. return 0;
  160. }
  161. luaL_buffinit( L, &b );
  162. for (i=0; i<size; i++)
  163. {
  164. luaL_addchar( &b, ( char )platform_spi_send_recv( id, spi_databits[id], def ) );
  165. }
  166. luaL_pushresult( &b );
  167. return 1;
  168. }
  169. // Lua: spi.set_mosi( id, offset, bitlen, data1, [data2], ..., [datan] )
  170. // Lua: spi.set_mosi( id, string )
  171. static int spi_set_mosi( lua_State *L )
  172. {
  173. int id = luaL_checkinteger( L, 1 );
  174. MOD_CHECK_ID( spi, id );
  175. if (lua_type( L, 2 ) == LUA_TSTRING) {
  176. size_t len;
  177. const char *data = luaL_checklstring( L, 2, &len );
  178. luaL_argcheck( L, 2, len <= 64, "out of range" );
  179. spi_mast_blkset( id, len * 8, data );
  180. } else {
  181. int offset = luaL_checkinteger( L, 2 );
  182. int bitlen = luaL_checkinteger( L, 3 );
  183. luaL_argcheck( L, 2, offset >= 0 && offset <= 511, "out of range" );
  184. luaL_argcheck( L, 3, bitlen >= 1 && bitlen <= 32, "out of range" );
  185. for (int argn = 4; argn <= lua_gettop( L ); argn++, offset += bitlen ) {
  186. u32 data = ( u32 )luaL_checkinteger(L, argn );
  187. if (offset + bitlen > 512) {
  188. return luaL_error( L, "data range exceeded > 512 bits" );
  189. }
  190. spi_mast_set_mosi( id, offset, bitlen, data );
  191. }
  192. }
  193. return 0;
  194. }
  195. // Lua: data = spi.get_miso( id, offset, bitlen, num )
  196. // Lua: string = spi.get_miso( id, len )
  197. static int spi_get_miso( lua_State *L )
  198. {
  199. int id = luaL_checkinteger( L, 1 );
  200. MOD_CHECK_ID( spi, id );
  201. if (lua_gettop( L ) == 2) {
  202. uint8_t data[64];
  203. int len = luaL_checkinteger( L, 2 );
  204. luaL_argcheck( L, 2, len >= 1 && len <= 64, "out of range" );
  205. spi_mast_blkget( id, len * 8, data );
  206. lua_pushlstring( L, data, len );
  207. return 1;
  208. } else {
  209. int offset = luaL_checkinteger( L, 2 );
  210. int bitlen = luaL_checkinteger( L, 3 );
  211. int num = luaL_checkinteger( L, 4 ), i;
  212. luaL_argcheck( L, 2, offset >= 0 && offset <= 511, "out of range" );
  213. luaL_argcheck( L, 3, bitlen >= 1 && bitlen <= 32, "out of range" );
  214. if (offset + bitlen * num > 512) {
  215. return luaL_error( L, "out of range" );
  216. }
  217. for (i = 0; i < num; i++) {
  218. lua_pushinteger( L, spi_mast_get_miso( id, offset + (bitlen * i), bitlen ) );
  219. }
  220. return num;
  221. }
  222. }
  223. // Lua: spi.transaction( id, cmd_bitlen, cmd_data, addr_bitlen, addr_data, mosi_bitlen, dummy_bitlen, miso_bitlen )
  224. static int spi_transaction( lua_State *L )
  225. {
  226. int id = luaL_checkinteger( L, 1 );
  227. MOD_CHECK_ID( spi, id );
  228. int cmd_bitlen = luaL_checkinteger( L, 2 );
  229. u16 cmd_data = ( u16 )luaL_checkinteger( L, 3 );
  230. luaL_argcheck( L, 2, cmd_bitlen >= 0 && cmd_bitlen <= 16, "out of range" );
  231. int addr_bitlen = luaL_checkinteger( L, 4 );
  232. u32 addr_data = ( u32 )luaL_checkinteger( L, 5 );
  233. luaL_argcheck( L, 4, addr_bitlen >= 0 && addr_bitlen <= 32, "out of range" );
  234. int mosi_bitlen = luaL_checkinteger( L, 6 );
  235. luaL_argcheck( L, 6, mosi_bitlen >= 0 && mosi_bitlen <= 512, "out of range" );
  236. int dummy_bitlen = luaL_checkinteger( L, 7 );
  237. luaL_argcheck( L, 7, dummy_bitlen >= 0 && dummy_bitlen <= 256, "out of range" );
  238. int miso_bitlen = luaL_checkinteger( L, 8 );
  239. luaL_argcheck( L, 8, miso_bitlen >= -512 && miso_bitlen <= 512, "out of range" );
  240. spi_mast_transaction( id, cmd_bitlen, cmd_data, addr_bitlen, addr_data,
  241. mosi_bitlen, dummy_bitlen, miso_bitlen );
  242. return 0;
  243. }
  244. // Module function map
  245. static const LUA_REG_TYPE spi_map[] = {
  246. { LSTRKEY( "setup" ), LFUNCVAL( spi_setup ) },
  247. { LSTRKEY( "send" ), LFUNCVAL( spi_send_recv ) },
  248. { LSTRKEY( "recv" ), LFUNCVAL( spi_recv ) },
  249. { LSTRKEY( "set_mosi" ), LFUNCVAL( spi_set_mosi ) },
  250. { LSTRKEY( "get_miso" ), LFUNCVAL( spi_get_miso ) },
  251. { LSTRKEY( "transaction" ), LFUNCVAL( spi_transaction ) },
  252. { LSTRKEY( "MASTER" ), LNUMVAL( PLATFORM_SPI_MASTER ) },
  253. { LSTRKEY( "SLAVE" ), LNUMVAL( PLATFORM_SPI_SLAVE) },
  254. { LSTRKEY( "CPHA_LOW" ), LNUMVAL( PLATFORM_SPI_CPHA_LOW) },
  255. { LSTRKEY( "CPHA_HIGH" ), LNUMVAL( PLATFORM_SPI_CPHA_HIGH) },
  256. { LSTRKEY( "CPOL_LOW" ), LNUMVAL( PLATFORM_SPI_CPOL_LOW) },
  257. { LSTRKEY( "CPOL_HIGH" ), LNUMVAL( PLATFORM_SPI_CPOL_HIGH) },
  258. { LSTRKEY( "DATABITS_8" ), LNUMVAL( 8 ) },
  259. { LSTRKEY( "HALFDUPLEX" ), LNUMVAL( SPI_HALFDUPLEX ) },
  260. { LSTRKEY( "FULLDUPLEX" ), LNUMVAL( SPI_FULLDUPLEX ) },
  261. { LNILKEY, LNILVAL }
  262. };
  263. NODEMCU_MODULE(SPI, "spi", spi_map, NULL);