source: PlatformSupport/CustomPeripherals/pcores/simple_spi_v1_00_a/src/simple_spi.c

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