Root/tornado/fw/mmc.c

1/*
2 * fw/mmc.c - MMC card access
3 *
4 * Written 2012 by Werner Almesberger
5 * Copyright 2012 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13/*
14 * Heavily influenced by the MMC driver in the Mass Storage for V-USB project
15 * by "lleeloo":
16 * http://we.easyelectronics.ru/AVR/usb-fleshka-na-atmega8-i-v-usb-ot-idei-k-gotovomu-ustroystvu.html
17 */
18
19#include <stdbool.h>
20#include <stdint.h>
21
22#include "delay.h"
23#include "mmc-hw.h"
24#include "mmc.h"
25
26
27#ifdef AVR
28
29#define DEBUG(fmt, ...)
30
31#else /* AVR */
32
33#include <stdio.h>
34
35#define DEBUG(fmt, ...) fprintf(stderr, fmt "\n", __VA_ARGS__)
36
37#endif /* !AVR */
38
39
40/* Command indices */
41
42enum {
43    MMC_GO_IDLE_STATE = 0,
44    MMC_SEND_OP_COND = 1,
45    MMC_SET_BLOCKLEN = 16,
46    MMC_READ_SINGLE_BLOCK = 17,
47    MMC_WRITE_BLOCK = 24,
48};
49
50
51/* Start block tokens */
52
53enum {
54    MMC_START_SINGLE_BLOCK = 0xfe,
55};
56
57
58static void mmc_begin(void)
59{
60    mmc_select();
61}
62
63
64static void mmc_end(void)
65{
66    mmc_send(0xff);
67    mmc_send(0xff);
68    mmc_deselect();
69    mmc_send(0xff);
70}
71
72static void mmc_command(uint8_t cmd, uint32_t arg)
73{
74    mmc_send(0x40 | cmd); /* start (0)+transmission(1)+cmd */
75    mmc_send(arg >> 24);
76    mmc_send(arg >> 16);
77    mmc_send(arg >> 8);
78    mmc_send(arg);
79    mmc_send(0x95); /* crc7+end(1) */
80}
81
82
83static uint8_t mmc_r1(void)
84{
85    uint8_t v, tries = 0xff;
86
87    do v = mmc_recv();
88    while ((v & 0x80) && --tries);
89    return v;
90}
91
92
93static bool mmc_wait(void)
94{
95    uint8_t v, tries = 0xff;
96
97    do {
98        v = mmc_recv();
99        if (v == MMC_START_SINGLE_BLOCK)
100            return 1;
101        _delay_ms(1);
102    }
103    while (--tries);
104    return 0;
105}
106
107
108bool mmc_begin_read(uint32_t addr)
109{
110    uint8_t res;
111
112    mmc_begin();
113    mmc_command(MMC_READ_SINGLE_BLOCK, addr);
114    res = mmc_r1();
115    DEBUG("mmc_begin_read: r1 = 0x%02x", res);
116    if (res) {
117        mmc_end();
118        return 0;
119    } else {
120        return mmc_wait();
121    }
122}
123
124
125uint8_t mmc_read(void)
126{
127    return mmc_recv();
128}
129
130
131bool mmc_end_read(void)
132{
133    mmc_end();
134    return 1;
135}
136
137
138bool mmc_begin_write(uint32_t addr)
139{
140    uint8_t res;
141
142    mmc_begin();
143    mmc_command(MMC_WRITE_BLOCK, addr);
144    res = mmc_r1();
145    DEBUG("mmc_begin_write: r1 = 0x%02x", res);
146    if (res) {
147        mmc_end();
148        return 0;
149    } else {
150        mmc_send(0xff);
151        mmc_send(0xff);
152        mmc_send(MMC_START_SINGLE_BLOCK);
153        return 1;
154    }
155}
156
157
158void mmc_write(uint8_t data)
159{
160    mmc_send(data);
161}
162
163
164bool mmc_end_write(void)
165{
166    mmc_send(0xff);
167    mmc_send(0xff);
168    mmc_recv();
169    while (!mmc_recv());
170    mmc_end();
171    return 1;
172}
173
174
175void mmc_off(void)
176{
177    mmc_deactivate();
178}
179
180
181static void send_clock(void)
182{
183    uint8_t i;
184
185    for (i = 0; i != 10; i++)
186        mmc_send(0xff);
187}
188
189
190bool mmc_init(void)
191{
192    uint16_t tries = 0xff;
193    uint8_t res;
194
195    mmc_activate();
196    send_clock();
197    mmc_begin();
198
199    do {
200        mmc_command(MMC_GO_IDLE_STATE, 0);
201        if (mmc_r1() == 0x01) /* in idle state */
202            break;
203    }
204    while (--tries);
205    mmc_end();
206    if (!tries)
207        return 0;
208
209    send_clock();
210
211    tries = 0x7ff;
212    do {
213        mmc_select();
214        mmc_command(MMC_SEND_OP_COND, 0);
215        res = mmc_r1();
216        mmc_deselect();
217        send_clock();
218    }
219    while (res && --tries);
220
221    mmc_end();
222
223    if (res) {
224        mmc_deactivate();
225        return 0;
226    }
227
228    mmc_begin();
229    mmc_command(MMC_SET_BLOCKLEN, MMC_BLOCK);
230    mmc_r1();
231    mmc_end();
232
233    return 1;
234}
235

Archive Download this file

Branches:
master
tornado-v1



interactive