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

Last change on this file since 390 was 388, checked in by cfuguet, 11 years ago

Modifications in tsar/trunk/softs/tsar_boot:

  • Improving the boot_ioc_read when using a SD card in FPGA platform.
  • Adding some instrumentation on the SD card driver (under preprocessor conditional directives).
  • Including Doxyfile for generate documentation using doxygen.
  • Improving the Makefile to include doc generation.
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    for ( i = 0; i < count; i++ )
231    {
232        *((char *) buf + i) = _sdcard_receive_char(sdcard);
233    }
234
235    /*
236     * Get the remainder of the block bytes and the CRC16 (comes
237     * at the end of the data block)
238     */
239    while( i++ < (sdcard->block_length + 2) ) _sdcard_receive_char(sdcard);
240
241    _sdcard_disable(sdcard);
242
243    /*
244     * Move the access pointer to the next block
245     */
246    sdcard->access_pointer += sdcard->block_length;
247
248    return 0;
249}
250
251unsigned int sdcard_dev_write(struct sdcard_dev *sdcard, void * buf, unsigned int count)
252{
253        return 0;
254}
255
256void sdcard_dev_lseek(struct sdcard_dev * sdcard, unsigned int blk_pos)
257{
258    sdcard->access_pointer = sdcard->block_length * blk_pos;
259}
260
261unsigned int sdcard_dev_get_capacity(struct sdcard_dev * sdcard)
262{
263        return sdcard->capacity;
264}
265
266int sdcard_dev_set_blocklen(struct sdcard_dev * sdcard, unsigned int len)
267{
268    unsigned char args[4];
269    unsigned char sdcard_rsp;
270    register int i;
271
272    for (i = 0; i < 4; i++)
273        args[i] = (len >> (32 - (i+1)*8)) & 0xFF;
274
275    _sdcard_enable(sdcard);
276
277    sdcard_rsp = _sdcard_send_command(sdcard, 16, SDCARD_CMD, args, 0x00);
278    if ( SDCARD_CHECK_R1_ERROR(sdcard_rsp) )
279    {
280        _sdcard_disable(sdcard);
281        return sdcard_rsp;
282    }
283
284    _sdcard_disable(sdcard);
285
286    sdcard->block_length = len;
287
288        return 0;
289}
290
291/*
292 * vim: tabstop=4 : shiftwidth=4 : expandtab : softtabstop=4
293 */
Note: See TracBrowser for help on using the repository browser.