machine_hw_spi.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #include <stdio.h>
  27. #include <stdint.h>
  28. #include <string.h>
  29. #include "py/runtime.h"
  30. #include "py/stream.h"
  31. #include "py/mphal.h"
  32. #include "extmod/machine_spi.h"
  33. #include "modmachine.h"
  34. #include "driver/spi_master.h"
  35. #define MP_HW_SPI_MAX_XFER_BYTES (4092)
  36. #define MP_HW_SPI_MAX_XFER_BITS (MP_HW_SPI_MAX_XFER_BYTES * 8) // Has to be an even multiple of 8
  37. typedef struct _machine_hw_spi_obj_t {
  38. mp_obj_base_t base;
  39. spi_host_device_t host;
  40. uint32_t baudrate;
  41. uint8_t polarity;
  42. uint8_t phase;
  43. uint8_t bits;
  44. uint8_t firstbit;
  45. int8_t sck;
  46. int8_t mosi;
  47. int8_t miso;
  48. spi_device_handle_t spi;
  49. enum {
  50. MACHINE_HW_SPI_STATE_NONE,
  51. MACHINE_HW_SPI_STATE_INIT,
  52. MACHINE_HW_SPI_STATE_DEINIT
  53. } state;
  54. } machine_hw_spi_obj_t;
  55. STATIC void machine_hw_spi_deinit_internal(machine_hw_spi_obj_t *self) {
  56. switch (spi_bus_remove_device(self->spi)) {
  57. case ESP_ERR_INVALID_ARG:
  58. mp_raise_msg(&mp_type_OSError, "invalid configuration");
  59. return;
  60. case ESP_ERR_INVALID_STATE:
  61. mp_raise_msg(&mp_type_OSError, "SPI device already freed");
  62. return;
  63. }
  64. switch (spi_bus_free(self->host)) {
  65. case ESP_ERR_INVALID_ARG:
  66. mp_raise_msg(&mp_type_OSError, "invalid configuration");
  67. return;
  68. case ESP_ERR_INVALID_STATE:
  69. mp_raise_msg(&mp_type_OSError, "SPI bus already freed");
  70. return;
  71. }
  72. int8_t pins[3] = {self->miso, self->mosi, self->sck};
  73. for (int i = 0; i < 3; i++) {
  74. if (pins[i] != -1) {
  75. gpio_pad_select_gpio(pins[i]);
  76. gpio_matrix_out(pins[i], SIG_GPIO_OUT_IDX, false, false);
  77. gpio_set_direction(pins[i], GPIO_MODE_INPUT);
  78. }
  79. }
  80. }
  81. STATIC void machine_hw_spi_init_internal(
  82. machine_hw_spi_obj_t *self,
  83. int8_t host,
  84. int32_t baudrate,
  85. int8_t polarity,
  86. int8_t phase,
  87. int8_t bits,
  88. int8_t firstbit,
  89. int8_t sck,
  90. int8_t mosi,
  91. int8_t miso) {
  92. // if we're not initialized, then we're
  93. // implicitly 'changed', since this is the init routine
  94. bool changed = self->state != MACHINE_HW_SPI_STATE_INIT;
  95. esp_err_t ret;
  96. machine_hw_spi_obj_t old_self = *self;
  97. if (host != -1 && host != self->host) {
  98. self->host = host;
  99. changed = true;
  100. }
  101. if (baudrate != -1 && baudrate != self->baudrate) {
  102. self->baudrate = baudrate;
  103. changed = true;
  104. }
  105. if (polarity != -1 && polarity != self->polarity) {
  106. self->polarity = polarity;
  107. changed = true;
  108. }
  109. if (phase != -1 && phase != self->phase) {
  110. self->phase = phase;
  111. changed = true;
  112. }
  113. if (bits != -1 && bits != self->bits) {
  114. self->bits = bits;
  115. changed = true;
  116. }
  117. if (firstbit != -1 && firstbit != self->firstbit) {
  118. self->firstbit = firstbit;
  119. changed = true;
  120. }
  121. if (sck != -2 && sck != self->sck) {
  122. self->sck = sck;
  123. changed = true;
  124. }
  125. if (mosi != -2 && mosi != self->mosi) {
  126. self->mosi = mosi;
  127. changed = true;
  128. }
  129. if (miso != -2 && miso != self->miso) {
  130. self->miso = miso;
  131. changed = true;
  132. }
  133. if (self->host != HSPI_HOST && self->host != VSPI_HOST) {
  134. mp_raise_ValueError("SPI ID must be either HSPI(1) or VSPI(2)");
  135. }
  136. if (changed) {
  137. if (self->state == MACHINE_HW_SPI_STATE_INIT) {
  138. self->state = MACHINE_HW_SPI_STATE_DEINIT;
  139. machine_hw_spi_deinit_internal(&old_self);
  140. }
  141. } else {
  142. return; // no changes
  143. }
  144. spi_bus_config_t buscfg = {
  145. .miso_io_num = self->miso,
  146. .mosi_io_num = self->mosi,
  147. .sclk_io_num = self->sck,
  148. .quadwp_io_num = -1,
  149. .quadhd_io_num = -1
  150. };
  151. spi_device_interface_config_t devcfg = {
  152. .clock_speed_hz = self->baudrate,
  153. .mode = self->phase | (self->polarity << 1),
  154. .spics_io_num = -1, // No CS pin
  155. .queue_size = 1,
  156. .flags = self->firstbit == MICROPY_PY_MACHINE_SPI_LSB ? SPI_DEVICE_TXBIT_LSBFIRST | SPI_DEVICE_RXBIT_LSBFIRST : 0,
  157. .pre_cb = NULL
  158. };
  159. //Initialize the SPI bus
  160. // FIXME: Does the DMA matter? There are two
  161. ret = spi_bus_initialize(self->host, &buscfg, 1);
  162. switch (ret) {
  163. case ESP_ERR_INVALID_ARG:
  164. mp_raise_msg(&mp_type_OSError, "invalid configuration");
  165. return;
  166. case ESP_ERR_INVALID_STATE:
  167. mp_raise_msg(&mp_type_OSError, "SPI device already in use");
  168. return;
  169. }
  170. ret = spi_bus_add_device(self->host, &devcfg, &self->spi);
  171. switch (ret) {
  172. case ESP_ERR_INVALID_ARG:
  173. mp_raise_msg(&mp_type_OSError, "invalid configuration");
  174. spi_bus_free(self->host);
  175. return;
  176. case ESP_ERR_NO_MEM:
  177. mp_raise_msg(&mp_type_OSError, "out of memory");
  178. spi_bus_free(self->host);
  179. return;
  180. case ESP_ERR_NOT_FOUND:
  181. mp_raise_msg(&mp_type_OSError, "no free slots");
  182. spi_bus_free(self->host);
  183. return;
  184. }
  185. self->state = MACHINE_HW_SPI_STATE_INIT;
  186. }
  187. STATIC void machine_hw_spi_deinit(mp_obj_base_t *self_in) {
  188. machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *) self_in;
  189. if (self->state == MACHINE_HW_SPI_STATE_INIT) {
  190. self->state = MACHINE_HW_SPI_STATE_DEINIT;
  191. machine_hw_spi_deinit_internal(self);
  192. }
  193. }
  194. STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
  195. machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
  196. if (self->state == MACHINE_HW_SPI_STATE_DEINIT) {
  197. mp_raise_msg(&mp_type_OSError, "transfer on deinitialized SPI");
  198. return;
  199. }
  200. struct spi_transaction_t transaction = { 0 };
  201. // Round to nearest whole set of bits
  202. int bits_to_send = len * 8 / self->bits * self->bits;
  203. if (len <= 4) {
  204. if (src != NULL) {
  205. memcpy(&transaction.tx_data, src, len);
  206. }
  207. transaction.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
  208. transaction.length = bits_to_send;
  209. spi_device_transmit(self->spi, &transaction);
  210. if (dest != NULL) {
  211. memcpy(dest, &transaction.rx_data, len);
  212. }
  213. } else {
  214. int offset = 0;
  215. int bits_remaining = bits_to_send;
  216. while (bits_remaining) {
  217. memset(&transaction, 0, sizeof(transaction));
  218. transaction.length =
  219. bits_remaining > MP_HW_SPI_MAX_XFER_BITS ? MP_HW_SPI_MAX_XFER_BITS : bits_remaining;
  220. if (src != NULL) {
  221. transaction.tx_buffer = src + offset;
  222. }
  223. if (dest != NULL) {
  224. transaction.rx_buffer = dest + offset;
  225. }
  226. spi_device_transmit(self->spi, &transaction);
  227. bits_remaining -= transaction.length;
  228. // doesn't need ceil(); loop ends when bits_remaining is 0
  229. offset += transaction.length / 8;
  230. }
  231. }
  232. }
  233. /******************************************************************************/
  234. // MicroPython bindings for hw_spi
  235. STATIC void machine_hw_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
  236. machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
  237. mp_printf(print, "SPI(id=%u, baudrate=%u, polarity=%u, phase=%u, bits=%u, firstbit=%u, sck=%d, mosi=%d, miso=%d)",
  238. self->host, self->baudrate, self->polarity,
  239. self->phase, self->bits, self->firstbit,
  240. self->sck, self->mosi, self->miso);
  241. }
  242. STATIC void machine_hw_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
  243. machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *) self_in;
  244. enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
  245. static const mp_arg_t allowed_args[] = {
  246. { MP_QSTR_id, MP_ARG_INT, {.u_int = -1} },
  247. { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
  248. { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
  249. { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
  250. { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
  251. { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
  252. { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
  253. { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
  254. { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
  255. };
  256. mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
  257. mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args),
  258. allowed_args, args);
  259. int8_t sck, mosi, miso;
  260. if (args[ARG_sck].u_obj == MP_OBJ_NULL) {
  261. sck = -2;
  262. } else if (args[ARG_sck].u_obj == mp_const_none) {
  263. sck = -1;
  264. } else {
  265. sck = machine_pin_get_id(args[ARG_sck].u_obj);
  266. }
  267. if (args[ARG_miso].u_obj == MP_OBJ_NULL) {
  268. miso = -2;
  269. } else if (args[ARG_miso].u_obj == mp_const_none) {
  270. miso = -1;
  271. } else {
  272. miso = machine_pin_get_id(args[ARG_miso].u_obj);
  273. }
  274. if (args[ARG_mosi].u_obj == MP_OBJ_NULL) {
  275. mosi = -2;
  276. } else if (args[ARG_mosi].u_obj == mp_const_none) {
  277. mosi = -1;
  278. } else {
  279. mosi = machine_pin_get_id(args[ARG_mosi].u_obj);
  280. }
  281. machine_hw_spi_init_internal(self, args[ARG_id].u_int, args[ARG_baudrate].u_int,
  282. args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int,
  283. args[ARG_firstbit].u_int, sck, mosi, miso);
  284. }
  285. mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
  286. enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
  287. static const mp_arg_t allowed_args[] = {
  288. { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
  289. { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} },
  290. { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
  291. { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
  292. { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
  293. { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_PY_MACHINE_SPI_MSB} },
  294. { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
  295. { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
  296. { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
  297. };
  298. mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
  299. mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
  300. machine_hw_spi_obj_t *self = m_new_obj(machine_hw_spi_obj_t);
  301. self->base.type = &machine_hw_spi_type;
  302. machine_hw_spi_init_internal(
  303. self,
  304. args[ARG_id].u_int,
  305. args[ARG_baudrate].u_int,
  306. args[ARG_polarity].u_int,
  307. args[ARG_phase].u_int,
  308. args[ARG_bits].u_int,
  309. args[ARG_firstbit].u_int,
  310. args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sck].u_obj),
  311. args[ARG_mosi].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_mosi].u_obj),
  312. args[ARG_miso].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_miso].u_obj));
  313. return MP_OBJ_FROM_PTR(self);
  314. }
  315. STATIC const mp_machine_spi_p_t machine_hw_spi_p = {
  316. .init = machine_hw_spi_init,
  317. .deinit = machine_hw_spi_deinit,
  318. .transfer = machine_hw_spi_transfer,
  319. };
  320. const mp_obj_type_t machine_hw_spi_type = {
  321. { &mp_type_type },
  322. .name = MP_QSTR_SPI,
  323. .print = machine_hw_spi_print,
  324. .make_new = machine_hw_spi_make_new,
  325. .protocol = &machine_hw_spi_p,
  326. .locals_dict = (mp_obj_dict_t *) &mp_machine_spi_locals_dict,
  327. };