Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / flight / pios / stm32f0x / pios_spi.c
blobf408ab798027ed6aaafe439b2a2507c9b8690385
1 /**
2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
4 * @{
5 * @addtogroup PIOS_SPI SPI Functions
6 * @brief PIOS interface to read and write from SPI ports
7 * @{
9 * @file pios_spi.c
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
13 * @notes
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
29 * for more details.
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 #include <pios.h>
38 #ifdef PIOS_INCLUDE_SPI
40 #include <pios_spi_priv.h>
42 #define SPI_MAX_BLOCK_PIO 128
44 static bool PIOS_SPI_validate(__attribute__((unused)) struct pios_spi_dev *com_dev)
46 /* Should check device magic here */
47 return true;
50 #if defined(PIOS_INCLUDE_FREERTOS)
51 static struct pios_spi_dev *PIOS_SPI_alloc(void)
53 return pvPortMalloc(sizeof(struct pios_spi_dev));
55 #else
56 static struct pios_spi_dev pios_spi_devs[PIOS_SPI_MAX_DEVS];
57 static uint8_t pios_spi_num_devs;
58 static struct pios_spi_dev *PIOS_SPI_alloc(void)
60 if (pios_spi_num_devs >= PIOS_SPI_MAX_DEVS) {
61 return NULL;
64 return &pios_spi_devs[pios_spi_num_devs++];
66 #endif
68 /**
69 * Initialises SPI pins
70 * \param[in] mode currently only mode 0 supported
71 * \return < 0 if initialisation failed
73 int32_t PIOS_SPI_Init(uint32_t *spi_id, const struct pios_spi_cfg *cfg)
75 uint32_t init_ssel = 0;
77 PIOS_Assert(spi_id);
78 PIOS_Assert(cfg);
80 struct pios_spi_dev *spi_dev;
82 spi_dev = (struct pios_spi_dev *)PIOS_SPI_alloc();
83 if (!spi_dev) {
84 goto out_fail;
87 /* Bind the configuration to the device instance */
88 spi_dev->cfg = cfg;
90 #if defined(PIOS_INCLUDE_FREERTOS)
91 vSemaphoreCreateBinary(spi_dev->busy);
92 xSemaphoreGive(spi_dev->busy);
93 #else
94 spi_dev->busy = 0;
95 #endif
96 /* Disable callback function */
97 spi_dev->callback = NULL;
99 /* Set rx/tx dummy bytes to a known value */
100 spi_dev->rx_dummy_byte = 0xFF;
101 spi_dev->tx_dummy_byte = 0xFF;
103 switch (spi_dev->cfg->init.SPI_NSS) {
104 case SPI_NSS_Soft:
105 if (spi_dev->cfg->init.SPI_Mode == SPI_Mode_Master) {
106 /* We're a master in soft NSS mode, make sure we see NSS high at all times. */
107 SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Set);
108 /* Init as many slave selects as the config advertises. */
109 init_ssel = spi_dev->cfg->slave_count;
110 } else {
111 /* We're a slave in soft NSS mode, make sure we see NSS low at all times. */
112 SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Reset);
114 break;
116 case SPI_NSS_Hard:
117 /* only legal for single-slave config */
118 PIOS_Assert(spi_dev->cfg->slave_count == 1);
119 init_ssel = 1;
120 SPI_SSOutputCmd(spi_dev->cfg->regs, (spi_dev->cfg->init.SPI_Mode == SPI_Mode_Master) ? ENABLE : DISABLE);
121 /* FIXME: Should this also call SPI_SSOutputCmd()? */
122 break;
124 default:
125 PIOS_Assert(0);
128 /* Initialize the GPIO pins */
129 /* note __builtin_ctz() due to the difference between GPIO_PinX and GPIO_PinSourceX */
130 GPIO_Init(spi_dev->cfg->sclk.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->sclk.init));
131 GPIO_Init(spi_dev->cfg->mosi.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->mosi.init));
132 GPIO_Init(spi_dev->cfg->miso.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->miso.init));
134 if (spi_dev->cfg->remap) {
135 GPIO_PinAFConfig(spi_dev->cfg->sclk.gpio,
136 __builtin_ctz(spi_dev->cfg->sclk.init.GPIO_Pin),
137 spi_dev->cfg->remap);
138 GPIO_PinAFConfig(spi_dev->cfg->mosi.gpio,
139 __builtin_ctz(spi_dev->cfg->mosi.init.GPIO_Pin),
140 spi_dev->cfg->remap);
141 GPIO_PinAFConfig(spi_dev->cfg->miso.gpio,
142 __builtin_ctz(spi_dev->cfg->miso.init.GPIO_Pin),
143 spi_dev->cfg->remap);
145 if (spi_dev->cfg->init.SPI_NSS != SPI_NSS_Hard) {
146 for (uint32_t i = 0; i < init_ssel; i++) {
147 /* Since we're driving the SSEL pin in software, ensure that the slave is deselected */
148 /* XXX multi-slave support - maybe have another SPI_NSS_ mode? */
149 GPIO_SetBits(spi_dev->cfg->ssel[i].gpio, spi_dev->cfg->ssel[i].init.GPIO_Pin);
150 GPIO_Init(spi_dev->cfg->ssel[i].gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->ssel[i].init));
154 /* Configure DMA for SPI Rx */
155 DMA_DeInit(spi_dev->cfg->dma.rx.channel);
156 DMA_Cmd(spi_dev->cfg->dma.rx.channel, DISABLE);
157 DMA_Init(spi_dev->cfg->dma.rx.channel, (DMA_InitTypeDef *)&(spi_dev->cfg->dma.rx.init));
159 /* Configure DMA for SPI Tx */
160 DMA_DeInit(spi_dev->cfg->dma.tx.channel);
161 DMA_Cmd(spi_dev->cfg->dma.tx.channel, DISABLE);
162 DMA_Init(spi_dev->cfg->dma.tx.channel, (DMA_InitTypeDef *)&(spi_dev->cfg->dma.tx.init));
164 /* Initialize the SPI block */
165 SPI_I2S_DeInit(spi_dev->cfg->regs);
166 SPI_Init(spi_dev->cfg->regs, (SPI_InitTypeDef *)&(spi_dev->cfg->init));
168 /* Configure CRC calculation */
169 if (spi_dev->cfg->use_crc) {
170 SPI_CalculateCRC(spi_dev->cfg->regs, ENABLE);
171 } else {
172 SPI_CalculateCRC(spi_dev->cfg->regs, DISABLE);
175 /* Enable SPI */
176 SPI_Cmd(spi_dev->cfg->regs, ENABLE);
178 /* Enable SPI interrupts to DMA */
179 SPI_I2S_DMACmd(spi_dev->cfg->regs, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);
181 /* Must store this before enabling interrupt */
182 *spi_id = (uint32_t)spi_dev;
184 /* Configure DMA interrupt */
185 NVIC_Init((NVIC_InitTypeDef *)&(spi_dev->cfg->dma.irq.init));
187 return 0;
189 out_fail:
190 return -1;
194 * (Re-)initialises SPI peripheral clock rate
196 * \param[in] spi SPI number (0 or 1)
197 * \param[in] spi_prescaler configures the SPI speed:
198 * <UL>
199 * <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)
200 * <LI>PIOS_SPI_PRESCALER_4: sets clock rate 55.5~ nS @ 72 MHz (18 MBit/s)
201 * <LI>PIOS_SPI_PRESCALER_8: sets clock rate 111.1~ nS @ 72 MHz (9 MBit/s)
202 * <LI>PIOS_SPI_PRESCALER_16: sets clock rate 222.2~ nS @ 72 MHz (4.5 MBit/s)
203 * <LI>PIOS_SPI_PRESCALER_32: sets clock rate 444.4~ nS @ 72 MHz (2.25 MBit/s)
204 * <LI>PIOS_SPI_PRESCALER_64: sets clock rate 888.8~ nS @ 72 MHz (1.125 MBit/s)
205 * <LI>PIOS_SPI_PRESCALER_128: sets clock rate 1.7~ nS @ 72 MHz (0.562 MBit/s)
206 * <LI>PIOS_SPI_PRESCALER_256: sets clock rate 3.5~ nS @ 72 MHz (0.281 MBit/s)
207 * </UL>
208 * \return 0 if no error
209 * \return -1 if disabled SPI port selected
210 * \return -3 if invalid spi_prescaler selected
212 int32_t PIOS_SPI_SetClockSpeed(uint32_t spi_id, SPIPrescalerTypeDef spi_prescaler)
214 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
216 bool valid = PIOS_SPI_validate(spi_dev);
218 PIOS_Assert(valid)
220 SPI_InitTypeDef SPI_InitStructure;
222 if (spi_prescaler >= 8) {
223 /* Invalid prescaler selected */
224 return -3;
227 /* Start with a copy of the default configuration for the peripheral */
228 SPI_InitStructure = spi_dev->cfg->init;
230 /* Adjust the prescaler for the peripheral's clock */
231 SPI_InitStructure.SPI_BaudRatePrescaler = ((uint16_t)spi_prescaler & 7) << 3;
233 /* Write back the new configuration */
234 SPI_Init(spi_dev->cfg->regs, &SPI_InitStructure);
236 PIOS_SPI_TransferByte(spi_id, 0xFF);
237 return 0;
241 * Claim the SPI bus semaphore. Calling the SPI functions does not require this
242 * \param[in] spi SPI number (0 or 1)
243 * \return 0 if no error
244 * \return -1 if timeout before claiming semaphore
246 int32_t PIOS_SPI_ClaimBus(uint32_t spi_id)
248 #if defined(PIOS_INCLUDE_FREERTOS)
249 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
251 bool valid = PIOS_SPI_validate(spi_dev);
252 PIOS_Assert(valid)
254 if (xSemaphoreTake(spi_dev->busy, 0xffff) != pdTRUE) {
255 return -1;
257 #else
258 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
259 uint32_t timeout = 0xffff;
260 while ((PIOS_SPI_Busy(spi_id) || spi_dev->busy) && --timeout) {
263 if (timeout == 0) { // timed out
264 return -1;
267 PIOS_IRQ_Disable();
268 if (spi_dev->busy) {
269 return -1;
271 spi_dev->busy = 1;
272 PIOS_IRQ_Enable();
273 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
274 return 0;
278 * Claim the SPI bus semaphore from an ISR. Has no timeout.
279 * \param[in] spi SPI number (0 or 1)
280 * \param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
281 * task has is now eligible to run, else unchanged
282 * \return 0 if no error
283 * \return -1 if timeout before claiming semaphore
285 int32_t PIOS_SPI_ClaimBusISR(uint32_t spi_id, bool *woken)
287 #if defined(PIOS_INCLUDE_FREERTOS)
288 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
289 signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE;
291 bool valid = PIOS_SPI_validate(spi_dev);
292 PIOS_Assert(valid)
294 if (xSemaphoreTakeFromISR(spi_dev->busy, &higherPriorityTaskWoken) != pdTRUE) {
295 return -1;
297 if (woken) {
298 *woken = *woken || (higherPriorityTaskWoken == pdTRUE);
300 return 0;
302 #else
303 if (woken) {
304 *woken = false;
306 return PIOS_SPI_ClaimBus(spi_id);
308 #endif
312 * Release the SPI bus semaphore. Calling the SPI functions does not require this
313 * \param[in] spi SPI number (0 or 1)
314 * \return 0 if no error
316 int32_t PIOS_SPI_ReleaseBus(uint32_t spi_id)
318 #if defined(PIOS_INCLUDE_FREERTOS)
319 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
321 bool valid = PIOS_SPI_validate(spi_dev);
322 PIOS_Assert(valid)
324 xSemaphoreGive(spi_dev->busy);
325 #else
326 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
327 PIOS_IRQ_Disable();
328 spi_dev->busy = 0;
329 PIOS_IRQ_Enable();
330 #endif
331 return 0;
335 * Release the SPI bus semaphore from ISR. Calling the SPI functions does not require this
336 * \param[in] spi SPI number (0 or 1)
337 * \param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
338 * task has is now eligible to run, else unchanged
339 * \return 0 if no error
341 int32_t PIOS_SPI_ReleaseBusISR(uint32_t spi_id, bool *woken)
343 #if defined(PIOS_INCLUDE_FREERTOS)
344 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
345 signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE;
347 bool valid = PIOS_SPI_validate(spi_dev);
348 PIOS_Assert(valid)
350 xSemaphoreGiveFromISR(spi_dev->busy, &higherPriorityTaskWoken);
351 if (woken) {
352 *woken = *woken || (higherPriorityTaskWoken == pdTRUE);
354 return 0;
356 #else
357 if (woken) {
358 *woken = false;
360 return PIOS_SPI_ReleaseBus(spi_id);
362 #endif
367 * Controls the RC (Register Clock alias Chip Select) pin of a SPI port
368 * \param[in] spi SPI number (0 or 1)
369 * \param[in] pin_value 0 or 1
370 * \return 0 if no error
372 int32_t PIOS_SPI_RC_PinSet(uint32_t spi_id, uint32_t slave_id, uint8_t pin_value)
374 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
376 bool valid = PIOS_SPI_validate(spi_dev);
378 PIOS_Assert(valid)
379 PIOS_Assert(slave_id <= spi_dev->cfg->slave_count)
381 /* XXX multi-slave support? */
382 if (pin_value) {
383 GPIO_SetBits(spi_dev->cfg->ssel[slave_id].gpio, spi_dev->cfg->ssel[slave_id].init.GPIO_Pin);
384 } else {
385 GPIO_ResetBits(spi_dev->cfg->ssel[slave_id].gpio, spi_dev->cfg->ssel[slave_id].init.GPIO_Pin);
388 return 0;
392 * Transfers a byte to SPI output and reads back the return value from SPI input
393 * \param[in] spi SPI number (0 or 1)
394 * \param[in] b the byte which should be transfered
396 int32_t PIOS_SPI_TransferByte(uint32_t spi_id, uint8_t b)
398 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
400 bool valid = PIOS_SPI_validate(spi_dev);
402 PIOS_Assert(valid)
404 // uint8_t dummy;
405 uint8_t rx_byte;
408 * Procedure taken from STM32F10xxx Reference Manual section 23.3.5
411 SPI_RxFIFOThresholdConfig(spi_dev->cfg->regs, SPI_RxFIFOThreshold_QF);
413 /* Make sure the RXNE flag is cleared by reading the DR register */
414 /*dummy =*/ (void)spi_dev->cfg->regs->DR;
416 /* Start the transfer */
417 SPI_SendData8(spi_dev->cfg->regs, b);
418 /* Wait until there is a byte to read */
419 while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_RXNE)) {
423 /* Read the rx'd byte */
424 rx_byte = SPI_ReceiveData8(spi_dev->cfg->regs);
425 /* Wait until the TXE goes high */
426 while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_TXE)) {
430 /* Wait for SPI transfer to have fully completed */
431 while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY) {
435 /* Return received byte */
436 return rx_byte;
440 * Transfers a block of bytes via DMA.
441 * \param[in] spi SPI number (0 or 1)
442 * \param[in] send_buffer pointer to buffer which should be sent.<BR>
443 * If NULL, 0xff (all-one) will be sent.
444 * \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
445 * If NULL, received bytes will be discarded.
446 * \param[in] len number of bytes which should be transfered
447 * \param[in] callback pointer to callback function which will be executed
448 * from DMA channel interrupt once the transfer is finished.
449 * If NULL, no callback function will be used, and PIOS_SPI_TransferBlock() will
450 * block until the transfer is finished.
451 * \return >= 0 if no error during transfer
452 * \return -1 if disabled SPI port selected
453 * \return -3 if function has been called during an ongoing DMA transfer
455 static int32_t SPI_DMA_TransferBlock(uint32_t spi_id, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, void *callback)
457 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
459 bool valid = PIOS_SPI_validate(spi_dev);
461 PIOS_Assert(valid)
463 DMA_InitTypeDef dma_init;
465 /* Exit if ongoing transfer */
466 if (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel)) {
467 return -3;
470 /* Disable the DMA channels */
471 DMA_Cmd(spi_dev->cfg->dma.rx.channel, DISABLE);
472 DMA_Cmd(spi_dev->cfg->dma.tx.channel, DISABLE);
474 /* Disable the SPI peripheral */
475 /* Initialize the SPI block */
476 SPI_I2S_DeInit(spi_dev->cfg->regs);
477 SPI_Init(spi_dev->cfg->regs, (SPI_InitTypeDef *)&(spi_dev->cfg->init));
478 SPI_Cmd(spi_dev->cfg->regs, DISABLE);
479 /* Configure CRC calculation */
480 if (spi_dev->cfg->use_crc) {
481 SPI_CalculateCRC(spi_dev->cfg->regs, ENABLE);
482 } else {
483 SPI_CalculateCRC(spi_dev->cfg->regs, DISABLE);
486 /* Enable SPI interrupts to DMA */
487 SPI_I2S_DMACmd(spi_dev->cfg->regs, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);
489 /* Set callback function */
490 spi_dev->callback = callback;
493 * Configure Rx channel
496 /* Start with the default configuration for this peripheral */
497 dma_init = spi_dev->cfg->dma.rx.init;
498 DMA_DeInit(spi_dev->cfg->dma.rx.channel);
499 if (receive_buffer != NULL) {
500 /* Enable memory addr. increment - bytes written into receive buffer */
501 dma_init.DMA_MemoryBaseAddr = (uint32_t)receive_buffer;
502 dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
503 } else {
504 /* Disable memory addr. increment - bytes written into dummy buffer */
505 spi_dev->rx_dummy_byte = 0xFF;
506 dma_init.DMA_MemoryBaseAddr = (uint32_t)&spi_dev->rx_dummy_byte;
507 dma_init.DMA_MemoryInc = DMA_MemoryInc_Disable;
509 if (spi_dev->cfg->use_crc) {
510 /* Make sure the CRC error flag is cleared before we start */
511 SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR);
514 dma_init.DMA_BufferSize = len;
515 DMA_Init(spi_dev->cfg->dma.rx.channel, &(dma_init));
518 * Configure Tx channel
521 /* Start with the default configuration for this peripheral */
522 dma_init = spi_dev->cfg->dma.tx.init;
523 DMA_DeInit(spi_dev->cfg->dma.tx.channel);
524 if (send_buffer != NULL) {
525 /* Enable memory addr. increment - bytes written into receive buffer */
526 dma_init.DMA_MemoryBaseAddr = (uint32_t)send_buffer;
527 dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
528 } else {
529 /* Disable memory addr. increment - bytes written into dummy buffer */
530 spi_dev->tx_dummy_byte = 0xFF;
531 dma_init.DMA_MemoryBaseAddr = (uint32_t)&spi_dev->tx_dummy_byte;
532 dma_init.DMA_MemoryInc = DMA_MemoryInc_Disable;
535 if (spi_dev->cfg->use_crc) {
536 /* The last byte of the payload will be replaced with the CRC8 */
537 dma_init.DMA_BufferSize = len - 1;
538 } else {
539 dma_init.DMA_BufferSize = len;
542 DMA_Init(spi_dev->cfg->dma.tx.channel, &(dma_init));
544 /* Enable DMA interrupt if callback function active */
545 DMA_ITConfig(spi_dev->cfg->dma.rx.channel, DMA_IT_TC, (callback != NULL) ? ENABLE : DISABLE);
547 /* Flush out the CRC registers */
548 SPI_CalculateCRC(spi_dev->cfg->regs, DISABLE);
549 (void)SPI_GetCRC(spi_dev->cfg->regs, SPI_CRC_Rx);
550 SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR);
552 /* Make sure to flush out the receive buffer */
553 (void)SPI_I2S_ReceiveData16(spi_dev->cfg->regs);
555 if (spi_dev->cfg->use_crc) {
556 /* Need a 0->1 transition to reset the CRC logic */
557 SPI_CalculateCRC(spi_dev->cfg->regs, ENABLE);
560 // TODO: Verify the LDMA_TX and LDMA_RX handling then len is not a multiple of two!!
562 /* Start DMA transfers */
563 DMA_Cmd(spi_dev->cfg->dma.rx.channel, ENABLE);
564 DMA_Cmd(spi_dev->cfg->dma.tx.channel, ENABLE);
566 /* Reenable the SPI device */
567 SPI_Cmd(spi_dev->cfg->regs, ENABLE);
569 if (callback) {
570 /* User has requested a callback, don't wait for the transfer to complete. */
571 return 0;
574 /* Wait until all bytes have been transmitted/received */
575 while (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel)) {
579 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
580 while (!(SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE))) {
584 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
585 while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) {
589 /* Check the CRC on the transfer if enabled. */
590 if (spi_dev->cfg->use_crc) {
591 /* Check the SPI CRC error flag */
592 if (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_FLAG_CRCERR)) {
593 return -4;
597 /* No error */
598 return 0;
602 * Transfers a block of bytes via PIO.
604 * \param[in] spi_id SPI device handle
605 * \param[in] send_buffer pointer to buffer which should be sent.<BR>
606 * If NULL, 0xff (all-one) will be sent.
607 * \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
608 * If NULL, received bytes will be discarded.
609 * \param[in] len number of bytes which should be transfered
610 * \return >= 0 if no error during transfer
611 * \return -1 if disabled SPI port selected
612 * \return -3 if function has been called during an ongoing DMA transfer
614 static int32_t SPI_PIO_TransferBlock(uint32_t spi_id, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len)
616 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
617 uint8_t b;
619 bool valid = PIOS_SPI_validate(spi_dev);
621 PIOS_Assert(valid)
622 SPI_RxFIFOThresholdConfig(spi_dev->cfg->regs, SPI_RxFIFOThreshold_QF);
623 /* Exit if ongoing transfer */
624 if (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel)) {
625 return -3;
628 /* Make sure the RXNE flag is cleared by reading the DR register */
629 b = spi_dev->cfg->regs->DR;
631 while (len--) {
632 /* get the byte to send */
633 b = send_buffer ? *(send_buffer++) : 0xff;
635 /* Start the transfer */
636 SPI_SendData8(spi_dev->cfg->regs, b);
637 /* Wait until there is a byte to read */
638 while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_RXNE)) {
642 /* Read the rx'd byte */
643 b = SPI_ReceiveData8(spi_dev->cfg->regs);
645 /* save the received byte */
646 if (receive_buffer) {
647 *(receive_buffer++) = b;
650 /* Wait until the TXE goes high */
651 while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_TXE)) {
656 /* Wait for SPI transfer to have fully completed */
657 while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY) {
661 return 0;
666 * Transfers a block of bytes via PIO or DMA.
667 * \param[in] spi_id SPI device handle
668 * \param[in] send_buffer pointer to buffer which should be sent.<BR>
669 * If NULL, 0xff (all-one) will be sent.
670 * \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
671 * If NULL, received bytes will be discarded.
672 * \param[in] len number of bytes which should be transfered
673 * \param[in] callback pointer to callback function which will be executed
674 * from DMA channel interrupt once the transfer is finished.
675 * If NULL, no callback function will be used, and PIOS_SPI_TransferBlock() will
676 * block until the transfer is finished.
677 * \return >= 0 if no error during transfer
678 * \return -1 if disabled SPI port selected
679 * \return -3 if function has been called during an ongoing DMA transfer
681 int32_t PIOS_SPI_TransferBlock(uint32_t spi_id, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, void *callback)
683 if (callback || len > SPI_MAX_BLOCK_PIO) {
684 return SPI_DMA_TransferBlock(spi_id, send_buffer, receive_buffer, len, callback);
686 return SPI_PIO_TransferBlock(spi_id, send_buffer, receive_buffer, len);
690 * Check if a transfer is in progress
691 * \param[in] spi SPI number (0 or 1)
692 * \return >= 0 if no transfer is in progress
693 * \return -1 if disabled SPI port selected
694 * \return -2 if unsupported SPI port selected
695 * \return -3 if function has been called during an ongoing DMA transfer
697 int32_t PIOS_SPI_Busy(uint32_t spi_id)
699 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
701 bool valid = PIOS_SPI_validate(spi_dev);
703 PIOS_Assert(valid)
705 /* DMA buffer has data or SPI transmit register not empty or SPI is busy*/
706 if (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel) ||
707 !SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) ||
708 SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) {
709 return -3;
712 return 0;
715 void PIOS_SPI_IRQ_Handler(uint32_t spi_id)
717 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
719 bool valid = PIOS_SPI_validate(spi_dev);
721 PIOS_Assert(valid)
723 // FIXME XXX Only RX channel or better clear flags for both channels?
724 DMA_ClearFlag(spi_dev->cfg->dma.irq.flags);
726 if (spi_dev->cfg->init.SPI_Mode == SPI_Mode_Master) {
727 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
728 while (!(SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE))) {
732 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
733 while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) {
738 if (spi_dev->callback != NULL) {
739 bool crc_ok = true;
740 uint8_t crc_val;
742 if (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_FLAG_CRCERR)) {
743 crc_ok = false;
744 SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR);
746 crc_val = SPI_GetCRC(spi_dev->cfg->regs, SPI_CRC_Rx);
747 spi_dev->callback(crc_ok, crc_val);
751 #endif /* PIOS_INCLUDE_SPI */
754 * @}
755 * @}