communication with SD card More...
Go to the source code of this file.
Data Structures | |
struct | sd_csd_data_s |
card-specific data More... | |
struct | sd_cid_data_s |
card identification data More... | |
struct | sd_rd_mult_block_data_s |
descriptor for read multiple block More... | |
struct | sd_wr_mult_block_data_s |
descriptor for write multiple block More... | |
Defines | |
#define | CMD(c) (((c) & 0x3f) | 0x40) |
convert SD command code into byte to transmit | |
#define | SD_GO_IDLE_STATE CMD(0) |
reset SD card | |
#define | SD_SEND_OP_COND CMD(1) |
send host capacity support information, start card initialization | |
#define | SD_SWITCH_FUNC CMD(6) |
check or set switchable function | |
#define | SD_SEND_IF_COND CMD(8) |
send card interface condition, check whether supplied voltage is acceptable to card | |
#define | SD_SEND_CSD CMD(9) |
get card specific data | |
#define | SD_SEND_CID CMD(10) |
get card identification | |
#define | SD_STOP_TRANSMISSION CMD(12) |
stop a multiple block read operation | |
#define | SD_SEND_STATUS CMD(13) |
get card status register | |
#define | SD_SET_BLOCKLEN CMD(16) |
set block length | |
#define | SD_READ_SINGLE_BLOCK CMD(17) |
read one data block | |
#define | SD_READ_MULTIPLE_BLOCK CMD(18) |
read multiple data blocks until STOP_TRANSMISSION | |
#define | SD_WRITE_BLOCK CMD(24) |
write one data block | |
#define | SD_WRITE_MULTIPLE_BLOCK CMD(25) |
write multiple data blocks | |
#define | SD_PROGRAM_CSD CMD(27) |
program programmable bits in card specific data | |
#define | SD_APP_CMD CMD(55) |
next command is application-specific command | |
#define | SD_READ_OCR CMD(58) |
get operation condition register | |
#define | SD_CRC_ON_OFF CMD(59) |
switch CRC checking on/off | |
#define | SD_A_SEND_NUM_WR_BLOCKS CMD(22) |
get number of successfully written data blocks | |
#define | SD_A_SEND_OP_COND CMD(41) |
send host capacity support information, start card initialization | |
#define | SDTOKEN_START (0b11111110) |
token for start of data transmission | |
#define | SDTOKEN_START_MULTIPLE (0b11111100) |
token for start of multiple-block data transmission | |
#define | SDTOKEN_STOP_MULTIPLE (0b11111101) |
token for stop of multiple-block data transmission | |
#define | CSD_STRUCTURE(csd) ((csd).csd_structure >> 6) |
#define | VAL_CSD_ACCESS_TIME_ASYNC_UNIT_RAW(v) ((v) & 0x07) |
#define | VAL_CSD_ACCESS_TIME_ASYNC_TIME_RAW(v) (((v) >> 3) & 0x0f) |
#define | VAL_CSD_ACCESS_TIME_ASYNC_UNIT_CONV(u) |
#define | VAL_CSD_ACCESS_TIME_ASYNC_TIME_CONV(t) |
#define | VAL_CSD_ACCESS_TIME_ASYNC(v) |
#define | CSD_ACCESS_TIME_ASYNC(csd) VAL_CSD_ACCESS_TIME_ASYNC((csd).taac) |
#define | VAL_CSD_TRAN_UNIT_RAW(v) ((v) & 7) |
#define | VAL_CSD_TRAN_TIME_RAW(v) (((v) >> 3) & 0x0f) |
#define | VAL_CSD_TRAN_UNIT_CONV(u) |
#define | VAL_CSD_TRAN_TIME_CONV(t) |
#define | VAL_CSD_TRAN_SPEED(v) |
#define | CSD_TRAN_SPEED(csd) VAL_CSD_TRAN_SPEED((csd.tran_speed)) |
#define | CSD_CCC(csd) |
#define | CSD_READ_BL_LEN(csd) ((csd).ccc_read_bl_len[1] & 0xf) |
#define | CSD_READ_BL_PARTIAL(csd) ((csd).flags1[0]>>7) |
#define | CSD_WRITE_BLK_MISALIGN(csd) (((csd).flags1[0]>>6) & 0x1) |
#define | CSD_READ_BLK_MISALIGN(csd) (((csd).flags1[0]>>5) & 0x1) |
#define | CSD_DSR_IMP(csd) (((csd).flags1[0]>>4) & 0x1) |
#define | CSD1_C_SIZE(csd) |
#define | CSD2_C_SIZE(csd) |
#define | CSD_VDD_R_CURR_MIN(csd) (((csd).flags1[2]>>3) & 0x7) |
#define | CSD_VDD_R_CURR_MAX(csd) (((csd).flags1[2]) & 0x7) |
#define | CSD_VDD_W_CURR_MIN(csd) (((csd).flags1[3]>>5) & 0x7) |
#define | CSD_VDD_W_CURR_MAX(csd) (((csd).flags1[3]>>2) & 0x7) |
#define | CSD_C_SIZE_MULT(csd) |
#define | CSD_ERASE_BLK_EN(csd) (((csd).flags1[4]>>6) & 0x1) |
#define | CSD_SECTOR_SIZE(csd) |
#define | CSD_WP_GRP_SIZE(csd) ((csd).flags1[5] & 0x7f) |
#define | CSD_WP_GRP_ENABLE(csd) ((csd).flags1[6]>>7) |
#define | CSD_R2W_FACTOR(csd) (((csd).flags1[6]>>2) & 0x7) |
#define | CSD_WRITE_BL_LEN(csd) |
#define | CSD_WRITE_BL_PARTIAL(csd) (((csd).flags1[7]>>5) & 0x1) |
#define | CSD_FILE_FORMAT_GRP(csd) ((csd).flags1[8]>>7) |
#define | CSD_COPY(csd) (((csd).flags1[8]>>6) & 0x1) |
#define | CSD_PERM_WRITE_PROTECT(csd) (((csd).flags1[8]>>5) & 0x1) |
#define | CSD_TMP_WRITE_PROTECT(csd) (((csd).flags1[8]>>4) & 0x1) |
#define | CSD_FILE_FORMAT(csd) (((csd).flags1[8]>>2) & 0x3) |
#define | CSD_CRC(csd) ((csd).flags1[9]>>1) |
#define | CSD1_CARD_CAPACITY_KB(csd) ((uint32_t)(CSD1_C_SIZE(csd)+1)<<(CSD_C_SIZE_MULT(csd)+2+CSD_READ_BL_LEN(csd)-10)) |
#define | CSD2_CARD_CAPACITY_KB(csd) ((uint32_t)(CSD2_C_SIZE(csd)+1)<<9) |
#define | CSD_CARD_CAPACITY_KB(csd) |
compute card capacity | |
#define | SECTOR_SHIFT (9) |
shift count for conversion between sector number and byte number | |
#define | SECTOR_SIZE (1<<SECTOR_SHIFT) |
size of one sector in bytes | |
SDcard_response_1 | |
#define | SDR1_IN_IDLE_STATE (1<<0) |
#define | SDR1_ERASE_RESET (1<<1) |
#define | SDR1_ILLEGAL_COMMAND (1<<2) |
#define | SDR1_COM_CRC_ERROR (1<<3) |
#define | SDR1_ERASE_SEQUENCE_ERROR (1<<4) |
#define | SDR1_ADDRESS_ERROR (1<<5) |
#define | SDR1_PARAMETER_ERROR (1<<6) |
Typedefs | |
typedef struct sd_csd_data_s | sd_csd_data_t |
card-specific data | |
typedef struct sd_cid_data_s | sd_cid_data_t |
card identification data | |
typedef uint16_t | sd_blen_t |
block length for SD transfers | |
typedef struct sd_rd_mult_block_data_s | sd_rd_mult_block_data_t |
descriptor for read multiple block | |
typedef struct sd_wr_mult_block_data_s | sd_wr_mult_block_data_t |
descriptor for write multiple block | |
Enumerations | |
enum | SD_State_t { SD_Inactive = 0, SD_Idle, SD_Ready, SD_Identify, SD_Standby, SD_Transfer, SD_SendData, SD_RecvData, SD_Program, SD_Disconnect } |
Functions | |
uint16_t | sd_resp16_crc (uint8_t sd_response[]) |
compute CRC for 136bit response block | |
uint8_t | sd_recv_data (uint8_t *data, sd_blen_t blocklen) |
read data from SD card | |
void | sd_send_data (const uint8_t *data, sd_blen_t blocklen, uint8_t token) |
write data to SD card | |
uint16_t | sd_init_card (uint8_t debug) |
initialize SPI interface and SD card | |
uint32_t | sd_block2addr (uint32_t block) |
convert block number into address used in sending R/W command to card | |
uint8_t | sd_read_block (uint8_t *data, uint32_t address) |
read one block from SD card | |
uint32_t | sd_write_block (const uint8_t *data, uint32_t address) |
write one block to SD card | |
uint8_t | sd_read_multiple_block (uint8_t *const data[], uint8_t cnt, uint32_t address) |
read multiple blocks from SD card | |
uint8_t | sd_read_multiple_block2 (sd_rd_mult_block_data_t const data[], uint8_t cnt, uint32_t address) |
read multiple blocks from SD card | |
uint8_t | sd_write_multiple_block (const uint8_t *const data[], uint8_t cnt, uint32_t address) |
write multiple blocks to SD card | |
uint8_t | sd_write_multiple_block2 (sd_wr_mult_block_data_t const data[], uint8_t cnt, uint32_t address) |
write multiple blocks to SD card | |
void | sd_force_deselect (void) |
communication with SD card
#define CSD1_C_SIZE | ( | csd | ) |
(((uint16_t)((csd).flags1[0] & 0x3) << 10) \ | ((uint16_t)((csd).flags1[1]) << 2) \ | ((uint16_t)((csd).flags1[2]) >> 6))
#define CSD2_C_SIZE | ( | csd | ) |
(((uint32_t)((csd).flags1[1] & 0x3f) << 16)\ | ((uint16_t)((csd).flags1[2]) << 8) \ | ((uint16_t)((csd).flags1[3]) ))
#define CSD_C_SIZE_MULT | ( | csd | ) |
((((csd).flags1[3] & 0x3) << 1) \ | ((csd).flags1[4]>>7))
#define CSD_CARD_CAPACITY_KB | ( | csd | ) |
(CSD_STRUCTURE(csd) == 0 ? CSD1_CARD_CAPACITY_KB(csd) \ : CSD2_CARD_CAPACITY_KB(csd))
compute card capacity
#define CSD_CCC | ( | csd | ) |
(((uint16_t)(csd).ccc_read_bl_len[0] << 4) \ | ((uint16_t)((csd).ccc_read_bl_len[1]) >> 4))
#define CSD_SECTOR_SIZE | ( | csd | ) |
(((csd).flags1[4] & 0x3f) \ | ((csd).flags1[5]>>7))
#define CSD_WRITE_BL_LEN | ( | csd | ) |
(((csd).flags1[6] & 0x3) \ | ((csd).flags1[7]>>6))
#define VAL_CSD_ACCESS_TIME_ASYNC | ( | v | ) |
(VAL_CSD_ACCESS_TIME_ASYNC_TIME_CONV(VAL_CSD_ACCESS_TIME_ASYNC_TIME_RAW(v)) \ * VAL_CSD_ACCESS_TIME_ASYNC_UNIT_CONV(VAL_CSD_ACCESS_TIME_UNIT_RAW(v)))
#define VAL_CSD_ACCESS_TIME_ASYNC_TIME_CONV | ( | t | ) |
(t == 1 ? 1.0 : t == 2 ? 1.2 : \ t == 3 ? 1.3 : t == 4 ? 1.5 : \ t == 5 ? 2.0 : t == 6 ? 2.5 : \ t == 7 ? 3.0 : t == 8 ? 3.5 : \ t == 9 ? 4.0 : t == 10 ? 4.5 : \ t == 11 ? 5.0: t == 12 ? 5.5 : \ t == 13 ? 6.0: t == 14 ? 7.0 : \ t == 15 ? 8.0: 0)
#define VAL_CSD_TRAN_SPEED | ( | v | ) |
(VAL_CSD_TRAN_TIME_CONV(VAL_CSD_TRAN_TIME_RAW(v)) \ * VAL_CSD_TRAN_UNIT_CONV(VAL_CSD_TRAN_UNIT_RAW(v)))
#define VAL_CSD_TRAN_TIME_CONV | ( | t | ) |
(t == 1 ? 1.0 : t == 2 ? 1.2 : \ t == 3 ? 1.3 : t == 4 ? 1.5 : \ t == 5 ? 2.0 : t == 6 ? 2.5 : \ t == 7 ? 3.0 : t == 8 ? 3.5 : \ t == 9 ? 4.0 : t == 10 ? 4.5 : \ t == 11 ? 5.0 : t == 12 ? 5.5 : \ t == 13 ? 6.0 : t == 14 ? 7.0 : \ t == 15 ? 8.0 : 0)
#define VAL_CSD_TRAN_UNIT_CONV | ( | u | ) |
(u == 0 ? 100e3 : u == 1 ? 1e6 : \ u == 2 ? 10e6 : u == 3 ? 100e6 : \ 0)
typedef uint16_t sd_blen_t |
block length for SD transfers
NOTE: we have no more than 2^16 bytes address space, so we will not be able to use all 32 bits defined in SD protocol anyway
typedef struct sd_rd_mult_block_data_s sd_rd_mult_block_data_t |
descriptor for read multiple block
This structure provides the pointers to data for the sd_read_multiple_block2() function. These will transfer up to num_blocks blocks using the data pointer, when one element has been used the functions will use the next descriptor.
typedef struct sd_wr_mult_block_data_s sd_wr_mult_block_data_t |
descriptor for write multiple block
This structure provides the pointers to data for the sd_write_multiple_block2() function. These will transfer up to num_blocks blocks using the data pointer, when one element has been used the functions will use the next descriptor.
uint32_t sd_block2addr | ( | uint32_t | block | ) |
convert block number into address used in sending R/W command to card
Depending on card type, the address must either be a byte address (standard capacity) or a block address (high capacity)
A standard capacity card is addressed by byte number
A high capacity card is addressed by sector number
{ if (!sd_if_cond.proto_hc) return block << SECTOR_SHIFT; else return block; }
void sd_force_deselect | ( | void | ) |
abort any SD transfer by deselecting the card
Please, use this only for debugging stuck cards.
{ sd_deselect (); }
uint16_t sd_init_card | ( | uint8_t | dbg | ) |
initialize SPI interface and SD card
Initialize SPI interface and SD card after power-up. This function needs to be called after power to card is brought up before the SD card can be used
debug | when !=0 print out debugging messages on stdout |
initialize SD card currently in slot for use.
{ uint8_t i; uint8_t r; uint8_t chk; uint8_t save_debug = debug; debug = dbg; spi_init (get_div_for_speed((9<<3)|0)); /* set SPIfreq <= 400kHz */ /* SD spec says to wait at least 74 clock cycles after power-up */ debug_msg("SD_INIT"); for (i=0; i<10; i++) spi_write (0xff); debug_msg("."); spi_select (); /* no wait for ready */ for (i=0; i<10; i++) spi_write (0xff); sd_deselect (); debug_msg(".\r\n"); i = 0; do { _delay_ms(5); debug_byte (i++); r = sd_go_idle (); } while (r & 0b11110000); do { /* the card needs some time after power-up */ sd_if_cond.vhs = 0b0001; sd_if_cond.check = chk = 0b10101010; r = sd_get_if_cond (&sd_if_cond.version, &sd_if_cond.vhs, &sd_if_cond.check); } while (r & 0b00000010); if (r & 0b00000100) { /* SEND_IF_COND not supported, version 1.x */ sd_if_cond.proto_version = 1; } else { sd_if_cond.proto_version = 2; dprintf_P (PSTR("IFC.ver=%02X .vhs=%02X .check=%02X\r\n"), sd_if_cond.version, sd_if_cond.vhs, sd_if_cond.check); } /* read Operation Condition Register */ do { r = sd_get_ocr (&sd_ocr); dprintf_P (PSTR("OCR.volt=%02X .ready=%02X\r\n"), (uint16_t)((sd_ocr & 0xFF0000) >> 16), (uint16_t)(sd_ocr >> 30)); } while (0 && !(sd_ocr >> 31)); /* initiate startup, set HC mode if v2.x */ do { r = sd_set_op_cond (sd_if_cond.proto_version >= 2); } while ((r & (1<<0)) && (r & (1<<2)) == 0); /* enable CRC checking, disabled by default in SPI mode */ r = sd_crc_on_off (1); r = sd_get_csd (&sd_csd); if (sd_if_cond.proto_version >= 2) { for (i = 0; i<16; i++) { r = sd_get_ocr (&sd_ocr); dprintf_P (PSTR("OCR.volt=%02X .ready=%02X\r\n"), (uint16_t)((sd_ocr & 0xFF0000) >> 16), (uint16_t)(sd_ocr >> 30)); if (sd_ocr & ((uint32_t)1<<31)) break; _delay_ms(1); } debug_msg ("SD2.0 "); if (sd_ocr & ((uint32_t)1<<30)) { sd_if_cond.proto_hc = 1; debug_msg ("HC"); } else { sd_if_cond.proto_hc = 0; debug_msg ("SC"); } } else { sd_if_cond.proto_hc = 0; debug_msg ("SD1.x"); } if (CSD_STRUCTURE(sd_csd) == 0 || CSD_STRUCTURE(sd_csd) == 1) { uint32_t capacity = CSD_CARD_CAPACITY_KB(sd_csd); uint8_t spi_div; /* convert and round to MB */ capacity >>= 9; capacity += capacity & 1; capacity >>= 1; dprintf_P(PSTR(" %5ld MB"), capacity); dprintf_P(PSTR(" (csd=%1d "), CSD_STRUCTURE(sd_csd)); if (CSD_STRUCTURE(sd_csd) == 0) { dprintf_P(PSTR("size=%X mult=%X blen=%X"), CSD1_C_SIZE(sd_csd), CSD_C_SIZE_MULT(sd_csd), CSD_READ_BL_LEN(sd_csd) ); } else { dprintf_P(PSTR("size=%ld"), CSD2_C_SIZE(sd_csd) ); } dprintf_P(PSTR(")\r\n")); dprintf_P(PSTR("Access time: %dE%dns + %d SPI clock cycles"), (int)VAL_CSD_ACCESS_TIME_ASYNC_TIME_CONV(VAL_CSD_ACCESS_TIME_ASYNC_TIME_RAW(sd_csd.taac))*10, VAL_CSD_ACCESS_TIME_ASYNC_UNIT_RAW(sd_csd.taac)-1, sd_csd.nsac); /* switch to max. allowed SPI speed */ spi_div = get_div_for_speed(sd_csd.tran_speed); spi_write (0xff); spi_set_speed (spi_div); spi_write (0xff); spi_select (); spi_write (0xff); spi_write (0xff); spi_deselect (); } debug_msg ("\r\n"); sd_init_cmd_profiles (&sd_csd); /* read and display identification from card */ r = sd_get_cid (&sd_cid); if (r == 0) { for (i = 0; i < sizeof(sd_cid.pnm); i++) if (!isprint (sd_cid.pnm[i])) sd_cid.pnm[i] = ' '; dprintf_P (PSTR("%02x %.2s %.5s %c.%c %8lx %d/%02d\r\n"), sd_cid.mid, sd_cid.oid, sd_cid.pnm, int2hex (sd_cid.prv >> 4), int2hex (sd_cid.prv & 0xf), sd_cid.psn, sd_cid.mdt[1] & 0xf, ((sd_cid.mdt[1] >> 4)|(sd_cid.mdt[0] << 4)) & 0xff); } debug = save_debug; return r; }
uint8_t sd_read_block | ( | uint8_t * | data, | |
uint32_t | address | |||
) |
read one block from SD card
data | pointer to buffer for read data | |
address | card address to read data from, use sd_block2addr() |
read one block from SD card
data | buffer to put data into | |
address | SD card address to read data from |
{ uint8_t r; sd_select (); sd_send_cmd_arg32 (SD_READ_SINGLE_BLOCK, address); r = sd_recv_response1 (&sd_cmd_profiles[sd_read_cmd_profile]); if (r == 0) { sd_recv_data (data, sd_current_blocklen); } sd_deselect (); if (r != 0) { /* error in sending command */ sd_r1_print_P (PSTR("SDread"), r); } return r; }
uint8_t sd_read_multiple_block | ( | uint8_t *const | data[], | |
uint8_t | cnt, | |||
uint32_t | address | |||
) |
read multiple blocks from SD card
Read some blocks from SD card. This function allows to put the read data into discontigous buffers.
data[] | array of pointers to data buffers | |
cnt | number of blocks to read | |
address | card address of first block to read, use sd_block2addr() |
{ uint8_t r; uint8_t save_debug = debug; debug = 1; sd_select (); sd_send_cmd_arg32 (SD_READ_MULTIPLE_BLOCK, address); r = sd_recv_response1 (&sd_cmd_profiles[sd_read_cmd_profile]); if (r == 0) { for (; cnt; cnt--) { r = sd_recv_data (*data++, sd_current_blocklen); if ((r & 0b00011111) != 0b00000101) break; } r = sd_stop_trans (); } sd_deselect (); debug = save_debug; return r; }
uint8_t sd_read_multiple_block2 | ( | sd_rd_mult_block_data_t const | data[], | |
uint8_t | cnt, | |||
uint32_t | address | |||
) |
read multiple blocks from SD card
Read some blocks from SD card. This function allows to put the read data into discontigous buffers.
data[] | array of pointers to data buffers | |
cnt | number of blocks to read | |
address | card address of first block to read, use sd_block2addr() |
{ uint8_t r; uint8_t save_debug = debug; debug = 1; sd_select (); sd_send_cmd_arg32 (SD_READ_MULTIPLE_BLOCK, address); r = sd_recv_response1 (&sd_cmd_profiles[sd_read_cmd_profile]); if (r == 0) { uint8_t * ptr = data->buffer; uint8_t num_blocks = data->num_blocks; for (; cnt; cnt--) { if (num_blocks == 0) break; r = sd_recv_data (ptr, sd_current_blocklen); if ((r & 0b00011111) != 0b00000101) break; if (--num_blocks == 0) { data++; ptr = data->buffer; num_blocks = data->num_blocks; } else { ptr += sd_current_blocklen; } } r = sd_stop_trans (); } sd_deselect (); debug = save_debug; return r; }
uint8_t sd_recv_data | ( | uint8_t * | data, | |
sd_blen_t | blocklen | |||
) |
read data from SD card
data | pointer to buffer for data | |
blocklen | number of bytes to receive |
{ uint16_t crc = 0x0000; uint16_t crc_read; sd_blen_t i; uint8_t t; do { t = spi_transfer (0xff, 0, 1); } while (t == 0xff); /* wait for start block token */ for (i=blocklen; i; i--) { uint8_t b = spi_transfer (0xff, 0, 1); *data++ = b; crc = _crc_xmodem_update (crc, b); } crc_read = spi_transfer (0xff, 0, 1); crc_read <<= 8; crc_read |= spi_transfer (0xff, 0, 1); return crc_read == crc; }
uint16_t sd_resp16_crc | ( | uint8_t | sd_response[] | ) |
compute CRC for 136bit response block
CRC: XMODEM
void sd_send_data | ( | const uint8_t * | data, | |
sd_blen_t | blocklen, | |||
uint8_t | token | |||
) |
write data to SD card
data | pointer to buffer with data | |
blocklen | number of bytes to send | |
token | token value to start transmission |
uint32_t sd_write_block | ( | const uint8_t * | data, | |
uint32_t | address | |||
) |
write one block to SD card
data | pointer to buffer for data to write | |
address | card address to write data to, use sd_block2addr() |
write one block to SD card
data | buffer with data to write | |
address | SD card address to write data to |
{ uint8_t r; uint8_t resp_token; uint16_t r2; do { sd_select (); sd_send_cmd_arg32 (SD_WRITE_BLOCK, address); r = sd_recv_response1 (&sd_cmd_profiles[sd_write_cmd_profile]); if (r == 0) { sd_send_data (data, sd_current_blocklen, SDTOKEN_START); resp_token = sd_recv_data_response (&sd_cmd_profiles[sd_write_data_profile]); if ((resp_token & 0x1F) == 0x05) /* data was accepted */ { sd_busy_wait (); } else { printf_P (PSTR("SDwrite: response %02x "), resp_token); } } sd_deselect (); } while (r == 0 && (resp_token & 0x1F) == 0x0B); /* repeat on CRC error */ if (r == 0) { /* check status */ sd_select (); sd_send_cmd_0 (SD_SEND_STATUS); r2 = sd_recv_response2 (&sd_cmd_profiles[sd_write_cmd_profile]); sd_deselect (); return r2; } else { /* error in sending command */ sd_r1_print_P (PSTR("SDwrite"), r); } return ((uint32_t)r) << 16; }
uint8_t sd_write_multiple_block | ( | const uint8_t *const | data[], | |
uint8_t | cnt, | |||
uint32_t | address | |||
) |
write multiple blocks to SD card
Write some blocks to SD card. This function allows to provide the data to write in discontigous buffers.
data[] | array of pointers to data buffers | |
cnt | number of blocks to write | |
address | card address of first block to write, use sd_block2addr() |
{ uint8_t r; sd_select (); sd_send_cmd_arg32 (SD_READ_MULTIPLE_BLOCK, address); r = sd_recv_response1 (&sd_cmd_profiles[sd_write_cmd_profile]); if (r == 0) { for (; cnt; cnt--, data) { sd_send_data (*data++, sd_current_blocklen, SDTOKEN_START_MULTIPLE); r = sd_recv_data_response (&sd_cmd_profiles[sd_write_data_profile]); if (r) break; sd_busy_wait (); } sd_send_data (0, 0, SDTOKEN_STOP_MULTIPLE); } sd_deselect (); return r; }
uint8_t sd_write_multiple_block2 | ( | sd_wr_mult_block_data_t const | data[], | |
uint8_t | cnt, | |||
uint32_t | address | |||
) |
write multiple blocks to SD card
Write some blocks to SD card. This function allows to provide the data to write in discontigous buffers.
data[] | array of pointers to data buffers | |
cnt | number of blocks to write | |
address | card address of first block to write, use sd_block2addr() |
{ uint8_t r; sd_select (); sd_send_cmd_arg32 (SD_READ_MULTIPLE_BLOCK, address); r = sd_recv_response1 (&sd_cmd_profiles[sd_write_cmd_profile]); if (r == 0) { const uint8_t * ptr = data->buffer; uint8_t num_blocks = data->num_blocks; for (; cnt; cnt--) { if (num_blocks == 0) break; sd_send_data (ptr, sd_current_blocklen, SDTOKEN_START_MULTIPLE); r = sd_recv_data_response (&sd_cmd_profiles[sd_write_data_profile]); if (r) break; if (--num_blocks == 0) { data++; ptr = data->buffer; num_blocks = data->num_blocks; } else { ptr += sd_current_blocklen; } sd_busy_wait (); } sd_send_data (0, 0, SDTOKEN_STOP_MULTIPLE); } sd_deselect (); return r; }