Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
spi_arch.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2013 AggieAir, A Remote Sensing Unmanned Aerial System for Scientific Applications
3 * Utah State University, http://aggieair.usu.edu/
4 *
5 * Michal Podhradsky (michal.podhradsky@aggiemail.usu.edu)
6 * Calvin Coopmans (c.r.coopmans@ieee.org)
7 *
8 * This file is part of paparazzi.
9 *
10 * paparazzi is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * paparazzi is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with paparazzi; see the file COPYING. If not, write to
22 * the Free Software Foundation, 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
24 */
31#include "mcu_periph/spi.h"
32#include "mcu_periph/gpio.h"
33#include BOARD_CONFIG
34
35#include <string.h>
36#include "mcu_periph/ram_arch.h"
37
38
39#if SPI_SLAVE
40#error "ChibiOS operates only in SPI_MASTER mode (Slave is TODO)"
41#endif
42
43#if USE_SPI0
44#error "ChibiOS architectures don't have SPI0"
45#endif
46
47// Default stack size
48#ifndef SPI_THREAD_STACK_SIZE
49#define SPI_THREAD_STACK_SIZE 512
50#endif
51
52// Default spi DMA buffer length for F7/H7
53#ifndef SPI_DMA_BUF_LEN
54#define SPI_DMA_BUF_LEN 512 // it has to be big enough
55#endif
56
57// private SPI init structure
58struct spi_init {
59#if defined(STM32F7XX) || defined(STM32H7XX)
62#endif
63 char *name;
65};
66
76{
77 switch (slave) {
78#if USE_SPI_SLAVE0
79 case 0:
81 break;
82#endif // USE_SPI_SLAVE0
83#if USE_SPI_SLAVE1
84 case 1:
86 break;
87#endif //USE_SPI_SLAVE1
88#if USE_SPI_SLAVE2
89 case 2:
91 break;
92#endif //USE_SPI_SLAVE2
93#if USE_SPI_SLAVE3
94 case 3:
96 break;
97#endif //USE_SPI_SLAVE3
98#if USE_SPI_SLAVE4
99 case 4:
101 break;
102#endif //USE_SPI_SLAVE4
103#if USE_SPI_SLAVE5
104 case 5:
106 break;
107#endif //USE_SPI_SLAVE5
108#if USE_SPI_SLAVE6
109 case 6:
111 break;
112#endif //USE_SPI_SLAVE6
113#if USE_SPI_SLAVE7
114 case 7:
116 break;
117#endif //USE_SPI_SLAVE7
118#if USE_SPI_SLAVE8
119 case 8:
121 break;
122#endif //USE_SPI_SLAVE8
123 default:
124 return 0;
125 break;
126 }
127}
128
138{
139 switch (slave) {
140#if USE_SPI_SLAVE0
141 case 0:
143 break;
144#endif // USE_SPI_SLAVE0
145#if USE_SPI_SLAVE1
146 case 1:
148 break;
149#endif //USE_SPI_SLAVE1
150#if USE_SPI_SLAVE2
151 case 2:
153 break;
154#endif //USE_SPI_SLAVE2
155#if USE_SPI_SLAVE3
156 case 3:
158 break;
159#endif //USE_SPI_SLAVE3
160#if USE_SPI_SLAVE4
161 case 4:
163 break;
164#endif //USE_SPI_SLAVE4
165#if USE_SPI_SLAVE5
166 case 5:
168 break;
169#endif //USE_SPI_SLAVE5
170#if USE_SPI_SLAVE6
171 case 6:
173 break;
174#endif //USE_SPI_SLAVE6
175#if USE_SPI_SLAVE7
176 case 7:
178 break;
179#endif //USE_SPI_SLAVE7
180#if USE_SPI_SLAVE8
181 case 8:
183 break;
184#endif //USE_SPI_SLAVE8
185 default:
186 return 0;
187 break;
188 }
189}
190
204{
205 uint32_t CR1 = 0;
206#if defined(STM32F1XX) || defined(STM32F4XX)
207 if (t->dss == SPIDss16bit) {
208 CR1 |= SPI_CR1_DFF;
209 }
210#endif
211#if defined(STM32F1XX) || defined(STM32F4XX) || defined(STM32F7XX)
212 if (t->bitorder == SPILSBFirst) {
214 }
215 if (t->cpha == SPICphaEdge2) {
216 CR1 |= SPI_CR1_CPHA;
217 }
218 if (t->cpol == SPICpolIdleHigh) {
219 CR1 |= SPI_CR1_CPOL;
220 }
221
222 switch (t->cdiv) {
223 case SPIDiv2://000
224 break;
225 case SPIDiv4://001
226 CR1 |= SPI_CR1_BR_0;
227 break;
228 case SPIDiv8://010
229 CR1 |= SPI_CR1_BR_1;
230 break;
231 case SPIDiv16://011
233 break;
234 case SPIDiv32://100
235 CR1 |= SPI_CR1_BR_2;
236 break;
237 case SPIDiv64://101
239 break;
240 case SPIDiv128://110
242 break;
243 case SPIDiv256://111
244 CR1 |= SPI_CR1_BR;
245 break;
246 default:
247 break;
248 }
249#endif /* STM32F1XX || STM32F4XX || STM32F7XX */
250#if defined(STM32H7XX)
251 if (t->dss == SPIDss16bit) {
252 CR1 |= SPI_CFG1_DSIZE_VALUE(15); // 16 bit transfer
253 } else {
254 CR1 |= SPI_CFG1_DSIZE_VALUE(7); // 8 bit transfer
255 }
256 CR1 |= SPI_CFG1_MBR_VALUE(t->cdiv);
257#endif /* STM32H7XX */
258 return CR1;
259}
260
274{
275 uint32_t CR2 = 0;
276#if defined(STM32F7XX)
277 if (t->dss == SPIDss16bit) {
279 } else {
281 }
282#endif /* STM32F7XX */
283#if defined(STM32H7XX)
284 if (t->bitorder == SPILSBFirst) {
286 }
287 if (t->cpha == SPICphaEdge2) {
289 }
290 if (t->cpol == SPICpolIdleHigh) {
292 }
293#endif /* STM32H7XX */
294 return CR2;
295}
296
302static void handle_spi_thd(struct spi_periph *p)
303{
304 struct spi_init *i = (struct spi_init *) p->init_struct;
305
306 // wait for a transaction to be pushed in the queue
307 chSemWait(&i->sem);
308
309 if ((p->trans_insert_idx == p->trans_extract_idx) || p->suspend) {
310 p->status = SPIIdle;
311 // no transaction pending
312 return;
313 }
314
315 // Get next transation in queue
316 struct spi_transaction *t = p->trans[p->trans_extract_idx];
317
319
321 false, // no circular buffer
322#if defined(HAL_LLD_SELECT_SPI_V2)
323 false, // no slave mode
324 NULL, // no callback
325#endif
326 NULL, // no callback
327 spi_resolve_slave_port(t->slave_idx),
328 spi_resolve_slave_pin(t->slave_idx),
331 };
332
333 // find max transaction length
334 static size_t t_length;
335 if (t->input_length >= t->output_length) {
336 t_length = (size_t)t->input_length;
337 } else {
338 t_length = (size_t)t->output_length;
339 }
340
341 // Configure SPI bus with the current slave select pin
342 spiStart((SPIDriver *)p->reg_addr, &spi_cfg);
343 // Select the slave after reconfiguration of the peripheral
344 if (t->select == SPISelectUnselect || t->select == SPISelect) {
345 spiSelect((SPIDriver *)p->reg_addr);
346 }
347
348 // Run the callback after selecting the slave
349 // FIXME warning: done in spi thread
350 if (t->before_cb != 0) {
351 t->before_cb(t);
352 }
353
354 // Start synchronous data transfer
355#if defined(STM32F7XX) || defined(STM32H7XX)
356 // we do stupid mem copy because F7/H7 needs a special RAM for DMA operation
357 memcpy(i->dma_buf_out, (void *)t->output_buf, (size_t)t->output_length);
358 cacheBufferFlush(i->dma_buf_out, t->output_length);
359 spiExchange((SPIDriver *)p->reg_addr, t_length, i->dma_buf_out, i->dma_buf_in);
360 cacheBufferInvalidate(i->dma_buf_in, t->input_length);
361 memcpy((void *)t->input_buf, i->dma_buf_in, (size_t)t->input_length);
362#else
363 spiExchange((SPIDriver *)p->reg_addr, t_length, (uint8_t *)t->output_buf, (uint8_t *)t->input_buf);
364#endif
365
366 // Unselect the slave
367 if (t->select == SPISelectUnselect || t->select == SPIUnselect) {
368 spiUnselect((SPIDriver *)p->reg_addr);
369 }
370
371 chSysLock();
372 // end of transaction, handle fifo
373 p->trans_extract_idx++;
374 if (p->trans_extract_idx >= SPI_TRANSACTION_QUEUE_LEN) {
375 p->trans_extract_idx = 0;
376 }
377 p->status = SPIIdle;
378 chSysUnlock();
379
380 // Report the transaction as success
381 t->status = SPITransSuccess;
382
383 /*
384 * Run the callback after deselecting the slave
385 * to avoid recursion and/or concurency over the bus
386 */
387 // FIXME warning: done in spi thread
388 if (t->after_cb != 0) {
389 t->after_cb(t);
390 }
391
392 pprz_bsem_signal(&t->bsem);
393}
394
400static __attribute__((noreturn)) void thd_spi(void *arg)
401{
402 struct spi_periph *spip = (struct spi_periph *)arg;
403 struct spi_init *init_s = (struct spi_init *)spip->init_struct;
405
406 while (TRUE) {
408 }
409}
410
415#if USE_SPI1
416// Local variables (in DMA safe memory)
418 .name = "spi1",
419 .sem = __SEMAPHORE_DATA(spi1_init_s.sem, 0),
420};
422
423// Initialize the interface
425{
426 spi1.reg_addr = &SPID1;
427 spi1.init_struct = &spi1_init_s;
428 // Create thread
430 NORMALPRIO + 1, thd_spi, (void *)&spi1);
431}
432#endif
433
434#if USE_SPI2
435// Local variables (in DMA safe memory)
436static IN_DMA_SECTION(struct spi_init spi2_init_s) = {
437 .name = "spi2",
438 .sem = __SEMAPHORE_DATA(spi2_init_s.sem, 0),
439};
441
442// Initialize the interface
444{
445 spi2.reg_addr = &SPID2;
446 spi2.init_struct = &spi2_init_s;
447 // Create thread
449 NORMALPRIO + 1, thd_spi, (void *)&spi2);
450}
451#endif
452
453#if USE_SPI3
454// Local variables (in DMA safe memory)
455static IN_DMA_SECTION(struct spi_init spi3_init_s) = {
456 .name = "spi3",
457 .sem = __SEMAPHORE_DATA(spi3_init_s.sem, 0),
458};
460
461// Initialize the interface
462void spi3_arch_init(void)
463{
464 spi3.reg_addr = &SPID3;
465 spi3.init_struct = &spi3_init_s;
466 // Create thread
468 NORMALPRIO + 1, thd_spi, (void *)&spi3);
469}
470#endif
471
472#if USE_SPI4
473// Local variables (in DMA safe memory)
474static IN_DMA_SECTION(struct spi_init spi4_init_s) = {
475 .name = "spi4",
476 .sem = __SEMAPHORE_DATA(spi4_init_s.sem, 0),
477};
479
480// Initialize the interface
481void spi4_arch_init(void)
482{
483 spi4.reg_addr = &SPID4;
484 spi4.init_struct = &spi4_init_s;
485 // Create thread
487 NORMALPRIO + 1, thd_spi, (void *)&spi4);
488}
489#endif
490
491#if USE_SPI6
492
493#if defined(STM32H7XX)
494// Local variables (in DMA safe memory)
495static IN_BDMA_SECTION(struct spi_init spi6_init_s) = {
496#else
497// Local variables (in DMA safe memory)
498static IN_DMA_SECTION(struct spi_init spi6_init_s) = {
499#endif
500 .name = "spi6",
501 .sem = __SEMAPHORE_DATA(spi6_init_s.sem, 0),
502};
504
505// Initialize the interface
506void spi6_arch_init(void)
507{
508 spi6.reg_addr = &SPID6;
509 spi6.init_struct = &spi6_init_s;
510 // Create thread
512 NORMALPRIO + 1, thd_spi, (void *)&spi6);
513}
514#endif
515
516
535{
536 // system lock
537 chSysLock();
538
539 uint8_t idx;
540 idx = p->trans_insert_idx + 1;
541 if (idx >= SPI_TRANSACTION_QUEUE_LEN) { idx = 0; }
542 if ((idx == p->trans_extract_idx) || ((t->input_length == 0) && (t->output_length == 0))) {
543 t->status = SPITransFailed;
544 chSysUnlock();
545 return FALSE; /* queue full or input_length and output_length both 0 */
546 // TODO can't tell why it failed here if it does
547 }
548
549 t->status = SPITransPending;
550
551 /* put transacation in queue */
552 p->trans[p->trans_insert_idx] = t;
553 p->trans_insert_idx = idx;
554
555 chSysUnlock();
556 pprz_bsem_init(&t->bsem, true);
557 chSemSignal(&((struct spi_init *)p->init_struct)->sem);
558 // transaction submitted
559 return TRUE;
560}
561
562
563
569{
570 switch (slave) {
571#if USE_SPI_SLAVE0
572 case 0:
574 break;
575#endif // USE_SPI_SLAVE0
576#if USE_SPI_SLAVE1
577 case 1:
579 break;
580#endif //USE_SPI_SLAVE1
581#if USE_SPI_SLAVE2
582 case 2:
584 break;
585#endif //USE_SPI_SLAVE2
586#if USE_SPI_SLAVE3
587 case 3:
589 break;
590#endif //USE_SPI_SLAVE3
591#if USE_SPI_SLAVE4
592 case 4:
594 break;
595#endif //USE_SPI_SLAVE4
596#if USE_SPI_SLAVE5
597 case 5:
599 break;
600#endif //USE_SPI_SLAVE5
601#if USE_SPI_SLAVE6
602 case 6:
604 break;
605#endif //USE_SPI_SLAVE6
606#if USE_SPI_SLAVE7
607 case 7:
609 break;
610#endif //USE_SPI_SLAVE7
611#if USE_SPI_SLAVE8
612 case 8:
614 break;
615#endif //USE_SPI_SLAVE8
616 default:
617 break;
618 }
619}
620
626{
627 switch (slave) {
628#if USE_SPI_SLAVE0
629 case 0:
631 break;
632#endif // USE_SPI_SLAVE0
633#if USE_SPI_SLAVE1
634 case 1:
636 break;
637#endif //USE_SPI_SLAVE1
638#if USE_SPI_SLAVE2
639 case 2:
641 break;
642#endif //USE_SPI_SLAVE2
643#if USE_SPI_SLAVE3
644 case 3:
646 break;
647#endif //USE_SPI_SLAVE3
648#if USE_SPI_SLAVE4
649 case 4:
651 break;
652#endif //USE_SPI_SLAVE4
653#if USE_SPI_SLAVE5
654 case 5:
656 break;
657#endif //USE_SPI_SLAVE5
658#if USE_SPI_SLAVE6
659 case 6:
661 break;
662#endif //USE_SPI_SLAVE6
663#if USE_SPI_SLAVE7
664 case 7:
666 break;
667#endif //USE_SPI_SLAVE7
668#if USE_SPI_SLAVE8
669 case 8:
671 break;
672#endif //USE_SPI_SLAVE8
673 default:
674 break;
675 }
676}
677
684{
685 if (slave < 254 && p->suspend == 0) {
686 p->suspend = slave + 1; // 0 is reserved for unlock state
687 return TRUE;
688 }
689 return FALSE;
690}
691
698{
699 if (p->suspend == slave + 1) {
700 // restart fifo
701 p->suspend = 0;
702 return TRUE;
703 }
704 return FALSE;
705}
706
712{
713#if USE_SPI_SLAVE0
716#endif
717
718#if USE_SPI_SLAVE1
721#endif
722
723#if USE_SPI_SLAVE2
726#endif
727
728#if USE_SPI_SLAVE3
731#endif
732
733#if USE_SPI_SLAVE4
736#endif
737
738#if USE_SPI_SLAVE5
741#endif
742
743#if USE_SPI_SLAVE6
746#endif
747
748#if USE_SPI_SLAVE7
751#endif
752
753#if USE_SPI_SLAVE8
756#endif
757}
#define SPI_SELECT_SLAVE3_PIN
Definition board.h:491
#define SPI_SELECT_SLAVE0_PORT
Definition board.h:481
#define SPI_SELECT_SLAVE1_PIN
Definition board.h:485
#define SPI_SELECT_SLAVE4_PORT
Definition board.h:493
#define SPI_SELECT_SLAVE0_PIN
Definition board.h:482
#define SPI_SELECT_SLAVE4_PIN
Definition board.h:494
#define SPI_SELECT_SLAVE3_PORT
Definition board.h:490
#define SPI_SELECT_SLAVE1_PORT
Definition board.h:484
#define SPI_SELECT_SLAVE2_PORT
Definition board.h:487
#define SPI_SELECT_SLAVE2_PIN
Definition board.h:488
void gpio_setup_output(ioportid_t port, uint16_t gpios)
Setup one or more pins of the given GPIO port as outputs.
Definition gpio_arch.c:33
static void gpio_set(ioportid_t port, uint16_t pin)
Set a gpio output to high level.
Definition gpio_arch.h:104
static void gpio_clear(ioportid_t port, uint16_t pin)
Clear a gpio output to low level.
Definition gpio_arch.h:114
#define SPI_THREAD_STACK_SIZE
Definition spi_arch.c:49
static void thd_spi(void *arg)
Default spi thread.
Definition spi_arch.c:400
char * name
Definition spi_arch.c:63
static uint32_t spi_resolve_CR1(struct spi_transaction *t)
Resolve CR1 (or CFG1)
Definition spi_arch.c:203
static void handle_spi_thd(struct spi_periph *p)
main thread function
Definition spi_arch.c:302
static THD_WORKING_AREA(wa_thd_spi1, SPI_THREAD_STACK_SIZE)
static uint32_t spi_resolve_CR2(struct spi_transaction *t)
Resolve CR2 (or CFG2)
Definition spi_arch.c:273
static ioportid_t spi_resolve_slave_port(uint8_t slave)
Resolve slave port.
Definition spi_arch.c:75
static uint16_t spi_resolve_slave_pin(uint8_t slave)
Resolve slave pin.
Definition spi_arch.c:137
#define SPI_DMA_BUF_LEN
Definition spi_arch.c:54
semaphore_t sem
Definition spi_arch.c:64
void pprz_bsem_init(pprz_bsem_t *bsem, bool taken)
void pprz_bsem_signal(pprz_bsem_t *bsem)
#define SPI_SELECT_SLAVE5_PIN
Definition chimera.h:541
#define SPI_SELECT_SLAVE5_PORT
Definition chimera.h:540
Some architecture independent helper functions for GPIOs.
enum SPITransactionStatus status
Definition spi.h:158
bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
Submit SPI transaction.
Definition spi_arch.c:534
bool spi_lock(struct spi_periph *p, uint8_t slave)
spi_lock() function
Definition spi_arch.c:683
#define SPI_TRANSACTION_QUEUE_LEN
SPI transaction queue length.
Definition spi.h:166
void spi_slave_unselect(uint8_t slave)
spi_slave_unselect() function
Definition spi_arch.c:625
void spi1_arch_init(void)
Architecture dependent SPI1 initialization.
Definition spi_arch.c:424
process_rx_dma_interrupt & spi2
receive transferred over DMA
Definition spi_arch.c:1004
void spi_slave_select(uint8_t slave)
spi_slave_select() function
Definition spi_arch.c:568
void spi2_arch_init(void)
Architecture dependent SPI2 initialization.
Definition spi_arch.c:443
process_rx_dma_interrupt & spi1
receive transferred over DMA
Definition spi_arch.c:967
bool spi_resume(struct spi_periph *p, uint8_t slave)
spi_resume() function
Definition spi_arch.c:697
void spi_init_slaves(void)
spi_init_slaves() function
Definition spi_arch.c:711
@ SPICphaEdge2
CPHA = 1.
Definition spi.h:71
@ SPIIdle
Definition spi.h:103
@ SPIRunning
Definition spi.h:104
@ SPITransFailed
Definition spi.h:96
@ SPITransSuccess
Definition spi.h:95
@ SPITransPending
Definition spi.h:93
@ SPICpolIdleHigh
CPOL = 1.
Definition spi.h:80
@ SPISelect
slave is selected before transaction but not unselected
Definition spi.h:60
@ SPISelectUnselect
slave is selected before transaction and unselected after
Definition spi.h:59
@ SPIUnselect
slave is not selected but unselected after transaction
Definition spi.h:61
@ SPILSBFirst
Definition spi.h:109
@ SPIDiv4
Definition spi.h:117
@ SPIDiv8
Definition spi.h:118
@ SPIDiv2
Definition spi.h:116
@ SPIDiv256
Definition spi.h:123
@ SPIDiv128
Definition spi.h:122
@ SPIDiv32
Definition spi.h:120
@ SPIDiv64
Definition spi.h:121
@ SPIDiv16
Definition spi.h:119
@ SPIDss16bit
Definition spi.h:87
SPI peripheral structure.
Definition spi.h:171
SPI transaction structure.
Definition spi.h:144
static float p[2][2]
uint16_t foo
Definition main_demo5.c:58
static uint32_t idx
Specific RAM section for DMA usage on F7.
#define IN_DMA_SECTION(var)
Definition ram_arch.h:87
#define IN_BDMA_SECTION(var)
Definition ram_arch.h:91
Architecture independent SPI (Serial Peripheral Interface) API.
#define TRUE
Definition std.h:4
#define FALSE
Definition std.h:5
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.