]> git.gag.com Git - fw/altos/blob - src/drivers/ao_sdcard.c
altos: Support normalized axes in mpu6000 and mmc5983
[fw/altos] / src / drivers / ao_sdcard.c
1 /*
2  * Copyright © 2013 Keith Packard <keithp@keithp.com>
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include "ao.h"
20 #include "ao_sdcard.h"
21
22 #if HAS_RADIO
23 extern uint8_t ao_radio_mutex;
24 #define get_radio()     ao_mutex_get(&ao_radio_mutex)
25 #define put_radio()     ao_mutex_put(&ao_radio_mutex)
26 #else
27 #define get_radio()
28 #define put_radio()
29 #endif
30
31 #define ao_sdcard_get_slow() do { get_radio(); ao_spi_get(AO_SDCARD_SPI_BUS, AO_SPI_SPEED_250kHz); } while (0)
32 #define ao_sdcard_get() do { get_radio(); ao_spi_get(AO_SDCARD_SPI_BUS, AO_SPI_SPEED_FAST); } while (0)
33 #define ao_sdcard_put() do { ao_spi_put(AO_SDCARD_SPI_BUS); put_radio(); } while (0)
34 #define ao_sdcard_send_fixed(d,l)       ao_spi_send_fixed((d), (l), AO_SDCARD_SPI_BUS)
35 #define ao_sdcard_send(d,l)             ao_spi_send((d), (l), AO_SDCARD_SPI_BUS)
36 #define ao_sdcard_recv(d,l)             ao_spi_recv((d), (l), AO_SDCARD_SPI_BUS)
37 #define ao_sdcard_select()              ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,0)
38 #define ao_sdcard_deselect()            ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,1)
39
40 /* Include SD card commands */
41 #ifndef SDCARD_DEBUG
42 #define SDCARD_DEBUG    0
43 #endif
44
45 /* Spew SD tracing */
46 #ifndef SDCARD_TRACE
47 #define SDCARD_TRACE    0
48 #endif
49
50 /* Emit error and warning messages */
51 #ifndef SDCARD_WARN
52 #define SDCARD_WARN     0
53 #endif
54
55 static uint8_t  initialized;
56 static uint8_t  present;
57 static uint8_t  mutex;
58 static enum ao_sdtype sdtype;
59
60 #define ao_sdcard_lock()        ao_mutex_get(&mutex)
61 #define ao_sdcard_unlock()      ao_mutex_put(&mutex)
62
63 #if SDCARD_TRACE
64 #define DBG(...) printf(__VA_ARGS__)
65 #else
66 #define DBG(...) (void) 0
67 #endif
68
69 #if SDCARD_WARN
70 #define WARN(...) printf(__VA_ARGS__)
71 #else
72 #define WARN(...) (void) 0
73 #endif
74
75 #define later(x,y)      ((int16_t) ((x) - (y)) >= 0)
76
77 /*
78  * Wait while the card is busy. The card will return a stream of 0xff
79  * when it is ready to accept a command
80  */
81
82 static uint8_t
83 ao_sdcard_wait_busy(void)
84 {
85         uint16_t        timeout = ao_time() + SDCARD_BUSY_TIMEOUT;
86         uint8_t         reply;
87         for (;;) {
88                 ao_sdcard_recv(&reply, 1);
89                 DBG("\t\twait busy %02x\n", reply);
90                 if (reply == 0xff)
91                         break;
92                 if (later(ao_time(), timeout)) {
93                         WARN("wait busy timeout\n");
94                         return 0;
95                 }
96         }
97         return 1;
98 }
99
100
101 /*
102  * Send an SD command and await the status reply
103  */
104
105 static uint8_t
106 ao_sdcard_send_cmd(uint8_t cmd, uint32_t arg)
107 {
108         uint8_t data[6];
109         uint8_t reply;
110         uint16_t timeout;
111
112         DBG ("\tsend_cmd %d arg %08x\n", cmd, arg);
113
114         /* Wait for the card to not be busy */
115         if (cmd != SDCARD_GO_IDLE_STATE) {
116                 if (!ao_sdcard_wait_busy())
117                         return SDCARD_STATUS_TIMEOUT;
118         }
119         
120         data[0] = (cmd & 0x3f) | 0x40;
121         data[1] = arg >> 24;
122         data[2] = arg >> 16;
123         data[3] = arg >> 8;
124         data[4] = arg;
125         if (cmd == SDCARD_GO_IDLE_STATE)
126                 data[5] = 0x95; /* Valid for 0 arg */
127         else if (cmd == SDCARD_SEND_IF_COND)
128                 data[5] = 0x87; /* Valid for 0x1aa arg */
129         else
130                 data[5] = 0xff; /* no CRC */
131         ao_sdcard_send(data, 6);
132
133         /* The first reply byte will be the status,
134          * which must have the high bit clear
135          */
136         timeout = ao_time() + SDCARD_CMD_TIMEOUT;
137         for (;;) {
138                 ao_sdcard_recv(&reply, 1);
139                 DBG ("\t\tgot byte %02x\n", reply);
140                 if ((reply & 0x80) == 0)
141                         break;
142                 if (later(ao_time(), timeout)) {
143                         WARN("send_cmd %02x timeout\n", cmd);
144                         return SDCARD_STATUS_TIMEOUT;
145                 }
146         }
147 #if SDCARD_WARN
148         if (reply != SDCARD_STATUS_READY_STATE && reply != SDCARD_STATUS_IDLE_STATE)
149                 WARN("send_cmd %d failed %02x\n", cmd, reply);
150 #endif
151         return reply;
152 }
153
154 /*
155  * Retrieve any reply, discarding the trailing CRC byte
156  */
157 static void
158 ao_sdcard_recv_reply(uint8_t *reply, int len)
159 {
160         uint8_t discard;
161
162         if (len)
163                 ao_sdcard_recv(reply, len);
164         /* trailing byte */
165         ao_sdcard_recv(&discard, 1);
166 }
167
168 /*
169  * Switch to 'idle' state. This is used to get the card into SPI mode
170  */
171 static uint8_t
172 ao_sdcard_go_idle_state(void)
173 {
174         uint8_t ret;
175
176         DBG ("go_idle_state\n");
177         ao_sdcard_select();
178         ret = ao_sdcard_send_cmd(SDCARD_GO_IDLE_STATE, 0);
179         ao_sdcard_recv_reply(NULL, 0);
180         ao_sdcard_deselect();
181         DBG ("\tgo_idle_state status %02x\n", ret);
182         return ret;
183 }
184
185 static uint8_t
186 ao_sdcard_send_op_cond(void)
187 {
188         uint8_t ret;
189
190         DBG ("send_op_cond\n");
191         ao_sdcard_select();
192         ret = ao_sdcard_send_cmd(SDCARD_SEND_OP_COND, 0);
193         ao_sdcard_recv_reply(NULL, 0);
194         ao_sdcard_deselect();
195         DBG ("\tsend_op_cond %02x\n", ret);
196         return ret;
197 }
198
199 static uint8_t
200 ao_sdcard_send_if_cond(uint32_t arg, uint8_t send_if_cond_response[4])
201 {
202         uint8_t ret;
203
204         DBG ("send_if_cond\n");
205         ao_sdcard_select();
206         ret = ao_sdcard_send_cmd(SDCARD_SEND_IF_COND, arg);
207         if (ret != SDCARD_STATUS_IDLE_STATE) {
208                 DBG ("\tsend_if_cond failed %02x\n", ret);
209                 return ret;
210         }
211         ao_sdcard_recv_reply(send_if_cond_response, 4);
212         DBG ("send_if_cond status %02x response %02x %02x %02x %02x\n",
213                 ret,
214                 send_if_cond_response[0],
215                 send_if_cond_response[1],
216                 send_if_cond_response[2],
217                 send_if_cond_response[3]);
218         ao_sdcard_deselect();
219         return ret;
220 }
221
222 /*
223  * _ao_sdcard_send_status
224  *
225  * Get the 2-byte status value.
226  *
227  * Called from other functions with CS held low already,
228  * hence prefixing the name with '_'
229  */
230 static uint16_t
231 _ao_sdcard_send_status(void)
232 {
233         uint8_t ret;
234         uint8_t extra;
235
236         DBG ("send_status\n");
237         ret = ao_sdcard_send_cmd(SDCARD_SEND_STATUS, 0);
238         ao_sdcard_recv_reply(&extra, 1);
239         if (ret != SDCARD_STATUS_READY_STATE)
240                 DBG ("\tsend_if_cond failed %02x\n", ret);
241         return ret | (extra << 8);
242 }
243
244 /*
245  * ao_sdcard_set_blocklen
246  *
247  * Set the block length for future read and write commands
248  */
249 static uint8_t
250 ao_sdcard_set_blocklen(uint32_t blocklen)
251 {
252         uint8_t ret;
253
254         DBG ("set_blocklen %d\n", blocklen);
255         ao_sdcard_select();
256         ret = ao_sdcard_send_cmd(SDCARD_SET_BLOCKLEN, blocklen);
257         ao_sdcard_recv_reply(NULL, 0);
258         ao_sdcard_deselect();
259         if (ret != SDCARD_STATUS_READY_STATE)
260                 DBG ("\tsend_if_cond failed %02x\n", ret);
261         return ret;
262 }
263
264 /*
265  * _ao_sdcard_app_cmd
266  *
267  * Send the app command prefix
268  *
269  * Called with the CS held low, hence
270  * the '_' prefix
271  */
272 static uint8_t
273 _ao_sdcard_app_cmd(void)
274 {
275         uint8_t ret;
276
277         DBG ("app_cmd\n");
278         ret = ao_sdcard_send_cmd(SDCARD_APP_CMD, 0);
279         ao_sdcard_recv_reply(NULL, 0);
280         DBG ("\tapp_cmd status %02x\n");
281         return ret;
282 }
283
284 static uint8_t
285 ao_sdcard_app_send_op_cond(uint32_t arg)
286 {
287         uint8_t ret;
288
289         DBG("send_op_comd\n");
290         ao_sdcard_select();
291         ret = _ao_sdcard_app_cmd();
292         if (ret != SDCARD_STATUS_IDLE_STATE)
293                 goto bail;
294         ret = ao_sdcard_send_cmd(SDCARD_APP_SEND_OP_COMD, arg);
295         ao_sdcard_recv_reply(NULL, 0);
296 bail:
297         ao_sdcard_deselect();
298         DBG ("\tapp_send_op_cond status %02x\n", ret);
299         return ret;
300 }
301
302 static uint8_t
303 ao_sdcard_read_ocr(uint8_t read_ocr_response[4])
304 {
305         uint8_t ret;
306
307         DBG ("read_ocr\n");
308         ao_sdcard_select();
309         ret = ao_sdcard_send_cmd(SDCARD_READ_OCR, 0);
310         if (ret != SDCARD_STATUS_READY_STATE)
311                 DBG ("\tread_ocr failed %02x\n", ret);
312         else {
313                 ao_sdcard_recv_reply(read_ocr_response, 4);
314                 DBG ("\tread_ocr status %02x response %02x %02x %02x %02x\n", ret,
315                         read_ocr_response[0], read_ocr_response[1],
316                         read_ocr_response[2], read_ocr_response[3]);
317         }
318         ao_sdcard_deselect();
319         return ret;
320 }
321
322 /*
323  * Follow the flow-chart defined by the SD group to
324  * initialize the card and figure out what kind it is
325  */
326 static void
327 ao_sdcard_setup(void)
328 {
329         int     i;
330         uint8_t ret;
331         uint8_t response[10];
332
333         DBG ("Testing sdcard\n");
334
335         ao_sdcard_get_slow();
336         /*
337          * min 74 clocks with CS high
338          */
339         ao_sdcard_send_fixed(0xff, 10);
340
341         /* Reset the card and get it into SPI mode */
342         for (i = 0; i < SDCARD_IDLE_RETRY; i++) {
343                 if (ao_sdcard_go_idle_state() == SDCARD_STATUS_IDLE_STATE)
344                         break;
345         }
346         if (i == SDCARD_IDLE_RETRY)
347                 goto bail;
348
349         /* Figure out what kind of card we have */
350         sdtype = ao_sdtype_unknown;
351
352         if (ao_sdcard_send_if_cond(0x1aa, response) == SDCARD_STATUS_IDLE_STATE) {
353                 uint32_t        arg = 0;
354                 uint8_t         sdver2 = 0;
355
356                 /* Check for SD version 2 */
357                 if ((response[2] & 0xf) == 1 && response[3] == 0xaa) {
358                         arg = 0x40000000;
359                         sdver2 = 1;
360                 }
361
362                 for (i = 0; i < SDCARD_OP_COND_RETRY; i++) {
363                         ao_delay(AO_MS_TO_TICKS(10));
364                         ret = ao_sdcard_app_send_op_cond(arg);
365                         if (ret != SDCARD_STATUS_IDLE_STATE)
366                                 break;
367                 }
368                 if (ret != SDCARD_STATUS_READY_STATE) {
369                         /* MMC */
370                         for (i = 0; i < SDCARD_OP_COND_RETRY; i++) {
371                                 ao_delay(AO_MS_TO_TICKS(10));
372                                 ret = ao_sdcard_send_op_cond();
373                                 if (ret != SDCARD_STATUS_IDLE_STATE)
374                                         break;
375                         }
376                         if (ret != SDCARD_STATUS_READY_STATE)
377                                 goto bail;
378                         sdtype = ao_sdtype_mmc3;
379                 } else {
380                         /* SD */
381                         if (sdver2 != 0) {
382                                 ret = ao_sdcard_read_ocr(response);
383                                 if (ret != SDCARD_STATUS_READY_STATE)
384                                         goto bail;
385                                 if ((response[0] & 0xc0) == 0xc0)
386                                         sdtype = ao_sdtype_sd2block;
387                                 else
388                                         sdtype = ao_sdtype_sd2byte;
389                         } else {
390                                 sdtype = ao_sdtype_sd1;
391                         }
392                 }
393
394                 /* For everything but SDHC cards, set the block length */
395                 if (sdtype != ao_sdtype_sd2block) {
396                         ret = ao_sdcard_set_blocklen(512);
397                         if (ret != SDCARD_STATUS_READY_STATE)
398                                 DBG ("set_blocklen failed, ignoring\n");
399                 }
400         }
401
402         DBG ("SD card detected, type %d\n", sdtype);
403 bail:
404         ao_sdcard_put();
405 }
406
407 static uint8_t
408 _ao_sdcard_reset(void)
409 {
410         int i;
411         uint8_t ret = 0x3f;
412         uint8_t response[10];
413
414         for (i = 0; i < SDCARD_IDLE_RETRY; i++) {
415                 if (ao_sdcard_go_idle_state() == SDCARD_STATUS_IDLE_STATE)
416                         break;
417         }
418         if (i == SDCARD_IDLE_RETRY) {
419                 ret = 0x3f;
420                 goto bail;
421         }
422
423         /* Follow the setup path to get the card out of idle state and
424          * up and running again
425          */
426         if (ao_sdcard_send_if_cond(0x1aa, response) == SDCARD_STATUS_IDLE_STATE) {
427                 uint32_t        arg = 0;
428 //              uint8_t         sdver2 = 0;
429
430                 /* Check for SD version 2 */
431                 if ((response[2] & 0xf) == 1 && response[3] == 0xaa) {
432                         arg = 0x40000000;
433 //                      sdver2 = 1;
434                 }
435
436                 for (i = 0; i < SDCARD_IDLE_RETRY; i++) {
437                         ret = ao_sdcard_app_send_op_cond(arg);
438                         if (ret != SDCARD_STATUS_IDLE_STATE)
439                                 break;
440                 }
441
442                 if (ret != SDCARD_STATUS_READY_STATE) {
443                         /* MMC */
444                         for (i = 0; i < SDCARD_IDLE_RETRY; i++) {
445                                 ret = ao_sdcard_send_op_cond();
446                                 if (ret != SDCARD_STATUS_IDLE_STATE)
447                                         break;
448                         }
449                         if (ret != SDCARD_STATUS_READY_STATE)
450                                 goto bail;
451                 }
452
453                 /* For everything but SDHC cards, set the block length */
454                 if (sdtype != ao_sdtype_sd2block) {
455                         ret = ao_sdcard_set_blocklen(512);
456                         if (ret != SDCARD_STATUS_READY_STATE)
457                                 DBG ("set_blocklen failed, ignoring\n");
458                 }
459         }
460 bail:
461         return ret;
462 }
463
464 /*
465  * The card will send 0xff until it is ready to send
466  * the data block at which point it will send the START_BLOCK
467  * marker followed by the data. This function waits while
468  * the card is sending 0xff
469  */
470 static uint8_t
471 ao_sdcard_wait_block_start(void)
472 {
473         uint8_t         v;
474         uint16_t        timeout = ao_time() + SDCARD_BLOCK_TIMEOUT;
475
476         DBG ("\twait_block_start\n");
477         for (;;) {
478                 ao_sdcard_recv(&v, 1);
479                 DBG("\t\trecv %02x\n", v);
480                 if (v != 0xff)
481                         break;
482                 if (later(ao_time(), timeout)) {
483                         printf ("wait block start timeout\n");
484                         return 0xff;
485                 }
486         }
487         return v;
488 }
489
490 /*
491  * Read a block of 512 bytes from the card
492  */
493 uint8_t
494 ao_sdcard_read_block(uint32_t block, uint8_t *data)
495 {
496         uint8_t ret = 0x3f;
497         uint8_t start_block;
498         uint8_t crc[2];
499         int tries;
500
501         ao_sdcard_lock();
502         if (!initialized) {
503                 ao_sdcard_setup();
504                 initialized = 1;
505                 if (sdtype != ao_sdtype_unknown)
506                         present = 1;
507         }
508         if (!present) {
509                 ao_sdcard_unlock();
510                 return 0;
511         }
512         DBG("read block %d\n", block);
513         if (sdtype != ao_sdtype_sd2block)
514                 block <<= 9;
515
516         ao_sdcard_get();
517         for (tries = 0; tries < 10; tries++) {
518                 ao_sdcard_select();
519
520                 ret = ao_sdcard_send_cmd(SDCARD_READ_BLOCK, block);
521                 ao_sdcard_recv_reply(NULL, 0);
522                 if (ret != SDCARD_STATUS_READY_STATE) {
523                         uint16_t        status;
524                         WARN ("read block command failed %d status %02x\n", block, ret);
525                         status = _ao_sdcard_send_status();
526                         WARN ("\tstatus now %04x\n", status);
527                         (void) status;
528                         goto bail;
529                 }
530
531                 ao_sdcard_send_fixed(0xff, 1);
532
533                 /* Wait for the data start block marker */
534                 start_block = ao_sdcard_wait_block_start();
535                 if (start_block != SDCARD_DATA_START_BLOCK) {
536                         WARN ("wait block start failed %02x\n", start_block);
537                         ret = 0x3f;
538                         goto bail;
539                 }
540
541                 ao_sdcard_recv(data, 512);
542                 ao_sdcard_recv(crc, 2);
543         bail:
544                 ao_sdcard_deselect();
545                 if (ret == SDCARD_STATUS_READY_STATE)
546                         break;
547                 if (ret == SDCARD_STATUS_IDLE_STATE) {
548                         ret = _ao_sdcard_reset();
549                         if (ret != SDCARD_STATUS_READY_STATE)
550                                 break;
551                 }
552         }
553         ao_sdcard_put();
554         ao_sdcard_unlock();
555
556 #if SDCARD_WARN
557         if (ret != SDCARD_STATUS_READY_STATE)
558                 WARN("read failed\n");
559         else if (tries)
560                 WARN("took %d tries to read %d\n", tries + 1, block);
561 #endif
562
563         DBG("read %s\n", ret == SDCARD_STATUS_READY_STATE ? "success" : "failure");
564         return ret == SDCARD_STATUS_READY_STATE;
565 }
566
567 /*
568  * Write a block of 512 bytes to the card
569  */
570 uint8_t
571 ao_sdcard_write_block(uint32_t block, uint8_t *data)
572 {
573         uint8_t ret;
574         uint8_t response[1];
575         uint8_t start_block[8];
576         uint16_t status;
577         int     tries;
578
579         ao_sdcard_lock();
580         if (!initialized) {
581                 ao_sdcard_setup();
582                 initialized = 1;
583                 if (sdtype != ao_sdtype_unknown)
584                         present = 1;
585         }
586         if (!present) {
587                 ao_sdcard_unlock();
588                 return 0;
589         }
590         DBG("write block %d\n", block);
591         if (sdtype != ao_sdtype_sd2block)
592                 block <<= 9;
593
594         ao_sdcard_get();
595
596         for (tries = 0; tries < 10; tries++) {
597                 ao_sdcard_select();
598
599                 ret = ao_sdcard_send_cmd(SDCARD_WRITE_BLOCK, block);
600                 ao_sdcard_recv_reply(NULL, 0);
601                 if (ret != SDCARD_STATUS_READY_STATE)
602                         goto bail;
603
604                 /* Write a pad byte followed by the data start block marker */
605                 start_block[0] = 0xff;
606                 start_block[1] = SDCARD_DATA_START_BLOCK;
607                 ao_sdcard_send(start_block, 2);
608
609                 /* Send the data */
610                 ao_sdcard_send(data, 512);
611
612                 /* Fake the CRC */
613                 ao_sdcard_send_fixed(0xff, 2);
614
615                 /* See if the card liked the data */
616                 ao_sdcard_recv(response, sizeof (response));
617                 if ((response[0] & SDCARD_DATA_RES_MASK) != SDCARD_DATA_RES_ACCEPTED) {
618                         int i;
619                         WARN("Data not accepted, response");
620                         for (i = 0; i < (int) sizeof (response); i++)
621                                 WARN(" %02x", response[i]);
622                         WARN("\n");
623                         ret = 0x3f;
624                         goto bail;
625                 }
626                 
627                 /* Wait for the bus to go idle (should be done with an interrupt?) */
628                 if (!ao_sdcard_wait_busy()) {
629                         ret = 0x3f;
630                         goto bail;
631                 }
632
633                 /* Check the current status after the write completes */
634                 status = _ao_sdcard_send_status();
635                 if ((status & 0xff) != SDCARD_STATUS_READY_STATE) {
636                         WARN ("send status after write %04x\n", status);
637                         ret = status & 0xff;
638                         goto bail;
639                 }
640         bail:
641                 ao_sdcard_deselect();
642                 DBG("write %s\n", ret == SDCARD_STATUS_READY_STATE ? "success" : "failure");
643                 if (ret == SDCARD_STATUS_READY_STATE)
644                         break;
645         }
646         ao_sdcard_put();
647         ao_sdcard_unlock();
648         if (tries)
649                 WARN("took %d tries to write %d\n", tries + 1, block);
650
651         return ret == SDCARD_STATUS_READY_STATE;
652 }
653
654 #if SDCARD_DEBUG
655 static uint8_t  test_data[512];
656
657 static void
658 ao_sdcard_test_read(void)
659 {
660         int i;
661
662         ao_cmd_decimal();
663         if (ao_cmd_status != ao_cmd_success)
664                 return;
665         
666         for (i = 0; i < 100; i++) {
667                 printf ("."); flush();
668                 if (!ao_sdcard_read_block(ao_cmd_lex_u32+i, test_data)) {
669                         printf ("read error %d\n", i);
670                         return;
671                 }
672         }
673         printf ("data:");
674         for (i = 0; i < 18; i++)
675                 printf (" %02x", test_data[i]);
676         printf ("\n");
677 }
678
679 static void
680 ao_sdcard_test_write(void)
681 {
682         int     i;
683         printf ("data:");
684         for (i = 0; i < 16; i++) {
685                 test_data[i]++;
686                 printf (" %02x", test_data[i]);
687         }
688         printf ("\n");
689         if (!ao_sdcard_write_block(1, test_data)) {
690                 printf ("write error\n");
691                 return;
692         }
693 }
694
695 static const struct ao_cmds ao_sdcard_cmds[] = {
696         { ao_sdcard_test_read,  "x\0Test read" },
697         { ao_sdcard_test_write, "y\0Test read" },
698         { 0, NULL },
699 };
700 #endif
701
702 void
703 ao_sdcard_init(void)
704 {
705         stm_pupdr_set(AO_SDCARD_SPI_PORT, AO_SDCARD_SPI_SCK_PIN, STM_PUPDR_PULL_UP);
706         stm_pupdr_set(AO_SDCARD_SPI_PORT, AO_SDCARD_SPI_MISO_PIN, STM_PUPDR_PULL_UP);
707         stm_pupdr_set(AO_SDCARD_SPI_PORT, AO_SDCARD_SPI_MOSI_PIN, STM_PUPDR_PULL_UP);
708         ao_spi_init_cs(AO_SDCARD_SPI_CS_PORT, (1 << AO_SDCARD_SPI_CS_PIN));
709 #if SDCARD_DEBUG
710         ao_cmd_register(&ao_sdcard_cmds[0]);
711 #endif
712 }