Paparazzi UAS  v5.15_devel-229-g3fb4ee4
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  // Select the slave after reconfiguration of the peripheral
285  if (t->select == SPISelectUnselect || t->select == SPISelect) {
286  spiSelect((SPIDriver *)p->reg_addr);
287  }
288 
289  // Run the callback after selecting the slave
290  // FIXME warning: done in spi thread
291  if (t->before_cb != 0) {
292  t->before_cb(t);
293  }
294 
295  // Start synchronous data transfer
296 #if defined STM32F7
297  // we do stupid mem copy because F7 needs a special RAM for DMA operation
298  memcpy(i->dma_buf_out, (void *)t->output_buf, (size_t)t->output_length);
299  spiExchange((SPIDriver *)p->reg_addr, t_length, i->dma_buf_out, i->dma_buf_in);
300  memcpy((void *)t->input_buf, i->dma_buf_in, (size_t)t->input_length);
301 #else
302  spiExchange((SPIDriver *)p->reg_addr, t_length, (uint8_t *)t->output_buf, (uint8_t *)t->input_buf);
303 #endif
304 
305  // Unselect the slave
306  if (t->select == SPISelectUnselect || t->select == SPIUnselect) {
307  spiUnselect((SPIDriver *)p->reg_addr);
308  }
309 
310  chSysLock();
311  // end of transaction, handle fifo
312  p->trans_extract_idx++;
314  p->trans_extract_idx = 0;
315  }
316  p->status = SPIIdle;
317  chSysUnlock();
318 
319  // Report the transaction as success
320  t->status = SPITransSuccess;
321 
322  /*
323  * Run the callback after deselecting the slave
324  * to avoid recursion and/or concurency over the bus
325  */
326  // FIXME warning: done in spi thread
327  if (t->after_cb != 0) {
328  t->after_cb(t);
329  }
330 
331 }
332 
337 #if USE_SPI1
338 static SEMAPHORE_DECL(spi1_sem, 0);
339 #if defined STM32F7
340 // We need a special buffer for DMA operations
341 static IN_DMA_SECTION(uint8_t spi1_dma_buf_out[SPI_DMA_BUF_LEN]);
342 static IN_DMA_SECTION(uint8_t spi1_dma_buf_in[SPI_DMA_BUF_LEN]);
343 static struct spi_init spi1_init_s = {
344  .sem = &spi1_sem,
345  .dma_buf_out = spi1_dma_buf_out,
346  .dma_buf_in = spi1_dma_buf_in
347 };
348 #else
349 static struct spi_init spi1_init_s = {
350  .sem = &spi1_sem,
351 };
352 #endif
353 
354 static __attribute__((noreturn)) void thd_spi1(void *arg)
355 {
356  (void) arg;
357  chRegSetThreadName("spi1");
358 
359  while (TRUE) {
361  }
362 }
363 
364 static THD_WORKING_AREA(wa_thd_spi1, SPI_THREAD_STACK_SIZE);
365 
366 void spi1_arch_init(void)
367 {
368  spi1.reg_addr = &SPID1;
369  spi1.init_struct = &spi1_init_s;
370  // Create thread
371  chThdCreateStatic(wa_thd_spi1, sizeof(wa_thd_spi1),
372  NORMALPRIO + 1, thd_spi1, NULL);
373 }
374 #endif
375 
376 #if USE_SPI2
377 static SEMAPHORE_DECL(spi2_sem, 0);
378 #if defined STM32F7
379 // We need a special buffer for DMA operations
380 static IN_DMA_SECTION(uint8_t spi2_dma_buf_out[SPI_DMA_BUF_LEN]);
381 static IN_DMA_SECTION(uint8_t spi2_dma_buf_in[SPI_DMA_BUF_LEN]);
382 static struct spi_init spi2_init_s = {
383  .sem = &spi2_sem,
384  .dma_buf_out = spi2_dma_buf_out,
385  .dma_buf_in = spi2_dma_buf_in
386 };
387 #else
388 static struct spi_init spi2_init_s = {
389  .sem = &spi2_sem,
390 };
391 #endif
392 
393 static __attribute__((noreturn)) void thd_spi2(void *arg)
394 {
395  (void) arg;
396  chRegSetThreadName("spi2");
397 
398  while (TRUE) {
400  }
401 }
402 
403 static THD_WORKING_AREA(wa_thd_spi2, SPI_THREAD_STACK_SIZE);
404 
405 void spi2_arch_init(void)
406 {
407  spi2.reg_addr = &SPID2;
408  spi2.init_struct = &spi2_init_s;
409  // Create thread
410  chThdCreateStatic(wa_thd_spi2, sizeof(wa_thd_spi2),
411  NORMALPRIO + 1, thd_spi2, NULL);
412 }
413 #endif
414 
415 #if USE_SPI3
416 static SEMAPHORE_DECL(spi3_sem, 0);
417 #if defined STM32F7
418 // We need a special buffer for DMA operations
419 static IN_DMA_SECTION(uint8_t spi3_dma_buf_out[SPI_DMA_BUF_LEN]);
420 static IN_DMA_SECTION(uint8_t spi3_dma_buf_in[SPI_DMA_BUF_LEN]);
421 static struct spi_init spi3_init_s = {
422  .sem = &spi3_sem,
423  .dma_buf_out = spi3_dma_buf_out,
424  .dma_buf_in = spi3_dma_buf_in
425 };
426 #else
427 static struct spi_init spi3_init_s = {
428  .sem = &spi3_sem,
429 };
430 #endif
431 
432 static __attribute__((noreturn)) void thd_spi3(void *arg)
433 {
434  (void) arg;
435  chRegSetThreadName("spi3");
436 
437  while (TRUE) {
438  handle_spi_thd(&spi3);
439  }
440 }
441 
442 static THD_WORKING_AREA(wa_thd_spi3, SPI_THREAD_STACK_SIZE);
443 
444 void spi3_arch_init(void)
445 {
446  spi3.reg_addr = &SPID3;
447  spi3.init_struct = &spi3_init_s;
448  // Create thread
449  chThdCreateStatic(wa_thd_spi3, sizeof(wa_thd_spi3),
450  NORMALPRIO + 1, thd_spi3, NULL);
451 }
452 #endif
453 
454 #if USE_SPI4
455 static SEMAPHORE_DECL(spi4_sem, 0);
456 #if defined STM32F7
457 // We need a special buffer for DMA operations
458 static IN_DMA_SECTION(uint8_t spi4_dma_buf_out[SPI_DMA_BUF_LEN]);
459 static IN_DMA_SECTION(uint8_t spi4_dma_buf_in[SPI_DMA_BUF_LEN]);
460 static struct spi_init spi4_init_s = {
461  .sem = &spi4_sem,
462  .dma_buf_out = spi4_dma_buf_out,
463  .dma_buf_in = spi4_dma_buf_in
464 };
465 #else
466 static struct spi_init spi4_init_s = {
467  .sem = &spi4_sem,
468 };
469 #endif
470 
471 static __attribute__((noreturn)) void thd_spi4(void *arg)
472 {
473  (void) arg;
474  chRegSetThreadName("spi4");
475 
476  while (TRUE) {
477  handle_spi_thd(&spi4);
478  }
479 }
480 
481 static THD_WORKING_AREA(wa_thd_spi4, 256);
482 
483 void spi4_arch_init(void)
484 {
485  spi4.reg_addr = &SPID4;
486  spi4.init_struct = &spi4_init_s;
487  // Create thread
488  chThdCreateStatic(wa_thd_spi4, sizeof(wa_thd_spi4),
489  NORMALPRIO + 1, thd_spi4, NULL);
490 }
491 #endif
492 
493 
511 bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
512 {
513  // system lock
514  chSysLock();
515 
516  uint8_t idx;
517  idx = p->trans_insert_idx + 1;
518  if (idx >= SPI_TRANSACTION_QUEUE_LEN) { idx = 0; }
519  if ((idx == p->trans_extract_idx) || ((t->input_length == 0) && (t->output_length == 0))) {
520  t->status = SPITransFailed;
521  chSysUnlock();
522  return FALSE; /* queue full or input_length and output_length both 0 */
523  // TODO can't tell why it failed here if it does
524  }
525 
526  t->status = SPITransPending;
527 
528  /* put transacation in queue */
529  p->trans[p->trans_insert_idx] = t;
530  p->trans_insert_idx = idx;
531 
532  chSysUnlock();
533  chSemSignal(((struct spi_init *)p->init_struct)->sem);
534  // transaction submitted
535  return TRUE;
536 }
537 
538 
539 
545 {
546  switch (slave) {
547 #if USE_SPI_SLAVE0
548  case 0:
550  break;
551 #endif // USE_SPI_SLAVE0
552 #if USE_SPI_SLAVE1
553  case 1:
555  break;
556 #endif //USE_SPI_SLAVE1
557 #if USE_SPI_SLAVE2
558  case 2:
560  break;
561 #endif //USE_SPI_SLAVE2
562 #if USE_SPI_SLAVE3
563  case 3:
565  break;
566 #endif //USE_SPI_SLAVE3
567 #if USE_SPI_SLAVE4
568  case 4:
570  break;
571 #endif //USE_SPI_SLAVE4
572 #if USE_SPI_SLAVE5
573  case 5:
575  break;
576 #endif //USE_SPI_SLAVE5
577  default:
578  break;
579  }
580 }
581 
587 {
588  switch (slave) {
589 #if USE_SPI_SLAVE0
590  case 0:
592  break;
593 #endif // USE_SPI_SLAVE0
594 #if USE_SPI_SLAVE1
595  case 1:
597  break;
598 #endif //USE_SPI_SLAVE1
599 #if USE_SPI_SLAVE2
600  case 2:
602  break;
603 #endif //USE_SPI_SLAVE2
604 #if USE_SPI_SLAVE3
605  case 3:
607  break;
608 #endif //USE_SPI_SLAVE3
609 #if USE_SPI_SLAVE4
610  case 4:
612  break;
613 #endif //USE_SPI_SLAVE4
614 #if USE_SPI_SLAVE5
615  case 5:
617  break;
618 #endif //USE_SPI_SLAVE5
619  default:
620  break;
621  }
622 }
623 
629 bool spi_lock(struct spi_periph *p, uint8_t slave)
630 {
631  if (slave < 254 && p->suspend == 0) {
632  p->suspend = slave + 1; // 0 is reserved for unlock state
633  return TRUE;
634  }
635  return FALSE;
636 }
637 
643 bool spi_resume(struct spi_periph *p, uint8_t slave)
644 {
645  if (p->suspend == slave + 1) {
646  // restart fifo
647  p->suspend = 0;
648  return TRUE;
649  }
650  return FALSE;
651 }
652 
657 void spi_init_slaves(void)
658 {
659 #if USE_SPI_SLAVE0
662 #endif
663 
664 #if USE_SPI_SLAVE1
667 #endif
668 
669 #if USE_SPI_SLAVE2
672 #endif
673 
674 #if USE_SPI_SLAVE3
677 #endif
678 
679 #if USE_SPI_SLAVE4
682 #endif
683 
684 #if USE_SPI_SLAVE5
687 #endif
688 }
689 
unsigned short uint16_t
Definition: types.h:16
Specific RAM section for DMA usage on F7.
static uint32_t idx
Definition: spi.h:124
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:152
#define SPI_SELECT_SLAVE4_PORT
Definition: board.h:534
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
slave is selected before transaction but not unselected
Definition: spi.h:64
void * reg_addr
Definition: spi.h:183
void spi1_arch_init(void)
Architecture dependent SPI1 initialization.
Definition: spi_arch.c:366
slave is not selected but unselected after transaction
Definition: spi.h:65
static uint16_t spi_resolve_CR1(struct spi_transaction *t)
Resolve CR1.
Definition: spi_arch.c:167
CPHA = 1.
Definition: spi.h:75
Some architecture independent helper functions for GPIOs.
semaphore_t * sem
Definition: spi_arch.c:53
Definition: spi.h:121
SPI transaction structure.
Definition: spi.h:148
bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
Submit SPI transaction.
Definition: spi_arch.c:511
CPOL = 1.
Definition: spi.h:84
static void handle_spi_thd(struct spi_periph *p)
main thread function
Definition: spi_arch.c:247
void * init_struct
Definition: spi.h:184
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:150
volatile uint8_t suspend
control for stop/resume of the fifo
Definition: spi.h:187
enum SPISlaveSelect select
slave selection behavior
Definition: spi.h:154
#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:525
Definition: spi.h:120
static struct spi_init spi1_init_s
Definition: spi_arch.c:349
static struct spi_init spi2_init_s
Definition: spi_arch.c:388
bool spi_lock(struct spi_periph *p, uint8_t slave)
spi_lock() function
Definition: spi_arch.c:629
#define TRUE
Definition: std.h:4
SPI peripheral structure.
Definition: spi.h:174
#define SPI_SELECT_SLAVE0_PIN
Definition: board.h:523
void spi_slave_unselect(uint8_t slave)
spi_slave_unselect() function
Definition: spi_arch.c:586
#define SPI_SELECT_SLAVE2_PORT
Definition: board.h:528
SPICallback after_cb
NULL or function called after the transaction.
Definition: spi.h:161
#define SPI_DMA_BUF_LEN
Definition: spi_arch.c:59
#define SPI_SELECT_SLAVE0_PORT
Definition: board.h:522
void spi2_arch_init(void)
Architecture dependent SPI2 initialization.
Definition: spi_arch.c:405
#define SPI_SELECT_SLAVE1_PIN
Definition: board.h:526
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:529
static THD_WORKING_AREA(wa_thd_spi1, SPI_THREAD_STACK_SIZE)
uint16_t input_length
number of data words to read
Definition: spi.h:151
enum SPIStatus status
internal state of the peripheral
Definition: spi.h:180
#define SPI_SELECT_SLAVE3_PIN
Definition: board.h:532
#define IN_DMA_SECTION(var)
Definition: ram_arch.h:76
unsigned char uint8_t
Definition: types.h:14
Definition: spi.h:107
#define SPI_SELECT_SLAVE4_PIN
Definition: board.h:535
bool spi_resume(struct spi_periph *p, uint8_t slave)
spi_resume() function
Definition: spi_arch.c:643
Definition: spi.h:123
Definition: spi.h:127
slave is selected before transaction and unselected after
Definition: spi.h:63
#define SPI_SELECT_SLAVE5_PIN
Definition: chimera.h:554
uint8_t trans_extract_idx
Definition: spi.h:178
uint8_t slave_idx
slave id: SPI_SLAVE0 to SPI_SLAVE4
Definition: spi.h:153
static void thd_spi1(void *arg)
Definition: spi_arch.c:354
Definition: spi.h:125
volatile uint8_t * input_buf
pointer to receive buffer for DMA
Definition: spi.h:149
static float p[2][2]
Definition: spi.h:122
SPICallback before_cb
NULL or function called before the transaction.
Definition: spi.h:160
#define SPI_TRANSACTION_QUEUE_LEN
SPI transaction queue length.
Definition: spi.h:169
static void thd_spi2(void *arg)
Definition: spi_arch.c:393
#define SPI_THREAD_STACK_SIZE
Definition: spi_arch.c:48
void spi_init_slaves(void)
spi_init_slaves() function
Definition: spi_arch.c:657
void spi_slave_select(uint8_t slave)
spi_slave_select() function
Definition: spi_arch.c:544
#define SPI_SELECT_SLAVE3_PORT
Definition: board.h:531
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:176
process_rx_dma_interrupt & spi1
receive transferred over DMA
Definition: spi_arch.c:967
Definition: spi.h:126
enum SPITransactionStatus status
Definition: spi.h:162
uint8_t trans_insert_idx
Definition: spi.h:177
static uint16_t spi_resolve_CR2(struct spi_transaction *t)
Resolve CR2.
Definition: spi_arch.c:229