| 1144 | kaklik | 1 |  | 
      
        |  |  | 2 | /* | 
      
        |  |  | 3 |  * Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> | 
      
        |  |  | 4 |  * | 
      
        |  |  | 5 |  * This file is free software; you can redistribute it and/or modify | 
      
        |  |  | 6 |  * it under the terms of either the GNU General Public License version 2 | 
      
        |  |  | 7 |  * or the GNU Lesser General Public License version 2.1, both as | 
      
        |  |  | 8 |  * published by the Free Software Foundation. | 
      
        |  |  | 9 |  */ | 
      
        |  |  | 10 |  | 
      
        |  |  | 11 | #include <string.h> | 
      
        |  |  | 12 | #include <avr/io.h> | 
      
        |  |  | 13 | #include "sd_raw.h" | 
      
        |  |  | 14 |  | 
      
        |  |  | 15 | /** | 
      
        |  |  | 16 |  * \addtogroup sd_raw MMC/SD card raw access | 
      
        |  |  | 17 |  * | 
      
        |  |  | 18 |  * This module implements read and write access to MMC and | 
      
        |  |  | 19 |  * SD cards. It serves as a low-level driver for the higher | 
      
        |  |  | 20 |  * level modules such as partition and file system access. | 
      
        |  |  | 21 |  * | 
      
        |  |  | 22 |  * @{ | 
      
        |  |  | 23 |  */ | 
      
        |  |  | 24 | /** | 
      
        |  |  | 25 |  * \file | 
      
        |  |  | 26 |  * MMC/SD raw access implementation (license: GPLv2 or LGPLv2.1) | 
      
        |  |  | 27 |  * | 
      
        |  |  | 28 |  * \author Roland Riegel | 
      
        |  |  | 29 |  */ | 
      
        |  |  | 30 |  | 
      
        |  |  | 31 | /** | 
      
        |  |  | 32 |  * \addtogroup sd_raw_config MMC/SD configuration | 
      
        |  |  | 33 |  * Preprocessor defines to configure the MMC/SD support. | 
      
        |  |  | 34 |  */ | 
      
        |  |  | 35 |  | 
      
        |  |  | 36 | /** | 
      
        |  |  | 37 |  * @} | 
      
        |  |  | 38 |  */ | 
      
        |  |  | 39 |  | 
      
        |  |  | 40 | /* commands available in SPI mode */ | 
      
        |  |  | 41 |  | 
      
        |  |  | 42 | /* CMD0: response R1 */ | 
      
        |  |  | 43 | #define CMD_GO_IDLE_STATE 0x00 | 
      
        |  |  | 44 | /* CMD1: response R1 */ | 
      
        |  |  | 45 | #define CMD_SEND_OP_COND 0x01 | 
      
        |  |  | 46 | /* CMD9: response R1 */ | 
      
        |  |  | 47 | #define CMD_SEND_CSD 0x09 | 
      
        |  |  | 48 | /* CMD10: response R1 */ | 
      
        |  |  | 49 | #define CMD_SEND_CID 0x0a | 
      
        |  |  | 50 | /* CMD12: response R1 */ | 
      
        |  |  | 51 | #define CMD_STOP_TRANSMISSION 0x0c | 
      
        |  |  | 52 | /* CMD13: response R2 */ | 
      
        |  |  | 53 | #define CMD_SEND_STATUS 0x0d | 
      
        |  |  | 54 | /* CMD16: arg0[31:0]: block length, response R1 */ | 
      
        |  |  | 55 | #define CMD_SET_BLOCKLEN 0x10 | 
      
        |  |  | 56 | /* CMD17: arg0[31:0]: data address, response R1 */ | 
      
        |  |  | 57 | #define CMD_READ_SINGLE_BLOCK 0x11 | 
      
        |  |  | 58 | /* CMD18: arg0[31:0]: data address, response R1 */ | 
      
        |  |  | 59 | #define CMD_READ_MULTIPLE_BLOCK 0x12 | 
      
        |  |  | 60 | /* CMD24: arg0[31:0]: data address, response R1 */ | 
      
        |  |  | 61 | #define CMD_WRITE_SINGLE_BLOCK 0x18 | 
      
        |  |  | 62 | /* CMD25: arg0[31:0]: data address, response R1 */ | 
      
        |  |  | 63 | #define CMD_WRITE_MULTIPLE_BLOCK 0x19 | 
      
        |  |  | 64 | /* CMD27: response R1 */ | 
      
        |  |  | 65 | #define CMD_PROGRAM_CSD 0x1b | 
      
        |  |  | 66 | /* CMD28: arg0[31:0]: data address, response R1b */ | 
      
        |  |  | 67 | #define CMD_SET_WRITE_PROT 0x1c | 
      
        |  |  | 68 | /* CMD29: arg0[31:0]: data address, response R1b */ | 
      
        |  |  | 69 | #define CMD_CLR_WRITE_PROT 0x1d | 
      
        |  |  | 70 | /* CMD30: arg0[31:0]: write protect data address, response R1 */ | 
      
        |  |  | 71 | #define CMD_SEND_WRITE_PROT 0x1e | 
      
        |  |  | 72 | /* CMD32: arg0[31:0]: data address, response R1 */ | 
      
        |  |  | 73 | #define CMD_TAG_SECTOR_START 0x20 | 
      
        |  |  | 74 | /* CMD33: arg0[31:0]: data address, response R1 */ | 
      
        |  |  | 75 | #define CMD_TAG_SECTOR_END 0x21 | 
      
        |  |  | 76 | /* CMD34: arg0[31:0]: data address, response R1 */ | 
      
        |  |  | 77 | #define CMD_UNTAG_SECTOR 0x22 | 
      
        |  |  | 78 | /* CMD35: arg0[31:0]: data address, response R1 */ | 
      
        |  |  | 79 | #define CMD_TAG_ERASE_GROUP_START 0x23 | 
      
        |  |  | 80 | /* CMD36: arg0[31:0]: data address, response R1 */ | 
      
        |  |  | 81 | #define CMD_TAG_ERASE_GROUP_END 0x24 | 
      
        |  |  | 82 | /* CMD37: arg0[31:0]: data address, response R1 */ | 
      
        |  |  | 83 | #define CMD_UNTAG_ERASE_GROUP 0x25 | 
      
        |  |  | 84 | /* CMD38: arg0[31:0]: stuff bits, response R1b */ | 
      
        |  |  | 85 | #define CMD_ERASE 0x26 | 
      
        |  |  | 86 | /* CMD42: arg0[31:0]: stuff bits, response R1b */ | 
      
        |  |  | 87 | #define CMD_LOCK_UNLOCK 0x2a | 
      
        |  |  | 88 | /* CMD58: response R3 */ | 
      
        |  |  | 89 | #define CMD_READ_OCR 0x3a | 
      
        |  |  | 90 | /* CMD59: arg0[31:1]: stuff bits, arg0[0:0]: crc option, response R1 */ | 
      
        |  |  | 91 | #define CMD_CRC_ON_OFF 0x3b | 
      
        |  |  | 92 |  | 
      
        |  |  | 93 | /* command responses */ | 
      
        |  |  | 94 | /* R1: size 1 byte */ | 
      
        |  |  | 95 | #define R1_IDLE_STATE 0 | 
      
        |  |  | 96 | #define R1_ERASE_RESET 1 | 
      
        |  |  | 97 | #define R1_ILL_COMMAND 2 | 
      
        |  |  | 98 | #define R1_COM_CRC_ERR 3 | 
      
        |  |  | 99 | #define R1_ERASE_SEQ_ERR 4 | 
      
        |  |  | 100 | #define R1_ADDR_ERR 5 | 
      
        |  |  | 101 | #define R1_PARAM_ERR 6 | 
      
        |  |  | 102 | /* R1b: equals R1, additional busy bytes */ | 
      
        |  |  | 103 | /* R2: size 2 bytes */ | 
      
        |  |  | 104 | #define R2_CARD_LOCKED 0 | 
      
        |  |  | 105 | #define R2_WP_ERASE_SKIP 1 | 
      
        |  |  | 106 | #define R2_ERR 2 | 
      
        |  |  | 107 | #define R2_CARD_ERR 3 | 
      
        |  |  | 108 | #define R2_CARD_ECC_FAIL 4 | 
      
        |  |  | 109 | #define R2_WP_VIOLATION 5 | 
      
        |  |  | 110 | #define R2_INVAL_ERASE 6 | 
      
        |  |  | 111 | #define R2_OUT_OF_RANGE 7 | 
      
        |  |  | 112 | #define R2_CSD_OVERWRITE 7 | 
      
        |  |  | 113 | #define R2_IDLE_STATE (R1_IDLE_STATE + 8) | 
      
        |  |  | 114 | #define R2_ERASE_RESET (R1_ERASE_RESET + 8) | 
      
        |  |  | 115 | #define R2_ILL_COMMAND (R1_ILL_COMMAND + 8) | 
      
        |  |  | 116 | #define R2_COM_CRC_ERR (R1_COM_CRC_ERR + 8) | 
      
        |  |  | 117 | #define R2_ERASE_SEQ_ERR (R1_ERASE_SEQ_ERR + 8) | 
      
        |  |  | 118 | #define R2_ADDR_ERR (R1_ADDR_ERR + 8) | 
      
        |  |  | 119 | #define R2_PARAM_ERR (R1_PARAM_ERR + 8) | 
      
        |  |  | 120 | /* R3: size 5 bytes */ | 
      
        |  |  | 121 | #define R3_OCR_MASK (0xffffffffUL) | 
      
        |  |  | 122 | #define R3_IDLE_STATE (R1_IDLE_STATE + 32) | 
      
        |  |  | 123 | #define R3_ERASE_RESET (R1_ERASE_RESET + 32) | 
      
        |  |  | 124 | #define R3_ILL_COMMAND (R1_ILL_COMMAND + 32) | 
      
        |  |  | 125 | #define R3_COM_CRC_ERR (R1_COM_CRC_ERR + 32) | 
      
        |  |  | 126 | #define R3_ERASE_SEQ_ERR (R1_ERASE_SEQ_ERR + 32) | 
      
        |  |  | 127 | #define R3_ADDR_ERR (R1_ADDR_ERR + 32) | 
      
        |  |  | 128 | #define R3_PARAM_ERR (R1_PARAM_ERR + 32) | 
      
        |  |  | 129 | /* Data Response: size 1 byte */ | 
      
        |  |  | 130 | #define DR_STATUS_MASK 0x0e | 
      
        |  |  | 131 | #define DR_STATUS_ACCEPTED 0x05 | 
      
        |  |  | 132 | #define DR_STATUS_CRC_ERR 0x0a | 
      
        |  |  | 133 | #define DR_STATUS_WRITE_ERR 0x0c | 
      
        |  |  | 134 |  | 
      
        |  |  | 135 | #if !SD_RAW_SAVE_RAM | 
      
        |  |  | 136 |  | 
      
        |  |  | 137 | /* static data buffer for acceleration */ | 
      
        |  |  | 138 | static uint8_t raw_block[512]; | 
      
        |  |  | 139 | /* offset where the data within raw_block lies on the card */ | 
      
        |  |  | 140 | static uint32_t raw_block_address; | 
      
        |  |  | 141 | #if SD_RAW_WRITE_BUFFERING | 
      
        |  |  | 142 | /* flag to remember if raw_block was written to the card */ | 
      
        |  |  | 143 | static uint8_t raw_block_written; | 
      
        |  |  | 144 | #endif | 
      
        |  |  | 145 |  | 
      
        |  |  | 146 | #endif | 
      
        |  |  | 147 |  | 
      
        |  |  | 148 | /* private helper functions */ | 
      
        |  |  | 149 | static void sd_raw_send_byte(uint8_t b); | 
      
        |  |  | 150 | static uint8_t sd_raw_rec_byte(); | 
      
        |  |  | 151 | static uint8_t sd_raw_send_command_r1(uint8_t command, uint32_t arg); | 
      
        |  |  | 152 | static uint16_t sd_raw_send_command_r2(uint8_t command, uint32_t arg); | 
      
        |  |  | 153 |  | 
      
        |  |  | 154 | /** | 
      
        |  |  | 155 |  * \ingroup sd_raw | 
      
        |  |  | 156 |  * Initializes memory card communication. | 
      
        |  |  | 157 |  * | 
      
        |  |  | 158 |  * \returns 0 on failure, 1 on success. | 
      
        |  |  | 159 |  */ | 
      
        |  |  | 160 | uint8_t sd_raw_init() | 
      
        |  |  | 161 | { | 
      
        |  |  | 162 |     /* enable inputs for reading card status */ | 
      
        |  |  | 163 |     configure_pin_available(); | 
      
        |  |  | 164 |     configure_pin_locked(); | 
      
        |  |  | 165 |  | 
      
        |  |  | 166 |     /* enable outputs for MOSI, SCK, SS, input for MISO */ | 
      
        |  |  | 167 |     configure_pin_mosi(); | 
      
        |  |  | 168 |     configure_pin_sck(); | 
      
        |  |  | 169 |     configure_pin_ss(); | 
      
        |  |  | 170 |     configure_pin_miso(); | 
      
        |  |  | 171 |  | 
      
        |  |  | 172 |     unselect_card(); | 
      
        |  |  | 173 |  | 
      
        |  |  | 174 |     /* initialize SPI with lowest frequency; max. 400kHz during identification mode of card */ | 
      
        |  |  | 175 |     SPCR = (0 << SPIE) | /* SPI Interrupt Enable */ | 
      
        |  |  | 176 |            (1 << SPE)  | /* SPI Enable */ | 
      
        |  |  | 177 |            (0 << DORD) | /* Data Order: MSB first */ | 
      
        |  |  | 178 |            (1 << MSTR) | /* Master mode */ | 
      
        |  |  | 179 |            (0 << CPOL) | /* Clock Polarity: SCK low when idle */ | 
      
        |  |  | 180 |            (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */ | 
      
        |  |  | 181 |            (1 << SPR1) | /* Clock Frequency: f_OSC / 128 */ | 
      
        |  |  | 182 |            (1 << SPR0); | 
      
        |  |  | 183 |     SPSR &= ~(1 << SPI2X); /* No doubled clock frequency */ | 
      
        |  |  | 184 |  | 
      
        |  |  | 185 |     /* initialization procedure */ | 
      
        |  |  | 186 |  | 
      
        |  |  | 187 |     if(!sd_raw_available()) | 
      
        |  |  | 188 |         return 0; | 
      
        |  |  | 189 |  | 
      
        |  |  | 190 |     /* card needs 74 cycles minimum to start up */ | 
      
        |  |  | 191 |     for(uint8_t i = 0; i < 10; ++i) | 
      
        |  |  | 192 |     { | 
      
        |  |  | 193 |         /* wait 8 clock cycles */ | 
      
        |  |  | 194 |         sd_raw_rec_byte(); | 
      
        |  |  | 195 |     } | 
      
        |  |  | 196 |  | 
      
        |  |  | 197 |     /* address card */ | 
      
        |  |  | 198 |     select_card(); | 
      
        |  |  | 199 |  | 
      
        |  |  | 200 |     /* reset card */ | 
      
        |  |  | 201 |     uint8_t response; | 
      
        |  |  | 202 |     for(uint16_t i = 0; ; ++i) | 
      
        |  |  | 203 |     { | 
      
        |  |  | 204 |         response = sd_raw_send_command_r1(CMD_GO_IDLE_STATE, 0); | 
      
        |  |  | 205 |         if(response == (1 << R1_IDLE_STATE)) | 
      
        |  |  | 206 |             break; | 
      
        |  |  | 207 |  | 
      
        |  |  | 208 |         if(i == 0x1ff) | 
      
        |  |  | 209 |         { | 
      
        |  |  | 210 |             unselect_card(); | 
      
        |  |  | 211 |             return 0; | 
      
        |  |  | 212 |         } | 
      
        |  |  | 213 |     } | 
      
        |  |  | 214 |  | 
      
        |  |  | 215 |     /* wait for card to get ready */ | 
      
        |  |  | 216 |     for(uint16_t i = 0; ; ++i) | 
      
        |  |  | 217 |     { | 
      
        |  |  | 218 |         response = sd_raw_send_command_r1(CMD_SEND_OP_COND, 0); | 
      
        |  |  | 219 |         if(!(response & (1 << R1_IDLE_STATE))) | 
      
        |  |  | 220 |             break; | 
      
        |  |  | 221 |  | 
      
        |  |  | 222 |         if(i == 0x7fff) | 
      
        |  |  | 223 |         { | 
      
        |  |  | 224 |             unselect_card(); | 
      
        |  |  | 225 |             return 0; | 
      
        |  |  | 226 |         } | 
      
        |  |  | 227 |     } | 
      
        |  |  | 228 |  | 
      
        |  |  | 229 |     /* set block size to 512 bytes */ | 
      
        |  |  | 230 |     if(sd_raw_send_command_r1(CMD_SET_BLOCKLEN, 512)) | 
      
        |  |  | 231 |     { | 
      
        |  |  | 232 |         unselect_card(); | 
      
        |  |  | 233 |         return 0; | 
      
        |  |  | 234 |     } | 
      
        |  |  | 235 |  | 
      
        |  |  | 236 |     /* deaddress card */ | 
      
        |  |  | 237 |     unselect_card(); | 
      
        |  |  | 238 |  | 
      
        |  |  | 239 |     /* switch to highest SPI frequency possible */ | 
      
        |  |  | 240 |     SPCR &= ~((1 << SPR1) | (1 << SPR0)); /* Clock Frequency: f_OSC / 4 */ | 
      
        |  |  | 241 |     SPSR |= (1 << SPI2X); /* Doubled Clock Frequency: f_OSC / 2 */ | 
      
        |  |  | 242 |  | 
      
        |  |  | 243 | #if !SD_RAW_SAVE_RAM | 
      
        |  |  | 244 |     /* the first block is likely to be accessed first, so precache it here */ | 
      
        |  |  | 245 |     raw_block_address = 0xffffffff; | 
      
        |  |  | 246 | #if SD_RAW_WRITE_BUFFERING | 
      
        |  |  | 247 |     raw_block_written = 1; | 
      
        |  |  | 248 | #endif | 
      
        |  |  | 249 |     if(!sd_raw_read(0, raw_block, sizeof(raw_block))) | 
      
        |  |  | 250 |         return 0; | 
      
        |  |  | 251 | #endif | 
      
        |  |  | 252 |  | 
      
        |  |  | 253 |     return 1; | 
      
        |  |  | 254 | } | 
      
        |  |  | 255 |  | 
      
        |  |  | 256 | /** | 
      
        |  |  | 257 |  * \ingroup sd_raw | 
      
        |  |  | 258 |  * Checks wether a memory card is located in the slot. | 
      
        |  |  | 259 |  * | 
      
        |  |  | 260 |  * \returns 1 if the card is available, 0 if it is not. | 
      
        |  |  | 261 |  */ | 
      
        |  |  | 262 | uint8_t sd_raw_available() | 
      
        |  |  | 263 | { | 
      
        |  |  | 264 |     return get_pin_available() == 0x00; | 
      
        |  |  | 265 | } | 
      
        |  |  | 266 |  | 
      
        |  |  | 267 | /** | 
      
        |  |  | 268 |  * \ingroup sd_raw | 
      
        |  |  | 269 |  * Checks wether the memory card is locked for write access. | 
      
        |  |  | 270 |  * | 
      
        |  |  | 271 |  * \returns 1 if the card is locked, 0 if it is not. | 
      
        |  |  | 272 |  */ | 
      
        |  |  | 273 | uint8_t sd_raw_locked() | 
      
        |  |  | 274 | { | 
      
        |  |  | 275 |     return get_pin_locked() == 0x00; | 
      
        |  |  | 276 | } | 
      
        |  |  | 277 |  | 
      
        |  |  | 278 | /** | 
      
        |  |  | 279 |  * \ingroup sd_raw | 
      
        |  |  | 280 |  * Sends a raw byte to the memory card. | 
      
        |  |  | 281 |  * | 
      
        |  |  | 282 |  * \param[in] b The byte to sent. | 
      
        |  |  | 283 |  * \see sd_raw_rec_byte | 
      
        |  |  | 284 |  */ | 
      
        |  |  | 285 | void sd_raw_send_byte(uint8_t b) | 
      
        |  |  | 286 | { | 
      
        |  |  | 287 |     SPDR = b; | 
      
        |  |  | 288 |     /* wait for byte to be shifted out */ | 
      
        |  |  | 289 |     while(!(SPSR & (1 << SPIF))); | 
      
        |  |  | 290 |     SPSR &= ~(1 << SPIF); | 
      
        |  |  | 291 | } | 
      
        |  |  | 292 |  | 
      
        |  |  | 293 | /** | 
      
        |  |  | 294 |  * \ingroup sd_raw | 
      
        |  |  | 295 |  * Receives a raw byte from the memory card. | 
      
        |  |  | 296 |  * | 
      
        |  |  | 297 |  * \returns The byte which should be read. | 
      
        |  |  | 298 |  * \see sd_raw_send_byte | 
      
        |  |  | 299 |  */ | 
      
        |  |  | 300 | uint8_t sd_raw_rec_byte() | 
      
        |  |  | 301 | { | 
      
        |  |  | 302 |     /* send dummy data for receiving some */ | 
      
        |  |  | 303 |     SPDR = 0xff; | 
      
        |  |  | 304 |     while(!(SPSR & (1 << SPIF))); | 
      
        |  |  | 305 |     SPSR &= ~(1 << SPIF); | 
      
        |  |  | 306 |  | 
      
        |  |  | 307 |     return SPDR; | 
      
        |  |  | 308 | } | 
      
        |  |  | 309 |  | 
      
        |  |  | 310 | /** | 
      
        |  |  | 311 |  * \ingroup sd_raw | 
      
        |  |  | 312 |  * Send a command to the memory card which responses with a R1 response. | 
      
        |  |  | 313 |  * | 
      
        |  |  | 314 |  * \param[in] command The command to send. | 
      
        |  |  | 315 |  * \param[in] arg The argument for command. | 
      
        |  |  | 316 |  * \returns The command answer. | 
      
        |  |  | 317 |  */ | 
      
        |  |  | 318 | uint8_t sd_raw_send_command_r1(uint8_t command, uint32_t arg) | 
      
        |  |  | 319 | { | 
      
        |  |  | 320 |     uint8_t response; | 
      
        |  |  | 321 |  | 
      
        |  |  | 322 |     /* wait some clock cycles */ | 
      
        |  |  | 323 |     sd_raw_rec_byte(); | 
      
        |  |  | 324 |  | 
      
        |  |  | 325 |     /* send command via SPI */ | 
      
        |  |  | 326 |     sd_raw_send_byte(0x40 | command); | 
      
        |  |  | 327 |     sd_raw_send_byte((arg >> 24) & 0xff); | 
      
        |  |  | 328 |     sd_raw_send_byte((arg >> 16) & 0xff); | 
      
        |  |  | 329 |     sd_raw_send_byte((arg >> 8) & 0xff); | 
      
        |  |  | 330 |     sd_raw_send_byte((arg >> 0) & 0xff); | 
      
        |  |  | 331 |     sd_raw_send_byte(command == CMD_GO_IDLE_STATE ? 0x95 : 0xff); | 
      
        |  |  | 332 |  | 
      
        |  |  | 333 |     /* receive response */ | 
      
        |  |  | 334 |     for(uint8_t i = 0; i < 10; ++i) | 
      
        |  |  | 335 |     { | 
      
        |  |  | 336 |         response = sd_raw_rec_byte(); | 
      
        |  |  | 337 |         if(response != 0xff) | 
      
        |  |  | 338 |             break; | 
      
        |  |  | 339 |     } | 
      
        |  |  | 340 |  | 
      
        |  |  | 341 |     return response; | 
      
        |  |  | 342 | } | 
      
        |  |  | 343 |  | 
      
        |  |  | 344 | /** | 
      
        |  |  | 345 |  * \ingroup sd_raw | 
      
        |  |  | 346 |  * Send a command to the memory card which responses with a R2 response. | 
      
        |  |  | 347 |  * | 
      
        |  |  | 348 |  * \param[in] command The command to send. | 
      
        |  |  | 349 |  * \param[in] arg The argument for command. | 
      
        |  |  | 350 |  * \returns The command answer. | 
      
        |  |  | 351 |  */ | 
      
        |  |  | 352 | uint16_t sd_raw_send_command_r2(uint8_t command, uint32_t arg) | 
      
        |  |  | 353 | { | 
      
        |  |  | 354 |     uint16_t response; | 
      
        |  |  | 355 |  | 
      
        |  |  | 356 |     /* wait some clock cycles */ | 
      
        |  |  | 357 |     sd_raw_rec_byte(); | 
      
        |  |  | 358 |  | 
      
        |  |  | 359 |     /* send command via SPI */ | 
      
        |  |  | 360 |     sd_raw_send_byte(0x40 | command); | 
      
        |  |  | 361 |     sd_raw_send_byte((arg >> 24) & 0xff); | 
      
        |  |  | 362 |     sd_raw_send_byte((arg >> 16) & 0xff); | 
      
        |  |  | 363 |     sd_raw_send_byte((arg >> 8) & 0xff); | 
      
        |  |  | 364 |     sd_raw_send_byte((arg >> 0) & 0xff); | 
      
        |  |  | 365 |     sd_raw_send_byte(command == CMD_GO_IDLE_STATE ? 0x95 : 0xff); | 
      
        |  |  | 366 |  | 
      
        |  |  | 367 |     /* receive response */ | 
      
        |  |  | 368 |     for(uint8_t i = 0; i < 10; ++i) | 
      
        |  |  | 369 |     { | 
      
        |  |  | 370 |         response = sd_raw_rec_byte(); | 
      
        |  |  | 371 |         if(response != 0xff) | 
      
        |  |  | 372 |             break; | 
      
        |  |  | 373 |     } | 
      
        |  |  | 374 |     response <<= 8; | 
      
        |  |  | 375 |     response |= sd_raw_rec_byte(); | 
      
        |  |  | 376 |  | 
      
        |  |  | 377 |     return response; | 
      
        |  |  | 378 | } | 
      
        |  |  | 379 |  | 
      
        |  |  | 380 | /** | 
      
        |  |  | 381 |  * \ingroup sd_raw | 
      
        |  |  | 382 |  * Reads raw data from the card. | 
      
        |  |  | 383 |  * | 
      
        |  |  | 384 |  * \param[in] offset The offset from which to read. | 
      
        |  |  | 385 |  * \param[out] buffer The buffer into which to write the data. | 
      
        |  |  | 386 |  * \param[in] length The number of bytes to read. | 
      
        |  |  | 387 |  * \returns 0 on failure, 1 on success. | 
      
        |  |  | 388 |  * \see sd_raw_read_interval, sd_raw_write, sd_raw_write_interval | 
      
        |  |  | 389 |  */ | 
      
        |  |  | 390 | uint8_t sd_raw_read(uint32_t offset, uint8_t* buffer, uint16_t length) | 
      
        |  |  | 391 | { | 
      
        |  |  | 392 |     uint32_t block_address; | 
      
        |  |  | 393 |     uint16_t block_offset; | 
      
        |  |  | 394 |     uint16_t read_length; | 
      
        |  |  | 395 |     while(length > 0) | 
      
        |  |  | 396 |     { | 
      
        |  |  | 397 |         /* determine byte count to read at once */ | 
      
        |  |  | 398 |         block_address = offset & 0xfffffe00; | 
      
        |  |  | 399 |         block_offset = offset & 0x01ff; | 
      
        |  |  | 400 |         read_length = 512 - block_offset; /* read up to block border */ | 
      
        |  |  | 401 |         if(read_length > length) | 
      
        |  |  | 402 |             read_length = length; | 
      
        |  |  | 403 |  | 
      
        |  |  | 404 | #if !SD_RAW_SAVE_RAM | 
      
        |  |  | 405 |         /* check if the requested data is cached */ | 
      
        |  |  | 406 |         if(block_address != raw_block_address) | 
      
        |  |  | 407 | #endif | 
      
        |  |  | 408 |         { | 
      
        |  |  | 409 | #if SD_RAW_WRITE_BUFFERING | 
      
        |  |  | 410 |             if(!raw_block_written) | 
      
        |  |  | 411 |             { | 
      
        |  |  | 412 |                 if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) | 
      
        |  |  | 413 |                     return 0; | 
      
        |  |  | 414 |             } | 
      
        |  |  | 415 | #endif | 
      
        |  |  | 416 |  | 
      
        |  |  | 417 |             /* address card */ | 
      
        |  |  | 418 |             select_card(); | 
      
        |  |  | 419 |  | 
      
        |  |  | 420 |             /* send single block request */ | 
      
        |  |  | 421 |             if(sd_raw_send_command_r1(CMD_READ_SINGLE_BLOCK, block_address)) | 
      
        |  |  | 422 |             { | 
      
        |  |  | 423 |                 unselect_card(); | 
      
        |  |  | 424 |                 return 0; | 
      
        |  |  | 425 |             } | 
      
        |  |  | 426 |  | 
      
        |  |  | 427 |             /* wait for data block (start byte 0xfe) */ | 
      
        |  |  | 428 |             while(sd_raw_rec_byte() != 0xfe); | 
      
        |  |  | 429 |  | 
      
        |  |  | 430 | #if SD_RAW_SAVE_RAM | 
      
        |  |  | 431 |             /* read byte block */ | 
      
        |  |  | 432 |             uint16_t read_to = block_offset + read_length; | 
      
        |  |  | 433 |             for(uint16_t i = 0; i < 512; ++i) | 
      
        |  |  | 434 |             { | 
      
        |  |  | 435 |                 uint8_t b = sd_raw_rec_byte(); | 
      
        |  |  | 436 |                 if(i >= block_offset && i < read_to) | 
      
        |  |  | 437 |                     *buffer++ = b; | 
      
        |  |  | 438 |             } | 
      
        |  |  | 439 | #else | 
      
        |  |  | 440 |             /* read byte block */ | 
      
        |  |  | 441 |             uint8_t* cache = raw_block; | 
      
        |  |  | 442 |             for(uint16_t i = 0; i < 512; ++i) | 
      
        |  |  | 443 |                 *cache++ = sd_raw_rec_byte(); | 
      
        |  |  | 444 |             raw_block_address = block_address; | 
      
        |  |  | 445 |  | 
      
        |  |  | 446 |             memcpy(buffer, raw_block + block_offset, read_length); | 
      
        |  |  | 447 |             buffer += read_length; | 
      
        |  |  | 448 | #endif | 
      
        |  |  | 449 |  | 
      
        |  |  | 450 |             /* read crc16 */ | 
      
        |  |  | 451 |             sd_raw_rec_byte(); | 
      
        |  |  | 452 |             sd_raw_rec_byte(); | 
      
        |  |  | 453 |  | 
      
        |  |  | 454 |             /* deaddress card */ | 
      
        |  |  | 455 |             unselect_card(); | 
      
        |  |  | 456 |  | 
      
        |  |  | 457 |             /* let card some time to finish */ | 
      
        |  |  | 458 |             sd_raw_rec_byte(); | 
      
        |  |  | 459 |         } | 
      
        |  |  | 460 | #if !SD_RAW_SAVE_RAM | 
      
        |  |  | 461 |         else | 
      
        |  |  | 462 |         { | 
      
        |  |  | 463 |             /* use cached data */ | 
      
        |  |  | 464 |             memcpy(buffer, raw_block + block_offset, read_length); | 
      
        |  |  | 465 |             buffer += read_length; | 
      
        |  |  | 466 |         } | 
      
        |  |  | 467 | #endif | 
      
        |  |  | 468 |  | 
      
        |  |  | 469 |         length -= read_length; | 
      
        |  |  | 470 |         offset += read_length; | 
      
        |  |  | 471 |     } | 
      
        |  |  | 472 |  | 
      
        |  |  | 473 |     return 1; | 
      
        |  |  | 474 | } | 
      
        |  |  | 475 |  | 
      
        |  |  | 476 | /** | 
      
        |  |  | 477 |  * \ingroup sd_raw | 
      
        |  |  | 478 |  * Continuously reads units of \c interval bytes and calls a callback function. | 
      
        |  |  | 479 |  * | 
      
        |  |  | 480 |  * This function starts reading at the specified offset. Every \c interval bytes, | 
      
        |  |  | 481 |  * it calls the callback function with the associated data buffer. | 
      
        |  |  | 482 |  * | 
      
        |  |  | 483 |  * By returning zero, the callback may stop reading. | 
      
        |  |  | 484 |  * | 
      
        |  |  | 485 |  * \note Within the callback function, you can not start another read or | 
      
        |  |  | 486 |  *       write operation. | 
      
        |  |  | 487 |  * \note This function only works if the following conditions are met: | 
      
        |  |  | 488 |  *       - (offset - (offset % 512)) % interval == 0 | 
      
        |  |  | 489 |  *       - length % interval == 0 | 
      
        |  |  | 490 |  * | 
      
        |  |  | 491 |  * \param[in] offset Offset from which to start reading. | 
      
        |  |  | 492 |  * \param[in] buffer Pointer to a buffer which is at least interval bytes in size. | 
      
        |  |  | 493 |  * \param[in] interval Number of bytes to read before calling the callback function. | 
      
        |  |  | 494 |  * \param[in] length Number of bytes to read altogether. | 
      
        |  |  | 495 |  * \param[in] callback The function to call every interval bytes. | 
      
        |  |  | 496 |  * \param[in] p An opaque pointer directly passed to the callback function. | 
      
        |  |  | 497 |  * \returns 0 on failure, 1 on success | 
      
        |  |  | 498 |  * \see sd_raw_write_interval, sd_raw_read, sd_raw_write | 
      
        |  |  | 499 |  */ | 
      
        |  |  | 500 | uint8_t sd_raw_read_interval(uint32_t offset, uint8_t* buffer, uint16_t interval, uint16_t length, sd_raw_read_interval_handler_t callback, void* p) | 
      
        |  |  | 501 | { | 
      
        |  |  | 502 |     if(!buffer || interval == 0 || length < interval || !callback) | 
      
        |  |  | 503 |         return 0; | 
      
        |  |  | 504 |  | 
      
        |  |  | 505 | #if !SD_RAW_SAVE_RAM | 
      
        |  |  | 506 |     while(length >= interval) | 
      
        |  |  | 507 |     { | 
      
        |  |  | 508 |         /* as reading is now buffered, we directly | 
      
        |  |  | 509 |          * hand over the request to sd_raw_read() | 
      
        |  |  | 510 |          */ | 
      
        |  |  | 511 |         if(!sd_raw_read(offset, buffer, interval)) | 
      
        |  |  | 512 |             return 0; | 
      
        |  |  | 513 |         if(!callback(buffer, offset, p)) | 
      
        |  |  | 514 |             break; | 
      
        |  |  | 515 |         offset += interval; | 
      
        |  |  | 516 |         length -= interval; | 
      
        |  |  | 517 |     } | 
      
        |  |  | 518 |  | 
      
        |  |  | 519 |     return 1; | 
      
        |  |  | 520 | #else | 
      
        |  |  | 521 |     /* address card */ | 
      
        |  |  | 522 |     select_card(); | 
      
        |  |  | 523 |  | 
      
        |  |  | 524 |     uint16_t block_offset; | 
      
        |  |  | 525 |     uint16_t read_length; | 
      
        |  |  | 526 |     uint8_t* buffer_cur; | 
      
        |  |  | 527 |     uint8_t finished = 0; | 
      
        |  |  | 528 |     do | 
      
        |  |  | 529 |     { | 
      
        |  |  | 530 |         /* determine byte count to read at once */ | 
      
        |  |  | 531 |         block_offset = offset & 0x01ff; | 
      
        |  |  | 532 |         read_length = 512 - block_offset; | 
      
        |  |  | 533 |  | 
      
        |  |  | 534 |         /* send single block request */ | 
      
        |  |  | 535 |         if(sd_raw_send_command_r1(CMD_READ_SINGLE_BLOCK, offset & 0xfffffe00)) | 
      
        |  |  | 536 |         { | 
      
        |  |  | 537 |             unselect_card(); | 
      
        |  |  | 538 |             return 0; | 
      
        |  |  | 539 |         } | 
      
        |  |  | 540 |  | 
      
        |  |  | 541 |         /* wait for data block (start byte 0xfe) */ | 
      
        |  |  | 542 |         while(sd_raw_rec_byte() != 0xfe); | 
      
        |  |  | 543 |  | 
      
        |  |  | 544 |         /* read up to the data of interest */ | 
      
        |  |  | 545 |         for(uint16_t i = 0; i < block_offset; ++i) | 
      
        |  |  | 546 |             sd_raw_rec_byte(); | 
      
        |  |  | 547 |  | 
      
        |  |  | 548 |         /* read interval bytes of data and execute the callback */ | 
      
        |  |  | 549 |         do | 
      
        |  |  | 550 |         { | 
      
        |  |  | 551 |             if(read_length < interval || length < interval) | 
      
        |  |  | 552 |                 break; | 
      
        |  |  | 553 |  | 
      
        |  |  | 554 |             buffer_cur = buffer; | 
      
        |  |  | 555 |             for(uint16_t i = 0; i < interval; ++i) | 
      
        |  |  | 556 |                 *buffer_cur++ = sd_raw_rec_byte(); | 
      
        |  |  | 557 |  | 
      
        |  |  | 558 |             if(!callback(buffer, offset + (512 - read_length), p)) | 
      
        |  |  | 559 |             { | 
      
        |  |  | 560 |                 finished = 1; | 
      
        |  |  | 561 |                 break; | 
      
        |  |  | 562 |             } | 
      
        |  |  | 563 |  | 
      
        |  |  | 564 |             read_length -= interval; | 
      
        |  |  | 565 |             length -= interval; | 
      
        |  |  | 566 |  | 
      
        |  |  | 567 |         } while(read_length > 0 && length > 0); | 
      
        |  |  | 568 |  | 
      
        |  |  | 569 |         /* read rest of data block */ | 
      
        |  |  | 570 |         while(read_length-- > 0) | 
      
        |  |  | 571 |             sd_raw_rec_byte(); | 
      
        |  |  | 572 |  | 
      
        |  |  | 573 |         /* read crc16 */ | 
      
        |  |  | 574 |         sd_raw_rec_byte(); | 
      
        |  |  | 575 |         sd_raw_rec_byte(); | 
      
        |  |  | 576 |  | 
      
        |  |  | 577 |         if(length < interval) | 
      
        |  |  | 578 |             break; | 
      
        |  |  | 579 |  | 
      
        |  |  | 580 |         offset = (offset & 0xfffffe00) + 512; | 
      
        |  |  | 581 |  | 
      
        |  |  | 582 |     } while(!finished); | 
      
        |  |  | 583 |  | 
      
        |  |  | 584 |     /* deaddress card */ | 
      
        |  |  | 585 |     unselect_card(); | 
      
        |  |  | 586 |  | 
      
        |  |  | 587 |     /* let card some time to finish */ | 
      
        |  |  | 588 |     sd_raw_rec_byte(); | 
      
        |  |  | 589 |  | 
      
        |  |  | 590 |     return 1; | 
      
        |  |  | 591 | #endif | 
      
        |  |  | 592 | } | 
      
        |  |  | 593 |  | 
      
        |  |  | 594 | /** | 
      
        |  |  | 595 |  * \ingroup sd_raw | 
      
        |  |  | 596 |  * Writes raw data to the card. | 
      
        |  |  | 597 |  * | 
      
        |  |  | 598 |  * \note If write buffering is enabled, you might have to | 
      
        |  |  | 599 |  *       call sd_raw_sync() before disconnecting the card | 
      
        |  |  | 600 |  *       to ensure all remaining data has been written. | 
      
        |  |  | 601 |  * | 
      
        |  |  | 602 |  * \param[in] offset The offset where to start writing. | 
      
        |  |  | 603 |  * \param[in] buffer The buffer containing the data to be written. | 
      
        |  |  | 604 |  * \param[in] length The number of bytes to write. | 
      
        |  |  | 605 |  * \returns 0 on failure, 1 on success. | 
      
        |  |  | 606 |  * \see sd_raw_write_interval, sd_raw_read, sd_raw_read_interval | 
      
        |  |  | 607 |  */ | 
      
        |  |  | 608 | uint8_t sd_raw_write(uint32_t offset, const uint8_t* buffer, uint16_t length) | 
      
        |  |  | 609 | { | 
      
        |  |  | 610 | #if SD_RAW_WRITE_SUPPORT | 
      
        |  |  | 611 |  | 
      
        |  |  | 612 |     if(get_pin_locked()) | 
      
        |  |  | 613 |         return 0; | 
      
        |  |  | 614 |  | 
      
        |  |  | 615 |     uint32_t block_address; | 
      
        |  |  | 616 |     uint16_t block_offset; | 
      
        |  |  | 617 |     uint16_t write_length; | 
      
        |  |  | 618 |     while(length > 0) | 
      
        |  |  | 619 |     { | 
      
        |  |  | 620 |         /* determine byte count to write at once */ | 
      
        |  |  | 621 |         block_address = offset & 0xfffffe00; | 
      
        |  |  | 622 |         block_offset = offset & 0x01ff; | 
      
        |  |  | 623 |         write_length = 512 - block_offset; /* write up to block border */ | 
      
        |  |  | 624 |         if(write_length > length) | 
      
        |  |  | 625 |             write_length = length; | 
      
        |  |  | 626 |  | 
      
        |  |  | 627 |         /* Merge the data to write with the content of the block. | 
      
        |  |  | 628 |          * Use the cached block if available. | 
      
        |  |  | 629 |          */ | 
      
        |  |  | 630 |         if(block_address != raw_block_address) | 
      
        |  |  | 631 |         { | 
      
        |  |  | 632 | #if SD_RAW_WRITE_BUFFERING | 
      
        |  |  | 633 |             if(!raw_block_written) | 
      
        |  |  | 634 |             { | 
      
        |  |  | 635 |                 if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) | 
      
        |  |  | 636 |                     return 0; | 
      
        |  |  | 637 |             } | 
      
        |  |  | 638 | #endif | 
      
        |  |  | 639 |  | 
      
        |  |  | 640 |             if(block_offset || write_length < 512) | 
      
        |  |  | 641 |             { | 
      
        |  |  | 642 |                 if(!sd_raw_read(block_address, raw_block, sizeof(raw_block))) | 
      
        |  |  | 643 |                     return 0; | 
      
        |  |  | 644 |             } | 
      
        |  |  | 645 |             raw_block_address = block_address; | 
      
        |  |  | 646 |         } | 
      
        |  |  | 647 |  | 
      
        |  |  | 648 |         if(buffer != raw_block) | 
      
        |  |  | 649 |         { | 
      
        |  |  | 650 |             memcpy(raw_block + block_offset, buffer, write_length); | 
      
        |  |  | 651 |  | 
      
        |  |  | 652 | #if SD_RAW_WRITE_BUFFERING | 
      
        |  |  | 653 |             raw_block_written = 0; | 
      
        |  |  | 654 |  | 
      
        |  |  | 655 |             if(length == write_length) | 
      
        |  |  | 656 |                 return 1; | 
      
        |  |  | 657 | #endif | 
      
        |  |  | 658 |         } | 
      
        |  |  | 659 |  | 
      
        |  |  | 660 |         buffer += write_length; | 
      
        |  |  | 661 |  | 
      
        |  |  | 662 |         /* address card */ | 
      
        |  |  | 663 |         select_card(); | 
      
        |  |  | 664 |  | 
      
        |  |  | 665 |         /* send single block request */ | 
      
        |  |  | 666 |         if(sd_raw_send_command_r1(CMD_WRITE_SINGLE_BLOCK, block_address)) | 
      
        |  |  | 667 |         { | 
      
        |  |  | 668 |             unselect_card(); | 
      
        |  |  | 669 |             return 0; | 
      
        |  |  | 670 |         } | 
      
        |  |  | 671 |  | 
      
        |  |  | 672 |         /* send start byte */ | 
      
        |  |  | 673 |         sd_raw_send_byte(0xfe); | 
      
        |  |  | 674 |  | 
      
        |  |  | 675 |         /* write byte block */ | 
      
        |  |  | 676 |         uint8_t* cache = raw_block; | 
      
        |  |  | 677 |         for(uint16_t i = 0; i < 512; ++i) | 
      
        |  |  | 678 |             sd_raw_send_byte(*cache++); | 
      
        |  |  | 679 |  | 
      
        |  |  | 680 |         /* write dummy crc16 */ | 
      
        |  |  | 681 |         sd_raw_send_byte(0xff); | 
      
        |  |  | 682 |         sd_raw_send_byte(0xff); | 
      
        |  |  | 683 |  | 
      
        |  |  | 684 |         /* wait while card is busy */ | 
      
        |  |  | 685 |         while(sd_raw_rec_byte() != 0xff); | 
      
        |  |  | 686 |         sd_raw_rec_byte(); | 
      
        |  |  | 687 |  | 
      
        |  |  | 688 |         /* deaddress card */ | 
      
        |  |  | 689 |         unselect_card(); | 
      
        |  |  | 690 |  | 
      
        |  |  | 691 |         length -= write_length; | 
      
        |  |  | 692 |         offset += write_length; | 
      
        |  |  | 693 |  | 
      
        |  |  | 694 | #if SD_RAW_WRITE_BUFFERING | 
      
        |  |  | 695 |         raw_block_written = 1; | 
      
        |  |  | 696 | #endif | 
      
        |  |  | 697 |     } | 
      
        |  |  | 698 |  | 
      
        |  |  | 699 |     return 1; | 
      
        |  |  | 700 | #else | 
      
        |  |  | 701 |     return 0; | 
      
        |  |  | 702 | #endif | 
      
        |  |  | 703 | } | 
      
        |  |  | 704 |  | 
      
        |  |  | 705 | /** | 
      
        |  |  | 706 |  * \ingroup sd_raw | 
      
        |  |  | 707 |  * Writes a continuous data stream obtained from a callback function. | 
      
        |  |  | 708 |  * | 
      
        |  |  | 709 |  * This function starts writing at the specified offset. To obtain the | 
      
        |  |  | 710 |  * next bytes to write, it calls the callback function. The callback fills the | 
      
        |  |  | 711 |  * provided data buffer and returns the number of bytes it has put into the buffer. | 
      
        |  |  | 712 |  * | 
      
        |  |  | 713 |  * By returning zero, the callback may stop writing. | 
      
        |  |  | 714 |  * | 
      
        |  |  | 715 |  * \param[in] offset Offset where to start writing. | 
      
        |  |  | 716 |  * \param[in] buffer Pointer to a buffer which is used for the callback function. | 
      
        |  |  | 717 |  * \param[in] length Number of bytes to write in total. May be zero for endless writes. | 
      
        |  |  | 718 |  * \param[in] callback The function used to obtain the bytes to write. | 
      
        |  |  | 719 |  * \param[in] p An opaque pointer directly passed to the callback function. | 
      
        |  |  | 720 |  * \returns 0 on failure, 1 on success | 
      
        |  |  | 721 |  * \see sd_raw_read_interval, sd_raw_write, sd_raw_read | 
      
        |  |  | 722 |  */ | 
      
        |  |  | 723 | uint8_t sd_raw_write_interval(uint32_t offset, uint8_t* buffer, uint16_t length, sd_raw_write_interval_handler_t callback, void* p) | 
      
        |  |  | 724 | { | 
      
        |  |  | 725 | #if SD_RAW_WRITE_SUPPORT | 
      
        |  |  | 726 |  | 
      
        |  |  | 727 | #if SD_RAW_SAVE_RAM | 
      
        |  |  | 728 |     #error "SD_RAW_WRITE_SUPPORT is not supported together with SD_RAW_SAVE_RAM" | 
      
        |  |  | 729 | #endif | 
      
        |  |  | 730 |  | 
      
        |  |  | 731 |     if(!buffer || !callback) | 
      
        |  |  | 732 |         return 0; | 
      
        |  |  | 733 |  | 
      
        |  |  | 734 |     uint8_t endless = (length == 0); | 
      
        |  |  | 735 |     while(endless || length > 0) | 
      
        |  |  | 736 |     { | 
      
        |  |  | 737 |         uint16_t bytes_to_write = callback(buffer, offset, p); | 
      
        |  |  | 738 |         if(!bytes_to_write) | 
      
        |  |  | 739 |             break; | 
      
        |  |  | 740 |         if(!endless && bytes_to_write > length) | 
      
        |  |  | 741 |             return 0; | 
      
        |  |  | 742 |  | 
      
        |  |  | 743 |         /* as writing is always buffered, we directly | 
      
        |  |  | 744 |          * hand over the request to sd_raw_write() | 
      
        |  |  | 745 |          */ | 
      
        |  |  | 746 |         if(!sd_raw_write(offset, buffer, bytes_to_write)) | 
      
        |  |  | 747 |             return 0; | 
      
        |  |  | 748 |  | 
      
        |  |  | 749 |         offset += bytes_to_write; | 
      
        |  |  | 750 |         length -= bytes_to_write; | 
      
        |  |  | 751 |     } | 
      
        |  |  | 752 |  | 
      
        |  |  | 753 |     return 1; | 
      
        |  |  | 754 |  | 
      
        |  |  | 755 | #else | 
      
        |  |  | 756 |     return 0; | 
      
        |  |  | 757 | #endif | 
      
        |  |  | 758 | } | 
      
        |  |  | 759 |  | 
      
        |  |  | 760 | /** | 
      
        |  |  | 761 |  * \ingroup sd_raw | 
      
        |  |  | 762 |  * Writes the write buffer's content to the card. | 
      
        |  |  | 763 |  * | 
      
        |  |  | 764 |  * \note When write buffering is enabled, you should | 
      
        |  |  | 765 |  *       call this function before disconnecting the | 
      
        |  |  | 766 |  *       card to ensure all remaining data has been | 
      
        |  |  | 767 |  *       written. | 
      
        |  |  | 768 |  * | 
      
        |  |  | 769 |  * \returns 0 on failure, 1 on success. | 
      
        |  |  | 770 |  * \see sd_raw_write | 
      
        |  |  | 771 |  */ | 
      
        |  |  | 772 | uint8_t sd_raw_sync() | 
      
        |  |  | 773 | { | 
      
        |  |  | 774 | #if SD_RAW_WRITE_SUPPORT | 
      
        |  |  | 775 | #if SD_RAW_WRITE_BUFFERING | 
      
        |  |  | 776 |     if(raw_block_written) | 
      
        |  |  | 777 |         return 1; | 
      
        |  |  | 778 |     if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) | 
      
        |  |  | 779 |         return 0; | 
      
        |  |  | 780 | #endif | 
      
        |  |  | 781 |     return 1; | 
      
        |  |  | 782 | #else | 
      
        |  |  | 783 |     return 0; | 
      
        |  |  | 784 | #endif | 
      
        |  |  | 785 | } | 
      
        |  |  | 786 |  | 
      
        |  |  | 787 | /** | 
      
        |  |  | 788 |  * \ingroup sd_raw | 
      
        |  |  | 789 |  * Reads informational data from the card. | 
      
        |  |  | 790 |  * | 
      
        |  |  | 791 |  * This function reads and returns the card's registers | 
      
        |  |  | 792 |  * containing manufacturing and status information. | 
      
        |  |  | 793 |  * | 
      
        |  |  | 794 |  * \note: The information retrieved by this function is | 
      
        |  |  | 795 |  *        not required in any way to operate on the card, | 
      
        |  |  | 796 |  *        but it might be nice to display some of the data | 
      
        |  |  | 797 |  *        to the user. | 
      
        |  |  | 798 |  * | 
      
        |  |  | 799 |  * \param[in] info A pointer to the structure into which to save the information. | 
      
        |  |  | 800 |  * \returns 0 on failure, 1 on success. | 
      
        |  |  | 801 |  */ | 
      
        |  |  | 802 | uint8_t sd_raw_get_info(struct sd_raw_info* info) | 
      
        |  |  | 803 | { | 
      
        |  |  | 804 |     if(!info || !sd_raw_available()) | 
      
        |  |  | 805 |         return 0; | 
      
        |  |  | 806 |  | 
      
        |  |  | 807 |     memset(info, 0, sizeof(*info)); | 
      
        |  |  | 808 |  | 
      
        |  |  | 809 |     select_card(); | 
      
        |  |  | 810 |  | 
      
        |  |  | 811 |     /* read cid register */ | 
      
        |  |  | 812 |     if(sd_raw_send_command_r1(CMD_SEND_CID, 0)) | 
      
        |  |  | 813 |     { | 
      
        |  |  | 814 |         unselect_card(); | 
      
        |  |  | 815 |         return 0; | 
      
        |  |  | 816 |     } | 
      
        |  |  | 817 |     while(sd_raw_rec_byte() != 0xfe); | 
      
        |  |  | 818 |     for(uint8_t i = 0; i < 18; ++i) | 
      
        |  |  | 819 |     { | 
      
        |  |  | 820 |         uint8_t b = sd_raw_rec_byte(); | 
      
        |  |  | 821 |  | 
      
        |  |  | 822 |         switch(i) | 
      
        |  |  | 823 |         { | 
      
        |  |  | 824 |             case 0: | 
      
        |  |  | 825 |                 info->manufacturer = b; | 
      
        |  |  | 826 |                 break; | 
      
        |  |  | 827 |             case 1: | 
      
        |  |  | 828 |             case 2: | 
      
        |  |  | 829 |                 info->oem[i - 1] = b; | 
      
        |  |  | 830 |                 break; | 
      
        |  |  | 831 |             case 3: | 
      
        |  |  | 832 |             case 4: | 
      
        |  |  | 833 |             case 5: | 
      
        |  |  | 834 |             case 6: | 
      
        |  |  | 835 |             case 7: | 
      
        |  |  | 836 |                 info->product[i - 3] = b; | 
      
        |  |  | 837 |                 break; | 
      
        |  |  | 838 |             case 8: | 
      
        |  |  | 839 |                 info->revision = b; | 
      
        |  |  | 840 |                 break; | 
      
        |  |  | 841 |             case 9: | 
      
        |  |  | 842 |             case 10: | 
      
        |  |  | 843 |             case 11: | 
      
        |  |  | 844 |             case 12: | 
      
        |  |  | 845 |                 info->serial |= (uint32_t) b << ((12 - i) * 8); | 
      
        |  |  | 846 |                 break; | 
      
        |  |  | 847 |             case 13: | 
      
        |  |  | 848 |                 info->manufacturing_year = b << 4; | 
      
        |  |  | 849 |                 break; | 
      
        |  |  | 850 |             case 14: | 
      
        |  |  | 851 |                 info->manufacturing_year |= b >> 4; | 
      
        |  |  | 852 |                 info->manufacturing_month = b & 0x0f; | 
      
        |  |  | 853 |                 break; | 
      
        |  |  | 854 |         } | 
      
        |  |  | 855 |     } | 
      
        |  |  | 856 |  | 
      
        |  |  | 857 |     /* read csd register */ | 
      
        |  |  | 858 |     uint8_t csd_read_bl_len = 0; | 
      
        |  |  | 859 |     uint8_t csd_c_size_mult = 0; | 
      
        |  |  | 860 |     uint16_t csd_c_size = 0; | 
      
        |  |  | 861 |     if(sd_raw_send_command_r1(CMD_SEND_CSD, 0)) | 
      
        |  |  | 862 |     { | 
      
        |  |  | 863 |         unselect_card(); | 
      
        |  |  | 864 |         return 0; | 
      
        |  |  | 865 |     } | 
      
        |  |  | 866 |     while(sd_raw_rec_byte() != 0xfe); | 
      
        |  |  | 867 |     for(uint8_t i = 0; i < 18; ++i) | 
      
        |  |  | 868 |     { | 
      
        |  |  | 869 |         uint8_t b = sd_raw_rec_byte(); | 
      
        |  |  | 870 |  | 
      
        |  |  | 871 |         switch(i) | 
      
        |  |  | 872 |         { | 
      
        |  |  | 873 |             case 5: | 
      
        |  |  | 874 |                 csd_read_bl_len = b & 0x0f; | 
      
        |  |  | 875 |                 break; | 
      
        |  |  | 876 |             case 6: | 
      
        |  |  | 877 |                 csd_c_size = (uint16_t) (b & 0x03) << 8; | 
      
        |  |  | 878 |                 break; | 
      
        |  |  | 879 |             case 7: | 
      
        |  |  | 880 |                 csd_c_size |= b; | 
      
        |  |  | 881 |                 csd_c_size <<= 2; | 
      
        |  |  | 882 |                 break; | 
      
        |  |  | 883 |             case 8: | 
      
        |  |  | 884 |                 csd_c_size |= b >> 6; | 
      
        |  |  | 885 |                 ++csd_c_size; | 
      
        |  |  | 886 |                 break; | 
      
        |  |  | 887 |             case 9: | 
      
        |  |  | 888 |                 csd_c_size_mult = (b & 0x03) << 1; | 
      
        |  |  | 889 |                 break; | 
      
        |  |  | 890 |             case 10: | 
      
        |  |  | 891 |                 csd_c_size_mult |= b >> 7; | 
      
        |  |  | 892 |  | 
      
        |  |  | 893 |                 info->capacity = (uint32_t) csd_c_size << (csd_c_size_mult + csd_read_bl_len + 2); | 
      
        |  |  | 894 |  | 
      
        |  |  | 895 |                 break; | 
      
        |  |  | 896 |             case 14: | 
      
        |  |  | 897 |                 if(b & 0x40) | 
      
        |  |  | 898 |                     info->flag_copy = 1; | 
      
        |  |  | 899 |                 if(b & 0x20) | 
      
        |  |  | 900 |                     info->flag_write_protect = 1; | 
      
        |  |  | 901 |                 if(b & 0x10) | 
      
        |  |  | 902 |                     info->flag_write_protect_temp = 1; | 
      
        |  |  | 903 |                 info->format = (b & 0x0c) >> 2; | 
      
        |  |  | 904 |                 break; | 
      
        |  |  | 905 |         } | 
      
        |  |  | 906 |     } | 
      
        |  |  | 907 |  | 
      
        |  |  | 908 |     unselect_card(); | 
      
        |  |  | 909 |  | 
      
        |  |  | 910 |     return 1; | 
      
        |  |  | 911 | } | 
      
        |  |  | 912 |  |