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