Revert "REVONANO - Workaround for the SBUS issue (use oversample 8 instead of 16...
[librepilot.git] / flight / pios / stm32f0x / pios_spi.c
blob5758ce7429a031902a52f5adfca21b0f3782def0
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 /* Enable the associated peripheral clock */
97 switch ((uint32_t)spi_dev->cfg->regs) {
98 case (uint32_t)SPI1:
99 /* Enable SPI peripheral clock (APB2 == high speed) */
100 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
101 break;
102 case (uint32_t)SPI2:
103 /* Enable SPI peripheral clock (APB1 == slow speed) */
104 RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
105 break;
107 /* Enable DMA clock */
108 RCC_AHBPeriphClockCmd(spi_dev->cfg->dma.ahb_clk, ENABLE);
110 /* Disable callback function */
111 spi_dev->callback = NULL;
113 /* Set rx/tx dummy bytes to a known value */
114 spi_dev->rx_dummy_byte = 0xFF;
115 spi_dev->tx_dummy_byte = 0xFF;
117 switch (spi_dev->cfg->init.SPI_NSS) {
118 case SPI_NSS_Soft:
119 if (spi_dev->cfg->init.SPI_Mode == SPI_Mode_Master) {
120 /* We're a master in soft NSS mode, make sure we see NSS high at all times. */
121 SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Set);
122 /* Init as many slave selects as the config advertises. */
123 init_ssel = spi_dev->cfg->slave_count;
124 } else {
125 /* We're a slave in soft NSS mode, make sure we see NSS low at all times. */
126 SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Reset);
128 break;
130 case SPI_NSS_Hard:
131 /* only legal for single-slave config */
132 PIOS_Assert(spi_dev->cfg->slave_count == 1);
133 init_ssel = 1;
134 SPI_SSOutputCmd(spi_dev->cfg->regs, (spi_dev->cfg->init.SPI_Mode == SPI_Mode_Master) ? ENABLE : DISABLE);
135 /* FIXME: Should this also call SPI_SSOutputCmd()? */
136 break;
138 default:
139 PIOS_Assert(0);
142 /* Initialize the GPIO pins */
143 /* note __builtin_ctz() due to the difference between GPIO_PinX and GPIO_PinSourceX */
144 GPIO_Init(spi_dev->cfg->sclk.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->sclk.init));
145 GPIO_Init(spi_dev->cfg->mosi.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->mosi.init));
146 GPIO_Init(spi_dev->cfg->miso.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->miso.init));
148 if (spi_dev->cfg->remap) {
149 GPIO_PinAFConfig(spi_dev->cfg->sclk.gpio,
150 __builtin_ctz(spi_dev->cfg->sclk.init.GPIO_Pin),
151 spi_dev->cfg->remap);
152 GPIO_PinAFConfig(spi_dev->cfg->mosi.gpio,
153 __builtin_ctz(spi_dev->cfg->mosi.init.GPIO_Pin),
154 spi_dev->cfg->remap);
155 GPIO_PinAFConfig(spi_dev->cfg->miso.gpio,
156 __builtin_ctz(spi_dev->cfg->miso.init.GPIO_Pin),
157 spi_dev->cfg->remap);
159 if (spi_dev->cfg->init.SPI_NSS != SPI_NSS_Hard) {
160 for (uint32_t i = 0; i < init_ssel; i++) {
161 /* Since we're driving the SSEL pin in software, ensure that the slave is deselected */
162 /* XXX multi-slave support - maybe have another SPI_NSS_ mode? */
163 GPIO_SetBits(spi_dev->cfg->ssel[i].gpio, spi_dev->cfg->ssel[i].init.GPIO_Pin);
164 GPIO_Init(spi_dev->cfg->ssel[i].gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->ssel[i].init));
168 /* Configure DMA for SPI Rx */
169 DMA_DeInit(spi_dev->cfg->dma.rx.channel);
170 DMA_Cmd(spi_dev->cfg->dma.rx.channel, DISABLE);
171 DMA_Init(spi_dev->cfg->dma.rx.channel, (DMA_InitTypeDef *)&(spi_dev->cfg->dma.rx.init));
173 /* Configure DMA for SPI Tx */
174 DMA_DeInit(spi_dev->cfg->dma.tx.channel);
175 DMA_Cmd(spi_dev->cfg->dma.tx.channel, DISABLE);
176 DMA_Init(spi_dev->cfg->dma.tx.channel, (DMA_InitTypeDef *)&(spi_dev->cfg->dma.tx.init));
178 /* Initialize the SPI block */
179 SPI_I2S_DeInit(spi_dev->cfg->regs);
180 SPI_Init(spi_dev->cfg->regs, (SPI_InitTypeDef *)&(spi_dev->cfg->init));
182 /* Configure CRC calculation */
183 if (spi_dev->cfg->use_crc) {
184 SPI_CalculateCRC(spi_dev->cfg->regs, ENABLE);
185 } else {
186 SPI_CalculateCRC(spi_dev->cfg->regs, DISABLE);
189 /* Enable SPI */
190 SPI_Cmd(spi_dev->cfg->regs, ENABLE);
192 /* Enable SPI interrupts to DMA */
193 SPI_I2S_DMACmd(spi_dev->cfg->regs, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);
195 /* Must store this before enabling interrupt */
196 *spi_id = (uint32_t)spi_dev;
198 /* Configure DMA interrupt */
199 NVIC_Init((NVIC_InitTypeDef *)&(spi_dev->cfg->dma.irq.init));
201 return 0;
203 out_fail:
204 return -1;
208 * (Re-)initialises SPI peripheral clock rate
210 * \param[in] spi SPI number (0 or 1)
211 * \param[in] spi_prescaler configures the SPI speed:
212 * <UL>
213 * <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)
214 * <LI>PIOS_SPI_PRESCALER_4: sets clock rate 55.5~ nS @ 72 MHz (18 MBit/s)
215 * <LI>PIOS_SPI_PRESCALER_8: sets clock rate 111.1~ nS @ 72 MHz (9 MBit/s)
216 * <LI>PIOS_SPI_PRESCALER_16: sets clock rate 222.2~ nS @ 72 MHz (4.5 MBit/s)
217 * <LI>PIOS_SPI_PRESCALER_32: sets clock rate 444.4~ nS @ 72 MHz (2.25 MBit/s)
218 * <LI>PIOS_SPI_PRESCALER_64: sets clock rate 888.8~ nS @ 72 MHz (1.125 MBit/s)
219 * <LI>PIOS_SPI_PRESCALER_128: sets clock rate 1.7~ nS @ 72 MHz (0.562 MBit/s)
220 * <LI>PIOS_SPI_PRESCALER_256: sets clock rate 3.5~ nS @ 72 MHz (0.281 MBit/s)
221 * </UL>
222 * \return 0 if no error
223 * \return -1 if disabled SPI port selected
224 * \return -3 if invalid spi_prescaler selected
226 int32_t PIOS_SPI_SetClockSpeed(uint32_t spi_id, SPIPrescalerTypeDef spi_prescaler)
228 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
230 bool valid = PIOS_SPI_validate(spi_dev);
232 PIOS_Assert(valid)
234 SPI_InitTypeDef SPI_InitStructure;
236 if (spi_prescaler >= 8) {
237 /* Invalid prescaler selected */
238 return -3;
241 /* Start with a copy of the default configuration for the peripheral */
242 SPI_InitStructure = spi_dev->cfg->init;
244 /* Adjust the prescaler for the peripheral's clock */
245 SPI_InitStructure.SPI_BaudRatePrescaler = ((uint16_t)spi_prescaler & 7) << 3;
247 /* Write back the new configuration */
248 SPI_Init(spi_dev->cfg->regs, &SPI_InitStructure);
250 PIOS_SPI_TransferByte(spi_id, 0xFF);
251 return 0;
255 * Claim the SPI bus semaphore. Calling the SPI functions does not require this
256 * \param[in] spi SPI number (0 or 1)
257 * \return 0 if no error
258 * \return -1 if timeout before claiming semaphore
260 int32_t PIOS_SPI_ClaimBus(uint32_t spi_id)
262 #if defined(PIOS_INCLUDE_FREERTOS)
263 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
265 bool valid = PIOS_SPI_validate(spi_dev);
266 PIOS_Assert(valid)
268 if (xSemaphoreTake(spi_dev->busy, 0xffff) != pdTRUE) {
269 return -1;
271 #else
272 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
273 uint32_t timeout = 0xffff;
274 while ((PIOS_SPI_Busy(spi_id) || spi_dev->busy) && --timeout) {
277 if (timeout == 0) { // timed out
278 return -1;
281 PIOS_IRQ_Disable();
282 if (spi_dev->busy) {
283 return -1;
285 spi_dev->busy = 1;
286 PIOS_IRQ_Enable();
287 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
288 return 0;
292 * Claim the SPI bus semaphore from an ISR. Has no timeout.
293 * \param[in] spi SPI number (0 or 1)
294 * \param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
295 * task has is now eligible to run, else unchanged
296 * \return 0 if no error
297 * \return -1 if timeout before claiming semaphore
299 int32_t PIOS_SPI_ClaimBusISR(uint32_t spi_id, bool *woken)
301 #if defined(PIOS_INCLUDE_FREERTOS)
302 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
303 signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE;
305 bool valid = PIOS_SPI_validate(spi_dev);
306 PIOS_Assert(valid)
308 if (xSemaphoreTakeFromISR(spi_dev->busy, &higherPriorityTaskWoken) != pdTRUE) {
309 return -1;
311 if (woken) {
312 *woken = *woken || (higherPriorityTaskWoken == pdTRUE);
314 return 0;
316 #else
317 if (woken) {
318 *woken = false;
320 return PIOS_SPI_ClaimBus(spi_id);
322 #endif
326 * Release the SPI bus semaphore. Calling the SPI functions does not require this
327 * \param[in] spi SPI number (0 or 1)
328 * \return 0 if no error
330 int32_t PIOS_SPI_ReleaseBus(uint32_t spi_id)
332 #if defined(PIOS_INCLUDE_FREERTOS)
333 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
335 bool valid = PIOS_SPI_validate(spi_dev);
336 PIOS_Assert(valid)
338 xSemaphoreGive(spi_dev->busy);
339 #else
340 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
341 PIOS_IRQ_Disable();
342 spi_dev->busy = 0;
343 PIOS_IRQ_Enable();
344 #endif
345 return 0;
349 * Release the SPI bus semaphore from ISR. Calling the SPI functions does not require this
350 * \param[in] spi SPI number (0 or 1)
351 * \param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
352 * task has is now eligible to run, else unchanged
353 * \return 0 if no error
355 int32_t PIOS_SPI_ReleaseBusISR(uint32_t spi_id, bool *woken)
357 #if defined(PIOS_INCLUDE_FREERTOS)
358 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
359 signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE;
361 bool valid = PIOS_SPI_validate(spi_dev);
362 PIOS_Assert(valid)
364 xSemaphoreGiveFromISR(spi_dev->busy, &higherPriorityTaskWoken);
365 if (woken) {
366 *woken = *woken || (higherPriorityTaskWoken == pdTRUE);
368 return 0;
370 #else
371 if (woken) {
372 *woken = false;
374 return PIOS_SPI_ReleaseBus(spi_id);
376 #endif
381 * Controls the RC (Register Clock alias Chip Select) pin of a SPI port
382 * \param[in] spi SPI number (0 or 1)
383 * \param[in] pin_value 0 or 1
384 * \return 0 if no error
386 int32_t PIOS_SPI_RC_PinSet(uint32_t spi_id, uint32_t slave_id, uint8_t pin_value)
388 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
390 bool valid = PIOS_SPI_validate(spi_dev);
392 PIOS_Assert(valid)
393 PIOS_Assert(slave_id <= spi_dev->cfg->slave_count)
395 /* XXX multi-slave support? */
396 if (pin_value) {
397 GPIO_SetBits(spi_dev->cfg->ssel[slave_id].gpio, spi_dev->cfg->ssel[slave_id].init.GPIO_Pin);
398 } else {
399 GPIO_ResetBits(spi_dev->cfg->ssel[slave_id].gpio, spi_dev->cfg->ssel[slave_id].init.GPIO_Pin);
402 return 0;
406 * Transfers a byte to SPI output and reads back the return value from SPI input
407 * \param[in] spi SPI number (0 or 1)
408 * \param[in] b the byte which should be transfered
410 int32_t PIOS_SPI_TransferByte(uint32_t spi_id, uint8_t b)
412 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
414 bool valid = PIOS_SPI_validate(spi_dev);
416 PIOS_Assert(valid)
418 // uint8_t dummy;
419 uint8_t rx_byte;
422 * Procedure taken from STM32F10xxx Reference Manual section 23.3.5
425 SPI_RxFIFOThresholdConfig(spi_dev->cfg->regs, SPI_RxFIFOThreshold_QF);
427 /* Make sure the RXNE flag is cleared by reading the DR register */
428 /*dummy =*/ (void)spi_dev->cfg->regs->DR;
430 /* Start the transfer */
431 SPI_SendData8(spi_dev->cfg->regs, b);
432 /* Wait until there is a byte to read */
433 while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_RXNE)) {
437 /* Read the rx'd byte */
438 rx_byte = SPI_ReceiveData8(spi_dev->cfg->regs);
439 /* Wait until the TXE goes high */
440 while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_TXE)) {
444 /* Wait for SPI transfer to have fully completed */
445 while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY) {
449 /* Return received byte */
450 return rx_byte;
454 * Transfers a block of bytes via DMA.
455 * \param[in] spi SPI number (0 or 1)
456 * \param[in] send_buffer pointer to buffer which should be sent.<BR>
457 * If NULL, 0xff (all-one) will be sent.
458 * \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
459 * If NULL, received bytes will be discarded.
460 * \param[in] len number of bytes which should be transfered
461 * \param[in] callback pointer to callback function which will be executed
462 * from DMA channel interrupt once the transfer is finished.
463 * If NULL, no callback function will be used, and PIOS_SPI_TransferBlock() will
464 * block until the transfer is finished.
465 * \return >= 0 if no error during transfer
466 * \return -1 if disabled SPI port selected
467 * \return -3 if function has been called during an ongoing DMA transfer
469 static int32_t SPI_DMA_TransferBlock(uint32_t spi_id, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, void *callback)
471 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
473 bool valid = PIOS_SPI_validate(spi_dev);
475 PIOS_Assert(valid)
477 DMA_InitTypeDef dma_init;
479 /* Exit if ongoing transfer */
480 if (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel)) {
481 return -3;
484 /* Disable the DMA channels */
485 DMA_Cmd(spi_dev->cfg->dma.rx.channel, DISABLE);
486 DMA_Cmd(spi_dev->cfg->dma.tx.channel, DISABLE);
488 /* Disable the SPI peripheral */
489 /* Initialize the SPI block */
490 SPI_I2S_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);
496 } else {
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_MemoryBaseAddr = (uint32_t)receive_buffer;
516 dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
517 } else {
518 /* Disable memory addr. increment - bytes written into dummy buffer */
519 spi_dev->rx_dummy_byte = 0xFF;
520 dma_init.DMA_MemoryBaseAddr = (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_MemoryBaseAddr = (uint32_t)send_buffer;
541 dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
542 } else {
543 /* Disable memory addr. increment - bytes written into dummy buffer */
544 spi_dev->tx_dummy_byte = 0xFF;
545 dma_init.DMA_MemoryBaseAddr = (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;
552 } else {
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_ReceiveData16(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 // TODO: Verify the LDMA_TX and LDMA_RX handling then len is not a multiple of two!!
576 /* Start DMA transfers */
577 DMA_Cmd(spi_dev->cfg->dma.rx.channel, ENABLE);
578 DMA_Cmd(spi_dev->cfg->dma.tx.channel, ENABLE);
580 /* Reenable the SPI device */
581 SPI_Cmd(spi_dev->cfg->regs, ENABLE);
583 if (callback) {
584 /* User has requested a callback, don't wait for the transfer to complete. */
585 return 0;
588 /* Wait until all bytes have been transmitted/received */
589 while (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel)) {
593 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
594 while (!(SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE))) {
598 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
599 while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) {
603 /* Check the CRC on the transfer if enabled. */
604 if (spi_dev->cfg->use_crc) {
605 /* Check the SPI CRC error flag */
606 if (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_FLAG_CRCERR)) {
607 return -4;
611 /* No error */
612 return 0;
616 * Transfers a block of bytes via PIO.
618 * \param[in] spi_id SPI device handle
619 * \param[in] send_buffer pointer to buffer which should be sent.<BR>
620 * If NULL, 0xff (all-one) will be sent.
621 * \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
622 * If NULL, received bytes will be discarded.
623 * \param[in] len number of bytes which should be transfered
624 * \return >= 0 if no error during transfer
625 * \return -1 if disabled SPI port selected
626 * \return -3 if function has been called during an ongoing DMA transfer
628 static int32_t SPI_PIO_TransferBlock(uint32_t spi_id, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len)
630 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
631 uint8_t b;
633 bool valid = PIOS_SPI_validate(spi_dev);
635 PIOS_Assert(valid)
636 SPI_RxFIFOThresholdConfig(spi_dev->cfg->regs, SPI_RxFIFOThreshold_QF);
637 /* Exit if ongoing transfer */
638 if (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel)) {
639 return -3;
642 /* Make sure the RXNE flag is cleared by reading the DR register */
643 b = spi_dev->cfg->regs->DR;
645 while (len--) {
646 /* get the byte to send */
647 b = send_buffer ? *(send_buffer++) : 0xff;
649 /* Start the transfer */
650 SPI_SendData8(spi_dev->cfg->regs, b);
651 /* Wait until there is a byte to read */
652 while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_RXNE)) {
656 /* Read the rx'd byte */
657 b = SPI_ReceiveData8(spi_dev->cfg->regs);
659 /* save the received byte */
660 if (receive_buffer) {
661 *(receive_buffer++) = b;
664 /* Wait until the TXE goes high */
665 while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_TXE)) {
670 /* Wait for SPI transfer to have fully completed */
671 while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY) {
675 return 0;
680 * Transfers a block of bytes via PIO or DMA.
681 * \param[in] spi_id SPI device handle
682 * \param[in] send_buffer pointer to buffer which should be sent.<BR>
683 * If NULL, 0xff (all-one) will be sent.
684 * \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
685 * If NULL, received bytes will be discarded.
686 * \param[in] len number of bytes which should be transfered
687 * \param[in] callback pointer to callback function which will be executed
688 * from DMA channel interrupt once the transfer is finished.
689 * If NULL, no callback function will be used, and PIOS_SPI_TransferBlock() will
690 * block until the transfer is finished.
691 * \return >= 0 if no error during transfer
692 * \return -1 if disabled SPI port selected
693 * \return -3 if function has been called during an ongoing DMA transfer
695 int32_t PIOS_SPI_TransferBlock(uint32_t spi_id, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, void *callback)
697 if (callback || len > SPI_MAX_BLOCK_PIO) {
698 return SPI_DMA_TransferBlock(spi_id, send_buffer, receive_buffer, len, callback);
700 return SPI_PIO_TransferBlock(spi_id, send_buffer, receive_buffer, len);
704 * Check if a transfer is in progress
705 * \param[in] spi SPI number (0 or 1)
706 * \return >= 0 if no transfer is in progress
707 * \return -1 if disabled SPI port selected
708 * \return -2 if unsupported SPI port selected
709 * \return -3 if function has been called during an ongoing DMA transfer
711 int32_t PIOS_SPI_Busy(uint32_t spi_id)
713 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
715 bool valid = PIOS_SPI_validate(spi_dev);
717 PIOS_Assert(valid)
719 /* DMA buffer has data or SPI transmit register not empty or SPI is busy*/
720 if (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel) ||
721 !SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) ||
722 SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) {
723 return -3;
726 return 0;
729 void PIOS_SPI_IRQ_Handler(uint32_t spi_id)
731 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
733 bool valid = PIOS_SPI_validate(spi_dev);
735 PIOS_Assert(valid)
737 // FIXME XXX Only RX channel or better clear flags for both channels?
738 DMA_ClearFlag(spi_dev->cfg->dma.irq.flags);
740 if (spi_dev->cfg->init.SPI_Mode == SPI_Mode_Master) {
741 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
742 while (!(SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE))) {
746 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
747 while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) {
752 if (spi_dev->callback != NULL) {
753 bool crc_ok = true;
754 uint8_t crc_val;
756 if (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_FLAG_CRCERR)) {
757 crc_ok = false;
758 SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR);
760 crc_val = SPI_GetCRC(spi_dev->cfg->regs, SPI_CRC_Rx);
761 spi_dev->callback(crc_ok, crc_val);
765 #endif /* PIOS_INCLUDE_SPI */
768 * @}
769 * @}