Paparazzi UAS  v5.15_devel-109-gee85905
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 #if SPI_SLAVE
39 #error "ChibiOS operates only in SPI_MASTER mode"
40 #endif
41 
42 #if USE_SPI0
43 #error "ChibiOS architectures don't have SPI0"
44 #endif
45 
46 // Default stack size
47 #ifndef SPI_THREAD_STACK_SIZE
48 #define SPI_THREAD_STACK_SIZE 512
49 #endif
50 
51 // private SPI init structure
52 struct spi_init {
53  semaphore_t *sem;
54 #ifdef STM32F7
55  uint8_t *dma_buf_out;
56  uint8_t *dma_buf_in;
57 #endif
58 };
59 #define SPI_DMA_BUF_LEN 512 // it has to be big enough
60 
69 static inline ioportid_t spi_resolve_slave_port(uint8_t slave)
70 {
71  switch (slave) {
72 #if USE_SPI_SLAVE0
73  case 0:
75  break;
76 #endif // USE_SPI_SLAVE0
77 #if USE_SPI_SLAVE1
78  case 1:
80  break;
81 #endif //USE_SPI_SLAVE1
82 #if USE_SPI_SLAVE2
83  case 2:
85  break;
86 #endif //USE_SPI_SLAVE2
87 #if USE_SPI_SLAVE3
88  case 3:
90  break;
91 #endif //USE_SPI_SLAVE3
92 #if USE_SPI_SLAVE4
93  case 4:
95  break;
96 #endif //USE_SPI_SLAVE4
97 #if USE_SPI_SLAVE5
98  case 5:
100  break;
101 #endif //USE_SPI_SLAVE5
102  default:
103  return 0;
104  break;
105  }
106 }
107 
117 {
118  switch (slave) {
119 #if USE_SPI_SLAVE0
120  case 0:
121  return SPI_SELECT_SLAVE0_PIN;
122  break;
123 #endif // USE_SPI_SLAVE0
124 #if USE_SPI_SLAVE1
125  case 1:
126  return SPI_SELECT_SLAVE1_PIN;
127  break;
128 #endif //USE_SPI_SLAVE1
129 #if USE_SPI_SLAVE2
130  case 2:
131  return SPI_SELECT_SLAVE2_PIN;
132  break;
133 #endif //USE_SPI_SLAVE2
134 #if USE_SPI_SLAVE3
135  case 3:
136  return SPI_SELECT_SLAVE3_PIN;
137  break;
138 #endif //USE_SPI_SLAVE3
139 #if USE_SPI_SLAVE4
140  case 4:
141  return SPI_SELECT_SLAVE4_PIN;
142  break;
143 #endif //USE_SPI_SLAVE4
144 #if USE_SPI_SLAVE5
145  case 5:
146  return SPI_SELECT_SLAVE5_PIN;
147  break;
148 #endif //USE_SPI_SLAVE5
149  default:
150  return 0;
151  break;
152  }
153 }
154 
167 static inline uint16_t spi_resolve_CR1(struct spi_transaction *t __attribute__((unused)))
168 {
169  uint16_t CR1 = 0;
170 #if defined(STM32F1) || defined(STM32F4)
171  if (t->dss == SPIDss16bit) {
172  CR1 |= SPI_CR1_DFF; // FIXME for F7
173  }
174 #endif
175 #if defined(STM32F1) || defined(STM32F4) || defined(STM32F7)
176  if (t->bitorder == SPILSBFirst) {
177  CR1 |= SPI_CR1_LSBFIRST;
178  }
179  if (t->cpha == SPICphaEdge2) {
180  CR1 |= SPI_CR1_CPHA;
181  }
182  if (t->cpol == SPICpolIdleHigh) {
183  CR1 |= SPI_CR1_CPOL;
184  }
185 
186  switch (t->cdiv) {
187  case SPIDiv2://000
188  break;
189  case SPIDiv4://001
190  CR1 |= SPI_CR1_BR_0;
191  break;
192  case SPIDiv8://010
193  CR1 |= SPI_CR1_BR_1;
194  break;
195  case SPIDiv16://011
196  CR1 |= SPI_CR1_BR_1 | SPI_CR1_BR_0;
197  break;
198  case SPIDiv32://100
199  CR1 |= SPI_CR1_BR_2;
200  break;
201  case SPIDiv64://101
202  CR1 |= SPI_CR1_BR_2 | SPI_CR1_BR_0;
203  break;
204  case SPIDiv128://110
205  CR1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1;
206  break;
207  case SPIDiv256://111
208  CR1 |= SPI_CR1_BR;
209  break;
210  default:
211  break;
212  }
213 #endif /* STM32F1 || STM32F4 || STM32F7 */
214  return CR1;
215 }
216 
229 static inline uint16_t spi_resolve_CR2(struct spi_transaction *t __attribute__((unused)))
230 {
231  uint16_t CR2 = 0;
232 #if defined(STM32F7)
233  if (t->dss == SPIDss16bit) {
234  CR2 |= SPI_CR2_DS_0 | SPI_CR2_DS_1 | SPI_CR2_DS_2 | SPI_CR2_DS_3;
235  } else {
236  CR2 |= SPI_CR2_DS_0 | SPI_CR2_DS_1 | SPI_CR2_DS_2;
237  }
238 #endif /* STM32F7 */
239  return CR2;
240 }
241 
247 static void handle_spi_thd(struct spi_periph *p)
248 {
249  struct spi_init *i = (struct spi_init *) p->init_struct;
250 
251  // wait for a transaction to be pushed in the queue
252  chSemWait(i->sem);
253 
254  if ((p->trans_insert_idx == p->trans_extract_idx) || p->suspend) {
255  p->status = SPIIdle;
256  // no transaction pending
257  return;
258  }
259 
260  // Get next transation in queue
261  struct spi_transaction *t = p->trans[p->trans_extract_idx];
262 
263  p->status = SPIRunning;
264 
265  SPIConfig spi_cfg = {
266  false, // no circular buffer
267  NULL, // no callback
270  spi_resolve_CR1(t),
271  spi_resolve_CR2(t)
272  };
273 
274  // find max transaction length
275  static size_t t_length;
276  if (t->input_length >= t->output_length) {
277  t_length = (size_t)t->input_length;
278  } else {
279  t_length = (size_t)t->output_length;
280  }
281 
282  // Configure SPI bus with the current slave select pin
283  spiStart((SPIDriver *)p->reg_addr, &spi_cfg);
284  spiSelect((SPIDriver *)p->reg_addr);
285 
286  // Run the callback after selecting the slave
287  // FIXME warning: done in spi thread
288  if (t->before_cb != 0) {
289  t->before_cb(t);
290  }
291 
292  // Start synchronous data transfer
293 #if defined STM32F7
294  // we do stupid mem copy because F7 needs a special RAM for DMA operation
295  memcpy(i->dma_buf_out, (void *)t->output_buf, (size_t)t->output_length);
296  spiExchange((SPIDriver *)p->reg_addr, t_length, i->dma_buf_out, i->dma_buf_in);
297  memcpy((void *)t->input_buf, i->dma_buf_in, (size_t)t->input_length);
298 #else
299  spiExchange((SPIDriver *)p->reg_addr, t_length, (uint8_t *)t->output_buf, (uint8_t *)t->input_buf);
300 #endif
301 
302  // Unselect the slave
303  spiUnselect((SPIDriver *)p->reg_addr);
304 
305  chSysLock();
306  // end of transaction, handle fifo
307  p->trans_extract_idx++;
309  p->trans_extract_idx = 0;
310  }
311  p->status = SPIIdle;
312  chSysUnlock();
313 
314  // Report the transaction as success
315  t->status = SPITransSuccess;
316 
317  /*
318  * Run the callback after deselecting the slave
319  * to avoid recursion and/or concurency over the bus
320  */
321  // FIXME warning: done in spi thread
322  if (t->after_cb != 0) {
323  t->after_cb(t);
324  }
325 }
326 
331 #if USE_SPI1
332 static SEMAPHORE_DECL(spi1_sem, 0);
333 #if defined STM32F7
334 // We need a special buffer for DMA operations
335 static IN_DMA_SECTION(uint8_t spi1_dma_buf_out[SPI_DMA_BUF_LEN]);
336 static IN_DMA_SECTION(uint8_t spi1_dma_buf_in[SPI_DMA_BUF_LEN]);
337 static struct spi_init spi1_init_s = {
338  .sem = &spi1_sem,
339  .dma_buf_out = spi1_dma_buf_out,
340  .dma_buf_in = spi1_dma_buf_in
341 };
342 #else
343 static struct spi_init spi1_init_s = {
344  .sem = &spi1_sem,
345 };
346 #endif
347 
348 static __attribute__((noreturn)) void thd_spi1(void *arg)
349 {
350  (void) arg;
351  chRegSetThreadName("spi1");
352 
353  while (TRUE) {
355  }
356 }
357 
358 static THD_WORKING_AREA(wa_thd_spi1, SPI_THREAD_STACK_SIZE);
359 
360 void spi1_arch_init(void)
361 {
362  spi1.reg_addr = &SPID1;
363  spi1.init_struct = &spi1_init_s;
364  // Create thread
365  chThdCreateStatic(wa_thd_spi1, sizeof(wa_thd_spi1),
366  NORMALPRIO + 1, thd_spi1, NULL);
367 }
368 #endif
369 
370 #if USE_SPI2
371 static SEMAPHORE_DECL(spi2_sem, 0);
372 #if defined STM32F7
373 // We need a special buffer for DMA operations
374 static IN_DMA_SECTION(uint8_t spi2_dma_buf_out[SPI_DMA_BUF_LEN]);
375 static IN_DMA_SECTION(uint8_t spi2_dma_buf_in[SPI_DMA_BUF_LEN]);
376 static struct spi_init spi2_init_s = {
377  .sem = &spi2_sem,
378  .dma_buf_out = spi2_dma_buf_out,
379  .dma_buf_in = spi2_dma_buf_in
380 };
381 #else
382 static struct spi_init spi2_init_s = {
383  .sem = &spi2_sem,
384 };
385 #endif
386 
387 static __attribute__((noreturn)) void thd_spi2(void *arg)
388 {
389  (void) arg;
390  chRegSetThreadName("spi2");
391 
392  while (TRUE) {
394  }
395 }
396 
397 static THD_WORKING_AREA(wa_thd_spi2, SPI_THREAD_STACK_SIZE);
398 
399 void spi2_arch_init(void)
400 {
401  spi2.reg_addr = &SPID2;
402  spi2.init_struct = &spi2_init_s;
403  // Create thread
404  chThdCreateStatic(wa_thd_spi2, sizeof(wa_thd_spi2),
405  NORMALPRIO + 1, thd_spi2, NULL);
406 }
407 #endif
408 
409 #if USE_SPI3
410 static SEMAPHORE_DECL(spi3_sem, 0);
411 #if defined STM32F7
412 // We need a special buffer for DMA operations
413 static IN_DMA_SECTION(uint8_t spi3_dma_buf_out[SPI_DMA_BUF_LEN]);
414 static IN_DMA_SECTION(uint8_t spi3_dma_buf_in[SPI_DMA_BUF_LEN]);
415 static struct spi_init spi3_init_s = {
416  .sem = &spi3_sem,
417  .dma_buf_out = spi3_dma_buf_out,
418  .dma_buf_in = spi3_dma_buf_in
419 };
420 #else
421 static struct spi_init spi3_init_s = {
422  .sem = &spi3_sem,
423 };
424 #endif
425 
426 static __attribute__((noreturn)) void thd_spi3(void *arg)
427 {
428  (void) arg;
429  chRegSetThreadName("spi3");
430 
431  while (TRUE) {
432  handle_spi_thd(&spi3);
433  }
434 }
435 
436 static THD_WORKING_AREA(wa_thd_spi3, SPI_THREAD_STACK_SIZE);
437 
438 void spi3_arch_init(void)
439 {
440  spi3.reg_addr = &SPID3;
441  spi3.init_struct = &spi3_init_s;
442  // Create thread
443  chThdCreateStatic(wa_thd_spi3, sizeof(wa_thd_spi3),
444  NORMALPRIO + 1, thd_spi3, NULL);
445 }
446 #endif
447 
448 #if USE_SPI4
449 static SEMAPHORE_DECL(spi4_sem, 0);
450 #if defined STM32F7
451 // We need a special buffer for DMA operations
452 static IN_DMA_SECTION(uint8_t spi4_dma_buf_out[SPI_DMA_BUF_LEN]);
453 static IN_DMA_SECTION(uint8_t spi4_dma_buf_in[SPI_DMA_BUF_LEN]);
454 static struct spi_init spi4_init_s = {
455  .sem = &spi4_sem,
456  .dma_buf_out = spi4_dma_buf_out,
457  .dma_buf_in = spi4_dma_buf_in
458 };
459 #else
460 static struct spi_init spi4_init_s = {
461  .sem = &spi4_sem,
462 };
463 #endif
464 
465 static __attribute__((noreturn)) void thd_spi4(void *arg)
466 {
467  (void) arg;
468  chRegSetThreadName("spi4");
469 
470  while (TRUE) {
471  handle_spi_thd(&spi4);
472  }
473 }
474 
475 static THD_WORKING_AREA(wa_thd_spi4, 256);
476 
477 void spi4_arch_init(void)
478 {
479  spi4.reg_addr = &SPID4;
480  spi4.init_struct = &spi4_init_s;
481  // Create thread
482  chThdCreateStatic(wa_thd_spi4, sizeof(wa_thd_spi4),
483  NORMALPRIO + 1, thd_spi4, NULL);
484 }
485 #endif
486 
487 
505 bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
506 {
507  // system lock
508  chSysLock();
509 
510  uint8_t idx;
511  idx = p->trans_insert_idx + 1;
512  if (idx >= SPI_TRANSACTION_QUEUE_LEN) { idx = 0; }
513  if ((idx == p->trans_extract_idx) || ((t->input_length == 0) && (t->output_length == 0))) {
514  t->status = SPITransFailed;
515  chSysUnlock();
516  return FALSE; /* queue full or input_length and output_length both 0 */
517  // TODO can't tell why it failed here if it does
518  }
519 
520  t->status = SPITransPending;
521 
522  /* put transacation in queue */
523  p->trans[p->trans_insert_idx] = t;
524  p->trans_insert_idx = idx;
525 
526  chSysUnlock();
527  chSemSignal(((struct spi_init *)p->init_struct)->sem);
528  // transaction submitted
529  return TRUE;
530 }
531 
532 
533 
539 {
540  switch (slave) {
541 #if USE_SPI_SLAVE0
542  case 0:
544  break;
545 #endif // USE_SPI_SLAVE0
546 #if USE_SPI_SLAVE1
547  case 1:
549  break;
550 #endif //USE_SPI_SLAVE1
551 #if USE_SPI_SLAVE2
552  case 2:
554  break;
555 #endif //USE_SPI_SLAVE2
556 #if USE_SPI_SLAVE3
557  case 3:
559  break;
560 #endif //USE_SPI_SLAVE3
561 #if USE_SPI_SLAVE4
562  case 4:
564  break;
565 #endif //USE_SPI_SLAVE4
566 #if USE_SPI_SLAVE5
567  case 5:
569  break;
570 #endif //USE_SPI_SLAVE5
571  default:
572  break;
573  }
574 }
575 
581 {
582  switch (slave) {
583 #if USE_SPI_SLAVE0
584  case 0:
586  break;
587 #endif // USE_SPI_SLAVE0
588 #if USE_SPI_SLAVE1
589  case 1:
591  break;
592 #endif //USE_SPI_SLAVE1
593 #if USE_SPI_SLAVE2
594  case 2:
596  break;
597 #endif //USE_SPI_SLAVE2
598 #if USE_SPI_SLAVE3
599  case 3:
601  break;
602 #endif //USE_SPI_SLAVE3
603 #if USE_SPI_SLAVE4
604  case 4:
606  break;
607 #endif //USE_SPI_SLAVE4
608 #if USE_SPI_SLAVE5
609  case 5:
611  break;
612 #endif //USE_SPI_SLAVE5
613  default:
614  break;
615  }
616 }
617 
623 bool spi_lock(struct spi_periph *p, uint8_t slave)
624 {
625  if (slave < 254 && p->suspend == 0) {
626  p->suspend = slave + 1; // 0 is reserved for unlock state
627  return TRUE;
628  }
629  return FALSE;
630 }
631 
637 bool spi_resume(struct spi_periph *p, uint8_t slave)
638 {
639  if (p->suspend == slave + 1) {
640  // restart fifo
641  p->suspend = 0;
642  return TRUE;
643  }
644  return FALSE;
645 }
646 
651 void spi_init_slaves(void)
652 {
653 #if USE_SPI_SLAVE0
656 #endif
657 
658 #if USE_SPI_SLAVE1
661 #endif
662 
663 #if USE_SPI_SLAVE2
666 #endif
667 
668 #if USE_SPI_SLAVE3
671 #endif
672 
673 #if USE_SPI_SLAVE4
676 #endif
677 
678 #if USE_SPI_SLAVE5
681 #endif
682 }
683 
unsigned short uint16_t
Definition: types.h:16
Specific RAM section for DMA usage on F7.
static uint32_t idx
Definition: spi.h:118
static uint16_t spi_resolve_slave_pin(uint8_t slave)
Resolve slave pin.
Definition: spi_arch.c:116
uint16_t output_length
number of data words to write
Definition: spi.h:146
#define SPI_SELECT_SLAVE4_PORT
Definition: board.h:531
process_rx_dma_interrupt & spi2
receive transferred over DMA
Definition: spi_arch.c:1004
static void gpio_clear(ioportid_t port, uint16_t pin)
Clear a gpio output to low level.
Definition: gpio_arch.h:108
void * reg_addr
Definition: spi.h:177
void spi1_arch_init(void)
Architecture dependent SPI1 initialization.
Definition: spi_arch.c:360
static uint16_t spi_resolve_CR1(struct spi_transaction *t)
Resolve CR1.
Definition: spi_arch.c:167
CPHA = 1.
Definition: spi.h:69
Some architecture independent helper functions for GPIOs.
semaphore_t * sem
Definition: spi_arch.c:53
Definition: spi.h:115
SPI transaction structure.
Definition: spi.h:142
bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
Submit SPI transaction.
Definition: spi_arch.c:505
CPOL = 1.
Definition: spi.h:78
static void handle_spi_thd(struct spi_periph *p)
main thread function
Definition: spi_arch.c:247
void * init_struct
Definition: spi.h:178
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
volatile uint8_t * output_buf
pointer to transmit buffer for DMA
Definition: spi.h:144
volatile uint8_t suspend
control for stop/resume of the fifo
Definition: spi.h:181
#define FALSE
Definition: std.h:5
static SEMAPHORE_DECL(spi1_sem, 0)
Configure SPI peripherals.
Architecture independent SPI (Serial Peripheral Interface) API.
#define SPI_SELECT_SLAVE1_PORT
Definition: board.h:522
Definition: spi.h:114
static struct spi_init spi1_init_s
Definition: spi_arch.c:343
static struct spi_init spi2_init_s
Definition: spi_arch.c:382
bool spi_lock(struct spi_periph *p, uint8_t slave)
spi_lock() function
Definition: spi_arch.c:623
#define TRUE
Definition: std.h:4
SPI peripheral structure.
Definition: spi.h:168
#define SPI_SELECT_SLAVE0_PIN
Definition: board.h:520
void spi_slave_unselect(uint8_t slave)
spi_slave_unselect() function
Definition: spi_arch.c:580
#define SPI_SELECT_SLAVE2_PORT
Definition: board.h:525
SPICallback after_cb
NULL or function called after the transaction.
Definition: spi.h:155
#define SPI_DMA_BUF_LEN
Definition: spi_arch.c:59
#define SPI_SELECT_SLAVE0_PORT
Definition: board.h:519
void spi2_arch_init(void)
Architecture dependent SPI2 initialization.
Definition: spi_arch.c:399
#define SPI_SELECT_SLAVE1_PIN
Definition: board.h:523
static ioportid_t spi_resolve_slave_port(uint8_t slave)
Resolve slave port.
Definition: spi_arch.c:69
#define SPI_SELECT_SLAVE2_PIN
Definition: board.h:526
static THD_WORKING_AREA(wa_thd_spi1, SPI_THREAD_STACK_SIZE)
uint16_t input_length
number of data words to read
Definition: spi.h:145
enum SPIStatus status
internal state of the peripheral
Definition: spi.h:174
#define SPI_SELECT_SLAVE3_PIN
Definition: board.h:529
#define IN_DMA_SECTION(var)
Definition: ram_arch.h:76
unsigned char uint8_t
Definition: types.h:14
Definition: spi.h:101
#define SPI_SELECT_SLAVE4_PIN
Definition: board.h:532
bool spi_resume(struct spi_periph *p, uint8_t slave)
spi_resume() function
Definition: spi_arch.c:637
Definition: spi.h:117
Definition: spi.h:121
#define SPI_SELECT_SLAVE5_PIN
Definition: chimera.h:554
uint8_t trans_extract_idx
Definition: spi.h:172
uint8_t slave_idx
slave id: SPI_SLAVE0 to SPI_SLAVE4
Definition: spi.h:147
static void thd_spi1(void *arg)
Definition: spi_arch.c:348
Definition: spi.h:119
volatile uint8_t * input_buf
pointer to receive buffer for DMA
Definition: spi.h:143
static float p[2][2]
Definition: spi.h:116
SPICallback before_cb
NULL or function called before the transaction.
Definition: spi.h:154
#define SPI_TRANSACTION_QUEUE_LEN
SPI transaction queue length.
Definition: spi.h:163
static void thd_spi2(void *arg)
Definition: spi_arch.c:387
#define SPI_THREAD_STACK_SIZE
Definition: spi_arch.c:48
void spi_init_slaves(void)
spi_init_slaves() function
Definition: spi_arch.c:651
void spi_slave_select(uint8_t slave)
spi_slave_select() function
Definition: spi_arch.c:538
#define SPI_SELECT_SLAVE3_PORT
Definition: board.h:528
static void gpio_set(ioportid_t port, uint16_t pin)
Set a gpio output to high level.
Definition: gpio_arch.h:98
#define SPI_SELECT_SLAVE5_PORT
Definition: chimera.h:553
struct spi_transaction * trans[SPI_TRANSACTION_QUEUE_LEN]
circular buffer holding transactions
Definition: spi.h:170
process_rx_dma_interrupt & spi1
receive transferred over DMA
Definition: spi_arch.c:967
Definition: spi.h:120
enum SPITransactionStatus status
Definition: spi.h:156
uint8_t trans_insert_idx
Definition: spi.h:171
static uint16_t spi_resolve_CR2(struct spi_transaction *t)
Resolve CR2.
Definition: spi_arch.c:229