spi_master.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // Module for interfacing with the SPI master hardware
  2. #include <string.h>
  3. #include "module.h"
  4. #include "lauxlib.h"
  5. #include "lextra.h"
  6. #include "driver/spi_master.h"
  7. #include "esp_heap_alloc_caps.h"
  8. #include "esp_log.h"
  9. #define SPI_MASTER_TAG "spi.master"
  10. #define UD_HOST_STR "spi.master"
  11. #define UD_DEVICE_STR "spi.device"
  12. static int no_err( esp_err_t err )
  13. {
  14. switch (err)
  15. {
  16. default:
  17. ESP_LOGI(SPI_MASTER_TAG, "unknown error");
  18. return 0;
  19. case ESP_ERR_INVALID_ARG:
  20. ESP_LOGI(SPI_MASTER_TAG, "invalid argument");
  21. return 0;
  22. case ESP_ERR_INVALID_STATE:
  23. ESP_LOGI(SPI_MASTER_TAG, "internal logic error");
  24. return 0;
  25. case ESP_ERR_NO_MEM:
  26. ESP_LOGI(SPI_MASTER_TAG, "no memory");
  27. return 0;
  28. case ESP_OK:
  29. return 1;
  30. }
  31. }
  32. // ****************************************************************************
  33. // Device related functions
  34. //
  35. typedef struct {
  36. spi_device_handle_t device;
  37. int host_ref, host;
  38. } lspi_device_t;
  39. #define GET_UD_DEVICE \
  40. lspi_device_t *ud = (lspi_device_t *)luaL_checkudata( L, 1, UD_DEVICE_STR );
  41. #define CONFIG_TRANS_FROM_FIELD(field) \
  42. lua_getfield( L, stack, #field ); \
  43. trans.field = luaL_optint( L, -1, 0 );
  44. static int lspi_device_free( lua_State *L )
  45. {
  46. GET_UD_DEVICE;
  47. if (ud->device) {
  48. spi_bus_remove_device( ud->device );
  49. ud->device = NULL;
  50. // unref host to unblock automatic gc from this object
  51. luaL_unref( L, LUA_REGISTRYINDEX, ud->host_ref );
  52. ud->host_ref = LUA_NOREF;
  53. }
  54. return 0;
  55. }
  56. // Lua:
  57. // recv = dev:transfer(trans_desc)
  58. // recv = dev:transfer(data)
  59. static int lspi_device_transfer( lua_State *L )
  60. {
  61. GET_UD_DEVICE;
  62. int stack = 1;
  63. luaL_argcheck( L, ud->device, stack, "no device" );
  64. spi_transaction_t trans;
  65. memset( &trans, 0, sizeof( trans ) );
  66. size_t data_len, rx_len;
  67. const char *data;
  68. int type = lua_type( L, ++stack );
  69. luaL_argcheck( L, type == LUA_TSTRING || type == LUA_TTABLE, stack, "string or table expected" );
  70. if (type == LUA_TSTRING) {
  71. data = luaL_checklstring( L, stack, &data_len );
  72. rx_len = data_len;
  73. } else {
  74. const char * const options[] = {"std", "dio", "qio"};
  75. const uint32_t options_flags[] = {0, SPI_TRANS_MODE_DIO, SPI_TRANS_MODE_QIO};
  76. CONFIG_TRANS_FROM_FIELD(command);
  77. CONFIG_TRANS_FROM_FIELD(address);
  78. //
  79. lua_getfield( L, stack, "rxlen" );
  80. rx_len = luaL_optint( L, -1, 0 );
  81. //
  82. lua_getfield( L, stack, "addr_mode" );
  83. trans.flags |= luaL_optbool( L, -1, false ) ? SPI_TRANS_MODE_DIOQIO_ADDR : 0;
  84. //
  85. lua_getfield( L, stack, "mode" );
  86. trans.flags |= options_flags[ luaL_checkoption( L, -1, options[0], options ) ];
  87. //
  88. lua_getfield( L, stack, "txdata" );
  89. data = luaL_optlstring( L, -1, "", &data_len );
  90. lua_settop( L, stack );
  91. }
  92. const char *msg = NULL;
  93. trans.length = data_len * 8;
  94. if (data_len == 0) {
  95. //no MOSI phase requested
  96. trans.tx_buffer = NULL;
  97. } else if (data_len <=4 ) {
  98. // use local tx data buffer
  99. trans.flags |= SPI_TRANS_USE_TXDATA;
  100. memcpy( trans.tx_data, data, data_len );
  101. } else {
  102. // use DMA'able buffer
  103. if ((trans.tx_buffer = pvPortMallocCaps( data_len, MALLOC_CAP_DMA ))) {
  104. memcpy( (void *)trans.tx_buffer, data, data_len );
  105. } else {
  106. msg = "no memory";
  107. goto free_mem;
  108. }
  109. }
  110. trans.rxlength = rx_len * 8;
  111. if (rx_len == 0) {
  112. // no MISO phase requested
  113. trans.rx_buffer = NULL;
  114. } else if (rx_len <= 4) {
  115. // use local rx data buffer
  116. trans.flags |= SPI_TRANS_USE_RXDATA;
  117. } else {
  118. // use DMA'able buffer
  119. if (!(trans.rx_buffer = pvPortMallocCaps( rx_len, MALLOC_CAP_DMA ))) {
  120. msg = "no mem";
  121. goto free_mem;
  122. }
  123. }
  124. // finally perform the transaction
  125. if (no_err( spi_device_transmit( ud->device, &trans ) )) {
  126. // evaluate receive data
  127. if (trans.flags & SPI_TRANS_USE_RXDATA) {
  128. lua_pushlstring( L, (const char *)&(trans.rx_data[0]), rx_len );
  129. } else {
  130. lua_pushlstring( L, trans.rx_buffer, rx_len );
  131. }
  132. } else
  133. msg = "transfer failed";
  134. free_mem:
  135. if (!(trans.flags & SPI_TRANS_USE_TXDATA) && trans.tx_buffer)
  136. free( (void *)trans.tx_buffer );
  137. if (!(trans.flags & SPI_TRANS_USE_RXDATA) && trans.rx_buffer)
  138. free( (void *)trans.rx_buffer );
  139. if (msg)
  140. return luaL_error( L, msg );
  141. return 1;
  142. }
  143. static const LUA_REG_TYPE lspi_device_map[] = {
  144. { LSTRKEY( "transfer" ), LFUNCVAL( lspi_device_transfer ) },
  145. { LSTRKEY( "remove" ), LFUNCVAL( lspi_device_free ) },
  146. { LSTRKEY( "__gc" ), LFUNCVAL( lspi_device_free ) },
  147. { LSTRKEY( "__index" ), LROVAL( lspi_device_map ) },
  148. {LNILKEY, LNILVAL}
  149. };
  150. // ****************************************************************************
  151. // Host related functions
  152. //
  153. typedef struct {
  154. int host;
  155. } lspi_host_t;
  156. #define GET_UD_HOST \
  157. lspi_host_t *ud = (lspi_host_t *)luaL_checkudata( L, 1, UD_HOST_STR );
  158. //
  159. #define CONFIG_BUS_PIN_FROM_FIELD(pin) \
  160. lua_getfield( L, stack, #pin ); \
  161. config.pin ## _io_num = luaL_optint( L, -1, -1 );
  162. //
  163. #define CONFIG_DEVICE_FROM_INT_FIELD(field) \
  164. lua_getfield( L, stack, #field ); \
  165. config.field = luaL_optint( L, -1, 0 );
  166. #define CONFIG_DEVICE_FROM_BOOL_FIELD(field, mask) \
  167. lua_getfield( L, stack, #field ); \
  168. config.flags |= luaL_optbool( L, -1, false ) ? mask : 0;
  169. static int lspi_host_free( lua_State *L )
  170. {
  171. GET_UD_HOST;
  172. if (ud->host >= 0) {
  173. spi_bus_free( ud->host );
  174. ud->host = -1;
  175. }
  176. return 0;
  177. }
  178. // Lua: master = spi.master(host, config)
  179. int lspi_master( lua_State *L )
  180. {
  181. int stack = 0;
  182. int host = luaL_checkint( L, ++stack );
  183. luaL_argcheck( L,
  184. host == SPI_HOST || host == HSPI_HOST || host == VSPI_HOST,
  185. stack,
  186. "invalid host" );
  187. luaL_checktype( L, ++stack, LUA_TTABLE );
  188. spi_bus_config_t config;
  189. memset( &config, 0, sizeof( config ) );
  190. //
  191. CONFIG_BUS_PIN_FROM_FIELD(sclk);
  192. CONFIG_BUS_PIN_FROM_FIELD(mosi);
  193. CONFIG_BUS_PIN_FROM_FIELD(miso);
  194. CONFIG_BUS_PIN_FROM_FIELD(quadwp);
  195. CONFIG_BUS_PIN_FROM_FIELD(quadhd);
  196. lua_settop( L, stack );
  197. //
  198. if (no_err( spi_bus_initialize( host, &config, 1 ) )) {
  199. lspi_host_t *ud = (lspi_host_t *)lua_newuserdata( L, sizeof( lspi_host_t ) );
  200. luaL_getmetatable( L, UD_HOST_STR );
  201. lua_setmetatable( L, -2 );
  202. ud->host = host;
  203. return 1;
  204. }
  205. return luaL_error( L, "bus init failed" );
  206. }
  207. // Lua: dev = master:device(config)
  208. static int lspi_host_device( lua_State *L )
  209. {
  210. GET_UD_HOST;
  211. int stack = 1;
  212. luaL_argcheck( L, ud->host >= 0, stack, "no active bus host" );
  213. luaL_checktype( L, ++stack, LUA_TTABLE );
  214. spi_device_interface_config_t config;
  215. memset( &config, 0, sizeof( config ) );
  216. // mandatory fields
  217. lua_getfield( L, stack, "cs" );
  218. config.spics_io_num = luaL_optint( L, -1, -1 );
  219. //
  220. lua_getfield( L, stack, "mode" );
  221. int mode = luaL_optint( L, -1, -1 );
  222. luaL_argcheck( L, mode >= 0, stack, "mode setting missing" );
  223. config.mode = (uint8_t)mode;
  224. //
  225. lua_getfield( L, stack, "freq" );
  226. int freq = luaL_optint( L, -1, -1 );
  227. luaL_argcheck( L, freq >= 0, stack, "freq setting missing" );
  228. config.clock_speed_hz = freq;
  229. //
  230. // optional fields
  231. CONFIG_DEVICE_FROM_INT_FIELD(command_bits);
  232. CONFIG_DEVICE_FROM_INT_FIELD(address_bits);
  233. CONFIG_DEVICE_FROM_INT_FIELD(dummy_bits);
  234. CONFIG_DEVICE_FROM_INT_FIELD(cs_ena_pretrans);
  235. CONFIG_DEVICE_FROM_INT_FIELD(cs_ena_posttrans);
  236. CONFIG_DEVICE_FROM_INT_FIELD(duty_cycle_pos);
  237. CONFIG_DEVICE_FROM_BOOL_FIELD(tx_lsb_first, SPI_DEVICE_TXBIT_LSBFIRST);
  238. CONFIG_DEVICE_FROM_BOOL_FIELD(rx_lsb_first, SPI_DEVICE_RXBIT_LSBFIRST);
  239. CONFIG_DEVICE_FROM_BOOL_FIELD(wire3, SPI_DEVICE_3WIRE);
  240. CONFIG_DEVICE_FROM_BOOL_FIELD(positive_cs, SPI_DEVICE_POSITIVE_CS);
  241. CONFIG_DEVICE_FROM_BOOL_FIELD(halfduplex, SPI_DEVICE_HALFDUPLEX);
  242. CONFIG_DEVICE_FROM_BOOL_FIELD(clk_as_cs, SPI_DEVICE_CLK_AS_CS);
  243. lua_settop( L, stack );
  244. //
  245. // fill remaining config entries
  246. config.queue_size = 1;
  247. lspi_device_t *dev = (lspi_device_t *)lua_newuserdata( L, sizeof( lspi_device_t ) );
  248. dev->device = NULL;
  249. if (no_err( spi_bus_add_device( ud->host, &config, &(dev->device) ) )) {
  250. luaL_getmetatable( L, UD_DEVICE_STR );
  251. lua_setmetatable( L, -2 );
  252. // reference host object to avoid automatic gc
  253. lua_pushvalue( L, 1 );
  254. dev->host_ref = luaL_ref( L, LUA_REGISTRYINDEX );
  255. dev->host = ud->host;
  256. return 1;
  257. }
  258. lua_pop( L, 1 );
  259. return luaL_error( L, "failed to add device" );
  260. }
  261. static const LUA_REG_TYPE lspi_master_map[] = {
  262. { LSTRKEY( "device" ), LFUNCVAL( lspi_host_device ) },
  263. { LSTRKEY( "close" ), LFUNCVAL( lspi_host_free ) },
  264. { LSTRKEY( "__gc" ), LFUNCVAL( lspi_host_free ) },
  265. { LSTRKEY( "__index" ), LROVAL( lspi_master_map ) },
  266. {LNILKEY, LNILVAL}
  267. };
  268. // ****************************************************************************
  269. // Generic
  270. //
  271. int luaopen_spi_master( lua_State *L ) {
  272. luaL_rometatable(L, UD_HOST_STR, (void *)lspi_master_map);
  273. luaL_rometatable(L, UD_DEVICE_STR, (void *)lspi_device_map);
  274. return 0;
  275. }