OpenCores
URL https://opencores.org/ocsvn/igor/igor/trunk

Subversion Repositories igor

[/] [igor/] [trunk/] [avr/] [eth-test/] [dev/] [mmc.c] - Blame information for rev 4

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 atypic
/************************************************************************
2
**
3
**  Copyright (C) 2006  Jesper Hansen <jesper@redegg.net>
4
**  Modified and extended with write supportfor use with the IGOR Lisp machine
5
**
6
**  Interface functions for MMC/SD cards
7
**
8
**  File mmc_if.h
9
**
10
*************************************************************************
11
**
12
**  This program is free software; you can redistribute it and/or
13
**  modify it under the terms of the GNU General Public License
14
**  as published by the Free Software Foundation; either version 2
15
**  of the License, or (at your option) any later version.
16
**
17
**  This program is distributed in the hope that it will be useful,
18
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
19
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
**  GNU General Public License for more details.
21
**
22
**  You should have received a copy of the GNU General Public License
23
**  along with this program; if not, write to the Free Software Foundation,
24
**  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25
**
26
*************************************************************************/
27
 
28
/** \file mmc_if.c
29
        Simple MMC/SD-card functionality
30
*/
31
 
32
 
33
#include <avr/io.h>
34
#include <inttypes.h>
35
#include <stdio.h>
36
#include "mmc.h"
37
#include <device.h>
38
 
39
igordev_read_fn_t mmc_recv;
40
igordev_write_fn_t mmc_send;
41
igordev_init_fn_t mmcdevice_init;
42
igordev_flush_fn_t mmc_flush;
43
 
44
struct igordev igordev_mmc = {
45
        .init = mmcdevice_init,
46
        .read = mmc_recv,
47
        .write = mmc_send,
48
        .flush = mmc_flush,
49
        .read_status = 0,
50
        .write_status = 0,
51
        .priv = NULL
52
};
53
 
54
//LBA of the most recently read sector
55
int32_t buffered_lba = -1;
56
 
57
//Used to store the most recently read sector
58
uint8_t sectorbuffer[512];
59
 
60
void mmcdevice_init()
61
{
62
        igordev_mmc.read_status = igordev_mmc.write_status = IDEV_STATUS_OK;
63
        igordev_mmc.id = (CAN_READ | CAN_WRITE | ADDR_READ | ADDR_WRITE |
64
            (DEVTYPE_STORAGE << DEVTYPE_OFFSET));
65
        //TODO do something useful if init fails?
66
        /*uint8_t returncode = */
67
        mmc_init();
68
}
69
 
70
//No write support specified in the current design draft,
71
//but can be implemented later
72
uint8_t
73
mmc_send(uint64_t addr, uint8_t *data, uint8_t num)
74
{
75
 
76
        //LBA of the sector we want to read
77
        uint32_t lba = addr/SECTOR_SIZE;
78
 
79
        //Byte position within the sector
80
        uint16_t byte_addr = addr-SECTOR_SIZE*lba;
81
 
82
        //Read the sector that will be overwritten
83
        if (read_sector_to_buffer(lba) != 0) {
84
                //Write error
85
                igordev_mmc.write_status = IDEV_STATUS_ERROR;
86
                return 0;
87
        }
88
 
89
        uint64_t i;
90
 
91
        //Fill the sector with new data
92
        for (i = byte_addr; i < byte_addr + num && i < SECTOR_SIZE; i++) {
93
                sectorbuffer[i] = *data;
94
                data++;
95
        }
96
 
97
        //Write the modified sector back
98
        if (write_buffer_to_sector(lba) != 0) {
99
                //Read error
100
                igordev_mmc.write_status = IDEV_STATUS_ERROR;
101
                return 0;
102
        }
103
 
104
        //Repeat if data spans two sectors
105
        if (byte_addr + num > SECTOR_SIZE) {
106
 
107
                //Read the new sector
108
                if (read_sector_to_buffer(lba+1) != 0) {
109
                        //Read error
110
                        igordev_mmc.write_status = IDEV_STATUS_ERROR;
111
                        return i - byte_addr;
112
                }
113
 
114
                //Store the remaining bytes
115
                uint8_t j;
116
                for (j = 0; j < byte_addr + num - SECTOR_SIZE; j++) {
117
                        sectorbuffer[j] = *data;
118
                        data++;
119
                }
120
 
121
                //Write the modified sector back
122
                if (write_buffer_to_sector(lba+1) != 0) {
123
                        //Write error
124
                        igordev_mmc.write_status = IDEV_STATUS_ERROR;
125
                        return i - byte_addr;
126
                }
127
 
128
                igordev_mmc.write_status = IDEV_STATUS_OK;
129
                return j + i - addr;
130
        }
131
 
132
        igordev_mmc.write_status = IDEV_STATUS_OK;
133
        return (i - addr) ;
134
}
135
 
