1 /*
2 * This file is part of the MicroPython project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013-2018 Damien P. George
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 <string.h>
29
30 #include "py/runtime.h"
31 #include "py/mphal.h"
32 #include "spi.h"
33
34 // Possible DMA configurations for SPI buses:
35 // SPI1_TX: DMA2_Stream3.CHANNEL_3 or DMA2_Stream5.CHANNEL_3
36 // SPI1_RX: DMA2_Stream0.CHANNEL_3 or DMA2_Stream2.CHANNEL_3
37 // SPI2_TX: DMA1_Stream4.CHANNEL_0
38 // SPI2_RX: DMA1_Stream3.CHANNEL_0
39 // SPI3_TX: DMA1_Stream5.CHANNEL_0 or DMA1_Stream7.CHANNEL_0
40 // SPI3_RX: DMA1_Stream0.CHANNEL_0 or DMA1_Stream2.CHANNEL_0
41 // SPI4_TX: DMA2_Stream4.CHANNEL_5 or DMA2_Stream1.CHANNEL_4
42 // SPI4_RX: DMA2_Stream3.CHANNEL_5 or DMA2_Stream0.CHANNEL_4
43 // SPI5_TX: DMA2_Stream4.CHANNEL_2 or DMA2_Stream6.CHANNEL_7
44 // SPI5_RX: DMA2_Stream3.CHANNEL_2 or DMA2_Stream5.CHANNEL_7
45 // SPI6_TX: DMA2_Stream5.CHANNEL_1
46 // SPI6_RX: DMA2_Stream6.CHANNEL_1
47
48 #if defined(MICROPY_HW_SPI1_SCK)
49 SPI_HandleTypeDef SPIHandle1 = {.Instance = NULL};
50 #endif
51 #if defined(MICROPY_HW_SPI2_SCK)
52 SPI_HandleTypeDef SPIHandle2 = {.Instance = NULL};
53 #endif
54 #if defined(MICROPY_HW_SPI3_SCK)
55 SPI_HandleTypeDef SPIHandle3 = {.Instance = NULL};
56 #endif
57 #if defined(MICROPY_HW_SPI4_SCK)
58 SPI_HandleTypeDef SPIHandle4 = {.Instance = NULL};
59 #endif
60 #if defined(MICROPY_HW_SPI5_SCK)
61 SPI_HandleTypeDef SPIHandle5 = {.Instance = NULL};
62 #endif
63 #if defined(MICROPY_HW_SPI6_SCK)
64 SPI_HandleTypeDef SPIHandle6 = {.Instance = NULL};
65 #endif
66
67 const spi_t spi_obj[6] = {
68 #if defined(MICROPY_HW_SPI1_SCK)
69 {&SPIHandle1, &dma_SPI_1_TX, &dma_SPI_1_RX},
70 #else
71 {NULL, NULL, NULL},
72 #endif
73 #if defined(MICROPY_HW_SPI2_SCK)
74 {&SPIHandle2, &dma_SPI_2_TX, &dma_SPI_2_RX},
75 #else
76 {NULL, NULL, NULL},
77 #endif
78 #if defined(MICROPY_HW_SPI3_SCK)
79 {&SPIHandle3, &dma_SPI_3_TX, &dma_SPI_3_RX},
80 #else
81 {NULL, NULL, NULL},
82 #endif
83 #if defined(MICROPY_HW_SPI4_SCK)
84 {&SPIHandle4, &dma_SPI_4_TX, &dma_SPI_4_RX},
85 #else
86 {NULL, NULL, NULL},
87 #endif
88 #if defined(MICROPY_HW_SPI5_SCK)
89 {&SPIHandle5, &dma_SPI_5_TX, &dma_SPI_5_RX},
90 #else
91 {NULL, NULL, NULL},
92 #endif
93 #if defined(MICROPY_HW_SPI6_SCK)
94 {&SPIHandle6, &dma_SPI_6_TX, &dma_SPI_6_RX},
95 #else
96 {NULL, NULL, NULL},
97 #endif
98 };
99
100 #if defined(STM32H7)
101 // STM32H7 HAL requires SPI IRQs to be enabled and handled.
102 #if defined(MICROPY_HW_SPI1_SCK)
SPI1_IRQHandler(void)103 void SPI1_IRQHandler(void) {
104 IRQ_ENTER(SPI1_IRQn);
105 HAL_SPI_IRQHandler(&SPIHandle1);
106 IRQ_EXIT(SPI1_IRQn);
107 }
108 #endif
109 #if defined(MICROPY_HW_SPI2_SCK)
SPI2_IRQHandler(void)110 void SPI2_IRQHandler(void) {
111 IRQ_ENTER(SPI2_IRQn);
112 HAL_SPI_IRQHandler(&SPIHandle2);
113 IRQ_EXIT(SPI2_IRQn);
114 }
115 #endif
116 #if defined(MICROPY_HW_SPI3_SCK)
SPI3_IRQHandler(void)117 void SPI3_IRQHandler(void) {
118 IRQ_ENTER(SPI3_IRQn);
119 HAL_SPI_IRQHandler(&SPIHandle3);
120 IRQ_EXIT(SPI3_IRQn);
121 }
122 #endif
123 #if defined(MICROPY_HW_SPI4_SCK)
SPI4_IRQHandler(void)124 void SPI4_IRQHandler(void) {
125 IRQ_ENTER(SPI4_IRQn);
126 HAL_SPI_IRQHandler(&SPIHandle4);
127 IRQ_EXIT(SPI4_IRQn);
128 }
129 #endif
130 #if defined(MICROPY_HW_SPI5_SCK)
SPI5_IRQHandler(void)131 void SPI5_IRQHandler(void) {
132 IRQ_ENTER(SPI5_IRQn);
133 HAL_SPI_IRQHandler(&SPIHandle5);
134 IRQ_EXIT(SPI5_IRQn);
135 }
136 #endif
137 #if defined(MICROPY_HW_SPI6_SCK)
SPI6_IRQHandler(void)138 void SPI6_IRQHandler(void) {
139 IRQ_ENTER(SPI6_IRQn);
140 HAL_SPI_IRQHandler(&SPIHandle6);
141 IRQ_EXIT(SPI6_IRQn);
142 }
143 #endif
144 #endif
145
spi_init0(void)146 void spi_init0(void) {
147 // Initialise the SPI handles.
148 // The structs live on the BSS so all other fields will be zero after a reset.
149 #if defined(MICROPY_HW_SPI1_SCK)
150 SPIHandle1.Instance = SPI1;
151 #endif
152 #if defined(MICROPY_HW_SPI2_SCK)
153 SPIHandle2.Instance = SPI2;
154 #endif
155 #if defined(MICROPY_HW_SPI3_SCK)
156 SPIHandle3.Instance = SPI3;
157 #endif
158 #if defined(MICROPY_HW_SPI4_SCK)
159 SPIHandle4.Instance = SPI4;
160 #endif
161 #if defined(MICROPY_HW_SPI5_SCK)
162 SPIHandle5.Instance = SPI5;
163 #endif
164 #if defined(MICROPY_HW_SPI6_SCK)
165 SPIHandle6.Instance = SPI6;
166 #endif
167 }
168
spi_find_index(mp_obj_t id)169 int spi_find_index(mp_obj_t id) {
170 int spi_id;
171 if (mp_obj_is_str(id)) {
172 // given a string id
173 const char *port = mp_obj_str_get_str(id);
174 if (0) {
175 #ifdef MICROPY_HW_SPI1_NAME
176 } else if (strcmp(port, MICROPY_HW_SPI1_NAME) == 0) {
177 spi_id = 1;
178 #endif
179 #ifdef MICROPY_HW_SPI2_NAME
180 } else if (strcmp(port, MICROPY_HW_SPI2_NAME) == 0) {
181 spi_id = 2;
182 #endif
183 #ifdef MICROPY_HW_SPI3_NAME
184 } else if (strcmp(port, MICROPY_HW_SPI3_NAME) == 0) {
185 spi_id = 3;
186 #endif
187 #ifdef MICROPY_HW_SPI4_NAME
188 } else if (strcmp(port, MICROPY_HW_SPI4_NAME) == 0) {
189 spi_id = 4;
190 #endif
191 #ifdef MICROPY_HW_SPI5_NAME
192 } else if (strcmp(port, MICROPY_HW_SPI5_NAME) == 0) {
193 spi_id = 5;
194 #endif
195 #ifdef MICROPY_HW_SPI6_NAME
196 } else if (strcmp(port, MICROPY_HW_SPI6_NAME) == 0) {
197 spi_id = 6;
198 #endif
199 } else {
200 mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%s) doesn't exist"), port);
201 }
202 } else {
203 // given an integer id
204 spi_id = mp_obj_get_int(id);
205 if (spi_id < 1 || spi_id > MP_ARRAY_SIZE(spi_obj) || spi_obj[spi_id - 1].spi == NULL) {
206 mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id);
207 }
208 }
209
210 // check if the SPI is reserved for system use or not
211 if (MICROPY_HW_SPI_IS_RESERVED(spi_id)) {
212 mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) is reserved"), spi_id);
213 }
214
215 return spi_id;
216 }
217
spi_get_source_freq(SPI_HandleTypeDef * spi)218 STATIC uint32_t spi_get_source_freq(SPI_HandleTypeDef *spi) {
219 #if defined(STM32F0)
220 return HAL_RCC_GetPCLK1Freq();
221 #elif defined(STM32H7)
222 if (spi->Instance == SPI1 || spi->Instance == SPI2 || spi->Instance == SPI3) {
223 return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123);
224 } else if (spi->Instance == SPI4 || spi->Instance == SPI5) {
225 return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI45);
226 } else {
227 return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6);
228 }
229 #else
230 #if defined(SPI2)
231 if (spi->Instance == SPI2) {
232 // SPI2 is on APB1
233 return HAL_RCC_GetPCLK1Freq();
234 } else
235 #endif
236 #if defined(SPI3)
237 if (spi->Instance == SPI3) {
238 // SPI3 is on APB1
239 return HAL_RCC_GetPCLK1Freq();
240 } else
241 #endif
242 {
243 // SPI1, SPI4, SPI5 and SPI6 are on APB2
244 return HAL_RCC_GetPCLK2Freq();
245 }
246 #endif
247 }
248
249 // sets the parameters in the SPI_InitTypeDef struct
250 // if an argument is -1 then the corresponding parameter is not changed
spi_set_params(const spi_t * spi_obj,uint32_t prescale,int32_t baudrate,int32_t polarity,int32_t phase,int32_t bits,int32_t firstbit)251 void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baudrate,
252 int32_t polarity, int32_t phase, int32_t bits, int32_t firstbit) {
253 SPI_HandleTypeDef *spi = spi_obj->spi;
254 SPI_InitTypeDef *init = &spi->Init;
255
256 if (prescale != 0xffffffff || baudrate != -1) {
257 if (prescale == 0xffffffff) {
258 // prescaler not given, so select one that yields at most the requested baudrate
259 prescale = (spi_get_source_freq(spi) + baudrate - 1) / baudrate;
260 }
261 if (prescale <= 2) {
262 init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
263 } else if (prescale <= 4) {
264 init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
265 } else if (prescale <= 8) {
266 init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
267 } else if (prescale <= 16) {
268 init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
269 } else if (prescale <= 32) {
270 init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
271 } else if (prescale <= 64) {
272 init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
273 } else if (prescale <= 128) {
274 init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
275 } else {
276 init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
277 }
278 }
279
280 if (polarity != -1) {
281 init->CLKPolarity = polarity == 0 ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH;
282 }
283
284 if (phase != -1) {
285 init->CLKPhase = phase == 0 ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE;
286 }
287
288 if (bits != -1) {
289 init->DataSize = (bits == 16) ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT;
290 }
291
292 if (firstbit != -1) {
293 init->FirstBit = firstbit;
294 }
295 }
296
297 // TODO allow to take a list of pins to use
spi_init(const spi_t * self,bool enable_nss_pin)298 void spi_init(const spi_t *self, bool enable_nss_pin) {
299 SPI_HandleTypeDef *spi = self->spi;
300 uint32_t irqn = 0;
301 const pin_obj_t *pins[4] = { NULL, NULL, NULL, NULL };
302
303 if (0) {
304 #if defined(MICROPY_HW_SPI1_SCK)
305 } else if (spi->Instance == SPI1) {
306 irqn = SPI1_IRQn;
307 #if defined(MICROPY_HW_SPI1_NSS)
308 pins[0] = MICROPY_HW_SPI1_NSS;
309 #endif
310 pins[1] = MICROPY_HW_SPI1_SCK;
311 #if defined(MICROPY_HW_SPI1_MISO)
312 pins[2] = MICROPY_HW_SPI1_MISO;
313 #endif
314 pins[3] = MICROPY_HW_SPI1_MOSI;
315 // enable the SPI clock
316 __HAL_RCC_SPI1_CLK_ENABLE();
317 #endif
318 #if defined(MICROPY_HW_SPI2_SCK)
319 } else if (spi->Instance == SPI2) {
320 irqn = SPI2_IRQn;
321 #if defined(MICROPY_HW_SPI2_NSS)
322 pins[0] = MICROPY_HW_SPI2_NSS;
323 #endif
324 pins[1] = MICROPY_HW_SPI2_SCK;
325 #if defined(MICROPY_HW_SPI2_MISO)
326 pins[2] = MICROPY_HW_SPI2_MISO;
327 #endif
328 pins[3] = MICROPY_HW_SPI2_MOSI;
329 // enable the SPI clock
330 __HAL_RCC_SPI2_CLK_ENABLE();
331 #endif
332 #if defined(MICROPY_HW_SPI3_SCK)
333 } else if (spi->Instance == SPI3) {
334 irqn = SPI3_IRQn;
335 #if defined(MICROPY_HW_SPI3_NSS)
336 pins[0] = MICROPY_HW_SPI3_NSS;
337 #endif
338 pins[1] = MICROPY_HW_SPI3_SCK;
339 #if defined(MICROPY_HW_SPI3_MISO)
340 pins[2] = MICROPY_HW_SPI3_MISO;
341 #endif
342 pins[3] = MICROPY_HW_SPI3_MOSI;
343 // enable the SPI clock
344 __HAL_RCC_SPI3_CLK_ENABLE();
345 #endif
346 #if defined(MICROPY_HW_SPI4_SCK)
347 } else if (spi->Instance == SPI4) {
348 irqn = SPI4_IRQn;
349 #if defined(MICROPY_HW_SPI4_NSS)
350 pins[0] = MICROPY_HW_SPI4_NSS;
351 #endif
352 pins[1] = MICROPY_HW_SPI4_SCK;
353 #if defined(MICROPY_HW_SPI4_MISO)
354 pins[2] = MICROPY_HW_SPI4_MISO;
355 #endif
356 pins[3] = MICROPY_HW_SPI4_MOSI;
357 // enable the SPI clock
358 __HAL_RCC_SPI4_CLK_ENABLE();
359 #endif
360 #if defined(MICROPY_HW_SPI5_SCK)
361 } else if (spi->Instance == SPI5) {
362 irqn = SPI5_IRQn;
363 #if defined(MICROPY_HW_SPI5_NSS)
364 pins[0] = MICROPY_HW_SPI5_NSS;
365 #endif
366 pins[1] = MICROPY_HW_SPI5_SCK;
367 #if defined(MICROPY_HW_SPI5_MISO)
368 pins[2] = MICROPY_HW_SPI5_MISO;
369 #endif
370 pins[3] = MICROPY_HW_SPI5_MOSI;
371 // enable the SPI clock
372 __HAL_RCC_SPI5_CLK_ENABLE();
373 #endif
374 #if defined(MICROPY_HW_SPI6_SCK)
375 } else if (spi->Instance == SPI6) {
376 irqn = SPI6_IRQn;
377 #if defined(MICROPY_HW_SPI6_NSS)
378 pins[0] = MICROPY_HW_SPI6_NSS;
379 #endif
380 pins[1] = MICROPY_HW_SPI6_SCK;
381 #if defined(MICROPY_HW_SPI6_MISO)
382 pins[2] = MICROPY_HW_SPI6_MISO;
383 #endif
384 pins[3] = MICROPY_HW_SPI6_MOSI;
385 // enable the SPI clock
386 __HAL_RCC_SPI6_CLK_ENABLE();
387 #endif
388 } else {
389 // SPI does not exist for this board (shouldn't get here, should be checked by caller)
390 return;
391 }
392
393 // init the GPIO lines
394 uint32_t mode = MP_HAL_PIN_MODE_ALT;
395 uint32_t pull = spi->Init.CLKPolarity == SPI_POLARITY_LOW ? MP_HAL_PIN_PULL_DOWN : MP_HAL_PIN_PULL_UP;
396 for (uint i = (enable_nss_pin ? 0 : 1); i < 4; i++) {
397 if (pins[i] == NULL) {
398 continue;
399 }
400 mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_SPI, (self - &spi_obj[0]) + 1);
401 }
402
403 // init the SPI device
404 if (HAL_SPI_Init(spi) != HAL_OK) {
405 // init error
406 // TODO should raise an exception, but this function is not necessarily going to be
407 // called via Python, so may not be properly wrapped in an NLR handler
408 printf("OSError: HAL_SPI_Init failed\n");
409 return;
410 }
411
412 // After calling HAL_SPI_Init() it seems that the DMA gets disconnected if
413 // it was previously configured. So we invalidate the DMA channel to force
414 // an initialisation the next time we use it.
415 dma_invalidate_channel(self->tx_dma_descr);
416 dma_invalidate_channel(self->rx_dma_descr);
417
418 #if defined(STM32H7)
419 NVIC_SetPriority(irqn, IRQ_PRI_SPI);
420 HAL_NVIC_EnableIRQ(irqn);
421 #else
422 (void)irqn;
423 #endif
424 }
425
spi_deinit(const spi_t * spi_obj)426 void spi_deinit(const spi_t *spi_obj) {
427 SPI_HandleTypeDef *spi = spi_obj->spi;
428 HAL_SPI_DeInit(spi);
429 if (0) {
430 #if defined(MICROPY_HW_SPI1_SCK)
431 } else if (spi->Instance == SPI1) {
432 __HAL_RCC_SPI1_FORCE_RESET();
433 __HAL_RCC_SPI1_RELEASE_RESET();
434 __HAL_RCC_SPI1_CLK_DISABLE();
435 HAL_NVIC_DisableIRQ(SPI1_IRQn);
436 #endif
437 #if defined(MICROPY_HW_SPI2_SCK)
438 } else if (spi->Instance == SPI2) {
439 __HAL_RCC_SPI2_FORCE_RESET();
440 __HAL_RCC_SPI2_RELEASE_RESET();
441 __HAL_RCC_SPI2_CLK_DISABLE();
442 HAL_NVIC_DisableIRQ(SPI2_IRQn);
443 #endif
444 #if defined(MICROPY_HW_SPI3_SCK)
445 } else if (spi->Instance == SPI3) {
446 __HAL_RCC_SPI3_FORCE_RESET();
447 __HAL_RCC_SPI3_RELEASE_RESET();
448 __HAL_RCC_SPI3_CLK_DISABLE();
449 HAL_NVIC_DisableIRQ(SPI3_IRQn);
450 #endif
451 #if defined(MICROPY_HW_SPI4_SCK)
452 } else if (spi->Instance == SPI4) {
453 __HAL_RCC_SPI4_FORCE_RESET();
454 __HAL_RCC_SPI4_RELEASE_RESET();
455 __HAL_RCC_SPI4_CLK_DISABLE();
456 HAL_NVIC_DisableIRQ(SPI4_IRQn);
457 #endif
458 #if defined(MICROPY_HW_SPI5_SCK)
459 } else if (spi->Instance == SPI5) {
460 __HAL_RCC_SPI5_FORCE_RESET();
461 __HAL_RCC_SPI5_RELEASE_RESET();
462 __HAL_RCC_SPI5_CLK_DISABLE();
463 HAL_NVIC_DisableIRQ(SPI5_IRQn);
464 #endif
465 #if defined(MICROPY_HW_SPI6_SCK)
466 } else if (spi->Instance == SPI6) {
467 __HAL_RCC_SPI6_FORCE_RESET();
468 __HAL_RCC_SPI6_RELEASE_RESET();
469 __HAL_RCC_SPI6_CLK_DISABLE();
470 HAL_NVIC_DisableIRQ(SPI6_IRQn);
471 #endif
472 }
473 }
474
spi_wait_dma_finished(const spi_t * spi,uint32_t t_start,uint32_t timeout)475 STATIC HAL_StatusTypeDef spi_wait_dma_finished(const spi_t *spi, uint32_t t_start, uint32_t timeout) {
476 volatile HAL_SPI_StateTypeDef *state = &spi->spi->State;
477 for (;;) {
478 // Do an atomic check of the state; WFI will exit even if IRQs are disabled
479 uint32_t irq_state = disable_irq();
480 if (*state == HAL_SPI_STATE_READY) {
481 enable_irq(irq_state);
482 return HAL_OK;
483 }
484 __WFI();
485 enable_irq(irq_state);
486 if (HAL_GetTick() - t_start >= timeout) {
487 return HAL_TIMEOUT;
488 }
489 }
490 return HAL_OK;
491 }
492
spi_transfer(const spi_t * self,size_t len,const uint8_t * src,uint8_t * dest,uint32_t timeout)493 void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint8_t *dest, uint32_t timeout) {
494 // Note: there seems to be a problem sending 1 byte using DMA the first
495 // time directly after the SPI/DMA is initialised. The cause of this is
496 // unknown but we sidestep the issue by using polling for 1 byte transfer.
497
498 // Note: DMA transfers are limited to 65535 bytes at a time.
499
500 HAL_StatusTypeDef status;
501
502 if (dest == NULL) {
503 // send only
504 if (len == 1 || query_irq() == IRQ_STATE_DISABLED) {
505 status = HAL_SPI_Transmit(self->spi, (uint8_t *)src, len, timeout);
506 } else {
507 DMA_HandleTypeDef tx_dma;
508 dma_init(&tx_dma, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, self->spi);
509 self->spi->hdmatx = &tx_dma;
510 self->spi->hdmarx = NULL;
511 MP_HAL_CLEAN_DCACHE(src, len);
512 uint32_t t_start = HAL_GetTick();
513 do {
514 uint32_t l = MIN(len, 65535);
515 status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t *)src, l);
516 if (status != HAL_OK) {
517 break;
518 }
519 status = spi_wait_dma_finished(self, t_start, timeout);
520 if (status != HAL_OK) {
521 break;
522 }
523 len -= l;
524 src += l;
525 } while (len);
526 dma_deinit(self->tx_dma_descr);
527 }
528 } else if (src == NULL) {
529 // receive only
530 if (len == 1 || query_irq() == IRQ_STATE_DISABLED) {
531 status = HAL_SPI_Receive(self->spi, dest, len, timeout);
532 } else {
533 DMA_HandleTypeDef tx_dma, rx_dma;
534 if (self->spi->Init.Mode == SPI_MODE_MASTER) {
535 // in master mode the HAL actually does a TransmitReceive call
536 dma_init(&tx_dma, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, self->spi);
537 self->spi->hdmatx = &tx_dma;
538 } else {
539 self->spi->hdmatx = NULL;
540 }
541 dma_init(&rx_dma, self->rx_dma_descr, DMA_PERIPH_TO_MEMORY, self->spi);
542 self->spi->hdmarx = &rx_dma;
543 MP_HAL_CLEANINVALIDATE_DCACHE(dest, len);
544 uint32_t t_start = HAL_GetTick();
545 do {
546 uint32_t l = MIN(len, 65535);
547 status = HAL_SPI_Receive_DMA(self->spi, dest, l);
548 if (status != HAL_OK) {
549 break;
550 }
551 status = spi_wait_dma_finished(self, t_start, timeout);
552 if (status != HAL_OK) {
553 break;
554 }
555 len -= l;
556 dest += l;
557 } while (len);
558 if (self->spi->hdmatx != NULL) {
559 dma_deinit(self->tx_dma_descr);
560 }
561 dma_deinit(self->rx_dma_descr);
562 }
563 } else {
564 // send and receive
565 if (len == 1 || query_irq() == IRQ_STATE_DISABLED) {
566 status = HAL_SPI_TransmitReceive(self->spi, (uint8_t *)src, dest, len, timeout);
567 } else {
568 DMA_HandleTypeDef tx_dma, rx_dma;
569 dma_init(&tx_dma, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, self->spi);
570 self->spi->hdmatx = &tx_dma;
571 dma_init(&rx_dma, self->rx_dma_descr, DMA_PERIPH_TO_MEMORY, self->spi);
572 self->spi->hdmarx = &rx_dma;
573 MP_HAL_CLEAN_DCACHE(src, len);
574 MP_HAL_CLEANINVALIDATE_DCACHE(dest, len);
575 uint32_t t_start = HAL_GetTick();
576 do {
577 uint32_t l = MIN(len, 65535);
578 status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t *)src, dest, l);
579 if (status != HAL_OK) {
580 break;
581 }
582 status = spi_wait_dma_finished(self, t_start, timeout);
583 if (status != HAL_OK) {
584 break;
585 }
586 len -= l;
587 src += l;
588 dest += l;
589 } while (len);
590 dma_deinit(self->tx_dma_descr);
591 dma_deinit(self->rx_dma_descr);
592 }
593 }
594
595 if (status != HAL_OK) {
596 mp_hal_raise(status);
597 }
598 }
599
spi_print(const mp_print_t * print,const spi_t * spi_obj,bool legacy)600 void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy) {
601 SPI_HandleTypeDef *spi = spi_obj->spi;
602
603 uint spi_num = 1; // default to SPI1
604 if (0) {
605 }
606 #if defined(SPI2)
607 else if (spi->Instance == SPI2) {
608 spi_num = 2;
609 }
610 #endif
611 #if defined(SPI3)
612 else if (spi->Instance == SPI3) {
613 spi_num = 3;
614 }
615 #endif
616 #if defined(SPI4)
617 else if (spi->Instance == SPI4) {
618 spi_num = 4;
619 }
620 #endif
621 #if defined(SPI5)
622 else if (spi->Instance == SPI5) {
623 spi_num = 5;
624 }
625 #endif
626 #if defined(SPI6)
627 else if (spi->Instance == SPI6) {
628 spi_num = 6;
629 }
630 #endif
631
632 mp_printf(print, "SPI(%u", spi_num);
633 if (spi->State != HAL_SPI_STATE_RESET) {
634 if (spi->Init.Mode == SPI_MODE_MASTER) {
635 // compute baudrate
636 #if defined(STM32H7)
637 uint log_prescaler = (spi->Init.BaudRatePrescaler >> 28) + 1;
638 #else
639 uint log_prescaler = (spi->Init.BaudRatePrescaler >> 3) + 1;
640 #endif
641 uint baudrate = spi_get_source_freq(spi) >> log_prescaler;
642 if (legacy) {
643 mp_printf(print, ", SPI.CONTROLLER");
644 }
645 mp_printf(print, ", baudrate=%u", baudrate);
646 if (legacy) {
647 mp_printf(print, ", prescaler=%u", 1 << log_prescaler);
648 }
649 } else {
650 mp_printf(print, ", SPI.PERIPHERAL");
651 }
652 mp_printf(print, ", polarity=%u, phase=%u, bits=%u", spi->Init.CLKPolarity == SPI_POLARITY_LOW ? 0 : 1, spi->Init.CLKPhase == SPI_PHASE_1EDGE ? 0 : 1, spi->Init.DataSize == SPI_DATASIZE_8BIT ? 8 : 16);
653 if (spi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) {
654 mp_printf(print, ", crc=0x%x", spi->Init.CRCPolynomial);
655 }
656 }
657 mp_print_str(print, ")");
658 }
659
spi_from_mp_obj(mp_obj_t o)660 const spi_t *spi_from_mp_obj(mp_obj_t o) {
661 if (mp_obj_is_type(o, &pyb_spi_type)) {
662 pyb_spi_obj_t *self = MP_OBJ_TO_PTR(o);
663 return self->spi;
664 } else if (mp_obj_is_type(o, &machine_hard_spi_type)) {
665 machine_hard_spi_obj_t *self = MP_OBJ_TO_PTR(o);
666 return self->spi;
667 } else {
668 mp_raise_TypeError(MP_ERROR_TEXT("expecting an SPI object"));
669 }
670 }
671
672 /******************************************************************************/
673 // Implementation of low-level SPI C protocol
674
spi_proto_ioctl(void * self_in,uint32_t cmd)675 STATIC int spi_proto_ioctl(void *self_in, uint32_t cmd) {
676 spi_proto_cfg_t *self = (spi_proto_cfg_t *)self_in;
677
678 switch (cmd) {
679 case MP_SPI_IOCTL_INIT:
680 self->spi->spi->Init.Mode = SPI_MODE_MASTER;
681 self->spi->spi->Init.Direction = SPI_DIRECTION_2LINES;
682 self->spi->spi->Init.NSS = SPI_NSS_SOFT;
683 self->spi->spi->Init.TIMode = SPI_TIMODE_DISABLE;
684 self->spi->spi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
685 spi_set_params(self->spi, 0xffffffff, self->baudrate,
686 self->polarity, self->phase, self->bits, self->firstbit);
687 spi_init(self->spi, false);
688 break;
689
690 case MP_SPI_IOCTL_DEINIT:
691 spi_deinit(self->spi);
692 break;
693 }
694
695 return 0;
696 }
697
spi_proto_transfer(void * self_in,size_t len,const uint8_t * src,uint8_t * dest)698 STATIC void spi_proto_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
699 spi_proto_cfg_t *self = (spi_proto_cfg_t *)self_in;
700 spi_transfer(self->spi, len, src, dest, SPI_TRANSFER_TIMEOUT(len));
701 }
702
703 const mp_spi_proto_t spi_proto = {
704 .ioctl = spi_proto_ioctl,
705 .transfer = spi_proto_transfer,
706 };
707