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}
393
399static __attribute__((noreturn)) void thd_spi(void *arg)
400{
401 struct spi_periph *spip = (struct spi_periph *)arg;
402 struct spi_init *init_s = (struct spi_init *)spip->init_struct;
404
405 while (TRUE) {
407 }
408}
409
414#if USE_SPI1
415// Local variables (in DMA safe memory)
417 .name = "spi1",
418 .sem = __SEMAPHORE_DATA(spi1_init_s.sem, 0),
419};
421
422// Initialize the interface
424{
425 spi1.reg_addr = &SPID1;
426 spi1.init_struct = &spi1_init_s;
427 // Create thread
429 NORMALPRIO + 1, thd_spi, (void *)&spi1);
430}
431#endif
432
433#if USE_SPI2
434// Local variables (in DMA safe memory)
435static IN_DMA_SECTION(struct spi_init spi2_init_s) = {
436 .name = "spi2",
437 .sem = __SEMAPHORE_DATA(spi2_init_s.sem, 0),
438};
440
441// Initialize the interface
443{
444 spi2.reg_addr = &SPID2;
445 spi2.init_struct = &spi2_init_s;
446 // Create thread
448 NORMALPRIO + 1, thd_spi, (void *)&spi2);
449}
450#endif
451
452#if USE_SPI3
453// Local variables (in DMA safe memory)
454static IN_DMA_SECTION(struct spi_init spi3_init_s) = {
455 .name = "spi3",
456 .sem = __SEMAPHORE_DATA(spi3_init_s.sem, 0),
457};
459
460// Initialize the interface
461void spi3_arch_init(void)
462{
463 spi3.reg_addr = &SPID3;
464 spi3.init_struct = &spi3_init_s;
465 // Create thread
467 NORMALPRIO + 1, thd_spi, (void *)&spi3);
468}
469#endif
470
471#if USE_SPI4
472// Local variables (in DMA safe memory)
473static IN_DMA_SECTION(struct spi_init spi4_init_s) = {
474 .name = "spi4",
475 .sem = __SEMAPHORE_DATA(spi4_init_s.sem, 0),
476};
478
479// Initialize the interface
480void spi4_arch_init(void)
481{
482 spi4.reg_addr = &SPID4;
483 spi4.init_struct = &spi4_init_s;
484 // Create thread
486 NORMALPRIO + 1, thd_spi, (void *)&spi4);
487}
488#endif
489
490#if USE_SPI6
491
492#if defined(STM32H7XX)
493// Local variables (in DMA safe memory)
494static IN_BDMA_SECTION(struct spi_init spi6_init_s) = {
495#else
496// Local variables (in DMA safe memory)
497static IN_DMA_SECTION(struct spi_init spi6_init_s) = {
498#endif
499 .name = "spi6",
500 .sem = __SEMAPHORE_DATA(spi6_init_s.sem, 0),
501};
503
504// Initialize the interface
505void spi6_arch_init(void)
506{
507 spi6.reg_addr = &SPID6;
508 spi6.init_struct = &spi6_init_s;
509 // Create thread
511 NORMALPRIO + 1, thd_spi, (void *)&spi6);
512}
513#endif
514
515
534{
535 // system lock
536 chSysLock();
537
538 uint8_t idx;
539 idx = p->trans_insert_idx + 1;
540 if (idx >= SPI_TRANSACTION_QUEUE_LEN) { idx = 0; }
541 if ((idx == p->trans_extract_idx) || ((t->input_length == 0) && (t->output_length == 0))) {
542 t->status = SPITransFailed;
543 chSysUnlock();
544 return FALSE; /* queue full or input_length and output_length both 0 */
545 // TODO can't tell why it failed here if it does
546 }
547
548 t->status = SPITransPending;
549
550 /* put transacation in queue */
551 p->trans[p->trans_insert_idx] = t;
552 p->trans_insert_idx = idx;
553
554 chSysUnlock();
555 chSemSignal(&((struct spi_init *)p->init_struct)->sem);
556 // transaction submitted
557 return TRUE;
558}
559
560
561
567{
568 switch (slave) {
569#if USE_SPI_SLAVE0
570 case 0:
572 break;
573#endif // USE_SPI_SLAVE0
574#if USE_SPI_SLAVE1
575 case 1:
577 break;
578#endif //USE_SPI_SLAVE1
579#if USE_SPI_SLAVE2
580 case 2:
582 break;
583#endif //USE_SPI_SLAVE2
584#if USE_SPI_SLAVE3
585 case 3:
587 break;
588#endif //USE_SPI_SLAVE3
589#if USE_SPI_SLAVE4
590 case 4:
592 break;
593#endif //USE_SPI_SLAVE4
594#if USE_SPI_SLAVE5
595 case 5:
597 break;
598#endif //USE_SPI_SLAVE5
599#if USE_SPI_SLAVE6
600 case 6:
602 break;
603#endif //USE_SPI_SLAVE6
604#if USE_SPI_SLAVE7
605 case 7:
607 break;
608#endif //USE_SPI_SLAVE7
609#if USE_SPI_SLAVE8
610 case 8:
612 break;
613#endif //USE_SPI_SLAVE8
614 default:
615 break;
616 }
617}
618
624{
625 switch (slave) {
626#if USE_SPI_SLAVE0
627 case 0:
629 break;
630#endif // USE_SPI_SLAVE0
631#if USE_SPI_SLAVE1
632 case 1:
634 break;
635#endif //USE_SPI_SLAVE1
636#if USE_SPI_SLAVE2
637 case 2:
639 break;
640#endif //USE_SPI_SLAVE2
641#if USE_SPI_SLAVE3
642 case 3:
644 break;
645#endif //USE_SPI_SLAVE3
646#if USE_SPI_SLAVE4
647 case 4:
649 break;
650#endif //USE_SPI_SLAVE4
651#if USE_SPI_SLAVE5
652 case 5:
654 break;
655#endif //USE_SPI_SLAVE5
656#if USE_SPI_SLAVE6
657 case 6:
659 break;
660#endif //USE_SPI_SLAVE6
661#if USE_SPI_SLAVE7
662 case 7:
664 break;
665#endif //USE_SPI_SLAVE7
666#if USE_SPI_SLAVE8
667 case 8:
669 break;
670#endif //USE_SPI_SLAVE8
671 default:
672 break;
673 }
674}
675
682{
683 if (slave < 254 && p->suspend == 0) {
684 p->suspend = slave + 1; // 0 is reserved for unlock state
685 return TRUE;
686 }
687 return FALSE;
688}
689
696{
697 if (p->suspend == slave + 1) {
698 // restart fifo
699 p->suspend = 0;
700 return TRUE;
701 }
702 return FALSE;
703}
704
710{
711#if USE_SPI_SLAVE0
714#endif
715
716#if USE_SPI_SLAVE1
719#endif
720
721#if USE_SPI_SLAVE2
724#endif
725
726#if USE_SPI_SLAVE3
729#endif
730
731#if USE_SPI_SLAVE4
734#endif
735
736#if USE_SPI_SLAVE5
739#endif
740
741#if USE_SPI_SLAVE6
744#endif
745
746#if USE_SPI_SLAVE7
749#endif
750
751#if USE_SPI_SLAVE8
754#endif
755}
#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:399
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
#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:162
bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
Submit SPI transaction.
Definition spi_arch.c:533
bool spi_lock(struct spi_periph *p, uint8_t slave)
spi_lock() function
Definition spi_arch.c:681
#define SPI_TRANSACTION_QUEUE_LEN
SPI transaction queue length.
Definition spi.h:169
void spi_slave_unselect(uint8_t slave)
spi_slave_unselect() function
Definition spi_arch.c:623
void spi1_arch_init(void)
Architecture dependent SPI1 initialization.
Definition spi_arch.c:423
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:566
void spi2_arch_init(void)
Architecture dependent SPI2 initialization.
Definition spi_arch.c:442
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:695
void spi_init_slaves(void)
spi_init_slaves() function
Definition spi_arch.c:709
@ SPICphaEdge2
CPHA = 1.
Definition spi.h:75
@ SPIIdle
Definition spi.h:107
@ SPIRunning
Definition spi.h:108
@ SPITransFailed
Definition spi.h:100
@ SPITransSuccess
Definition spi.h:99
@ SPITransPending
Definition spi.h:97
@ SPICpolIdleHigh
CPOL = 1.
Definition spi.h:84
@ SPISelect
slave is selected before transaction but not unselected
Definition spi.h:64
@ SPISelectUnselect
slave is selected before transaction and unselected after
Definition spi.h:63
@ SPIUnselect
slave is not selected but unselected after transaction
Definition spi.h:65
@ SPILSBFirst
Definition spi.h:113
@ SPIDiv4
Definition spi.h:121
@ SPIDiv8
Definition spi.h:122
@ SPIDiv2
Definition spi.h:120
@ SPIDiv256
Definition spi.h:127
@ SPIDiv128
Definition spi.h:126
@ SPIDiv32
Definition spi.h:124
@ SPIDiv64
Definition spi.h:125
@ SPIDiv16
Definition spi.h:123
@ SPIDss16bit
Definition spi.h:91
SPI peripheral structure.
Definition spi.h:174
SPI transaction structure.
Definition spi.h:148
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.