source: trunk/softs/tsar_boot/src/sdcard.c @ 476

Last change on this file since 476 was 398, checked in by bouyer, 11 years ago

Use 128bits transfers at the SPI controller level when possible;
this speeds up the boot

File size: 6.8 KB
Line 
1/**
2 * \file    : sdcard.c
3 * \date    : 30 August 2012
4 * \author  : Cesar Fuguet
5 *
6 * This file defines the driver of a SD Card device using an SPI controller
7 */
8
9#include <sdcard.h>
10
11/**
12 * \param   sdcard: Initialized pointer to the block device
13 *
14 * \return  void
15 *
16 * \brief   Enable SD Card select signal
17 */
18static void _sdcard_enable(struct sdcard_dev * sdcard)
19{
20    spi_ss_assert(sdcard->spi, sdcard->slave_id);
21}
22
23/**
24 * \param   sdcard: Initialized pointer to the block device
25 *
26 * \return  void
27 *
28 * \brief   Disable SD Card select signal
29 */
30static void _sdcard_disable(struct sdcard_dev * sdcard)
31{
32    spi_ss_deassert(sdcard->spi, sdcard->slave_id);
33}
34
35/**
36 * \param   tick_count: SD Card clock ticks number
37 *
38 * \return  void
39 *
40 * \brief   Enable SD Card clock
41 *          The tick count is byte measured (1 tick, 8 clock)
42 */
43static void _sdcard_gen_tick(struct sdcard_dev * sdcard, unsigned int tick_count)
44{
45    register int i = 0;
46    while(i++ < tick_count) spi_put_tx(sdcard->spi, 0xFF, 0);
47}
48
49/**
50 * \param   sdcard: Initialized pointer to the block device
51 *
52 * \return  char from the SD card
53 *
54 * \brief   Get a byte from the SD Card
55 */
56static unsigned char _sdcard_receive_char(struct sdcard_dev * sdcard)
57{
58    _sdcard_gen_tick(sdcard, 1);
59
60    return spi_get_rx(sdcard->spi, 0);
61}
62
63/**
64 * \param   sdcard: Initialized pointer to the block device
65 *
66 * \return  sdcard response
67 *
68 * \brief   Wait for a valid response after the send of a command
69 *          This function can return if one of the next two conditions are true:
70 *           1. Bit valid received
71 *           2. Timeout (not valid bit received after SDCARD_COMMAND_TIMEOUT
72 *              wait ticks)
73 */
74static unsigned char _sdcard_wait_response(struct sdcard_dev * sdcard)
75{
76    unsigned char sdcard_rsp;
77    register int  iter;
78
79    iter       = 0;
80    sdcard_rsp = _sdcard_receive_char(sdcard);
81    while (
82            (iter < SDCARD_COMMAND_TIMEOUT) &&
83            !SDCARD_CHECK_R1_VALID(sdcard_rsp)
84          )
85    {
86        sdcard_rsp = _sdcard_receive_char(sdcard);
87        iter++;
88    }
89
90    return sdcard_rsp;
91}
92
93/**
94 * \params  sdcard: Initialized pointer to the block device
95 *
96 * \return  void
97 *
98 * \brief   Wait data block start marker
99 */
100static void _sdcard_wait_data_block(struct sdcard_dev * sdcard)
101{
102        while (_sdcard_receive_char(sdcard) != 0xFE);
103}
104
105/**
106 * \param   sdcard  : Initialized pointer to block device
107 * \param   index   : SD card CMD index
108 * \param   app     : Type of command, 0 for normal command or 1 for application specific
109 * \param   args    : SD card CMD arguments
110 *
111 * \return  response first byte
112 *
113 * \brief   Send command to the SD card
114 */
115static int _sdcard_send_command    (
116        struct sdcard_dev * sdcard ,
117        int                 index  ,
118        int                 app    ,
119        void *              args   ,
120        unsigned            crc7   )
121{
122    unsigned char sdcard_rsp;
123    unsigned char * _args;
124
125    _sdcard_gen_tick(sdcard, 5); 
126
127    if (app == SDCARD_ACMD)
128    {
129        spi_put_tx(sdcard->spi, 0x40 | 55         , 0 );/* CMD and START bit */
130        spi_put_tx(sdcard->spi, 0x00              , 0 );/* Argument[0]       */
131        spi_put_tx(sdcard->spi, 0x00              , 0 );/* Argument[1]       */
132        spi_put_tx(sdcard->spi, 0x00              , 0 );/* Argument[2]       */
133        spi_put_tx(sdcard->spi, 0x00              , 0 );/* Argument[3]       */
134        spi_put_tx(sdcard->spi, 0x01 | (crc7 << 1), 0 );/* END bit           */
135
136        sdcard_rsp = _sdcard_wait_response(sdcard);
137        if (SDCARD_CHECK_R1_ERROR(sdcard_rsp))
138        {
139            return sdcard_rsp;       
140        }
141    }
142
143    _args = (unsigned char *) args;
144
145    _sdcard_gen_tick(sdcard, 1); 
146
147    spi_put_tx(sdcard->spi, 0x40 | index      , 0 );
148    spi_put_tx(sdcard->spi, _args[0]          , 0 );
149    spi_put_tx(sdcard->spi, _args[1]          , 0 );
150    spi_put_tx(sdcard->spi, _args[2]          , 0 );
151    spi_put_tx(sdcard->spi, _args[3]          , 0 );
152    spi_put_tx(sdcard->spi, 0x01 | (crc7 << 1), 0 );
153
154    return _sdcard_wait_response(sdcard);
155}
156
157int sdcard_dev_open(struct sdcard_dev * sdcard, struct spi_dev * spi, int ss)
158{
159    unsigned char args[4];
160        unsigned char sdcard_rsp;
161        unsigned int  iter;
162
163        sdcard->spi      = spi;
164    sdcard->slave_id = ss;
165
166        /*
167     * Supply SD card ramp up time (min 74 cycles)
168     */
169        _sdcard_gen_tick(sdcard, 10);
170
171    /*
172     * Assert slave select signal
173     * Send CMD0 (Reset Command)
174     * Deassert slave select signal
175     */
176        _sdcard_enable(sdcard);
177
178    args[0] = 0;
179    args[1] = 0;
180    args[2] = 0;
181    args[3] = 0;
182        sdcard_rsp = _sdcard_send_command(sdcard, 0, SDCARD_CMD, args, 0x4A);
183        if ( sdcard_rsp != 0x01 )
184        {
185                return sdcard_rsp;
186        }
187
188        _sdcard_disable(sdcard);
189        _sdcard_enable(sdcard);
190
191        iter = 0;
192        while( iter++ < SDCARD_COMMAND_TIMEOUT )
193        {
194                sdcard_rsp = _sdcard_send_command(sdcard, 41, SDCARD_ACMD, args, 0x00);
195                if( sdcard_rsp == 0x01 )
196                {
197                        continue;
198                }
199
200                break;
201        }
202
203        _sdcard_disable(sdcard);
204
205        return sdcard_rsp;
206}
207
208int sdcard_dev_read(struct sdcard_dev * sdcard, void * buf, unsigned int count)
209{
210    unsigned char args[4];
211    unsigned char sdcard_rsp;
212    register int  i;
213
214    for (i = 0; i < 4; i++)
215    {
216        args[i] = (sdcard->access_pointer >> (32 - (i+1)*8)) & 0xFF;
217    }
218
219    _sdcard_enable(sdcard);
220
221    sdcard_rsp = _sdcard_send_command(sdcard, 17, SDCARD_CMD, args, 0x00);
222    if ( SDCARD_CHECK_R1_ERROR(sdcard_rsp) )
223    {
224        _sdcard_disable(sdcard);
225        return sdcard_rsp;
226    }
227
228    _sdcard_wait_data_block(sdcard);
229
230    spi_get_data(sdcard->spi, buf, count);
231
232    /*
233     * Get the remainder of the block bytes and the CRC16 (comes
234     * at the end of the data block)
235     */
236    i = count;
237    while( i++ < (sdcard->block_length + 2) ) _sdcard_receive_char(sdcard);
238
239    _sdcard_disable(sdcard);
240
241    /*
242     * Move the access pointer to the next block
243     */
244    sdcard->access_pointer += sdcard->block_length;
245
246    return 0;
247}
248
249unsigned int sdcard_dev_write(struct sdcard_dev *sdcard, void * buf, unsigned int count)
250{
251        return 0;
252}
253
254void sdcard_dev_lseek(struct sdcard_dev * sdcard, unsigned int blk_pos)
255{
256    sdcard->access_pointer = sdcard->block_length * blk_pos;
257}
258
259unsigned int sdcard_dev_get_capacity(struct sdcard_dev * sdcard)
260{
261        return sdcard->capacity;
262}
263
264int sdcard_dev_set_blocklen(struct sdcard_dev * sdcard, unsigned int len)
265{
266    unsigned char args[4];
267    unsigned char sdcard_rsp;
268    register int i;
269
270    for (i = 0; i < 4; i++)
271        args[i] = (len >> (32 - (i+1)*8)) & 0xFF;
272
273    _sdcard_enable(sdcard);
274
275    sdcard_rsp = _sdcard_send_command(sdcard, 16, SDCARD_CMD, args, 0x00);
276    if ( SDCARD_CHECK_R1_ERROR(sdcard_rsp) )
277    {
278        _sdcard_disable(sdcard);
279        return sdcard_rsp;
280    }
281
282    _sdcard_disable(sdcard);
283
284    sdcard->block_length = len;
285
286        return 0;
287}
288
289/*
290 * vim: tabstop=4 : shiftwidth=4 : expandtab : softtabstop=4
291 */
Note: See TracBrowser for help on using the repository browser.