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

Subversion Repositories igor

[/] [igor/] [trunk/] [avr/] [src/] [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
//Initialize igordev
61
void mmcdevice_init()
62
{
63
        igordev_mmc.read_status = igordev_mmc.write_status = IDEV_STATUS_OK;
64
        igordev_mmc.id = (CAN_READ | CAN_WRITE | ADDR_READ | ADDR_WRITE |
65
            (DEVTYPE_STORAGE << DEVTYPE_OFFSET));
66
 
67
        mmc_init();
68
}
69
 
70
/* Write data on the memory card. All transfers are done in sectors of 512
71
 * bytes, so this function will first read the sector from the card, replace the
72
 * modified bytes, and write the sector back.
73
 */
74
uint8_t
75
mmc_send(uint64_t addr, uint8_t *data, uint8_t num)
76
{
77
 
78
        //LBA of the sector we want to read
79
        uint32_t lba = addr/SECTOR_SIZE;
80
 
81
        //Byte position within the sector
82
        uint16_t byte_addr = addr-SECTOR_SIZE*lba;
83
 
84
        //Read the sector that will be overwritten
85
        if (read_sector_to_buffer(lba) != 0) {
86
                //Write error
87
                igordev_mmc.write_status = IDEV_STATUS_ERROR;
88
                return 0;
89
        }
90
 
91
        uint64_t i;
92
 
93
        //Fill the sector with new data
94
        for (i = byte_addr; i < byte_addr + num && i < SECTOR_SIZE; i++) {
95
                sectorbuffer[i] = *data;
96
                data++;
97
        }
98
 
99
        //Write the modified sector back
100
        if (write_buffer_to_sector(lba) != 0) {
101
                //Read error
102
                igordev_mmc.write_status = IDEV_STATUS_ERROR;
103
                return 0;
104
        }
105
 
106
        //Repeat if data spans two sectors
107
        if (byte_addr + num > SECTOR_SIZE) {
108
 
109
                //Read the new sector
110
                if (read_sector_to_buffer(lba+1) != 0) {
111
                        //Read error
112
                        igordev_mmc.write_status = IDEV_STATUS_ERROR;
113
                        return i - byte_addr;
114
                }
115
 
116
                //Store the remaining bytes
117
                uint8_t j;
118
                for (j = 0; j < byte_addr + num - SECTOR_SIZE; j++) {
119
                        sectorbuffer[j] = *data;
120
                        data++;
121
                }
122
 
123
                //Write the modified sector back
124
                if (write_buffer_to_sector(lba+1) != 0) {
125
                        //Write error
126
                        igordev_mmc.write_status = IDEV_STATUS_ERROR;
127
                        return i - byte_addr;
128
                }
129
 
130
                igordev_mmc.write_status = IDEV_STATUS_OK;
131
                return j + i - addr;
132
        }
133
 
134
        igordev_mmc.write_status = IDEV_STATUS_OK;
135
        return (i - addr) ;
136
}
137
 
138
/* Read data from the memory card. All transfers are done in sectors of 512
139
 * bytes, so this function will first read the sector from the card, extract
140
 * the requested bytes and write them to the given data buffer.
141
 */
142
uint8_t
143
mmc_recv(uint64_t addr, uint8_t *data, uint8_t num)
144
{
145
 
146
        //LBA of the sector we want to read
147
        uint32_t lba = addr/SECTOR_SIZE;
148
 
149
        //Byte position within the sector
150
        uint16_t byte_addr = addr-SECTOR_SIZE*lba;
151
 
152
        //Read the sector
153
        if (read_sector_to_buffer(lba) != 0) {
154
                //Read error
155
                igordev_mmc.read_status = IDEV_STATUS_ERROR;
156
                return 0;
157
        }
158
 
159
        uint64_t i;
160
 
161
        //Loop through the sector data and store only the bytes that we want
162
        //for (i = byte_addr; i < byte_addr + num && i < SECTOR_SIZE; i++) {
163
        //      *data++ = sectorbuffer[i];
164
        for (i = byte_addr; i < byte_addr + num && i < SECTOR_SIZE; i++) {
165
                *data = sectorbuffer[i];
166
                data++;
167
        }
168
 
169
        if (byte_addr + num > SECTOR_SIZE) {
170
                //We didn't get all of the data in the first go,
171
                //so we must continue reading on the next sector
172
 
173
                //Read the new sector
174
                if (read_sector_to_buffer(lba+1) != 0) {
175
                        //Read error
176
                        igordev_mmc.read_status = IDEV_STATUS_ERROR;
177
                        return i - byte_addr;
178
                }
179
 
180
                //Store the remaining bytes
181
                uint8_t j;
182
                for (j = 0; j < byte_addr + num - SECTOR_SIZE; j++) {
183
                        *data = sectorbuffer[j];
184
                        data++;
185
                }
186
 
187
                igordev_mmc.read_status = IDEV_STATUS_OK;
188
                return j + i - addr;
189
        }
190
 
191
        igordev_mmc.read_status = IDEV_STATUS_OK;
192
        return (i - addr) ;
193
}
194
 
195
//Read a sector into the sector buffer
196
uint8_t read_sector_to_buffer(uint32_t lba)
197
{
198
        if (buffered_lba != lba) {
199
                if (mmc_readsector(lba, sectorbuffer) != 0) {
200
                        //We have a read error
201
 
202
                        //The buffered sector may be corrupted,
203
                        //so we make sure it's invalidated
204
                        buffered_lba = -1;
205
 
206
                        return 1;
207
 
208
                } else { //Successful read
209
                        buffered_lba = lba;
210
                        return 0;
211
                }
212
        }
213
        return 0;
214
}
215
 
216
//Write the sector buffer into a sector
217
uint8_t write_buffer_to_sector(uint32_t lba)
218
{
219
        if (mmc_writesector(lba, sectorbuffer) != 0) {
220
                //We have a write error
221
 
222
                //Invalidate the buffered sector
223
                buffered_lba = -1;
224
 
225
                return 1;
226
 
227
        } else { //Successful write
228
                buffered_lba = lba;
229
                return 0;
230
        }
231
}
232
 
233
/** Hardware SPI I/O.
234
        \param byte Data to send over SPI bus
235
        \return Received data from SPI bus
236
*/
237
uint8_t spi_byte(uint8_t byte)
238
{
239
        SPDR = byte;
240
        while(!(SPSR & (1<<SPIF)))
241
        {}
242
        return SPDR;
243
}
244
 
245
 
246
 
247
/** Send a command to the MMC/SD card.
248
        \param command  Command to send
249
        \param px       Command parameter 1
250
        \param py       Command parameter 2
251
*/
252
void mmc_send_command(uint8_t command, uint16_t px, uint16_t py)
253
{
254
        register union u16convert r;
255
 
256
        SPI_PORT &= ~(1 << MMC_CS);     // enable CS
257
 
258
        spi_byte(0xff);                 // dummy byte
259
 
260
        spi_byte(command | 0x40);
261
 
262
        r.value = px;
263
        spi_byte(r.bytes.high); // high byte of param x
264
        spi_byte(r.bytes.low);  // low byte of param x
265
 
266
        r.value = py;
267
        spi_byte(r.bytes.high); // high byte of param y
268
        spi_byte(r.bytes.low);  // low byte of param y
269
 
270
        spi_byte(0x95); // correct CRC for first command in SPI.
271
                        // After that CRC is ignored, so no problem with
272
                        // always sending 0x95
273
 
274
        spi_byte(0xff); // ignore return byte
275
}
276
 
277
 
278
/** Get Token.
279
        Wait for and return a non-ff token from the MMC/SD card
280
        \return The received token or 0xFF if timeout
281
*/
282
uint8_t mmc_get(void)
283
{
284
        uint16_t i = 0xffff;
285
        uint8_t b = 0xff;
286
 
287
        while ((b == 0xff) && (--i))
288
        {
289
                b = spi_byte(0xff);
290
        }
291
        return b;
292
 
293
}
294
 
295
/** Get Datatoken.
296
        Wait for and return a data token from the MMC/SD card
297
        \return The received token or 0xFF if timeout
298
*/
299
uint8_t mmc_datatoken(void)
300
{
301
        uint16_t i = 0xffff;
302
        uint8_t b = 0xff;
303
 
304
        while ((b != 0xfe) && (--i))
305
        {
306
                b = spi_byte(0xff);
307
        }
308
        return b;
309
}
310
 
311
 
312
/** Finish Clocking and Release card.
313
        Send 10 clocks to the MMC/SD card
314
        and release the CS line
315
*/
316
void mmc_clock_and_release(void)
317
{
318
        uint8_t i;
319
 
320
        // SD cards require at least 8 final clocks
321
        for(i=0;i<10;i++)
322
                spi_byte(0xff);
323
 
324
        SPI_PORT |= (1 << MMC_CS);      // release CS
325
}
326
 
327
 
328
 
329
/** Read MMC/SD sector.
330
         Read a single 512 byte sector from the MMC/SD card
331
        \param lba      Logical sectornumber to read
332
        \param buffer   Pointer to buffer for received data
333
        \return 0 on success, -1 on error
334
*/
335
int mmc_readsector(uint32_t lba, uint8_t *buffer)
336
{
337
        uint16_t i;
338
 
339
        // send read command and logical sector address
340
        mmc_send_command(17,(lba>>7) & 0xffff, (lba<<9) & 0xffff);
341
 
342
        if (mmc_datatoken() != 0xfe)            // if no valid token
343
        {
344
                mmc_clock_and_release();        // cleanup and  
345
                return -1;                      // return error code
346
        }
347
 
348
        for (i=0;i<512;i++)                      // read sector data
349
                *buffer++ = spi_byte(0xff);
350
 
351
        spi_byte(0xff);                         // ignore dummy checksum
352
        spi_byte(0xff);                         // ignore dummy checksum
353
 
354
        mmc_clock_and_release();                // cleanup
355
 
356
        return 0;                                // return success
357
}
358
 
359
//Write MMC/SD sector
360
int mmc_writesector(uint32_t lba, uint8_t *buffer)
361
{
362
        uint16_t i;
363
 
364
        // send write command and logical sector address
365
        mmc_send_command(24,(lba>>7) & 0xffff, (lba<<9) & 0xffff);
366
 
367
        spi_byte(0xfe);                         //Send data token
368
 
369
        for (i=0;i<512;i++)                      //Send sector data
370
                spi_byte(*buffer++);
371
 
372
        spi_byte(0xff);                         //Send dummy 16-bit checksum
373
        spi_byte(0xff);
374
 
375
        if ((mmc_get() & 0x0f) != 0x05) {       //Receive response token
376
                mmc_clock_and_release();
377
                return -1;                      //Write error
378
        }
379
 
380
        while (spi_byte(0xff) == 0x00) {
381
                //Wait for the card to finish writing, this can take
382
                //a very long time, i.e. several hundred milliseconds
383
        }
384
 
385
        mmc_clock_and_release();                //Cleanup
386
 
387
        return 0;                                //Return success
388
}
389
 
390
 
391
 
392
 
393
/** Init MMC/SD card.
394
        Initialize I/O ports for the MMC/SD interface and
395
        send init commands to the MMC/SD card
396
        \return 0 on success, other values on error
397
*/
398
uint8_t mmc_init(void)
399
{
400
//Run configure_spi() to setup the SPI port before initializing MMC.
401
 
402
        int i;
403
 
404
        for(i=0;i<10;i++)        // send 8 clocks while card power stabilizes
405
                spi_byte(0xff);
406
 
407
        mmc_send_command(0,0,0);   // send CMD0 - reset card
408
 
409
        if (mmc_get() != 1)                     // if no valid response code
410
        {
411
                mmc_clock_and_release();
412
                return 1;                       // card cannot be detected
413
        }
414
 
415
        //
416
        // send CMD1 until we get a 0 back, indicating card is done initializing 
417
        //
418
        i = 0xffff;                             // max timeout
419
        while ((spi_byte(0xff) != 0) && (--i))   // wait for it
420
        {
421
                mmc_send_command(1,0,0);  // send CMD1 - activate card init
422
        }
423
 
424
        mmc_clock_and_release();                // clean up
425
 
426
        if (i == 0)                              // if we timed out above
427
                return 2;                       // return failure code
428
 
429
        return 0;
430
}
431
 
432
void
433
mmc_flush(void) {}

powered by: WebSVN 2.1.0

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