Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
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#if USE_SPI_SLAVE9
124 case 9:
126 break;
127#endif //USE_SPI_SLAVE9
128 default:
129 return 0;
130 break;
131 }
132}
133
143{
144 switch (slave) {
145#if USE_SPI_SLAVE0
146 case 0:
148 break;
149#endif // USE_SPI_SLAVE0
150#if USE_SPI_SLAVE1
151 case 1:
153 break;
154#endif //USE_SPI_SLAVE1
155#if USE_SPI_SLAVE2
156 case 2:
158 break;
159#endif //USE_SPI_SLAVE2
160#if USE_SPI_SLAVE3
161 case 3:
163 break;
164#endif //USE_SPI_SLAVE3
165#if USE_SPI_SLAVE4
166 case 4:
168 break;
169#endif //USE_SPI_SLAVE4
170#if USE_SPI_SLAVE5
171 case 5:
173 break;
174#endif //USE_SPI_SLAVE5
175#if USE_SPI_SLAVE6
176 case 6:
178 break;
179#endif //USE_SPI_SLAVE6
180#if USE_SPI_SLAVE7
181 case 7:
183 break;
184#endif //USE_SPI_SLAVE7
185#if USE_SPI_SLAVE8
186 case 8:
188 break;
189#endif //USE_SPI_SLAVE8
190#if USE_SPI_SLAVE9
191 case 9:
193 break;
194#endif //USE_SPI_SLAVE9
195 default:
196 return 0;
197 break;
198 }
199}
200
214{
215 uint32_t CR1 = 0;
216#if defined(STM32F1XX) || defined(STM32F4XX)
217 if (t->dss == SPIDss16bit) {
218 CR1 |= SPI_CR1_DFF;
219 }
220#endif
221#if defined(STM32F1XX) || defined(STM32F4XX) || defined(STM32F7XX)
222 if (t->bitorder == SPILSBFirst) {
224 }
225 if (t->cpha == SPICphaEdge2) {
226 CR1 |= SPI_CR1_CPHA;
227 }
228 if (t->cpol == SPICpolIdleHigh) {
229 CR1 |= SPI_CR1_CPOL;
230 }
231
232 switch (t->cdiv) {
233 case SPIDiv2://000
234 break;
235 case SPIDiv4://001
236 CR1 |= SPI_CR1_BR_0;
237 break;
238 case SPIDiv8://010
239 CR1 |= SPI_CR1_BR_1;
240 break;
241 case SPIDiv16://011
243 break;
244 case SPIDiv32://100
245 CR1 |= SPI_CR1_BR_2;
246 break;
247 case SPIDiv64://101
249 break;
250 case SPIDiv128://110
252 break;
253 case SPIDiv256://111
254 CR1 |= SPI_CR1_BR;
255 break;
256 default:
257 break;
258 }
259#endif /* STM32F1XX || STM32F4XX || STM32F7XX */
260#if defined(STM32H7XX)
261 if (t->dss == SPIDss16bit) {
262 CR1 |= SPI_CFG1_DSIZE_VALUE(15); // 16 bit transfer
263 } else {
264 CR1 |= SPI_CFG1_DSIZE_VALUE(7); // 8 bit transfer
265 }
266 CR1 |= SPI_CFG1_MBR_VALUE(t->cdiv);
267#endif /* STM32H7XX */
268 return CR1;
269}
270
284{
285 uint32_t CR2 = 0;
286#if defined(STM32F7XX)
287 if (t->dss == SPIDss16bit) {
289 } else {
291 }
292#endif /* STM32F7XX */
293#if defined(STM32H7XX)
294 if (t->bitorder == SPILSBFirst) {
296 }
297 if (t->cpha == SPICphaEdge2) {
299 }
300 if (t->cpol == SPICpolIdleHigh) {
302 }
303#endif /* STM32H7XX */
304 return CR2;
305}
306
312static void handle_spi_thd(struct spi_periph *p)
313{
314 struct spi_init *i = (struct spi_init *) p->init_struct;
315
316 // wait for a transaction to be pushed in the queue
317 chSemWait(&i->sem);
318
319 if ((p->trans_insert_idx == p->trans_extract_idx) || p->suspend) {
320 p->status = SPIIdle;
321 // no transaction pending
322 return;
323 }
324
325 // Get next transation in queue
326 struct spi_transaction *t = p->trans[p->trans_extract_idx];
327
329
331 false, // no circular buffer
332#if defined(HAL_LLD_SELECT_SPI_V2)
333 false, // no slave mode
334 NULL, // no callback
335#endif
336 NULL, // no callback
337 spi_resolve_slave_port(t->slave_idx),
338 spi_resolve_slave_pin(t->slave_idx),
341 };
342
343 // find max transaction length
344 static size_t t_length;
345 if (t->input_length >= t->output_length) {
346 t_length = (size_t)t->input_length;
347 } else {
348 t_length = (size_t)t->output_length;
349 }
350
351 // Configure SPI bus with the current slave select pin
352 spiStart((SPIDriver *)p->reg_addr, &spi_cfg);
353 // Select the slave after reconfiguration of the peripheral
354 if (t->select == SPISelectUnselect || t->select == SPISelect) {
355 spiSelect((SPIDriver *)p->reg_addr);
356 }
357
358 // Run the callback after selecting the slave
359 // FIXME warning: done in spi thread
360 if (t->before_cb != 0) {
361 t->before_cb(t);
362 }
363
364 // Start synchronous data transfer
365#if defined(STM32F7XX) || defined(STM32H7XX)
366 // we do stupid mem copy because F7/H7 needs a special RAM for DMA operation
367 memcpy(i->dma_buf_out, (void *)t->output_buf, (size_t)t->output_length);
368 cacheBufferFlush(i->dma_buf_out, t->output_length);
369 spiExchange((SPIDriver *)p->reg_addr, t_length, i->dma_buf_out, i->dma_buf_in);
370 cacheBufferInvalidate(i->dma_buf_in, t->input_length);
371 memcpy((void *)t->input_buf, i->dma_buf_in, (size_t)t->input_length);
372#else
373 spiExchange((SPIDriver *)p->reg_addr, t_length, (uint8_t *)t->output_buf, (uint8_t *)t->input_buf);
374#endif
375
376 // Unselect the slave
377 if (t->select == SPISelectUnselect || t->select == SPIUnselect) {
378 spiUnselect((SPIDriver *)p->reg_addr);
379 }
380
381 chSysLock();
382 // end of transaction, handle fifo
383 p->trans_extract_idx++;
384 if (p->trans_extract_idx >= SPI_TRANSACTION_QUEUE_LEN) {
385 p->trans_extract_idx = 0;
386 }
387 p->status = SPIIdle;
388 chSysUnlock();
389
390 // Report the transaction as success
391 t->status = SPITransSuccess;
392
393 /*
394 * Run the callback after deselecting the slave
395 * to avoid recursion and/or concurency over the bus
396 */
397 // FIXME warning: done in spi thread
398 if (t->after_cb != 0) {
399 t->after_cb(t);
400 }
401
402 pprz_bsem_signal(&t->bsem);
403}
404
410static __attribute__((noreturn)) void thd_spi(void *arg)
411{
412 struct spi_periph *spip = (struct spi_periph *)arg;
413 struct spi_init *init_s = (struct spi_init *)spip->init_struct;
415
416 while (TRUE) {
418 }
419}
420
425#if USE_SPI1
426// Local variables (in DMA safe memory)
428 .name = "spi1",
429 .sem = __SEMAPHORE_DATA(spi1_init_s.sem, 0),
430};
432
433// Initialize the interface
435{
436 spi1.reg_addr = &SPID1;
437 spi1.init_struct = &spi1_init_s;
438 // Create thread
440 NORMALPRIO + 1, thd_spi, (void *)&spi1);
441}
442#endif
443
444#if USE_SPI2
445// Local variables (in DMA safe memory)
446static IN_DMA_SECTION(struct spi_init spi2_init_s) = {
447 .name = "spi2",
448 .sem = __SEMAPHORE_DATA(spi2_init_s.sem, 0),
449};
451
452// Initialize the interface
454{
455 spi2.reg_addr = &SPID2;
456 spi2.init_struct = &spi2_init_s;
457 // Create thread
459 NORMALPRIO + 1, thd_spi, (void *)&spi2);
460}
461#endif
462
463#if USE_SPI3
464// Local variables (in DMA safe memory)
465static IN_DMA_SECTION(struct spi_init spi3_init_s) = {
466 .name = "spi3",
467 .sem = __SEMAPHORE_DATA(spi3_init_s.sem, 0),
468};
470
471// Initialize the interface
472void spi3_arch_init(void)
473{
474 spi3.reg_addr = &SPID3;
475 spi3.init_struct = &spi3_init_s;
476 // Create thread
478 NORMALPRIO + 1, thd_spi, (void *)&spi3);
479}
480#endif
481
482#if USE_SPI4
483// Local variables (in DMA safe memory)
484static IN_DMA_SECTION(struct spi_init spi4_init_s) = {
485 .name = "spi4",
486 .sem = __SEMAPHORE_DATA(spi4_init_s.sem, 0),
487};
489
490// Initialize the interface
491void spi4_arch_init(void)
492{
493 spi4.reg_addr = &SPID4;
494 spi4.init_struct = &spi4_init_s;
495 // Create thread
497 NORMALPRIO + 1, thd_spi, (void *)&spi4);
498}
499#endif
500
501#if USE_SPI6
502
503#if defined(STM32H7XX)
504// Local variables (in DMA safe memory)
505static IN_BDMA_SECTION(struct spi_init spi6_init_s) = {
506#else
507// Local variables (in DMA safe memory)
508static IN_DMA_SECTION(struct spi_init spi6_init_s) = {
509#endif
510 .name = "spi6",
511 .sem = __SEMAPHORE_DATA(spi6_init_s.sem, 0),
512};
514
515// Initialize the interface
516void spi6_arch_init(void)
517{
518 spi6.reg_addr = &SPID6;
519 spi6.init_struct = &spi6_init_s;
520 // Create thread
522 NORMALPRIO + 1, thd_spi, (void *)&spi6);
523}
524#endif
525
526
545{
546 // system lock
547 chSysLock();
548
549 uint8_t idx;
550 idx = p->trans_insert_idx + 1;
551 if (idx >= SPI_TRANSACTION_QUEUE_LEN) { idx = 0; }
552 if ((idx == p->trans_extract_idx) || ((t->input_length == 0) && (t->output_length == 0))) {
553 t->status = SPITransFailed;
554 chSysUnlock();
555 return FALSE; /* queue full or input_length and output_length both 0 */
556 // TODO can't tell why it failed here if it does
557 }
558
559 t->status = SPITransPending;
560
561 /* put transacation in queue */
562 p->trans[p->trans_insert_idx] = t;
563 p->trans_insert_idx = idx;
564
565 chSysUnlock();
566 pprz_bsem_init(&t->bsem, true);
567 chSemSignal(&((struct spi_init *)p->init_struct)->sem);
568 // transaction submitted
569 return TRUE;
570}
571
572
573
579{
580 switch (slave) {
581#if USE_SPI_SLAVE0
582 case 0:
584 break;
585#endif // USE_SPI_SLAVE0
586#if USE_SPI_SLAVE1
587 case 1:
589 break;
590#endif //USE_SPI_SLAVE1
591#if USE_SPI_SLAVE2
592 case 2:
594 break;
595#endif //USE_SPI_SLAVE2
596#if USE_SPI_SLAVE3
597 case 3:
599 break;
600#endif //USE_SPI_SLAVE3
601#if USE_SPI_SLAVE4
602 case 4:
604 break;
605#endif //USE_SPI_SLAVE4
606#if USE_SPI_SLAVE5
607 case 5:
609 break;
610#endif //USE_SPI_SLAVE5
611#if USE_SPI_SLAVE6
612 case 6:
614 break;
615#endif //USE_SPI_SLAVE6
616#if USE_SPI_SLAVE7
617 case 7:
619 break;
620#endif //USE_SPI_SLAVE7
621#if USE_SPI_SLAVE8
622 case 8:
624 break;
625#endif //USE_SPI_SLAVE8
626#if USE_SPI_SLAVE9
627 case 9:
629 break;
630#endif //USE_SPI_SLAVE9
631 default:
632 break;
633 }
634}
635
641{
642 switch (slave) {
643#if USE_SPI_SLAVE0
644 case 0:
646 break;
647#endif // USE_SPI_SLAVE0
648#if USE_SPI_SLAVE1
649 case 1:
651 break;
652#endif //USE_SPI_SLAVE1
653#if USE_SPI_SLAVE2
654 case 2:
656 break;
657#endif //USE_SPI_SLAVE2
658#if USE_SPI_SLAVE3
659 case 3:
661 break;
662#endif //USE_SPI_SLAVE3
663#if USE_SPI_SLAVE4
664 case 4:
666 break;
667#endif //USE_SPI_SLAVE4
668#if USE_SPI_SLAVE5
669 case 5:
671 break;
672#endif //USE_SPI_SLAVE5
673#if USE_SPI_SLAVE6
674 case 6:
676 break;
677#endif //USE_SPI_SLAVE6
678#if USE_SPI_SLAVE7
679 case 7:
681 break;
682#endif //USE_SPI_SLAVE7
683#if USE_SPI_SLAVE8
684 case 8:
686 break;
687#endif //USE_SPI_SLAVE8
688#if USE_SPI_SLAVE9
689 case 9:
691 break;
692#endif //USE_SPI_SLAVE9
693 default:
694 break;
695 }
696}
697
704{
705 if (slave < 254 && p->suspend == 0) {
706 p->suspend = slave + 1; // 0 is reserved for unlock state
707 return TRUE;
708 }
709 return FALSE;
710}
711
718{
719 if (p->suspend == slave + 1) {
720 // restart fifo
721 p->suspend = 0;
722 return TRUE;
723 }
724 return FALSE;
725}
726
732{
733#if USE_SPI_SLAVE0
736#endif
737
738#if USE_SPI_SLAVE1
741#endif
742
743#if USE_SPI_SLAVE2
746#endif
747
748#if USE_SPI_SLAVE3
751#endif
752
753#if USE_SPI_SLAVE4
756#endif
757
758#if USE_SPI_SLAVE5
761#endif
762
763#if USE_SPI_SLAVE6
766#endif
767
768#if USE_SPI_SLAVE7
771#endif
772
773#if USE_SPI_SLAVE8
776#endif
777
778#if USE_SPI_SLAVE9
781#endif
782}
#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:410
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:213
static void handle_spi_thd(struct spi_periph *p)
main thread function
Definition spi_arch.c:312
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:283
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:142
#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:544
bool spi_lock(struct spi_periph *p, uint8_t slave)
spi_lock() function
Definition spi_arch.c:703
#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:640
void spi1_arch_init(void)
Architecture dependent SPI1 initialization.
Definition spi_arch.c:434
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:578
void spi2_arch_init(void)
Architecture dependent SPI2 initialization.
Definition spi_arch.c:453
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:717
void spi_init_slaves(void)
spi_init_slaves() function
Definition spi_arch.c:731
@ 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.