Paparazzi UAS  v5.10_stable-5-g83a0da5-dirty
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 #if SPI_SLAVE
35 #error "ChibiOS operates only in SPI_MASTER mode"
36 #endif
37 
38 #if USE_SPI0
39 #error "ChibiOS architectures don't have SPI0"
40 #endif
41 
50 static inline ioportid_t spi_resolve_slave_port(uint8_t slave)
51 {
52  switch (slave) {
53 #if USE_SPI_SLAVE0
54  case 0:
56  break;
57 #endif // USE_SPI_SLAVE0
58 #if USE_SPI_SLAVE1
59  case 1:
61  break;
62 #endif //USE_SPI_SLAVE1
63 #if USE_SPI_SLAVE2
64  case 2:
66  break;
67 #endif //USE_SPI_SLAVE2
68 #if USE_SPI_SLAVE3
69  case 3:
71  break;
72 #endif //USE_SPI_SLAVE3
73 #if USE_SPI_SLAVE4
74  case 4:
76  break;
77 #endif //USE_SPI_SLAVE4
78 #if USE_SPI_SLAVE5
79  case 5:
81  break;
82 #endif //USE_SPI_SLAVE5
83  default:
84  return 0;
85  break;
86  }
87 }
88 
98 {
99  switch (slave) {
100 #if USE_SPI_SLAVE0
101  case 0:
102  return SPI_SELECT_SLAVE0_PIN;
103  break;
104 #endif // USE_SPI_SLAVE0
105 #if USE_SPI_SLAVE1
106  case 1:
107  return SPI_SELECT_SLAVE1_PIN;
108  break;
109 #endif //USE_SPI_SLAVE1
110 #if USE_SPI_SLAVE2
111  case 2:
112  return SPI_SELECT_SLAVE2_PIN;
113  break;
114 #endif //USE_SPI_SLAVE2
115 #if USE_SPI_SLAVE3
116  case 3:
117  return SPI_SELECT_SLAVE3_PIN;
118  break;
119 #endif //USE_SPI_SLAVE3
120 #if USE_SPI_SLAVE4
121  case 4:
122  return SPI_SELECT_SLAVE4_PIN;
123  break;
124 #endif //USE_SPI_SLAVE4
125 #if USE_SPI_SLAVE5
126  case 5:
127  return SPI_SELECT_SLAVE5_PIN;
128  break;
129 #endif //USE_SPI_SLAVE5
130  default:
131  return 0;
132  break;
133  }
134 }
135 
148 static inline uint16_t spi_resolve_CR1(struct spi_transaction *t)
149 {
150  uint16_t CR1 = 0;
151 #if defined(__STM32F10x_H) || defined(__STM32F4xx_H)
152  if (t->dss == SPIDss16bit) {
153  CR1 |= SPI_CR1_DFF;
154  }
155  if (t->bitorder == SPILSBFirst) {
156  CR1 |= SPI_CR1_LSBFIRST;
157  }
158  if (t->cpha == SPICphaEdge2) {
159  CR1 |= SPI_CR1_CPHA;
160  }
161  if (t->cpol == SPICpolIdleHigh) {
162  CR1 |= SPI_CR1_CPOL;
163  }
164 
165  switch (t->cdiv) {
166  case SPIDiv2://000
167  break;
168  case SPIDiv4://001
169  CR1 |= SPI_CR1_BR_0;
170  break;
171  case SPIDiv8://010
172  CR1 |= SPI_CR1_BR_1;
173  break;
174  case SPIDiv16://011
175  CR1 |= SPI_CR1_BR_1 | SPI_CR1_BR_0;
176  break;
177  case SPIDiv32://100
178  CR1 |= SPI_CR1_BR_2;
179  break;
180  case SPIDiv64://101
181  CR1 |= SPI_CR1_BR_2 | SPI_CR1_BR_0;
182  break;
183  case SPIDiv128://110
184  CR1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1;
185  break;
186  case SPIDiv256://111
187  CR1 |= SPI_CR1_BR;
188  break;
189  default:
190  break;
191  }
192 #endif /* STM32F10x_H || STM32F4xx_H */
193  return CR1;
194 }
195 
201 static void handle_spi_thd(struct spi_periph *p)
202 {
203  // wait for a transaction to be pushed in the queue
204  chSemWait ((semaphore_t *) p->init_struct);
205 
206  if ((p->trans_insert_idx == p->trans_extract_idx) || p->suspend) {
207  p->status = SPIIdle;
208  // no transaction pending
209  return;
210  }
211 
212  // Get next transation in queue
213  struct spi_transaction *t = p->trans[p->trans_extract_idx];
214 
215  p->status = SPIRunning;
216 
217  SPIConfig spi_cfg = {
218  NULL, // no callback
221  spi_resolve_CR1(t)
222  };
223 
224  // find max transaction length
225  static size_t t_length;
226  if (t->input_length >= t->output_length) {
227  t_length = (size_t)t->input_length;
228  } else {
229  t_length = (size_t)t->output_length;
230  }
231 
232  // Configure SPI bus with the current slave select pin
233  spiStart((SPIDriver *)p->reg_addr, &spi_cfg);
234  spiSelect((SPIDriver *)p->reg_addr);
235 
236  // Run the callback after selecting the slave
237  // FIXME warning: done in spi thread
238  if (t->before_cb != 0) {
239  t->before_cb(t);
240  }
241 
242  // Start synchronous data transfer
243  spiExchange((SPIDriver *)p->reg_addr, t_length, (uint8_t*)t->output_buf, (uint8_t*)t->input_buf);
244 
245  // Unselect the slave
246  spiUnselect((SPIDriver *)p->reg_addr);
247 
248  chSysLock();
249  // end of transaction, handle fifo
250  p->trans_extract_idx++;
252  p->trans_extract_idx = 0;
253  }
254  p->status = SPIIdle;
255  chSysUnlock();
256 
257  // Report the transaction as success
258  t->status = SPITransSuccess;
259 
260  /*
261  * Run the callback after deselecting the slave
262  * to avoid recursion and/or concurency over the bus
263  */
264  // FIXME warning: done in spi thread
265  if (t->after_cb != 0) {
266  t->after_cb(t);
267  }
268 }
269 
274 #if USE_SPI1
275 static SEMAPHORE_DECL(spi1_sem, 0);
276 static __attribute__((noreturn)) void thd_spi1(void *arg)
277 {
278  (void) arg;
279  chRegSetThreadName("spi1");
280 
281  while (TRUE) {
283  }
284 }
285 
286 static THD_WORKING_AREA(wa_thd_spi1, 1024);
287 
288 void spi1_arch_init(void)
289 {
290  spi1.reg_addr = &SPID1;
291  spi1.init_struct = &spi1_sem;
292  // Create thread
293  chThdCreateStatic(wa_thd_spi1, sizeof(wa_thd_spi1),
294  NORMALPRIO+1, thd_spi1, NULL);
295 }
296 #endif
297 
298 #if USE_SPI2
299 static SEMAPHORE_DECL(spi2_sem, 0);
300 static __attribute__((noreturn)) void thd_spi2(void *arg)
301 {
302  (void) arg;
303  chRegSetThreadName("spi2");
304 
305  while (TRUE) {
307  }
308 }
309 
310 static THD_WORKING_AREA(wa_thd_spi2, 1024);
311 
312 void spi2_arch_init(void)
313 {
314  spi2.reg_addr = &SPID2;
315  spi2.init_struct = &spi2_sem;
316  // Create thread
317  chThdCreateStatic(wa_thd_spi2, sizeof(wa_thd_spi2),
318  NORMALPRIO+1, thd_spi2, NULL);
319 }
320 #endif
321 
322 #if USE_SPI3
323 static SEMAPHORE_DECL(spi3_sem, 0);
324 static __attribute__((noreturn)) void thd_spi3(void *arg)
325 {
326  (void) arg;
327  chRegSetThreadName("spi3");
328 
329  while (TRUE) {
330  handle_spi_thd(&spi3);
331  }
332 }
333 
334 static THD_WORKING_AREA(wa_thd_spi3, 1024);
335 
336 void spi3_arch_init(void)
337 {
338  spi3.reg_addr = &SPID3;
339  spi3.init_struct = &spi3_sem;
340  // Create thread
341  chThdCreateStatic(wa_thd_spi3, sizeof(wa_thd_spi3),
342  NORMALPRIO+1, thd_spi3, NULL);
343 }
344 #endif
345 
346 
364 bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
365 {
366  // system lock
367  chSysLock();
368 
369  uint8_t idx;
370  idx = p->trans_insert_idx + 1;
371  if (idx >= SPI_TRANSACTION_QUEUE_LEN) { idx = 0; }
372  if ((idx == p->trans_extract_idx) || ((t->input_length == 0) && (t->output_length == 0))) {
373  t->status = SPITransFailed;
374  chSysUnlock();
375  return FALSE; /* queue full or input_length and output_length both 0 */
376  // TODO can't tell why it failed here if it does
377  }
378 
379  t->status = SPITransPending;
380 
381  /* put transacation in queue */
382  p->trans[p->trans_insert_idx] = t;
383  p->trans_insert_idx = idx;
384 
385  chSysUnlock();
386  chSemSignal ((semaphore_t *) p->init_struct);
387  // transaction submitted
388  return TRUE;
389 }
390 
391 
392 
398 {
399  switch (slave) {
400 #if USE_SPI_SLAVE0
401  case 0:
403  break;
404 #endif // USE_SPI_SLAVE0
405 #if USE_SPI_SLAVE1
406  case 1:
408  break;
409 #endif //USE_SPI_SLAVE1
410 #if USE_SPI_SLAVE2
411  case 2:
413  break;
414 #endif //USE_SPI_SLAVE2
415 #if USE_SPI_SLAVE3
416  case 3:
418  break;
419 #endif //USE_SPI_SLAVE3
420 #if USE_SPI_SLAVE4
421  case 4:
423  break;
424 #endif //USE_SPI_SLAVE4
425 #if USE_SPI_SLAVE5
426  case 5:
428  break;
429 #endif //USE_SPI_SLAVE5
430  default:
431  break;
432  }
433 }
434 
440 {
441  switch (slave) {
442 #if USE_SPI_SLAVE0
443  case 0:
445  break;
446 #endif // USE_SPI_SLAVE0
447 #if USE_SPI_SLAVE1
448  case 1:
450  break;
451 #endif //USE_SPI_SLAVE1
452 #if USE_SPI_SLAVE2
453  case 2:
455  break;
456 #endif //USE_SPI_SLAVE2
457 #if USE_SPI_SLAVE3
458  case 3:
460  break;
461 #endif //USE_SPI_SLAVE3
462 #if USE_SPI_SLAVE4
463  case 4:
465  break;
466 #endif //USE_SPI_SLAVE4
467 #if USE_SPI_SLAVE5
468  case 5:
470  break;
471 #endif //USE_SPI_SLAVE5
472  default:
473  break;
474  }
475 }
476 
482 bool spi_lock(struct spi_periph *p, uint8_t slave)
483 {
484  if (slave < 254 && p->suspend == 0) {
485  p->suspend = slave + 1; // 0 is reserved for unlock state
486  return TRUE;
487  }
488  return FALSE;
489 }
490 
496 bool spi_resume(struct spi_periph *p, uint8_t slave)
497 {
498  if (p->suspend == slave + 1) {
499  // restart fifo
500  p->suspend = 0;
501  return TRUE;
502  }
503  return FALSE;
504 }
505 
510 void spi_init_slaves(void)
511 {
512 #if USE_SPI_SLAVE0
515 #endif
516 
517 #if USE_SPI_SLAVE1
520 #endif
521 
522 #if USE_SPI_SLAVE2
525 #endif
526 
527 #if USE_SPI_SLAVE3
530 #endif
531 
532 #if USE_SPI_SLAVE4
535 #endif
536 
537 #if USE_SPI_SLAVE5
540 #endif
541 }
542 
unsigned short uint16_t
Definition: types.h:16
enum SPIClockPolarity cpol
clock polarity control
Definition: spi.h:149
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:97
enum SPIClockDiv cdiv
prescaler of main clock to use as SPI clock
Definition: spi.h:153
uint16_t output_length
number of data words to write
Definition: spi.h:146
#define SPI_SELECT_SLAVE4_PORT
Definition: board.h:982
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:103
void * reg_addr
Definition: spi.h:177
void spi1_arch_init(void)
Architecture dependent SPI1 initialization.
Definition: spi_arch.c:288
static uint16_t spi_resolve_CR1(struct spi_transaction *t)
Resolve CR1.
Definition: spi_arch.c:148
CPHA = 1.
Definition: spi.h:69
Some architecture independent helper functions for GPIOs.
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:364
CPOL = 1.
Definition: spi.h:78
static void handle_spi_thd(struct spi_periph *p)
main thread function
Definition: spi_arch.c:201
enum SPIBitOrder bitorder
MSB/LSB order.
Definition: spi.h:152
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_SLAVE5_PIN
Definition: elle0_common.h:244
#define SPI_SELECT_SLAVE1_PORT
Definition: board.h:973
Definition: spi.h:114
enum SPIClockPhase cpha
clock phase control
Definition: spi.h:150
bool spi_lock(struct spi_periph *p, uint8_t slave)
spi_lock() function
Definition: spi_arch.c:482
#define TRUE
Definition: std.h:4
SPI peripheral structure.
Definition: spi.h:168
#define SPI_SELECT_SLAVE0_PIN
Definition: board.h:971
void spi_slave_unselect(uint8_t slave)
spi_slave_unselect() function
Definition: spi_arch.c:439
#define SPI_SELECT_SLAVE2_PORT
Definition: board.h:976
SPICallback after_cb
NULL or function called after the transaction.
Definition: spi.h:155
#define SPI_SELECT_SLAVE0_PORT
Definition: board.h:970
void spi2_arch_init(void)
Architecture dependent SPI2 initialization.
Definition: spi_arch.c:312
#define SPI_SELECT_SLAVE1_PIN
Definition: board.h:974
static ioportid_t spi_resolve_slave_port(uint8_t slave)
Resolve slave port.
Definition: spi_arch.c:50
#define SPI_SELECT_SLAVE2_PIN
Definition: board.h:977
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:980
unsigned char uint8_t
Definition: types.h:14
Definition: spi.h:101
#define SPI_SELECT_SLAVE4_PIN
Definition: board.h:983
bool spi_resume(struct spi_periph *p, uint8_t slave)
spi_resume() function
Definition: spi_arch.c:496
Definition: spi.h:117
Definition: spi.h:121
uint8_t trans_extract_idx
Definition: spi.h:172
enum SPIDataSizeSelect dss
data transfer word size
Definition: spi.h:151
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:276
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:300
void spi_init_slaves(void)
spi_init_slaves() function
Definition: spi_arch.c:510
void spi_slave_select(uint8_t slave)
spi_slave_select() function
Definition: spi_arch.c:397
#define SPI_SELECT_SLAVE5_PORT
Definition: elle0_common.h:243
#define SPI_SELECT_SLAVE3_PORT
Definition: board.h:979
static void gpio_set(ioportid_t port, uint16_t pin)
Set a gpio output to high level.
Definition: gpio_arch.h:93
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
static THD_WORKING_AREA(wa_thd_spi1, 1024)
enum SPITransactionStatus status
Definition: spi.h:156
uint8_t trans_insert_idx
Definition: spi.h:171