Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / flight / pios / stm32f30x / pios_spi.c
blobb1058366550d86f91fbeb8aeae2ae239fde8b381
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 12800
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 pios_malloc(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
97 /* Disable callback function */
98 spi_dev->callback = NULL;
100 /* Set rx/tx dummy bytes to a known value */
101 spi_dev->rx_dummy_byte = 0xFF;
102 spi_dev->tx_dummy_byte = 0xFF;
104 switch (spi_dev->cfg->init.SPI_NSS) {
105 case SPI_NSS_Soft:
106 if (spi_dev->cfg->init.SPI_Mode == SPI_Mode_Master) {
107 /* We're a master in soft NSS mode, make sure we see NSS high at all times. */
108 SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Set);
109 /* Init as many slave selects as the config advertises. */
110 init_ssel = spi_dev->cfg->slave_count;
111 } else {
112 /* We're a slave in soft NSS mode, make sure we see NSS low at all times. */
113 SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Reset);
115 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 /* FIXME: Should this also call SPI_SSOutputCmd()? */
121 break;
123 default:
124 PIOS_Assert(0);
127 /* Initialize the GPIO pins */
128 /* note __builtin_ctz() due to the difference between GPIO_PinX and GPIO_PinSourceX */
129 if (spi_dev->cfg->remap) {
130 GPIO_PinAFConfig(spi_dev->cfg->sclk.gpio,
131 __builtin_ctz(spi_dev->cfg->sclk.init.GPIO_Pin),
132 spi_dev->cfg->remap);
133 GPIO_PinAFConfig(spi_dev->cfg->mosi.gpio,
134 __builtin_ctz(spi_dev->cfg->mosi.init.GPIO_Pin),
135 spi_dev->cfg->remap);
136 GPIO_PinAFConfig(spi_dev->cfg->miso.gpio,
137 __builtin_ctz(spi_dev->cfg->miso.init.GPIO_Pin),
138 spi_dev->cfg->remap);
139 for (uint32_t i = 0; i < init_ssel; i++) {
140 GPIO_PinAFConfig(spi_dev->cfg->ssel[i].gpio,
141 __builtin_ctz(spi_dev->cfg->ssel[i].init.GPIO_Pin),
142 spi_dev->cfg->remap);
146 /* Initialize the GPIO pins */
147 GPIO_Init(spi_dev->cfg->sclk.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->sclk.init));
148 GPIO_Init(spi_dev->cfg->mosi.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->mosi.init));
149 GPIO_Init(spi_dev->cfg->miso.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->miso.init));
150 for (uint32_t i = 0; i < init_ssel; i++) {
151 /* Since we're driving the SSEL pin in software, ensure that the slave is deselected */
152 /* XXX multi-slave support - maybe have another SPI_NSS_ mode? */
153 GPIO_SetBits(spi_dev->cfg->ssel[i].gpio, spi_dev->cfg->ssel[i].init.GPIO_Pin);
154 GPIO_Init(spi_dev->cfg->ssel[i].gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->ssel[i].init));
157 /* Enable the associated peripheral clock */
158 switch ((uint32_t)spi_dev->cfg->regs) {
159 case (uint32_t)SPI1:
160 /* Enable SPI peripheral clock (APB2 == high speed) */
161 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
162 break;
163 case (uint32_t)SPI2:
164 /* Enable SPI peripheral clock (APB1 == slow speed) */
165 RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
166 break;
167 case (uint32_t)SPI3:
168 /* Enable SPI peripheral clock (APB1 == slow speed) */
169 RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
170 break;
173 bool use_dma = spi_dev->cfg->dma.rx.channel && spi_dev->cfg->dma.tx.channel;
175 /* Enable DMA clock */
176 if (use_dma) {
177 RCC_AHBPeriphClockCmd(spi_dev->cfg->dma.ahb_clk, ENABLE);
179 /* Configure DMA for SPI Rx */
180 DMA_Cmd(spi_dev->cfg->dma.rx.channel, DISABLE);
181 DMA_Init(spi_dev->cfg->dma.rx.channel, (DMA_InitTypeDef *)&(spi_dev->cfg->dma.rx.init));
183 /* Configure DMA for SPI Tx */
184 DMA_Cmd(spi_dev->cfg->dma.tx.channel, DISABLE);
185 DMA_Init(spi_dev->cfg->dma.tx.channel, (DMA_InitTypeDef *)&(spi_dev->cfg->dma.tx.init));
188 /* Initialize the SPI block */
189 SPI_I2S_DeInit(spi_dev->cfg->regs);
190 SPI_Init(spi_dev->cfg->regs, (SPI_InitTypeDef *)&(spi_dev->cfg->init));
192 /* Configure CRC calculation */
193 if (spi_dev->cfg->use_crc) {
194 SPI_CalculateCRC(spi_dev->cfg->regs, ENABLE);
195 } else {
196 SPI_CalculateCRC(spi_dev->cfg->regs, DISABLE);
199 /* Configure the RX FIFO Threshold -- 8 bits */
200 SPI_RxFIFOThresholdConfig(spi_dev->cfg->regs, SPI_RxFIFOThreshold_QF);
202 /* Enable SPI */
203 SPI_Cmd(spi_dev->cfg->regs, ENABLE);
205 /* Enable SPI interrupts to DMA */
206 if (use_dma) {
207 SPI_I2S_DMACmd(spi_dev->cfg->regs, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);
210 /* Configure DMA interrupt */
211 NVIC_Init((NVIC_InitTypeDef *)&(spi_dev->cfg->dma.irq.init));
213 *spi_id = (uint32_t)spi_dev;
214 return 0;
216 out_fail:
217 return -1;
221 * (Re-)initialises SPI peripheral clock rate
223 * \param[in] spi SPI number (0 or 1)
224 * \param[in] spi_prescaler configures the SPI speed:
225 * <UL>
226 * <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)
227 * <LI>PIOS_SPI_PRESCALER_4: sets clock rate 55.5~ nS @ 72 MHz (18 MBit/s)
228 * <LI>PIOS_SPI_PRESCALER_8: sets clock rate 111.1~ nS @ 72 MHz (9 MBit/s)
229 * <LI>PIOS_SPI_PRESCALER_16: sets clock rate 222.2~ nS @ 72 MHz (4.5 MBit/s)
230 * <LI>PIOS_SPI_PRESCALER_32: sets clock rate 444.4~ nS @ 72 MHz (2.25 MBit/s)
231 * <LI>PIOS_SPI_PRESCALER_64: sets clock rate 888.8~ nS @ 72 MHz (1.125 MBit/s)
232 * <LI>PIOS_SPI_PRESCALER_128: sets clock rate 1.7~ nS @ 72 MHz (0.562 MBit/s)
233 * <LI>PIOS_SPI_PRESCALER_256: sets clock rate 3.5~ nS @ 72 MHz (0.281 MBit/s)
234 * </UL>
235 * \return 0 if no error
236 * \return -1 if disabled SPI port selected
237 * \return -3 if invalid spi_prescaler selected
239 int32_t PIOS_SPI_SetClockSpeed(uint32_t spi_id, SPIPrescalerTypeDef spi_prescaler)
241 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
243 bool valid = PIOS_SPI_validate(spi_dev);
245 PIOS_Assert(valid)
247 SPI_InitTypeDef SPI_InitStructure;
249 if (spi_prescaler >= 8) {
250 /* Invalid prescaler selected */
251 return -3;
254 /* Start with a copy of the default configuration for the peripheral */
255 SPI_InitStructure = spi_dev->cfg->init;
257 /* Adjust the prescaler for the peripheral's clock */
258 SPI_InitStructure.SPI_BaudRatePrescaler = ((uint16_t)spi_prescaler & 7) << 3;
260 /* Write back the new configuration */
261 SPI_Init(spi_dev->cfg->regs, &SPI_InitStructure);
263 PIOS_SPI_TransferByte(spi_id, 0xFF);
264 return 0;
268 * Claim the SPI bus semaphore. Calling the SPI functions does not require this
269 * \param[in] spi SPI number (0 or 1)
270 * \return 0 if no error
271 * \return -1 if timeout before claiming semaphore
273 int32_t PIOS_SPI_ClaimBus(uint32_t spi_id)
275 #if defined(PIOS_INCLUDE_FREERTOS)
276 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
278 bool valid = PIOS_SPI_validate(spi_dev);
279 PIOS_Assert(valid)
281 if (xSemaphoreTake(spi_dev->busy, 0xffff) != pdTRUE) {
282 return -1;
284 #else
285 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
286 uint32_t timeout = 0xffff;
287 while ((PIOS_SPI_Busy(spi_id) || spi_dev->busy) && --timeout) {
290 if (timeout == 0) { // timed out
291 return -1;
294 PIOS_IRQ_Disable();
295 if (spi_dev->busy) {
296 return -1;
298 spi_dev->busy = 1;
299 PIOS_IRQ_Enable();
300 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
301 return 0;
305 * Claim the SPI bus semaphore from an ISR. Has no timeout.
306 * \param[in] spi SPI number (0 or 1)
307 * \param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
308 * task has is now eligible to run, else unchanged
309 * \return 0 if no error
310 * \return -1 if timeout before claiming semaphore
312 int32_t PIOS_SPI_ClaimBusISR(uint32_t spi_id, bool *woken)
314 #if defined(PIOS_INCLUDE_FREERTOS)
315 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
316 signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE;
318 bool valid = PIOS_SPI_validate(spi_dev);
319 PIOS_Assert(valid)
321 if (xSemaphoreTakeFromISR(spi_dev->busy, &higherPriorityTaskWoken) != pdTRUE) {
322 return -1;
324 if (woken) {
325 *woken = *woken || (higherPriorityTaskWoken == pdTRUE);
327 return 0;
329 #else
330 if (woken) {
331 *woken = false;
333 return PIOS_SPI_ClaimBus(spi_id);
335 #endif
339 * Release the SPI bus semaphore. Calling the SPI functions does not require this
340 * \param[in] spi SPI number (0 or 1)
341 * \return 0 if no error
343 int32_t PIOS_SPI_ReleaseBus(uint32_t spi_id)
345 #if defined(PIOS_INCLUDE_FREERTOS)
346 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
348 bool valid = PIOS_SPI_validate(spi_dev);
349 PIOS_Assert(valid)
351 xSemaphoreGive(spi_dev->busy);
352 #else
353 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
354 PIOS_IRQ_Disable();
355 spi_dev->busy = 0;
356 PIOS_IRQ_Enable();
357 #endif
358 return 0;
362 * Release the SPI bus semaphore from ISR. Calling the SPI functions does not require this
363 * \param[in] spi SPI number (0 or 1)
364 * \param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
365 * task has is now eligible to run, else unchanged
366 * \return 0 if no error
368 int32_t PIOS_SPI_ReleaseBusISR(uint32_t spi_id, bool *woken)
370 #if defined(PIOS_INCLUDE_FREERTOS)
371 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
372 signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE;
374 bool valid = PIOS_SPI_validate(spi_dev);
375 PIOS_Assert(valid)
377 xSemaphoreGiveFromISR(spi_dev->busy, &higherPriorityTaskWoken);
378 if (woken) {
379 *woken = *woken || (higherPriorityTaskWoken == pdTRUE);
381 return 0;
383 #else
384 if (woken) {
385 *woken = false;
387 return PIOS_SPI_ReleaseBus(spi_id);
389 #endif
394 * Controls the RC (Register Clock alias Chip Select) pin of a SPI port
395 * \param[in] spi SPI number (0 or 1)
396 * \param[in] pin_value 0 or 1
397 * \return 0 if no error
399 int32_t PIOS_SPI_RC_PinSet(uint32_t spi_id, uint32_t slave_id, uint8_t pin_value)
401 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
403 bool valid = PIOS_SPI_validate(spi_dev);
405 PIOS_Assert(valid)
406 PIOS_Assert(slave_id <= spi_dev->cfg->slave_count)
408 /* XXX multi-slave support? */
409 if (pin_value) {
410 GPIO_SetBits(spi_dev->cfg->ssel[slave_id].gpio, spi_dev->cfg->ssel[slave_id].init.GPIO_Pin);
411 } else {
412 GPIO_ResetBits(spi_dev->cfg->ssel[slave_id].gpio, spi_dev->cfg->ssel[slave_id].init.GPIO_Pin);
415 return 0;
419 * Transfers a byte to SPI output and reads back the return value from SPI input
420 * \param[in] spi SPI number (0 or 1)
421 * \param[in] b the byte which should be transfered
423 int32_t PIOS_SPI_TransferByte(uint32_t spi_id, uint8_t b)
425 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
427 bool valid = PIOS_SPI_validate(spi_dev);
429 PIOS_Assert(valid)
431 uint8_t rx_byte;
433 /* Make sure the RXNE flag is cleared by reading the DR register */
434 SPI_ReceiveData8(spi_dev->cfg->regs);
436 /* Wait until the TXE goes high */
437 while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) == RESET) {
441 /* Start the transfer */
442 SPI_SendData8(spi_dev->cfg->regs, b);
444 /* Wait until there is a byte to read */
445 while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_RXNE) == RESET) {
449 /* Read the rx'd byte */
450 rx_byte = SPI_ReceiveData8(spi_dev->cfg->regs);
452 /* Wait until the TXE goes high */
453 while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_TXE)) {
457 /* Wait for SPI transfer to have fully completed */
458 while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY) {
462 /* Return received byte */
463 return rx_byte;
468 * Transfers a block of bytes via PIO.
470 * \param[in] spi_id SPI device handle
471 * \param[in] send_buffer pointer to buffer which should be sent.<BR>
472 * If NULL, 0xff (all-one) will be sent.
473 * \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
474 * If NULL, received bytes will be discarded.
475 * \param[in] len number of bytes which should be transfered
476 * \return >= 0 if no error during transfer
477 * \return -1 if disabled SPI port selected
479 static int32_t PIOS_SPI_TransferBlock_PIO(struct pios_spi_dev *spi_dev, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, __attribute__((unused)) void *callback)
481 uint8_t b;
483 while (len--) {
484 /* get the byte to send */
485 b = send_buffer ? *(send_buffer++) : 0xff;
487 /* Wait until the TXE goes high */
488 while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) == RESET) {
492 /* Start the transfer */
493 SPI_SendData8(spi_dev->cfg->regs, b);
495 /* Wait until there is a byte to read */
496 while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_RXNE) == RESET) {
500 /* Read the rx'd byte */
501 b = SPI_ReceiveData8(spi_dev->cfg->regs);
503 /* save the received byte */
504 if (receive_buffer) {
505 *(receive_buffer++) = b;
509 /* Wait for SPI transfer to have fully completed */
510 while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY) {
514 return 0;
519 * Transfers a block of bytes via DMA.
520 * \param[in] spi SPI number (0 or 1)
521 * \param[in] send_buffer pointer to buffer which should be sent.<BR>
522 * If NULL, 0xff (all-one) will be sent.
523 * \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
524 * If NULL, received bytes will be discarded.
525 * \param[in] len number of bytes which should be transfered
526 * \param[in] callback pointer to callback function which will be executed
527 * from DMA channel interrupt once the transfer is finished.
528 * If NULL, no callback function will be used, and PIOS_SPI_TransferBlock() will
529 * block until the transfer is finished.
530 * \return >= 0 if no error during transfer
531 * \return -1 if disabled SPI port selected
532 * \return -3 if function has been called during an ongoing DMA transfer
534 static int32_t PIOS_SPI_TransferBlock_DMA(struct pios_spi_dev *spi_dev, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, void *callback)
536 DMA_InitTypeDef dma_init;
538 /* Exit if ongoing transfer */
539 if (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel)) {
540 return -3;
543 /* Disable the SPI peripheral */
544 SPI_Cmd(spi_dev->cfg->regs, DISABLE);
546 /* Disable the DMA channels */
547 DMA_Cmd(spi_dev->cfg->dma.rx.channel, DISABLE);
548 DMA_Cmd(spi_dev->cfg->dma.tx.channel, DISABLE);
550 /* Set callback function */
551 spi_dev->callback = callback;
554 * Configure Rx channel
557 /* Start with the default configuration for this peripheral */
558 dma_init = spi_dev->cfg->dma.rx.init;
560 if (receive_buffer != NULL) {
561 /* Enable memory addr. increment - bytes written into receive buffer */
562 dma_init.DMA_MemoryBaseAddr = (uint32_t)receive_buffer;
563 dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
564 } else {
565 /* Disable memory addr. increment - bytes written into dummy buffer */
566 spi_dev->rx_dummy_byte = 0xFF;
567 dma_init.DMA_MemoryBaseAddr = (uint32_t)&spi_dev->rx_dummy_byte;
568 dma_init.DMA_MemoryInc = DMA_MemoryInc_Disable;
570 if (spi_dev->cfg->use_crc) {
571 /* Make sure the CRC error flag is cleared before we start */
572 SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR);
575 dma_init.DMA_BufferSize = len;
576 DMA_Init(spi_dev->cfg->dma.rx.channel, &(dma_init));
579 * Configure Tx channel
582 /* Start with the default configuration for this peripheral */
583 dma_init = spi_dev->cfg->dma.tx.init;
585 if (send_buffer != NULL) {
586 /* Enable memory addr. increment - bytes written into receive buffer */
587 dma_init.DMA_MemoryBaseAddr = (uint32_t)send_buffer;
588 dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
589 } else {
590 /* Disable memory addr. increment - bytes written into dummy buffer */
591 spi_dev->tx_dummy_byte = 0xFF;
592 dma_init.DMA_MemoryBaseAddr = (uint32_t)&spi_dev->tx_dummy_byte;
593 dma_init.DMA_MemoryInc = DMA_MemoryInc_Disable;
596 if (spi_dev->cfg->use_crc) {
597 /* The last byte of the payload will be replaced with the CRC8 */
598 dma_init.DMA_BufferSize = len - 1;
599 } else {
600 dma_init.DMA_BufferSize = len;
603 DMA_Init(spi_dev->cfg->dma.tx.channel, &(dma_init));
605 /* Enable DMA interrupt if callback function active */
606 DMA_ITConfig(spi_dev->cfg->dma.rx.channel, DMA_IT_TC, (callback != NULL) ? ENABLE : DISABLE);
608 /* Flush out the CRC registers */
609 SPI_CalculateCRC(spi_dev->cfg->regs, DISABLE);
610 (void)SPI_GetCRC(spi_dev->cfg->regs, SPI_CRC_Rx);
611 SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR);
613 /* Make sure to flush out the receive buffer */
614 (void)SPI_I2S_ReceiveData16(spi_dev->cfg->regs);
616 if (spi_dev->cfg->use_crc) {
617 /* Need a 0->1 transition to reset the CRC logic */
618 SPI_CalculateCRC(spi_dev->cfg->regs, ENABLE);
621 /* Start DMA transfers */
622 DMA_Cmd(spi_dev->cfg->dma.rx.channel, ENABLE);
623 DMA_Cmd(spi_dev->cfg->dma.tx.channel, ENABLE);
625 /* Reenable the SPI device */
626 SPI_Cmd(spi_dev->cfg->regs, ENABLE);
628 if (callback) {
629 /* User has requested a callback, don't wait for the transfer to complete. */
630 return 0;
633 /* Wait until all bytes have been transmitted/received */
634 while (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel)) {
638 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
639 while (!(SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE))) {
643 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
644 while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) {
648 /* Check the CRC on the transfer if enabled. */
649 if (spi_dev->cfg->use_crc) {
650 /* Check the SPI CRC error flag */
651 if (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_FLAG_CRCERR)) {
652 return -4;
656 /* No error */
657 return 0;
660 int32_t PIOS_SPI_TransferBlock(uint32_t spi_id, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, void *callback)
662 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
664 bool valid = PIOS_SPI_validate(spi_dev);
666 PIOS_Assert(valid)
668 if ((len > SPI_MAX_BLOCK_PIO) && spi_dev->cfg->dma.rx.channel && spi_dev->cfg->dma.tx.channel) {
669 return PIOS_SPI_TransferBlock_DMA(spi_dev, send_buffer, receive_buffer, len, callback);
672 return PIOS_SPI_TransferBlock_PIO(spi_dev, send_buffer, receive_buffer, len, callback);
676 * Check if a transfer is in progress
677 * \param[in] spi SPI number (0 or 1)
678 * \return >= 0 if no transfer is in progress
679 * \return -1 if disabled SPI port selected
680 * \return -2 if unsupported SPI port selected
681 * \return -3 if function has been called during an ongoing DMA transfer
683 int32_t PIOS_SPI_Busy(uint32_t spi_id)
685 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
687 bool valid = PIOS_SPI_validate(spi_dev);
689 PIOS_Assert(valid)
691 /* DMA buffer has data or SPI transmit register not empty or SPI is busy*/
692 if (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel) ||
693 !SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) ||
694 SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) {
695 return -3;
698 return 0;
701 void PIOS_SPI_SetPrescalar(uint32_t spi_id, uint32_t prescaler)
703 struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
705 bool valid = PIOS_SPI_validate(spi_dev);
707 PIOS_Assert(valid);
708 PIOS_Assert(IS_SPI_BAUDRATE_PRESCALER(prescaler));
710 spi_dev->cfg->regs->CR1 = (spi_dev->cfg->regs->CR1 & ~0x0038) | prescaler;
713 void PIOS_SPI_IRQ_Handler(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);
719 PIOS_Assert(valid)
721 DMA_ClearFlag(spi_dev->cfg->dma.irq.flags);
723 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
724 while (!(SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE))) {
728 /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
729 while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) {
733 if (spi_dev->callback != NULL) {
734 bool crc_ok = true;
735 uint8_t crc_val;
737 if (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_FLAG_CRCERR)) {
738 crc_ok = false;
739 SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR);
741 crc_val = SPI_GetCRC(spi_dev->cfg->regs, SPI_CRC_Rx);
742 spi_dev->callback(crc_ok, crc_val);
746 #endif /* PIOS_INCLUDE_SPI */
749 * @}
750 * @}