2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_SPI SPI Functions
6 * @brief PIOS interface to read and write from SPI ports
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
11 * @brief Hardware Abstraction Layer for SPI ports of STM32
12 * @see The GNU Public License (GPL) Version 3
15 * Note that additional chip select lines can be easily added by using
16 * the remaining free GPIOs of the core module. Shared SPI ports should be
17 * arbitrated with (FreeRTOS based) Mutexes to avoid collisions!
19 *****************************************************************************/
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 3 of the License, or
24 * (at your option) any later version.
26 * This program is distributed in the hope that it will be useful, but
27 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
28 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
31 * You should have received a copy of the GNU General Public License along
32 * with this program; if not, write to the Free Software Foundation, Inc.,
33 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
36 * @todo Clocking is wrong (interface is badly defined, should be speed not prescaler magic numbers)
37 * @todo DMA doesn't work. Fix it.
41 #ifdef PIOS_INCLUDE_SPI
43 #include <pios_spi_priv.h>
45 #define SPI_MAX_BLOCK_PIO 128
47 static bool PIOS_SPI_validate(__attribute__((unused
)) struct pios_spi_dev
*com_dev
)
49 /* Should check device magic here */
53 #if defined(PIOS_INCLUDE_FREERTOS)
54 static struct pios_spi_dev
*PIOS_SPI_alloc(void)
56 return pios_malloc(sizeof(struct pios_spi_dev
));
59 static struct pios_spi_dev pios_spi_devs
[PIOS_SPI_MAX_DEVS
];
60 static uint8_t pios_spi_num_devs
;
61 static struct pios_spi_dev
*PIOS_SPI_alloc(void)
63 if (pios_spi_num_devs
>= PIOS_SPI_MAX_DEVS
) {
67 return &pios_spi_devs
[pios_spi_num_devs
++];
72 * Initialises SPI pins
73 * \param[in] mode currently only mode 0 supported
74 * \return < 0 if initialisation failed
76 int32_t PIOS_SPI_Init(uint32_t *spi_id
, const struct pios_spi_cfg
*cfg
)
78 uint32_t init_ssel
= 0;
83 struct pios_spi_dev
*spi_dev
;
85 spi_dev
= (struct pios_spi_dev
*)PIOS_SPI_alloc();
90 /* Bind the configuration to the device instance */
93 #if defined(PIOS_INCLUDE_FREERTOS)
94 vSemaphoreCreateBinary(spi_dev
->busy
);
95 xSemaphoreGive(spi_dev
->busy
);
98 /* Disable callback function */
99 spi_dev
->callback
= NULL
;
101 /* Set rx/tx dummy bytes to a known value */
102 spi_dev
->rx_dummy_byte
= 0xFF;
103 spi_dev
->tx_dummy_byte
= 0xFF;
105 switch (spi_dev
->cfg
->init
.SPI_NSS
) {
107 if (spi_dev
->cfg
->init
.SPI_Mode
== SPI_Mode_Master
) {
108 /* We're a master in soft NSS mode, make sure we see NSS high at all times. */
109 SPI_NSSInternalSoftwareConfig(spi_dev
->cfg
->regs
, SPI_NSSInternalSoft_Set
);
110 /* Init as many slave selects as the config advertises. */
111 init_ssel
= spi_dev
->cfg
->slave_count
;
113 /* We're a slave in soft NSS mode, make sure we see NSS low at all times. */
114 SPI_NSSInternalSoftwareConfig(spi_dev
->cfg
->regs
, SPI_NSSInternalSoft_Reset
);
119 /* only legal for single-slave config */
120 PIOS_Assert(spi_dev
->cfg
->slave_count
== 1);
122 SPI_SSOutputCmd(spi_dev
->cfg
->regs
, (spi_dev
->cfg
->init
.SPI_Mode
== SPI_Mode_Master
) ? ENABLE
: DISABLE
);
123 /* FIXME: Should this also call SPI_SSOutputCmd()? */
130 /* Initialize the GPIO pins */
131 /* note __builtin_ctz() due to the difference between GPIO_PinX and GPIO_PinSourceX */
132 if (spi_dev
->cfg
->remap
) {
133 GPIO_PinAFConfig(spi_dev
->cfg
->sclk
.gpio
,
134 __builtin_ctz(spi_dev
->cfg
->sclk
.init
.GPIO_Pin
),
135 spi_dev
->cfg
->remap
);
136 GPIO_PinAFConfig(spi_dev
->cfg
->mosi
.gpio
,
137 __builtin_ctz(spi_dev
->cfg
->mosi
.init
.GPIO_Pin
),
138 spi_dev
->cfg
->remap
);
139 GPIO_PinAFConfig(spi_dev
->cfg
->miso
.gpio
,
140 __builtin_ctz(spi_dev
->cfg
->miso
.init
.GPIO_Pin
),
141 spi_dev
->cfg
->remap
);
142 for (uint32_t i
= 0; i
< init_ssel
; i
++) {
143 GPIO_PinAFConfig(spi_dev
->cfg
->ssel
[i
].gpio
,
144 __builtin_ctz(spi_dev
->cfg
->ssel
[i
].init
.GPIO_Pin
),
145 spi_dev
->cfg
->remap
);
148 GPIO_Init(spi_dev
->cfg
->sclk
.gpio
, (GPIO_InitTypeDef
*)&(spi_dev
->cfg
->sclk
.init
));
149 GPIO_Init(spi_dev
->cfg
->mosi
.gpio
, (GPIO_InitTypeDef
*)&(spi_dev
->cfg
->mosi
.init
));
150 GPIO_Init(spi_dev
->cfg
->miso
.gpio
, (GPIO_InitTypeDef
*)&(spi_dev
->cfg
->miso
.init
));
152 if (spi_dev
->cfg
->init
.SPI_NSS
!= SPI_NSS_Hard
) {
153 for (uint32_t i
= 0; i
< init_ssel
; i
++) {
154 /* Since we're driving the SSEL pin in software, ensure that the slave is deselected */
155 /* XXX multi-slave support - maybe have another SPI_NSS_ mode? */
156 GPIO_SetBits(spi_dev
->cfg
->ssel
[i
].gpio
, spi_dev
->cfg
->ssel
[i
].init
.GPIO_Pin
);
157 GPIO_Init(spi_dev
->cfg
->ssel
[i
].gpio
, (GPIO_InitTypeDef
*)&(spi_dev
->cfg
->ssel
[i
].init
));
161 /* Configure DMA for SPI Rx */
162 DMA_DeInit(spi_dev
->cfg
->dma
.rx
.channel
);
163 DMA_Cmd(spi_dev
->cfg
->dma
.rx
.channel
, DISABLE
);
164 DMA_Init(spi_dev
->cfg
->dma
.rx
.channel
, (DMA_InitTypeDef
*)&(spi_dev
->cfg
->dma
.rx
.init
));
166 /* Configure DMA for SPI Tx */
167 DMA_DeInit(spi_dev
->cfg
->dma
.tx
.channel
);
168 DMA_Cmd(spi_dev
->cfg
->dma
.tx
.channel
, DISABLE
);
169 DMA_Init(spi_dev
->cfg
->dma
.tx
.channel
, (DMA_InitTypeDef
*)&(spi_dev
->cfg
->dma
.tx
.init
));
171 /* Initialize the SPI block */
172 SPI_DeInit(spi_dev
->cfg
->regs
);
173 SPI_Init(spi_dev
->cfg
->regs
, (SPI_InitTypeDef
*)&(spi_dev
->cfg
->init
));
175 /* Configure CRC calculation */
176 if (spi_dev
->cfg
->use_crc
) {
177 SPI_CalculateCRC(spi_dev
->cfg
->regs
, ENABLE
);
179 SPI_CalculateCRC(spi_dev
->cfg
->regs
, DISABLE
);
183 SPI_Cmd(spi_dev
->cfg
->regs
, ENABLE
);
185 /* Enable SPI interrupts to DMA */
186 SPI_I2S_DMACmd(spi_dev
->cfg
->regs
, SPI_I2S_DMAReq_Tx
| SPI_I2S_DMAReq_Rx
, ENABLE
);
188 /* Must store this before enabling interrupt */
189 *spi_id
= (uint32_t)spi_dev
;
191 /* Configure DMA interrupt */
192 NVIC_Init((NVIC_InitTypeDef
*)&(spi_dev
->cfg
->dma
.irq
.init
));
201 * (Re-)initialises SPI peripheral clock rate
203 * \param[in] spi SPI number (0 or 1)
204 * \param[in] spi_prescaler configures the SPI speed:
206 * <LI>PIOS_SPI_PRESCALER_2: sets clock rate 27.7~ nS @ 72 MHz (36 MBit/s) (only supported for spi==0, spi1 uses 4 instead)
207 * <LI>PIOS_SPI_PRESCALER_4: sets clock rate 55.5~ nS @ 72 MHz (18 MBit/s)
208 * <LI>PIOS_SPI_PRESCALER_8: sets clock rate 111.1~ nS @ 72 MHz (9 MBit/s)
209 * <LI>PIOS_SPI_PRESCALER_16: sets clock rate 222.2~ nS @ 72 MHz (4.5 MBit/s)
210 * <LI>PIOS_SPI_PRESCALER_32: sets clock rate 444.4~ nS @ 72 MHz (2.25 MBit/s)
211 * <LI>PIOS_SPI_PRESCALER_64: sets clock rate 888.8~ nS @ 72 MHz (1.125 MBit/s)
212 * <LI>PIOS_SPI_PRESCALER_128: sets clock rate 1.7~ nS @ 72 MHz (0.562 MBit/s)
213 * <LI>PIOS_SPI_PRESCALER_256: sets clock rate 3.5~ nS @ 72 MHz (0.281 MBit/s)
215 * \return 0 if no error
216 * \return -1 if disabled SPI port selected
217 * \return -3 if invalid spi_prescaler selected
219 int32_t PIOS_SPI_SetClockSpeed(uint32_t spi_id
, SPIPrescalerTypeDef spi_prescaler
)
221 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
223 bool valid
= PIOS_SPI_validate(spi_dev
);
227 SPI_InitTypeDef SPI_InitStructure
;
229 if (spi_prescaler
>= 8) {
230 /* Invalid prescaler selected */
234 /* Start with a copy of the default configuration for the peripheral */
235 SPI_InitStructure
= spi_dev
->cfg
->init
;
237 /* Adjust the prescaler for the peripheral's clock */
238 SPI_InitStructure
.SPI_BaudRatePrescaler
= ((uint16_t)spi_prescaler
& 7) << 3;
240 /* Write back the new configuration */
241 SPI_Init(spi_dev
->cfg
->regs
, &SPI_InitStructure
);
243 PIOS_SPI_TransferByte(spi_id
, 0xFF);
248 * Claim the SPI bus semaphore. Calling the SPI functions does not require this
249 * \param[in] spi SPI number (0 or 1)
250 * \return 0 if no error
251 * \return -1 if timeout before claiming semaphore
253 int32_t PIOS_SPI_ClaimBus(uint32_t spi_id
)
255 #if defined(PIOS_INCLUDE_FREERTOS)
256 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
258 bool valid
= PIOS_SPI_validate(spi_dev
);
261 if (xSemaphoreTake(spi_dev
->busy
, 0xffff) != pdTRUE
) {
265 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
266 uint32_t timeout
= 0xffff;
267 while ((PIOS_SPI_Busy(spi_id
) || spi_dev
->busy
) && --timeout
) {
270 if (timeout
== 0) { // timed out
280 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
285 * Claim the SPI bus semaphore from an ISR. Has no timeout.
286 * \param[in] spi SPI number (0 or 1)
287 * \param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
288 * task has is now eligible to run, else unchanged
289 * \return 0 if no error
290 * \return -1 if timeout before claiming semaphore
292 int32_t PIOS_SPI_ClaimBusISR(uint32_t spi_id
, bool *woken
)
294 #if defined(PIOS_INCLUDE_FREERTOS)
295 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
296 signed portBASE_TYPE higherPriorityTaskWoken
= pdFALSE
;
298 bool valid
= PIOS_SPI_validate(spi_dev
);
301 if (xSemaphoreTakeFromISR(spi_dev
->busy
, &higherPriorityTaskWoken
) != pdTRUE
) {
305 *woken
= *woken
|| (higherPriorityTaskWoken
== pdTRUE
);
313 return PIOS_SPI_ClaimBus(spi_id
);
319 * Release the SPI bus semaphore. Calling the SPI functions does not require this
320 * \param[in] spi SPI number (0 or 1)
321 * \return 0 if no error
323 int32_t PIOS_SPI_ReleaseBus(uint32_t spi_id
)
325 #if defined(PIOS_INCLUDE_FREERTOS)
326 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
328 bool valid
= PIOS_SPI_validate(spi_dev
);
331 xSemaphoreGive(spi_dev
->busy
);
333 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
342 * Release the SPI bus semaphore from ISR. Calling the SPI functions does not require this
343 * \param[in] spi SPI number (0 or 1)
344 * \param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
345 * task has is now eligible to run, else unchanged
346 * \return 0 if no error
348 int32_t PIOS_SPI_ReleaseBusISR(uint32_t spi_id
, bool *woken
)
350 #if defined(PIOS_INCLUDE_FREERTOS)
351 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
352 signed portBASE_TYPE higherPriorityTaskWoken
= pdFALSE
;
354 bool valid
= PIOS_SPI_validate(spi_dev
);
357 xSemaphoreGiveFromISR(spi_dev
->busy
, &higherPriorityTaskWoken
);
359 *woken
= *woken
|| (higherPriorityTaskWoken
== pdTRUE
);
367 return PIOS_SPI_ReleaseBus(spi_id
);
374 * Controls the RC (Register Clock alias Chip Select) pin of a SPI port
375 * \param[in] spi SPI number (0 or 1)
376 * \param[in] pin_value 0 or 1
377 * \return 0 if no error
379 int32_t PIOS_SPI_RC_PinSet(uint32_t spi_id
, uint32_t slave_id
, uint8_t pin_value
)
381 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
383 bool valid
= PIOS_SPI_validate(spi_dev
);
386 PIOS_Assert(slave_id
<= spi_dev
->cfg
->slave_count
)
388 /* XXX multi-slave support? */
390 GPIO_SetBits(spi_dev
->cfg
->ssel
[slave_id
].gpio
, spi_dev
->cfg
->ssel
[slave_id
].init
.GPIO_Pin
);
392 GPIO_ResetBits(spi_dev
->cfg
->ssel
[slave_id
].gpio
, spi_dev
->cfg
->ssel
[slave_id
].init
.GPIO_Pin
);
399 * Transfers a byte to SPI output and reads back the return value from SPI input
400 * \param[in] spi SPI number (0 or 1)
401 * \param[in] b the byte which should be transfered
403 int32_t PIOS_SPI_TransferByte(uint32_t spi_id
, uint8_t b
)
405 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
407 bool valid
= PIOS_SPI_validate(spi_dev
);
415 * Procedure taken from STM32F10xxx Reference Manual section 23.3.5
418 /* Make sure the RXNE flag is cleared by reading the DR register */
419 /*dummy =*/ (void)spi_dev
->cfg
->regs
->DR
;
421 /* Start the transfer */
422 spi_dev
->cfg
->regs
->DR
= b
;
424 /* Wait until there is a byte to read */
425 while (!(spi_dev
->cfg
->regs
->SR
& SPI_I2S_FLAG_RXNE
)) {
429 /* Read the rx'd byte */
430 rx_byte
= spi_dev
->cfg
->regs
->DR
;
432 /* Wait until the TXE goes high */
433 while (!(spi_dev
->cfg
->regs
->SR
& SPI_I2S_FLAG_TXE
)) {
437 /* Wait for SPI transfer to have fully completed */
438 while (spi_dev
->cfg
->regs
->SR
& SPI_I2S_FLAG_BSY
) {
442 /* Return received byte */
447 * Transfers a block of bytes via DMA.
448 * \param[in] spi SPI number (0 or 1)
449 * \param[in] send_buffer pointer to buffer which should be sent.<BR>
450 * If NULL, 0xff (all-one) will be sent.
451 * \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
452 * If NULL, received bytes will be discarded.
453 * \param[in] len number of bytes which should be transfered
454 * \param[in] callback pointer to callback function which will be executed
455 * from DMA channel interrupt once the transfer is finished.
456 * If NULL, no callback function will be used, and PIOS_SPI_TransferBlock() will
457 * block until the transfer is finished.
458 * \return >= 0 if no error during transfer
459 * \return -1 if disabled SPI port selected
460 * \return -3 if function has been called during an ongoing DMA transfer
462 static int32_t SPI_DMA_TransferBlock(uint32_t spi_id
, const uint8_t *send_buffer
, uint8_t *receive_buffer
, uint16_t len
, void *callback
)
464 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
466 bool valid
= PIOS_SPI_validate(spi_dev
);
470 DMA_InitTypeDef dma_init
;
472 /* Exit if ongoing transfer */
473 if (DMA_GetCurrDataCounter(spi_dev
->cfg
->dma
.rx
.channel
)) {
477 /* Disable the DMA channels */
478 DMA_Cmd(spi_dev
->cfg
->dma
.rx
.channel
, DISABLE
);
479 DMA_Cmd(spi_dev
->cfg
->dma
.tx
.channel
, DISABLE
);
481 while (DMA_GetCmdStatus(spi_dev
->cfg
->dma
.rx
.channel
) == ENABLE
) {
484 while (DMA_GetCmdStatus(spi_dev
->cfg
->dma
.tx
.channel
) == ENABLE
) {
488 /* Disable the SPI peripheral */
489 /* Initialize the SPI block */
490 SPI_DeInit(spi_dev
->cfg
->regs
);
491 SPI_Init(spi_dev
->cfg
->regs
, (SPI_InitTypeDef
*)&(spi_dev
->cfg
->init
));
492 SPI_Cmd(spi_dev
->cfg
->regs
, DISABLE
);
493 /* Configure CRC calculation */
494 if (spi_dev
->cfg
->use_crc
) {
495 SPI_CalculateCRC(spi_dev
->cfg
->regs
, ENABLE
);
497 SPI_CalculateCRC(spi_dev
->cfg
->regs
, DISABLE
);
500 /* Enable SPI interrupts to DMA */
501 SPI_I2S_DMACmd(spi_dev
->cfg
->regs
, SPI_I2S_DMAReq_Tx
| SPI_I2S_DMAReq_Rx
, ENABLE
);
503 /* Set callback function */
504 spi_dev
->callback
= callback
;
507 * Configure Rx channel
510 /* Start with the default configuration for this peripheral */
511 dma_init
= spi_dev
->cfg
->dma
.rx
.init
;
512 DMA_DeInit(spi_dev
->cfg
->dma
.rx
.channel
);
513 if (receive_buffer
!= NULL
) {
514 /* Enable memory addr. increment - bytes written into receive buffer */
515 dma_init
.DMA_Memory0BaseAddr
= (uint32_t)receive_buffer
;
516 dma_init
.DMA_MemoryInc
= DMA_MemoryInc_Enable
;
518 /* Disable memory addr. increment - bytes written into dummy buffer */
519 spi_dev
->rx_dummy_byte
= 0xFF;
520 dma_init
.DMA_Memory0BaseAddr
= (uint32_t)&spi_dev
->rx_dummy_byte
;
521 dma_init
.DMA_MemoryInc
= DMA_MemoryInc_Disable
;
523 if (spi_dev
->cfg
->use_crc
) {
524 /* Make sure the CRC error flag is cleared before we start */
525 SPI_I2S_ClearFlag(spi_dev
->cfg
->regs
, SPI_FLAG_CRCERR
);
528 dma_init
.DMA_BufferSize
= len
;
529 DMA_Init(spi_dev
->cfg
->dma
.rx
.channel
, &(dma_init
));
532 * Configure Tx channel
535 /* Start with the default configuration for this peripheral */
536 dma_init
= spi_dev
->cfg
->dma
.tx
.init
;
537 DMA_DeInit(spi_dev
->cfg
->dma
.tx
.channel
);
538 if (send_buffer
!= NULL
) {
539 /* Enable memory addr. increment - bytes written into receive buffer */
540 dma_init
.DMA_Memory0BaseAddr
= (uint32_t)send_buffer
;
541 dma_init
.DMA_MemoryInc
= DMA_MemoryInc_Enable
;
543 /* Disable memory addr. increment - bytes written into dummy buffer */
544 spi_dev
->tx_dummy_byte
= 0xFF;
545 dma_init
.DMA_Memory0BaseAddr
= (uint32_t)&spi_dev
->tx_dummy_byte
;
546 dma_init
.DMA_MemoryInc
= DMA_MemoryInc_Disable
;
549 if (spi_dev
->cfg
->use_crc
) {
550 /* The last byte of the payload will be replaced with the CRC8 */
551 dma_init
.DMA_BufferSize
= len
- 1;
553 dma_init
.DMA_BufferSize
= len
;
556 DMA_Init(spi_dev
->cfg
->dma
.tx
.channel
, &(dma_init
));
558 /* Enable DMA interrupt if callback function active */
559 DMA_ITConfig(spi_dev
->cfg
->dma
.rx
.channel
, DMA_IT_TC
, (callback
!= NULL
) ? ENABLE
: DISABLE
);
561 /* Flush out the CRC registers */
562 SPI_CalculateCRC(spi_dev
->cfg
->regs
, DISABLE
);
563 (void)SPI_GetCRC(spi_dev
->cfg
->regs
, SPI_CRC_Rx
);
564 SPI_I2S_ClearFlag(spi_dev
->cfg
->regs
, SPI_FLAG_CRCERR
);
566 /* Make sure to flush out the receive buffer */
567 (void)SPI_I2S_ReceiveData(spi_dev
->cfg
->regs
);
569 if (spi_dev
->cfg
->use_crc
) {
570 /* Need a 0->1 transition to reset the CRC logic */
571 SPI_CalculateCRC(spi_dev
->cfg
->regs
, ENABLE
);
574 /* Start DMA transfers */
575 DMA_Cmd(spi_dev
->cfg
->dma
.rx
.channel
, ENABLE
);
576 DMA_Cmd(spi_dev
->cfg
->dma
.tx
.channel
, ENABLE
);
578 /* Reenable the SPI device */
579 SPI_Cmd(spi_dev
->cfg
->regs
, ENABLE
);
582 /* User has requested a callback, don't wait for the transfer to complete. */
586 /* Wait until all bytes have been transmitted/received */
587 while (DMA_GetCurrDataCounter(spi_dev
->cfg
->dma
.rx
.channel
)) {
588 #if defined(PIOS_INCLUDE_FREERTOS)
594 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
595 while (!(SPI_I2S_GetFlagStatus(spi_dev
->cfg
->regs
, SPI_I2S_FLAG_TXE
))) {
599 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
600 while (SPI_I2S_GetFlagStatus(spi_dev
->cfg
->regs
, SPI_I2S_FLAG_BSY
)) {
604 /* Check the CRC on the transfer if enabled. */
605 if (spi_dev
->cfg
->use_crc
) {
606 /* Check the SPI CRC error flag */
607 if (SPI_I2S_GetFlagStatus(spi_dev
->cfg
->regs
, SPI_FLAG_CRCERR
)) {
617 * Transfers a block of bytes via PIO.
619 * \param[in] spi_id SPI device handle
620 * \param[in] send_buffer pointer to buffer which should be sent.<BR>
621 * If NULL, 0xff (all-one) will be sent.
622 * \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
623 * If NULL, received bytes will be discarded.
624 * \param[in] len number of bytes which should be transfered
625 * \return >= 0 if no error during transfer
626 * \return -1 if disabled SPI port selected
627 * \return -3 if function has been called during an ongoing DMA transfer
629 static int32_t SPI_PIO_TransferBlock(uint32_t spi_id
, const uint8_t *send_buffer
, uint8_t *receive_buffer
, uint16_t len
)
631 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
634 bool valid
= PIOS_SPI_validate(spi_dev
);
638 /* Exit if ongoing transfer */
639 if (DMA_GetCurrDataCounter(spi_dev
->cfg
->dma
.rx
.channel
)) {
643 /* Make sure the RXNE flag is cleared by reading the DR register */
644 b
= spi_dev
->cfg
->regs
->DR
;
647 /* get the byte to send */
648 b
= send_buffer
? *(send_buffer
++) : 0xff;
650 /* Start the transfer */
651 spi_dev
->cfg
->regs
->DR
= b
;
653 /* Wait until there is a byte to read */
654 while (!(spi_dev
->cfg
->regs
->SR
& SPI_I2S_FLAG_RXNE
)) {
658 /* Read the rx'd byte */
659 b
= spi_dev
->cfg
->regs
->DR
;
661 /* save the received byte */
662 if (receive_buffer
) {
663 *(receive_buffer
++) = b
;
666 /* Wait until the TXE goes high */
667 while (!(spi_dev
->cfg
->regs
->SR
& SPI_I2S_FLAG_TXE
)) {
672 /* Wait for SPI transfer to have fully completed */
673 while (spi_dev
->cfg
->regs
->SR
& SPI_I2S_FLAG_BSY
) {
682 * Transfers a block of bytes via PIO or DMA.
683 * \param[in] spi_id SPI device handle
684 * \param[in] send_buffer pointer to buffer which should be sent.<BR>
685 * If NULL, 0xff (all-one) will be sent.
686 * \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
687 * If NULL, received bytes will be discarded.
688 * \param[in] len number of bytes which should be transfered
689 * \param[in] callback pointer to callback function which will be executed
690 * from DMA channel interrupt once the transfer is finished.
691 * If NULL, no callback function will be used, and PIOS_SPI_TransferBlock() will
692 * block until the transfer is finished.
693 * \return >= 0 if no error during transfer
694 * \return -1 if disabled SPI port selected
695 * \return -3 if function has been called during an ongoing DMA transfer
697 int32_t PIOS_SPI_TransferBlock(uint32_t spi_id
, const uint8_t *send_buffer
, uint8_t *receive_buffer
, uint16_t len
, void *callback
)
699 if (callback
|| len
> SPI_MAX_BLOCK_PIO
) {
700 return SPI_DMA_TransferBlock(spi_id
, send_buffer
, receive_buffer
, len
, callback
);
702 return SPI_PIO_TransferBlock(spi_id
, send_buffer
, receive_buffer
, len
);
706 * Check if a transfer is in progress
707 * \param[in] spi SPI number (0 or 1)
708 * \return >= 0 if no transfer is in progress
709 * \return -1 if disabled SPI port selected
710 * \return -2 if unsupported SPI port selected
711 * \return -3 if function has been called during an ongoing DMA transfer
713 int32_t PIOS_SPI_Busy(uint32_t spi_id
)
715 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
717 bool valid
= PIOS_SPI_validate(spi_dev
);
721 /* DMA buffer has data or SPI transmit register not empty or SPI is busy*/
722 if (DMA_GetCurrDataCounter(spi_dev
->cfg
->dma
.rx
.channel
) ||
723 !SPI_I2S_GetFlagStatus(spi_dev
->cfg
->regs
, SPI_I2S_FLAG_TXE
) ||
724 SPI_I2S_GetFlagStatus(spi_dev
->cfg
->regs
, SPI_I2S_FLAG_BSY
)) {
731 void PIOS_SPI_IRQ_Handler(uint32_t spi_id
)
733 struct pios_spi_dev
*spi_dev
= (struct pios_spi_dev
*)spi_id
;
735 bool valid
= PIOS_SPI_validate(spi_dev
);
739 // FIXME XXX Only RX channel or better clear flags for both channels?
740 DMA_ClearFlag(spi_dev
->cfg
->dma
.rx
.channel
, spi_dev
->cfg
->dma
.irq
.flags
);
742 if (spi_dev
->cfg
->init
.SPI_Mode
== SPI_Mode_Master
) {
743 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
744 while (!(SPI_I2S_GetFlagStatus(spi_dev
->cfg
->regs
, SPI_I2S_FLAG_TXE
))) {
748 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
749 while (SPI_I2S_GetFlagStatus(spi_dev
->cfg
->regs
, SPI_I2S_FLAG_BSY
)) {
754 if (spi_dev
->callback
!= NULL
) {
758 if (SPI_I2S_GetFlagStatus(spi_dev
->cfg
->regs
, SPI_FLAG_CRCERR
)) {
760 SPI_I2S_ClearFlag(spi_dev
->cfg
->regs
, SPI_FLAG_CRCERR
);
762 crc_val
= SPI_GetCRC(spi_dev
->cfg
->regs
, SPI_CRC_Rx
);
763 spi_dev
->callback(crc_ok
, crc_val
);
767 #endif /* PIOS_INCLUDE_SPI */