source: PlatformSupport/CustomPeripherals/pcores/w3_sd_spi_v1_00_a/src/sd_spi.c

Last change on this file was 2447, checked in by murphpo, 10 years ago
File size: 5.0 KB
Line 
1/*****************************************************************
2* File: sd_spi.c
3* Copyright (c) 2013 Mango Communications, all rights reseved
4* Released under the WARP License
5* See http://warpproject.org/license for details
6*****************************************************************/
7#include "sd_spi.h"
8
9inline u8 simple_spi_read(u32 baseaddr) {
10    Xil_Out32(baseaddr + SSPI_REG_SPITX, 0xFF);
11    return (u8)(Xil_In32(baseaddr + SSPI_REG_SPIRX) & 0xFF);
12}
13
14inline void simple_spi_write(u32 baseaddr, u8 txByte) {
15    Xil_Out32(baseaddr + SSPI_REG_SPITX, (u32)(txByte & 0xFF));
16    return;
17}
18
19void sd_send_cmd(u32 ba, u8 cmd, u32 args, u8 last_byte) {
20
21    simple_spi_write(ba, 0xFF); //flush that Sandisk cards seem to require...
22    simple_spi_write(ba, cmd);
23    simple_spi_write(ba, (u8)(0xFF & (args>>24)));
24    simple_spi_write(ba, (u8)(0xFF & (args>>16)));
25    simple_spi_write(ba, (u8)(0xFF & (args>> 8)));
26    simple_spi_write(ba, (u8)(0xFF & (args>> 0)));
27    simple_spi_write(ba, last_byte);
28}
29
30
31int sd_read_block(u32 ba, u32 blk_offset, u8* buf, u32 blk_size) {
32    int i;
33    u8 rx_byte;
34
35    sd_send_cmd(ba, SD_CMD17, blk_offset, 0x01);
36
37    for(i=0; i<8; i++) {
38        rx_byte = simple_spi_read(ba);
39        if(rx_byte == 0xFF) continue;
40        if(rx_byte == 0x00) break;
41    }
42
43    for(i=0; i<100; i++) {
44        usleep(10000);
45        rx_byte = simple_spi_read(ba);
46        if(rx_byte == SD_DATA_TOKEN_RD) break;
47    }
48    if(i==100) {xil_printf("sd_read_block: No token received - Quitting\n"); return -1;}
49
50    //Read exactly blk_size bytes
51    for(i=0; i<blk_size; i++) {
52        buf[i] = simple_spi_read(ba);
53    }
54
55    //Read and discard CRC bytes
56    simple_spi_read(ba);
57    simple_spi_read(ba);
58
59    return 0;
60}
61
62int sd_write_block(u32 ba, u32 blk_offset, u8* buf, u32 blk_size) {
63    int i;
64    u8 rx_byte;
65
66    sd_send_cmd(ba, SD_CMD24, blk_offset, 0x01);
67
68    for(i=0; i<8; i++) {
69        rx_byte = simple_spi_read(ba);
70        if(rx_byte == 0xFF) continue;
71        if(rx_byte == 0x00) break;
72    }
73    if(i==8) {xil_printf("CMD24 error - invalid response\n"); return -1;}
74
75    //Send 1-byte write token
76    simple_spi_write(ba, SD_DATA_TOKEN_WR_SINGLE);
77
78    //Send blk_size bytes
79    for(i=0; i<blk_size; i++) {
80        simple_spi_write(ba, buf[i]);
81    }
82
83    //Write dummy 2-byte CRC (CRC not checked in SPI mode)
84    simple_spi_write(ba, 0xFF);
85    simple_spi_write(ba, 0xFF);
86
87    //Read data response
88    rx_byte = simple_spi_read(ba);
89    if((rx_byte & 0x1F) != 0x05) {xil_printf("Write data response indicated error[%2d]: 0x%02x\n", i, rx_byte); return -1;}
90
91    //Wait for SD card to indicate write is finished
92    rx_byte = 0x00; i=0;
93    while(rx_byte != 0xFF) {
94        rx_byte = simple_spi_read(ba);
95        i++;
96    }
97    //xil_printf("Idle after %d byte reads\n", i);
98
99    return 0;
100}
101
102int sd_rw_init(u32 ba) {
103    int i, j;
104    int init_tries;
105    u8 sd_idle;
106    u8 rx_byte;
107
108    //SD cards I tested don't seem to require a slow clock for init
109
110    //CLK_DIV param selects bit index in clk counter
111    // Higher index -> faster SCLK
112    // For 80MHz bus clock CLK_DIV=6 -> SCLK=20MHz
113    simple_spi_set_clkDiv(ba, 6);
114
115    //CMD0 sometimes fails on the first try - try it twice before punting
116    for(j=0; j<2; j++) {
117        //SD init requires >74 SCLK cycles with CS de-asserted and MOSI = 1
118        simple_spi_set_cs(ba, 0);
119        for(i=0; i<20; i++) {
120            simple_spi_write(ba, 0xFF);
121        }
122
123        //Wait for a while before sending IDLE command
124        usleep(10000);
125
126        //Assert CS and leave asserted
127        simple_spi_set_cs(ba, 1);
128
129        //Send GO_IDLE command
130        // 0x95 is valid CRC for CMD0 msg
131        // Later cmds don't need CRC (ignored in SPI mode)
132        sd_send_cmd(ba, SD_CMD0, 0x0, 0x95);
133
134        //Wait for command response
135        // Response should be 0x01 = No errors, IDLE=1
136        for(i=0; i<32; i++) {
137            rx_byte = simple_spi_read(ba);
138
139            if(rx_byte == 0xFF) continue;
140            else if(rx_byte == 0x01) break;
141        }
142        if(j==1 && i==32) {
143            //Punt if both CMD0 attempts fail
144            xil_printf("Error in CMD0 - no valid response\n");
145            return -1;
146        }
147    }
148
149    //Start SD card init with CMD55-ACMD41 sequence
150    // Keep sending these commands until the card reports not-IDLE
151    sd_idle = 1;
152    init_tries = 0;
153    while((sd_idle == 1) && (init_tries < 64)) {
154        sd_send_cmd(ba, SD_CMD55, 0x0, 0x01);
155        for(i=0; i<8; i++) {
156            rx_byte = simple_spi_read(ba);
157            if(rx_byte == 0xFF) continue;
158            //xil_printf("CMD55 [%02d]: rx_byte = 0x%02x\n", i, rx_byte);
159            if((rx_byte & 0x1) == 0) {sd_idle = 0; break;}
160        }
161
162        sd_send_cmd(ba, SD_ACMD41, 0x0, 0x01);
163        for(i=0; i<8; i++) {
164            rx_byte = simple_spi_read(ba);
165            if(rx_byte == 0xFF) continue;
166            //xil_printf("ACMD41 [%02d]: rx_byte = 0x%02x\n", i, rx_byte);
167            if((rx_byte & 0x1) == 0) {sd_idle = 0; break;}
168        }
169        usleep(100000);
170        init_tries++;
171    }
172    if(sd_idle == 1) {xil_printf("Error in SD init - ACMD41 never reported not IDLE\n"); return -1;}
173
174    //Set block length to 512B
175    sd_send_cmd(ba, SD_CMD16, SD_BLK_SIZE, 0x01);
176    for(i=0; i<8; i++) {
177        rx_byte = simple_spi_read(ba);
178        if(rx_byte == 0xFF) continue;
179        if(rx_byte == 0x00) break;
180    }
181    if(i==8) {xil_printf("Error in CMD16 - no valid response\n"); return -1;}
182
183    return 0;
184}
Note: See TracBrowser for help on using the repository browser.