136
uint8_t
137
mmc_recv(uint64_t addr, uint8_t *data, uint8_t num)
138
{
139
 
140
        //LBA of the sector we want to read
141
        uint32_t lba = addr/SECTOR_SIZE;
142
 
143
        //Byte position within the sector
144
        uint16_t byte_addr = addr-SECTOR_SIZE*lba;
145
 
146
        //Read the sector
147
        if (read_sector_to_buffer(lba) != 0) {
148
                //Read error
149
                igordev_mmc.read_status = IDEV_STATUS_ERROR;
150
                return 0;
151
        }
152
 
153
        uint64_t i;
154
 
155
        //Loop through the sector data and store only the bytes that we want
156
        //for (i = byte_addr; i < byte_addr + num && i < SECTOR_SIZE; i++) {
157
        //      *data++ = sectorbuffer[i];
158
        for (i = byte_addr; i < byte_addr + num && i < SECTOR_SIZE; i++) {
159
                *data = sectorbuffer[i];
160
                data++;
161
        }
162
 
163
        if (byte_addr + num > SECTOR_SIZE) {
164
                //We didn't get all of the data in the first go,
165
                //so we must continue reading on the next sector
166
 
167
                //Read the new sector
168
                if (read_sector_to_buffer(lba+1) != 0) {
169
                        //Read error
170
                        igordev_mmc.read_status = IDEV_STATUS_ERROR;
171
                        return i - byte_addr;
172
                }
173
 
174
                //Store the remaining bytes
175
                uint8_t j;
176
                for (j = 0; j < byte_addr + num - SECTOR_SIZE; j++) {
177
                        *data = sectorbuffer[j];
178
                        data++;
179
                }
180
 
181
                igordev_mmc.read_status = IDEV_STATUS_OK;
182
                return j + i - addr;
183
        }
184
 
185
        igordev_mmc.read_status = IDEV_STATUS_OK;
186
        return (i - addr) ;
187
}
188
 
189
//Read a sector into the sector buffer
190
uint8_t read_sector_to_buffer(uint32_t lba)
191
{
192
        if (buffered_lba != lba) {
193
                if (mmc_readsector(lba, sectorbuffer) != 0) {
194
                        //We have a read error
195
 
196
                        //The buffered sector may be corrupted,
197
                        //so we make sure it's invalidated
198
                        buffered_lba = -1;
199
 
200
                        return 1;
201
 
202
                } else { //Successful read
203
                        buffered_lba = lba;
204
                        return 0;
205
                }
206
        }
207
        return 0;
208
}
209
 
210
//Write the sector buffer into a sector
211
uint8_t write_buffer_to_sector(uint32_t lba)
212
{
213
        if (mmc_writesector(lba, sectorbuffer) != 0) {
214
                //We have a write error
215
 
216
                //Invalidate the buffered sector
217
                buffered_lba = -1;
218
 
219
                return 1;
220
 
221
        } else { //Successful write
222
                buffered_lba = lba;
223
                return 0;
224
        }
225
}
226
 
227
/** Hardware SPI I/O.
228
        \param byte Data to send over SPI bus
229
        \return Received data from SPI bus
230
*/
231
uint8_t spi_byte(uint8_t byte)
232
{
233
        SPDR = byte;
234
        while(!(SPSR & (1<<SPIF)))
235
        {}
236
        return SPDR;
237
}
238
 
239
 
240
 
241
/** Send a command to the MMC/SD card.
242
        \param command  Command to send
243
        \param px       Command parameter 1
244
        \param py       Command parameter 2
245
*/
246
void mmc_send_command(uint8_t command, uint16_t px, uint16_t py)
247
{
248
        register union u16convert r;
249
 
250
        SPI_PORT &= ~(1 << MMC_CS);     // enable CS
251
 
252
        spi_byte(0xff);                 // dummy byte
253
 
254
        spi_byte(command | 0x40);
255
 
256
        r.value = px;
257
        spi_byte(r.bytes.high); // high byte of param x
258
        spi_byte(r.bytes.low);  // low byte of param x
259
 
260
        r.value = py;
261
        spi_byte(r.bytes.high); // high byte of param y
262
        spi_byte(r.bytes.low);  // low byte of param y
263
 
264
        spi_byte(0x95);                 // correct CRC for first command in SPI
265
                                        // after that CRC is ignored, so no problem with
266
                                        // always sending 0x95
267
        spi_byte(0xff);                 // ignore return byte
268
}
269
 
270
 
