Paparazzi UAS  v5.14.0_stable-0-g3f680d1
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 
34 #include <string.h>
35 #include "mcu_periph/ram_arch.h"
36 
37 #if SPI_SLAVE
38 #error "ChibiOS operates only in SPI_MASTER mode"
39 #endif
40 
41 #if USE_SPI0
42 #error "ChibiOS architectures don't have SPI0"
43 #endif
44 
45 // private SPI init structure
46 struct spi_init {
47  semaphore_t *sem;
48 #ifdef STM32F7
49  uint8_t *dma_buf_out;
50  uint8_t *dma_buf_in;
51 #endif
52 };
53 #define SPI_DMA_BUF_LEN 512 // it has to be big enough
54 
63 static inline ioportid_t spi_resolve_slave_port(uint8_t slave)
64 {
65  switch (slave) {
66 #if USE_SPI_SLAVE0
67  case 0:
69  break;
70 #endif // USE_SPI_SLAVE0
71 #if USE_SPI_SLAVE1
72  case 1:
74  break;
75 #endif //USE_SPI_SLAVE1
76 #if USE_SPI_SLAVE2
77  case 2:
79  break;
80 #endif //USE_SPI_SLAVE2
81 #if USE_SPI_SLAVE3
82  case 3:
84  break;
85 #endif //USE_SPI_SLAVE3
86 #if USE_SPI_SLAVE4
87  case 4:
89  break;
90 #endif //USE_SPI_SLAVE4
91 #if USE_SPI_SLAVE5
92  case 5:
94  break;
95 #endif //USE_SPI_SLAVE5
96  default:
97  return 0;
98  break;
99  }
100 }
101 
111 {
112  switch (slave) {
113 #if USE_SPI_SLAVE0
114  case 0:
115  return SPI_SELECT_SLAVE0_PIN;
116  break;
117 #endif // USE_SPI_SLAVE0
118 #if USE_SPI_SLAVE1
119  case 1:
120  return SPI_SELECT_SLAVE1_PIN;
121  break;
122 #endif //USE_SPI_SLAVE1
123 #if USE_SPI_SLAVE2
124  case 2:
125  return SPI_SELECT_SLAVE2_PIN;
126  break;
127 #endif //USE_SPI_SLAVE2
128 #if USE_SPI_SLAVE3
129  case 3:
130  return SPI_SELECT_SLAVE3_PIN;
131  break;
132 #endif //USE_SPI_SLAVE3
133 #if USE_SPI_SLAVE4
134  case 4:
135  return SPI_SELECT_SLAVE4_PIN;
136  break;
137 #endif //USE_SPI_SLAVE4
138 #if USE_SPI_SLAVE5
139  case 5:
140  return SPI_SELECT_SLAVE5_PIN;
141  break;
142 #endif //USE_SPI_SLAVE5
143  default:
144  return 0;
145  break;
146  }
147 }
148 
161 static inline uint16_t spi_resolve_CR1(struct spi_transaction *t __attribute__((unused)))
162 {
163  uint16_t CR1 = 0;
164 #if defined(STM32F1) || defined(STM32F4) || defined(STM32F7)
165  if (t->dss == SPIDss16bit) {
166  CR1 |= SPI_CR1_DFF;
167  }
168  if (t->bitorder == SPILSBFirst) {
169  CR1 |= SPI_CR1_LSBFIRST;
170  }
171  if (t->cpha == SPICphaEdge2) {
172  CR1 |= SPI_CR1_CPHA;
173  }
174  if (t->cpol == SPICpolIdleHigh) {
175  CR1 |= SPI_CR1_CPOL;
176  }
177 
178  switch (t->cdiv) {
179  case SPIDiv2://000
180  break;
181  case SPIDiv4://001
182  CR1 |= SPI_CR1_BR_0;
183  break;
184  case SPIDiv8://010
185  CR1 |= SPI_CR1_BR_1;
186  break;
187  case SPIDiv16://011
188  CR1 |= SPI_CR1_BR_1 | SPI_CR1_BR_0;
189  break;
190  case SPIDiv32://100
191  CR1 |= SPI_CR1_BR_2;
192  break;
193  case SPIDiv64://101
194  CR1 |= SPI_CR1_BR_2 | SPI_CR1_BR_0;
195  break;
196  case SPIDiv128://110
197  CR1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1;
198  break;
199  case SPIDiv256://111
200  CR1 |= SPI_CR1_BR;
201  break;
202  default:
203  break;
204  }
205 #endif /* STM32F1 || STM32F4 || STM32F7 */
206  return CR1;
207 }
208 
221 static inline uint16_t spi_resolve_CR2(struct spi_transaction *t __attribute__((unused)))
222 {
223  uint16_t CR2 = 0;
224 #if defined(STM32F7)
225  if (t->dss == SPIDss16bit) {
226  CR2 |= SPI_CR2_DS_0 | SPI_CR2_DS_1 | SPI_CR2_DS_2 | SPI_CR2_DS_3;
227  } else {
228  CR2 |= SPI_CR2_DS_0 | SPI_CR2_DS_1 | SPI_CR2_DS_2;
229  }
230 #endif /* STM32F7 */
231  return CR2;
232 }
233 
239 static void handle_spi_thd(struct spi_periph *p)
240 {
241  struct spi_init *i = (struct spi_init *) p->init_struct;
242 
243  // wait for a transaction to be pushed in the queue
244  chSemWait(i->sem);
245 
246  if ((p->trans_insert_idx == p->trans_extract_idx) || p->suspend) {
247  p->status = SPIIdle;
248  // no transaction pending
249  return;
250  }
251 
252  // Get next transation in queue
253  struct spi_transaction *t = p->trans[p->trans_extract_idx];
254 
255  p->status = SPIRunning;
256 
257  SPIConfig spi_cfg = {
258  false, // no circular buffer
259  NULL, // no callback
262  spi_resolve_CR1(t),
263  spi_resolve_CR2(t)
264  };
265 
266  // find max transaction length
267  static size_t t_length;
268  if (t->input_length >= t->output_length) {
269  t_length = (size_t)t->input_length;
270  } else {
271  t_length = (size_t)t->output_length;
272  }
273 
274  // Configure SPI bus with the current slave select pin
275  spiStart((SPIDriver *)p->reg_addr, &spi_cfg);
276  spiSelect((SPIDriver *)p->reg_addr);
277 
278  // Run the callback after selecting the slave
279  // FIXME warning: done in spi thread
280  if (t->before_cb != 0) {
281  t->before_cb(t);
282  }
283 
284  // Start synchronous data transfer
285 #if defined STM32F7
286  // we do stupid mem copy because F7 needs a special RAM for DMA operation
287  memcpy(i->dma_buf_out, (void *)t->output_buf, (size_t)t->output_length);
288  spiExchange((SPIDriver *)p->reg_addr, t_length, i->dma_buf_out, i->dma_buf_in);
289  memcpy((void *)t->input_buf, i->dma_buf_in, (size_t)t->input_length);
290 #else
291  spiExchange((SPIDriver *)p->reg_addr, t_length, (uint8_t *)t->output_buf, (uint8_t *)t->input_buf);
292 #endif
293 
294  // Unselect the slave
295  spiUnselect((SPIDriver *)p->reg_addr);
296 
297  chSysLock();
298  // end of transaction, handle fifo
299  p->trans_extract_idx++;
301  p->trans_extract_idx = 0;
302  }
303  p->status = SPIIdle;
304  chSysUnlock();
305 
306  // Report the transaction as success
307  t->status = SPITransSuccess;
308 
309  /*
310  * Run the callback after deselecting the slave
311  * to avoid recursion and/or concurency over the bus
312  */
313  // FIXME warning: done in spi thread
314  if (t->after_cb != 0) {
315  t->after_cb(t);
316  }
317 }
318 
323 #if USE_SPI1
324 static SEMAPHORE_DECL(spi1_sem, 0);
325 #if defined STM32F7
326 // We need a special buffer for DMA operations
327 static IN_DMA_SECTION(uint8_t spi1_dma_buf_out[SPI_DMA_BUF_LEN]);
328 static IN_DMA_SECTION(uint8_t spi1_dma_buf_in[SPI_DMA_BUF_LEN]);
329 static struct spi_init spi1_init_s = {
330  .sem = &spi1_sem,
331  .dma_buf_out = spi1_dma_buf_out,
332  .dma_buf_in = spi1_dma_buf_in
333 };
334 #else
335 static struct spi_init spi1_init_s = {
336  .sem = &spi1_sem,
337 };
338 #endif
339 
340 static __attribute__((noreturn)) void thd_spi1(void *arg)
341 {
342  (void) arg;
343  chRegSetThreadName("spi1");
344 
345  while (TRUE) {
347  }
348 }
349 
350 static THD_WORKING_AREA(wa_thd_spi1, 256);
351 
352 void spi1_arch_init(void)
353 {
354  spi1.reg_addr = &SPID1;
355  spi1.init_struct = &spi1_init_s;
356  // Create thread
357  chThdCreateStatic(wa_thd_spi1, sizeof(wa_thd_spi1),
358  NORMALPRIO + 1, thd_spi1, NULL);
359 }
360 #endif
361 
362 #if USE_SPI2
363 static SEMAPHORE_DECL(spi2_sem, 0);
364 #if defined STM32F7
365 // We need a special buffer for DMA operations
366 static IN_DMA_SECTION(uint8_t spi2_dma_buf_out[SPI_DMA_BUF_LEN]);
367 static IN_DMA_SECTION(uint8_t spi2_dma_buf_in[SPI_DMA_BUF_LEN]);
368 static struct spi_init spi2_init_s = {
369  .sem = &spi2_sem,
370  .dma_buf_out = spi2_dma_buf_out,
371  .dma_buf_in = spi2_dma_buf_in
372 };
373 #else
374 static struct spi_init spi2_init_s = {
375  .sem = &spi2_sem,
376 };
377 #endif
378 
379 static __attribute__((noreturn)) void thd_spi2(void *arg)
380 {
381  (void) arg;
382  chRegSetThreadName("spi2");
383 
384  while (TRUE) {
386  }
387 }
388 
389 static THD_WORKING_AREA(wa_thd_spi2, 256);
390 
391 void spi2_arch_init(void)
392 {
393  spi2.reg_addr = &SPID2;
394  spi2.init_struct = &spi2_init_s;
395  // Create thread
396  chThdCreateStatic(wa_thd_spi2, sizeof(wa_thd_spi2),
397  NORMALPRIO + 1, thd_spi2, NULL);
398 }
399 #endif
400 
401 #if USE_SPI3
402 static SEMAPHORE_DECL(spi3_sem, 0);
403 #if defined STM32F7
404 // We need a special buffer for DMA operations
405 static IN_DMA_SECTION(uint8_t spi3_dma_buf_out[SPI_DMA_BUF_LEN]);
406 static IN_DMA_SECTION(uint8_t spi3_dma_buf_in[SPI_DMA_BUF_LEN]);
407 static struct spi_init spi3_init_s = {
408  .sem = &spi3_sem,
409  .dma_buf_out = spi3_dma_buf_out,
410  .dma_buf_in = spi3_dma_buf_in
411 };
412 #else
413 static struct spi_init spi3_init_s = {
414  .sem = &spi3_sem,
415 };
416 #endif
417 
418 static __attribute__((noreturn)) void thd_spi3(void *arg)
419 {
420  (void) arg;
421  chRegSetThreadName("spi3");
422 
423  while (TRUE) {
424  handle_spi_thd(&spi3);
425  }
426 }
427 
428 static THD_WORKING_AREA(wa_thd_spi3, 1024);
429 
430 void spi3_arch_init(void)
431 {
432  spi3.reg_addr = &SPID3;
433  spi3.init_struct = &spi3_init_s;
434  // Create thread
435  chThdCreateStatic(wa_thd_spi3, sizeof(wa_thd_spi3),
436  NORMALPRIO + 1, thd_spi3, NULL);
437 }
438 #endif
439 
440 
458 bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
459 {
460  // system lock
461  chSysLock();
462 
463  uint8_t idx;
464  idx = p->trans_insert_idx + 1;
465  if (idx >= SPI_TRANSACTION_QUEUE_LEN) { idx = 0; }
466  if ((idx == p->trans_extract_idx) || ((t->input_length == 0) && (t->output_length == 0))) {
467  t->status = SPITransFailed;
468  chSysUnlock();
469  return FALSE; /* queue full or input_length and output_length both 0 */
470  // TODO can't tell why it failed here if it does
471  }
472 
473  t->status = SPITransPending;
474 
475  /* put transacation in queue */
476  p->trans[p->trans_insert_idx] = t;
477  p->trans_insert_idx = idx;
478 
479  chSysUnlock();
480  chSemSignal(((struct spi_init *)p->init_struct)->sem);
481  // transaction submitted
482  return TRUE;
483 }
484 
485 
486 
492 {
493  switch (slave) {
494 #if USE_SPI_SLAVE0
495  case 0:
497  break;
498 #endif // USE_SPI_SLAVE0
499 #if USE_SPI_SLAVE1
500  case 1:
502  break;
503 #endif //USE_SPI_SLAVE1
504 #if USE_SPI_SLAVE2
505  case 2:
507  break;
508 #endif //USE_SPI_SLAVE2
509 #if USE_SPI_SLAVE3
510  case 3:
512  break;
513 #endif //USE_SPI_SLAVE3
514 #if USE_SPI_SLAVE4
515  case 4:
517  break;
518 #endif //USE_SPI_SLAVE4
519 #if USE_SPI_SLAVE5
520  case 5:
522  break;
523 #endif //USE_SPI_SLAVE5
524  default:
525  break;
526  }
527 }
528 
534 {
535  switch (slave) {
536 #if USE_SPI_SLAVE0
537  case 0:
539  break;
540 #endif // USE_SPI_SLAVE0
541 #if USE_SPI_SLAVE1
542  case 1:
544  break;
545 #endif //USE_SPI_SLAVE1
546 #if USE_SPI_SLAVE2
547  case 2:
549  break;
550 #endif //USE_SPI_SLAVE2
551 #if USE_SPI_SLAVE3
552  case 3:
554  break;
555 #endif //USE_SPI_SLAVE3
556 #if USE_SPI_SLAVE4
557  case 4:
559  break;
560 #endif //USE_SPI_SLAVE4
561 #if USE_SPI_SLAVE5
562  case 5:
564  break;
565 #endif //USE_SPI_SLAVE5
566  default:
567  break;
568  }
569 }
570 
576 bool spi_lock(struct spi_periph *p, uint8_t slave)
577 {
578  if (slave < 254 && p->suspend == 0) {
579  p->suspend = slave + 1; // 0 is reserved for unlock state
580  return TRUE;
581  }
582  return FALSE;
583 }
584 
590 bool spi_resume(struct spi_periph *p, uint8_t slave)
591 {
592  if (p->suspend == slave + 1) {
593  // restart fifo
594  p->suspend = 0;
595  return TRUE;
596  }
597  return FALSE;
598 }
599 
604 void spi_init_slaves(void)
605 {
606 #if USE_SPI_SLAVE0
609 #endif
610 
611 #if USE_SPI_SLAVE1
614 #endif
615 
616 #if USE_SPI_SLAVE2
619 #endif
620 
621 #if USE_SPI_SLAVE3
624 #endif
625 
626 #if USE_SPI_SLAVE4
629 #endif
630 
631 #if USE_SPI_SLAVE5
634 #endif
635 }
636 
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:110
uint16_t output_length
number of data words to write
Definition: spi.h:146
#define SPI_SELECT_SLAVE4_PORT
Definition: board.h:456
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:352
static uint16_t spi_resolve_CR1(struct spi_transaction *t)
Resolve CR1.
Definition: spi_arch.c:161
CPHA = 1.
Definition: spi.h:69
Some architecture independent helper functions for GPIOs.
semaphore_t * sem
Definition: spi_arch.c:47
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:458
static THD_WORKING_AREA(wa_thd_spi1, 256)
CPOL = 1.
Definition: spi.h:78
static void handle_spi_thd(struct spi_periph *p)
main thread function
Definition: spi_arch.c:239
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:447
Definition: spi.h:114
static struct spi_init spi1_init_s
Definition: spi_arch.c:335
static struct spi_init spi2_init_s
Definition: spi_arch.c:374
bool spi_lock(struct spi_periph *p, uint8_t slave)
spi_lock() function
Definition: spi_arch.c:576
#define TRUE
Definition: std.h:4
SPI peripheral structure.
Definition: spi.h:168
#define SPI_SELECT_SLAVE0_PIN
Definition: board.h:445
void spi_slave_unselect(uint8_t slave)
spi_slave_unselect() function
Definition: spi_arch.c:533
#define SPI_SELECT_SLAVE2_PORT
Definition: board.h:450
SPICallback after_cb
NULL or function called after the transaction.
Definition: spi.h:155
#define SPI_DMA_BUF_LEN
Definition: spi_arch.c:53
#define SPI_SELECT_SLAVE0_PORT
Definition: board.h:444
void spi2_arch_init(void)
Architecture dependent SPI2 initialization.
Definition: spi_arch.c:391
#define SPI_SELECT_SLAVE1_PIN
Definition: board.h:448
static ioportid_t spi_resolve_slave_port(uint8_t slave)
Resolve slave port.
Definition: spi_arch.c:63
#define SPI_SELECT_SLAVE2_PIN
Definition: board.h:451
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:454
#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:457
bool spi_resume(struct spi_periph *p, uint8_t slave)
spi_resume() function
Definition: spi_arch.c:590
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:340
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:379
void spi_init_slaves(void)
spi_init_slaves() function
Definition: spi_arch.c:604
void spi_slave_select(uint8_t slave)
spi_slave_select() function
Definition: spi_arch.c:491
#define SPI_SELECT_SLAVE3_PORT
Definition: board.h:453
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:221