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
27 #include <stdio.h>
28 #include <stdint.h>
29 #include <string.h>
30
31 #include "py/runtime.h"
32 #include "py/stream.h"
33 #include "py/mphal.h"
34 #include "extmod/machine_spi.h"
35 #include "modmachine.h"
36
37 #include "driver/spi_master.h"
38
39 // Default pins for SPI(1), can be overridden by a board
40 #ifndef MICROPY_HW_SPI1_SCK
41 #define MICROPY_HW_SPI1_SCK (14)
42 #define MICROPY_HW_SPI1_MOSI (13)
43 #define MICROPY_HW_SPI1_MISO (12)
44 #endif
45
46 // Default pins for SPI(2), can be overridden by a board
47 #ifndef MICROPY_HW_SPI2_SCK
48 #define MICROPY_HW_SPI2_SCK (18)
49 #define MICROPY_HW_SPI2_MOSI (23)
50 #define MICROPY_HW_SPI2_MISO (19)
51 #endif
52
53 #define MP_HW_SPI_MAX_XFER_BYTES (4092)
54 #define MP_HW_SPI_MAX_XFER_BITS (MP_HW_SPI_MAX_XFER_BYTES * 8) // Has to be an even multiple of 8
55
56 #if CONFIG_IDF_TARGET_ESP32C3
57 #define HSPI_HOST SPI2_HOST
58 #endif
59
60 typedef struct _machine_hw_spi_default_pins_t {
61 int8_t sck;
62 int8_t mosi;
63 int8_t miso;
64 } machine_hw_spi_default_pins_t;
65
66 typedef struct _machine_hw_spi_obj_t {
67 mp_obj_base_t base;
68 spi_host_device_t host;
69 uint32_t baudrate;
70 uint8_t polarity;
71 uint8_t phase;
72 uint8_t bits;
73 uint8_t firstbit;
74 int8_t sck;
75 int8_t mosi;
76 int8_t miso;
77 spi_device_handle_t spi;
78 enum {
79 MACHINE_HW_SPI_STATE_NONE,
80 MACHINE_HW_SPI_STATE_INIT,
81 MACHINE_HW_SPI_STATE_DEINIT
82 } state;
83 } machine_hw_spi_obj_t;
84
85 // Default pin mappings for the hardware SPI instances
86 STATIC const machine_hw_spi_default_pins_t machine_hw_spi_default_pins[2] = {
87 { .sck = MICROPY_HW_SPI1_SCK, .mosi = MICROPY_HW_SPI1_MOSI, .miso = MICROPY_HW_SPI1_MISO },
88 { .sck = MICROPY_HW_SPI2_SCK, .mosi = MICROPY_HW_SPI2_MOSI, .miso = MICROPY_HW_SPI2_MISO },
89 };
90
91 // Static objects mapping to HSPI and VSPI hardware peripherals
92 STATIC machine_hw_spi_obj_t machine_hw_spi_obj[2];
93
machine_hw_spi_deinit_internal(machine_hw_spi_obj_t * self)94 STATIC void machine_hw_spi_deinit_internal(machine_hw_spi_obj_t *self) {
95 switch (spi_bus_remove_device(self->spi)) {
96 case ESP_ERR_INVALID_ARG:
97 mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("invalid configuration"));
98 return;
99
100 case ESP_ERR_INVALID_STATE:
101 mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("SPI device already freed"));
102 return;
103 }
104
105 switch (spi_bus_free(self->host)) {
106 case ESP_ERR_INVALID_ARG:
107 mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("invalid configuration"));
108 return;
109
110 case ESP_ERR_INVALID_STATE:
111 mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("SPI bus already freed"));
112 return;
113 }
114
115 int8_t pins[3] = {self->miso, self->mosi, self->sck};
116
117 for (int i = 0; i < 3; i++) {
118 if (pins[i] != -1) {
119 gpio_pad_select_gpio(pins[i]);
120 gpio_matrix_out(pins[i], SIG_GPIO_OUT_IDX, false, false);
121 gpio_set_direction(pins[i], GPIO_MODE_INPUT);
122 }
123 }
124 }
125
machine_hw_spi_init_internal(machine_hw_spi_obj_t * self,int8_t host,int32_t baudrate,int8_t polarity,int8_t phase,int8_t bits,int8_t firstbit,int8_t sck,int8_t mosi,int8_t miso)126 STATIC void machine_hw_spi_init_internal(
127 machine_hw_spi_obj_t *self,
128 int8_t host,
129 int32_t baudrate,
130 int8_t polarity,
131 int8_t phase,
132 int8_t bits,
133 int8_t firstbit,
134 int8_t sck,
135 int8_t mosi,
136 int8_t miso) {
137
138 // if we're not initialized, then we're
139 // implicitly 'changed', since this is the init routine
140 bool changed = self->state != MACHINE_HW_SPI_STATE_INIT;
141
142 esp_err_t ret;
143
144 machine_hw_spi_obj_t old_self = *self;
145
146 if (host != -1 && host != self->host) {
147 self->host = host;
148 changed = true;
149 }
150
151 if (baudrate != -1) {
152 // calculate the actual clock frequency that the SPI peripheral can produce
153 baudrate = spi_get_actual_clock(APB_CLK_FREQ, baudrate, 0);
154 if (baudrate != self->baudrate) {
155 self->baudrate = baudrate;
156 changed = true;
157 }
158 }
159
160 if (polarity != -1 && polarity != self->polarity) {
161 self->polarity = polarity;
162 changed = true;
163 }
164
165 if (phase != -1 && phase != self->phase) {
166 self->phase = phase;
167 changed = true;
168 }
169
170 if (bits != -1 && bits != self->bits) {
171 self->bits = bits;
172 changed = true;
173 }
174
175 if (firstbit != -1 && firstbit != self->firstbit) {
176 self->firstbit = firstbit;
177 changed = true;
178 }
179
180 if (sck != -2 && sck != self->sck) {
181 self->sck = sck;
182 changed = true;
183 }
184
185 if (mosi != -2 && mosi != self->mosi) {
186 self->mosi = mosi;
187 changed = true;
188 }
189
190 if (miso != -2 && miso != self->miso) {
191 self->miso = miso;
192 changed = true;
193 }
194
195 if (self->host != HSPI_HOST
196 #ifdef VSPI_HOST
197 && self->host != VSPI_HOST
198 #endif
199 ) {
200 mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), self->host);
201 }
202
203 if (changed) {
204 if (self->state == MACHINE_HW_SPI_STATE_INIT) {
205 self->state = MACHINE_HW_SPI_STATE_DEINIT;
206 machine_hw_spi_deinit_internal(&old_self);
207 }
208 } else {
209 return; // no changes
210 }
211
212 spi_bus_config_t buscfg = {
213 .miso_io_num = self->miso,
214 .mosi_io_num = self->mosi,
215 .sclk_io_num = self->sck,
216 .quadwp_io_num = -1,
217 .quadhd_io_num = -1
218 };
219
220 spi_device_interface_config_t devcfg = {
221 .clock_speed_hz = self->baudrate,
222 .mode = self->phase | (self->polarity << 1),
223 .spics_io_num = -1, // No CS pin
224 .queue_size = 2,
225 .flags = self->firstbit == MICROPY_PY_MACHINE_SPI_LSB ? SPI_DEVICE_TXBIT_LSBFIRST | SPI_DEVICE_RXBIT_LSBFIRST : 0,
226 .pre_cb = NULL
227 };
228
229 // Initialize the SPI bus
230
231 // Select DMA channel based on the hardware SPI host
232 int dma_chan = 0;
233 if (self->host == HSPI_HOST) {
234 dma_chan = 1;
235 #ifdef VSPI_HOST
236 } else if (self->host == VSPI_HOST) {
237 dma_chan = 2;
238 #endif
239 }
240
241 ret = spi_bus_initialize(self->host, &buscfg, dma_chan);
242 switch (ret) {
243 case ESP_ERR_INVALID_ARG:
244 mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("invalid configuration"));
245 return;
246
247 case ESP_ERR_INVALID_STATE:
248 mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("SPI host already in use"));
249 return;
250 }
251
252 ret = spi_bus_add_device(self->host, &devcfg, &self->spi);
253 switch (ret) {
254 case ESP_ERR_INVALID_ARG:
255 mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("invalid configuration"));
256 spi_bus_free(self->host);
257 return;
258
259 case ESP_ERR_NO_MEM:
260 mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("out of memory"));
261 spi_bus_free(self->host);
262 return;
263
264 case ESP_ERR_NOT_FOUND:
265 mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("no free slots"));
266 spi_bus_free(self->host);
267 return;
268 }
269 self->state = MACHINE_HW_SPI_STATE_INIT;
270 }
271
machine_hw_spi_deinit(mp_obj_base_t * self_in)272 STATIC void machine_hw_spi_deinit(mp_obj_base_t *self_in) {
273 machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *)self_in;
274 if (self->state == MACHINE_HW_SPI_STATE_INIT) {
275 self->state = MACHINE_HW_SPI_STATE_DEINIT;
276 machine_hw_spi_deinit_internal(self);
277 }
278 }
279
gcd(mp_uint_t x,mp_uint_t y)280 STATIC mp_uint_t gcd(mp_uint_t x, mp_uint_t y) {
281 while (x != y) {
282 if (x > y) {
283 x -= y;
284 } else {
285 y -= x;
286 }
287 }
288 return x;
289 }
290
machine_hw_spi_transfer(mp_obj_base_t * self_in,size_t len,const uint8_t * src,uint8_t * dest)291 STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
292 machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
293
294 if (self->state == MACHINE_HW_SPI_STATE_DEINIT) {
295 mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("transfer on deinitialized SPI"));
296 return;
297 }
298
299 // Round to nearest whole set of bits
300 int bits_to_send = len * 8 / self->bits * self->bits;
301
302 if (!bits_to_send) {
303 mp_raise_ValueError(MP_ERROR_TEXT("buffer too short"));
304 }
305
306 if (len <= 4) {
307 spi_transaction_t transaction = { 0 };
308
309 if (src != NULL) {
310 memcpy(&transaction.tx_data, src, len);
311 }
312
313 transaction.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
314 transaction.length = bits_to_send;
315 spi_device_transmit(self->spi, &transaction);
316
317 if (dest != NULL) {
318 memcpy(dest, &transaction.rx_data, len);
319 }
320 } else {
321 int offset = 0;
322 int bits_remaining = bits_to_send;
323 int optimum_word_size = 8 * self->bits / gcd(8, self->bits);
324 int max_transaction_bits = MP_HW_SPI_MAX_XFER_BITS / optimum_word_size * optimum_word_size;
325 spi_transaction_t *transaction, *result, transactions[2];
326 int i = 0;
327
328 spi_device_acquire_bus(self->spi, portMAX_DELAY);
329
330 while (bits_remaining) {
331 transaction = transactions + i++ % 2;
332 memset(transaction, 0, sizeof(spi_transaction_t));
333
334 transaction->length =
335 bits_remaining > max_transaction_bits ? max_transaction_bits : bits_remaining;
336
337 if (src != NULL) {
338 transaction->tx_buffer = src + offset;
339 }
340 if (dest != NULL) {
341 transaction->rx_buffer = dest + offset;
342 }
343
344 spi_device_queue_trans(self->spi, transaction, portMAX_DELAY);
345 bits_remaining -= transaction->length;
346
347 if (offset > 0) {
348 // wait for previously queued transaction
349 MP_THREAD_GIL_EXIT();
350 spi_device_get_trans_result(self->spi, &result, portMAX_DELAY);
351 MP_THREAD_GIL_ENTER();
352 }
353
354 // doesn't need ceil(); loop ends when bits_remaining is 0
355 offset += transaction->length / 8;
356 }
357
358 // wait for last transaction
359 MP_THREAD_GIL_EXIT();
360 spi_device_get_trans_result(self->spi, &result, portMAX_DELAY);
361 MP_THREAD_GIL_ENTER();
362 spi_device_release_bus(self->spi);
363 }
364 }
365
366 /******************************************************************************/
367 // MicroPython bindings for hw_spi
368
machine_hw_spi_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)369 STATIC void machine_hw_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
370 machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
371 mp_printf(print, "SPI(id=%u, baudrate=%u, polarity=%u, phase=%u, bits=%u, firstbit=%u, sck=%d, mosi=%d, miso=%d)",
372 self->host, self->baudrate, self->polarity,
373 self->phase, self->bits, self->firstbit,
374 self->sck, self->mosi, self->miso);
375 }
376
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)377 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) {
378 machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *)self_in;
379
380 enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
381 static const mp_arg_t allowed_args[] = {
382 { MP_QSTR_id, MP_ARG_INT, {.u_int = -1} },
383 { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
384 { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
385 { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
386 { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
387 { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
388 { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
389 { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
390 { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
391 };
392
393 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
394 mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args),
395 allowed_args, args);
396 int8_t sck, mosi, miso;
397
398 if (args[ARG_sck].u_obj == MP_OBJ_NULL) {
399 sck = -2;
400 } else if (args[ARG_sck].u_obj == mp_const_none) {
401 sck = -1;
402 } else {
403 sck = machine_pin_get_id(args[ARG_sck].u_obj);
404 }
405
406 if (args[ARG_miso].u_obj == MP_OBJ_NULL) {
407 miso = -2;
408 } else if (args[ARG_miso].u_obj == mp_const_none) {
409 miso = -1;
410 } else {
411 miso = machine_pin_get_id(args[ARG_miso].u_obj);
412 }
413
414 if (args[ARG_mosi].u_obj == MP_OBJ_NULL) {
415 mosi = -2;
416 } else if (args[ARG_mosi].u_obj == mp_const_none) {
417 mosi = -1;
418 } else {
419 mosi = machine_pin_get_id(args[ARG_mosi].u_obj);
420 }
421
422 machine_hw_spi_init_internal(self, args[ARG_id].u_int, args[ARG_baudrate].u_int,
423 args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int,
424 args[ARG_firstbit].u_int, sck, mosi, miso);
425 }
426
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)427 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) {
428 MP_MACHINE_SPI_CHECK_FOR_LEGACY_SOFTSPI_CONSTRUCTION(n_args, n_kw, all_args);
429
430 enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
431 static const mp_arg_t allowed_args[] = {
432 { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
433 { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} },
434 { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
435 { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
436 { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
437 { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_PY_MACHINE_SPI_MSB} },
438 { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
439 { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
440 { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
441 };
442 mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
443 mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
444
445 machine_hw_spi_obj_t *self;
446 const machine_hw_spi_default_pins_t *default_pins;
447 if (args[ARG_id].u_int == HSPI_HOST) {
448 self = &machine_hw_spi_obj[0];
449 default_pins = &machine_hw_spi_default_pins[0];
450 } else {
451 self = &machine_hw_spi_obj[1];
452 default_pins = &machine_hw_spi_default_pins[1];
453 }
454 self->base.type = &machine_hw_spi_type;
455
456 int8_t sck, mosi, miso;
457
458 if (args[ARG_sck].u_obj == MP_OBJ_NULL) {
459 sck = default_pins->sck;
460 } else if (args[ARG_sck].u_obj == mp_const_none) {
461 sck = -1;
462 } else {
463 sck = machine_pin_get_id(args[ARG_sck].u_obj);
464 }
465
466 if (args[ARG_mosi].u_obj == MP_OBJ_NULL) {
467 mosi = default_pins->mosi;
468 } else if (args[ARG_mosi].u_obj == mp_const_none) {
469 mosi = -1;
470 } else {
471 mosi = machine_pin_get_id(args[ARG_mosi].u_obj);
472 }
473
474 if (args[ARG_miso].u_obj == MP_OBJ_NULL) {
475 miso = default_pins->miso;
476 } else if (args[ARG_miso].u_obj == mp_const_none) {
477 miso = -1;
478 } else {
479 miso = machine_pin_get_id(args[ARG_miso].u_obj);
480 }
481
482 machine_hw_spi_init_internal(
483 self,
484 args[ARG_id].u_int,
485 args[ARG_baudrate].u_int,
486 args[ARG_polarity].u_int,
487 args[ARG_phase].u_int,
488 args[ARG_bits].u_int,
489 args[ARG_firstbit].u_int,
490 sck,
491 mosi,
492 miso);
493
494 return MP_OBJ_FROM_PTR(self);
495 }
496
497 STATIC const mp_machine_spi_p_t machine_hw_spi_p = {
498 .init = machine_hw_spi_init,
499 .deinit = machine_hw_spi_deinit,
500 .transfer = machine_hw_spi_transfer,
501 };
502
503 const mp_obj_type_t machine_hw_spi_type = {
504 { &mp_type_type },
505 .name = MP_QSTR_SPI,
506 .print = machine_hw_spi_print,
507 .make_new = machine_hw_spi_make_new,
508 .protocol = &machine_hw_spi_p,
509 .locals_dict = (mp_obj_dict_t *)&mp_machine_spi_locals_dict,
510 };
511