271
/** Get Token.
272
        Wait for and return a non-ff token from the MMC/SD card
273
        \return The received token or 0xFF if timeout
274
*/
275
uint8_t mmc_get(void)
276
{
277
        uint16_t i = 0xffff;
278
        uint8_t b = 0xff;
279
 
280
        while ((b == 0xff) && (--i))
281
        {
282
                b = spi_byte(0xff);
283
        }
284
        return b;
285
 
286
}
287
 
288
/** Get Datatoken.
289
        Wait for and return a data token from the MMC/SD card
290
        \return The received token or 0xFF if timeout
291
*/
292
uint8_t mmc_datatoken(void)
293
{
294
        uint16_t i = 0xffff;
295
        uint8_t b = 0xff;
296
 
297
        while ((b != 0xfe) && (--i))
298
        {
299
                b = spi_byte(0xff);
300
        }
301
        return b;
302
}
303
 
304
 
305
/** Finish Clocking and Release card.
306
        Send 10 clocks to the MMC/SD card
307
         and release the CS line
308
*/
309
void mmc_clock_and_release(void)
310
{
311
        uint8_t i;
312
 
313
        // SD cards require at least 8 final clocks
314
        for(i=0;i<10;i++)
315
                spi_byte(0xff);
316
 
317
        SPI_PORT |= (1 << MMC_CS);      // release CS
318
}
319
 
320
 
321
 
322
/** Read MMC/SD sector.
323
         Read a single 512 byte sector from the MMC/SD card
324
        \param lba      Logical sectornumber to read
325
        \param buffer   Pointer to buffer for received data
326
        \return 0 on success, -1 on error
327
*/
328
int mmc_readsector(uint32_t lba, uint8_t *buffer)
329
{
330
        uint16_t i;
331
 
332
        // send read command and logical sector address
333
        mmc_send_command(17,(lba>>7) & 0xffff, (lba<<9) & 0xffff);
334
 
335
        if (mmc_datatoken() != 0xfe)            // if no valid token
336
        {
337
                mmc_clock_and_release();        // cleanup and  
338
                return -1;                      // return error code
339
        }
340
 
341
        for (i=0;i<512;i++)                      // read sector data
342
                *buffer++ = spi_byte(0xff);
343
 
344
        spi_byte(0xff);                         // ignore dummy checksum
345
        spi_byte(0xff);                         // ignore dummy checksum
346
 
347
        mmc_clock_and_release();                // cleanup
348
 
349
        return 0;                                // return success
350
}
351
 
352
//Write MMC/SD sector
353
int mmc_writesector(uint32_t lba, uint8_t *buffer)
354
{
355
        uint16_t i;
356
 
357
        // send write command and logical sector address
358
        mmc_send_command(24,(lba>>7) & 0xffff, (lba<<9) & 0xffff);
359
 
360
        spi_byte(0xfe);                         //Send data token
361
 
362
        for (i=0;i<512;i++)                      //Send sector data
363
                spi_byte(*buffer++);
364
 
365
        spi_byte(0xff);                         //Send dummy 16-bit checksum
366
        spi_byte(0xff);
367
 
368
        if ((mmc_get() & 0x0f) != 0x05) {       //Receive response token
369
                mmc_clock_and_release();
370
                return -1;                      //Write error
371
        }
372
 
373
        while (spi_byte(0xff) == 0x00) {
374
                //Wait for the card to finish writing, this can take
375
                //a very long time, i.e. several hundred milliseconds
376
        }
377
 
378
        mmc_clock_and_release();                //Cleanup
379
 
380
        return 0;                                //Return success
381
}
382
 
383
 
384
 
385
 
386
/** Init MMC/SD card.
387
        Initialize I/O ports for the MMC/SD interface and
388
        send init commands to the MMC/SD card
389
        \return 0 on success, other values on error
390
*/
391
uint8_t mmc_init(void)
392
{
393
//Run configure_spi() to setup the SPI port before initializing MMC.
394
 
395
        int i;
396
 
397
        for(i=0;i<10;i++)                // send 8 clocks while card power stabilizes
398
                spi_byte(0xff);
399
 
400
        mmc_send_command(0,0,0);   // send CMD0 - reset card
401
 
402
        if (mmc_get() != 1)                     // if no valid response code
403
        {
404
                mmc_clock_and_release();
405
                return 1;                               // card cannot be detected
406
        }
407
 
408
        //
409
        // send CMD1 until we get a 0 back, indicating card is done initializing 
410
        //
411
        i = 0xffff;                                             // max timeout
412
        while ((spi_byte(0xff) != 0) && (--i))   // wait for it
413
        {
414
                mmc_send_command(1,0,0);  // send CMD1 - activate card init
415
        }
416
 
417
        mmc_clock_and_release();                // clean up
418
 
419
        if (i == 0)                                              // if we timed out above
420
                return 2;                                       // return failure code
421
 
422
        return 0;
423
}
424
 
425
void
426
mmc_flush(void)
427
{
428
 
429
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.