2 * Copyright © 2012 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 struct ao_spi_stm_info {
22 uint8_t miso_dma_index;
23 uint8_t mosi_dma_index;
24 struct stm_spi *stm_spi;
27 static uint8_t ao_spi_mutex[STM_NUM_SPI];
28 static uint8_t ao_spi_index[STM_NUM_SPI];
30 static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
32 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX),
33 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX),
37 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX),
38 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX),
43 static uint8_t spi_dev_null;
52 static uint8_t spi_task_index;
55 validate_spi(struct stm_spi *stm_spi, int which, uint16_t len)
57 uint32_t sr = stm_spi->sr;
59 if (stm_spi != &stm_spi2)
61 spi_tasks[spi_task_index].task = ao_cur_task ? ao_cur_task->task_id : 0;
62 spi_tasks[spi_task_index].which = which;
63 spi_tasks[spi_task_index].tick = ao_time();
64 spi_tasks[spi_task_index].len = len;
65 spi_task_index = (spi_task_index + 1) & (63);
66 if (sr & (1 << STM_SPI_SR_FRE))
68 if (sr & (1 << STM_SPI_SR_BSY))
70 if (sr & (1 << STM_SPI_SR_OVR))
72 if (sr & (1 << STM_SPI_SR_MODF))
74 if (sr & (1 << STM_SPI_SR_UDR))
76 if ((sr & (1 << STM_SPI_SR_TXE)) == 0)
78 if (sr & (1 << STM_SPI_SR_RXNE))
80 if (which != 5 && which != 6 && which != 13)
81 if (ao_cur_task->task_id != ao_spi_mutex[1])
85 #define validate_spi(stm_spi, which, len) do { (void) (which); (void) (len); } while (0)
89 ao_spi_run(uint8_t id, uint8_t which, uint16_t len)
91 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
92 uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
93 uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
95 validate_spi(stm_spi, which, len);
97 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
98 (0 << STM_SPI_CR2_RXNEIE) |
99 (0 << STM_SPI_CR2_ERRIE) |
100 (0 << STM_SPI_CR2_SSOE) |
101 (1 << STM_SPI_CR2_TXDMAEN) |
102 (1 << STM_SPI_CR2_RXDMAEN));
104 ao_dma_start(miso_dma_index);
105 ao_dma_start(mosi_dma_index);
108 while (!ao_dma_done[miso_dma_index])
109 ao_sleep(&ao_dma_done[miso_dma_index]);
112 while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
113 while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
115 validate_spi(stm_spi, which+1, len);
119 ao_dma_done_transfer(mosi_dma_index);
120 ao_dma_done_transfer(miso_dma_index);
124 ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
126 uint8_t id = AO_SPI_INDEX(spi_index);
127 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
128 uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
129 uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
131 /* Set up the transmit DMA to deliver data */
132 ao_dma_set_transfer(mosi_dma_index,
136 (0 << STM_DMA_CCR_MEM2MEM) |
137 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
138 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
139 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
140 (1 << STM_DMA_CCR_MINC) |
141 (0 << STM_DMA_CCR_PINC) |
142 (0 << STM_DMA_CCR_CIRC) |
143 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
145 /* Set up the receive DMA -- when this is done, we know the SPI unit
146 * is idle. Without this, we'd have to poll waiting for the BSY bit to
149 ao_dma_set_transfer(miso_dma_index,
153 (0 << STM_DMA_CCR_MEM2MEM) |
154 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
155 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
156 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
157 (0 << STM_DMA_CCR_MINC) |
158 (0 << STM_DMA_CCR_PINC) |
159 (0 << STM_DMA_CCR_CIRC) |
160 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
162 ao_spi_run(id, 1, len);
166 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
168 uint8_t id = AO_SPI_INDEX(spi_index);
169 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
170 uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
171 uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
173 /* Set up the transmit DMA to deliver data */
174 ao_dma_set_transfer(mosi_dma_index,
178 (0 << STM_DMA_CCR_MEM2MEM) |
179 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
180 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
181 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
182 (0 << STM_DMA_CCR_MINC) |
183 (0 << STM_DMA_CCR_PINC) |
184 (0 << STM_DMA_CCR_CIRC) |
185 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
187 /* Set up the receive DMA -- when this is done, we know the SPI unit
188 * is idle. Without this, we'd have to poll waiting for the BSY bit to
191 ao_dma_set_transfer(miso_dma_index,
195 (0 << STM_DMA_CCR_MEM2MEM) |
196 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
197 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
198 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
199 (0 << STM_DMA_CCR_MINC) |
200 (0 << STM_DMA_CCR_PINC) |
201 (0 << STM_DMA_CCR_CIRC) |
202 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
204 ao_spi_run(id, 3, len);
208 ao_spi_start_bytes(uint8_t spi_index)
210 uint8_t id = AO_SPI_INDEX(spi_index);
211 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
213 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
214 (0 << STM_SPI_CR2_RXNEIE) |
215 (0 << STM_SPI_CR2_ERRIE) |
216 (0 << STM_SPI_CR2_SSOE) |
217 (0 << STM_SPI_CR2_TXDMAEN) |
218 (0 << STM_SPI_CR2_RXDMAEN));
219 validate_spi(stm_spi, 5, 0xffff);
223 ao_spi_stop_bytes(uint8_t spi_index)
225 uint8_t id = AO_SPI_INDEX(spi_index);
226 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
228 while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
230 while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
232 /* Clear the OVR flag */
235 validate_spi(stm_spi, 6, 0xffff);
240 ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
242 uint8_t id = AO_SPI_INDEX(spi_index);
243 const uint8_t *b = block;
244 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
246 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
247 (0 << STM_SPI_CR2_RXNEIE) |
248 (0 << STM_SPI_CR2_ERRIE) |
249 (0 << STM_SPI_CR2_SSOE) |
250 (0 << STM_SPI_CR2_TXDMAEN) |
251 (0 << STM_SPI_CR2_RXDMAEN));
252 validate_spi(stm_spi, 7, len);
254 while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
257 while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
259 while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
261 /* Clear the OVR flag */
264 validate_spi(stm_spi, 8, len);
268 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
270 uint8_t id = AO_SPI_INDEX(spi_index);
271 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
272 uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
273 uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
277 /* Set up transmit DMA to make the SPI hardware actually run */
278 ao_dma_set_transfer(mosi_dma_index,
282 (0 << STM_DMA_CCR_MEM2MEM) |
283 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
284 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
285 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
286 (0 << STM_DMA_CCR_MINC) |
287 (0 << STM_DMA_CCR_PINC) |
288 (0 << STM_DMA_CCR_CIRC) |
289 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
291 /* Set up the receive DMA to capture data */
292 ao_dma_set_transfer(miso_dma_index,
296 (0 << STM_DMA_CCR_MEM2MEM) |
297 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
298 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
299 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
300 (1 << STM_DMA_CCR_MINC) |
301 (0 << STM_DMA_CCR_PINC) |
302 (0 << STM_DMA_CCR_CIRC) |
303 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
305 ao_spi_run(id, 9, len);
309 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
311 uint8_t id = AO_SPI_INDEX(spi_index);
312 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
313 uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
314 uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
316 /* Set up transmit DMA to send data */
317 ao_dma_set_transfer(mosi_dma_index,
321 (0 << STM_DMA_CCR_MEM2MEM) |
322 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
323 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
324 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
325 (1 << STM_DMA_CCR_MINC) |
326 (0 << STM_DMA_CCR_PINC) |
327 (0 << STM_DMA_CCR_CIRC) |
328 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
330 /* Set up the receive DMA to capture data */
331 ao_dma_set_transfer(miso_dma_index,
335 (0 << STM_DMA_CCR_MEM2MEM) |
336 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
337 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
338 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
339 (1 << STM_DMA_CCR_MINC) |
340 (0 << STM_DMA_CCR_PINC) |
341 (0 << STM_DMA_CCR_CIRC) |
342 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
343 ao_spi_run(id, 11, len);
347 ao_spi_disable_index(uint8_t spi_index)
349 /* Disable current config
352 case AO_SPI_1_PA5_PA6_PA7:
353 stm_gpio_set(&stm_gpioa, 5, 1);
354 stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
355 stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
356 stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
358 case AO_SPI_1_PB3_PB4_PB5:
359 stm_gpio_set(&stm_gpiob, 3, 1);
360 stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
361 stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
362 stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
364 case AO_SPI_1_PE13_PE14_PE15:
365 stm_gpio_set(&stm_gpioe, 13, 1);
366 stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT);
367 stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT);
368 stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT);
370 case AO_SPI_2_PB13_PB14_PB15:
371 stm_gpio_set(&stm_gpiob, 13, 1);
372 stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
373 stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
374 stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
376 case AO_SPI_2_PD1_PD3_PD4:
377 stm_gpio_set(&stm_gpiod, 1, 1);
378 stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT);
379 stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT);
380 stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT);
386 ao_spi_enable_index(uint8_t spi_index)
391 case AO_SPI_1_PA5_PA6_PA7:
392 stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
393 stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
394 stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
396 case AO_SPI_1_PB3_PB4_PB5:
397 stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
398 stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
399 stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
401 case AO_SPI_1_PE13_PE14_PE15:
402 stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
403 stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
404 stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
406 case AO_SPI_2_PB13_PB14_PB15:
407 stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
408 stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
409 stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
411 case AO_SPI_2_PD1_PD3_PD4:
412 stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
413 stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
414 stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
420 ao_spi_config(uint8_t spi_index, uint32_t speed)
422 uint8_t id = AO_SPI_INDEX(spi_index);
423 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
425 if (spi_index != ao_spi_index[id]) {
427 /* Disable old config
429 ao_spi_disable_index(ao_spi_index[id]);
433 ao_spi_enable_index(spi_index);
435 /* Remember current config
437 ao_spi_index[id] = spi_index;
439 stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */
440 (0 << STM_SPI_CR1_BIDIOE) |
441 (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
442 (0 << STM_SPI_CR1_CRCNEXT) |
443 (0 << STM_SPI_CR1_DFF) |
444 (0 << STM_SPI_CR1_RXONLY) |
445 (1 << STM_SPI_CR1_SSM) | /* Software SS handling */
446 (1 << STM_SPI_CR1_SSI) | /* ... */
447 (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
448 (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
449 (speed << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
450 (1 << STM_SPI_CR1_MSTR) |
451 (0 << STM_SPI_CR1_CPOL) | /* Format 0 */
452 (0 << STM_SPI_CR1_CPHA));
453 validate_spi(stm_spi, 13, 0);
457 ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
459 uint8_t id = AO_SPI_INDEX(spi_index);
461 if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
463 ao_spi_config(spi_index, speed);
468 ao_spi_get(uint8_t spi_index, uint32_t speed)
470 uint8_t id = AO_SPI_INDEX(spi_index);
472 ao_mutex_get(&ao_spi_mutex[id]);
473 ao_spi_config(spi_index, speed);
477 ao_spi_put(uint8_t spi_index)
479 uint8_t id = AO_SPI_INDEX(spi_index);
480 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
483 ao_mutex_put(&ao_spi_mutex[id]);
487 ao_spi_channel_init(uint8_t spi_index)
489 uint8_t id = AO_SPI_INDEX(spi_index);
490 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
492 ao_spi_disable_index(spi_index);
495 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
496 (0 << STM_SPI_CR2_RXNEIE) |
497 (0 << STM_SPI_CR2_ERRIE) |
498 (0 << STM_SPI_CR2_SSOE) |
499 (0 << STM_SPI_CR2_TXDMAEN) |
500 (0 << STM_SPI_CR2_RXDMAEN));
502 /* Clear any pending data and error flags */
509 ao_spi_dump_cmd(void)
513 for (s = 0; s < 64; s++) {
514 int i = (spi_task_index + s) & 63;
515 if (spi_tasks[i].which) {
517 const char *name = "(none)";
518 for (t = 0; t < ao_num_tasks; t++)
519 if (ao_tasks[t]->task_id == spi_tasks[i].task) {
520 name = ao_tasks[t]->name;
523 printf("%2d: %5d task %2d which %2d len %5d %s\n",
532 for (s = 0; s < STM_NUM_SPI; s++) {
533 struct stm_spi *spi = ao_spi_stm_info[s].stm_spi;
535 printf("%1d: mutex %2d index %3d miso dma %3d mosi dma %3d",
536 s, ao_spi_mutex[s], ao_spi_index[s],
537 ao_spi_stm_info[s].miso_dma_index,
538 ao_spi_stm_info[s].mosi_dma_index);
539 printf(" cr1 %04x cr2 %02x sr %03x\n",
540 spi->cr1, spi->cr2, spi->sr);
545 static const struct ao_cmds ao_spi_cmds[] = {
546 { ao_spi_dump_cmd, "S\0Dump SPI status" },
555 # if SPI_1_PA5_PA6_PA7
556 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
557 stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
558 stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
559 stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
561 # if SPI_1_PB3_PB4_PB5
562 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
563 stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
564 stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR);
565 stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR);
567 # if SPI_1_PE13_PE14_PE15
568 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN);
569 stm_ospeedr_set(&stm_gpioe, 13, SPI_1_OSPEEDR);
570 stm_ospeedr_set(&stm_gpioe, 14, SPI_1_OSPEEDR);
571 stm_ospeedr_set(&stm_gpioe, 15, SPI_1_OSPEEDR);
573 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
574 ao_spi_index[0] = AO_SPI_CONFIG_NONE;
575 ao_spi_channel_init(0);
579 # if SPI_2_PB13_PB14_PB15
580 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
581 stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR);
582 stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR);
583 stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR);
585 # if SPI_2_PD1_PD3_PD4
586 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
587 stm_ospeedr_set(&stm_gpiod, 1, SPI_2_OSPEEDR);
588 stm_ospeedr_set(&stm_gpiod, 3, SPI_2_OSPEEDR);
589 stm_ospeedr_set(&stm_gpiod, 4, SPI_2_OSPEEDR);
591 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
592 ao_spi_index[1] = AO_SPI_CONFIG_NONE;
593 ao_spi_channel_init(1);
596 ao_cmd_register(&ao_spi_cmds[0]);