/** * \ingroup sd_raw * Send a command to the memory card which responses with a R1 response. * * \param[in] command The command to send. * \param[in] arg The argument for command. * \returns The command answer. */ uint8_t sd_raw_send_command_r1(uint8_t command, uint32_t arg) { uint8_t response; uint8_t i; /* wait some clock cycles */ sd_raw_rec_byte(); /* send command via SPI */ sd_raw_send_byte(0x40 | command); sd_raw_send_byte((arg >> 24) & 0xff); sd_raw_send_byte((arg >> 16) & 0xff); sd_raw_send_byte((arg >> 8) & 0xff); sd_raw_send_byte((arg >> 0) & 0xff); sd_raw_send_byte(command == CMD_GO_IDLE_STATE ? 0x95 : 0xff); /* receive response */ for(i = 0; i < 10; ++i) { response = sd_raw_rec_byte(); if(response != 0xff) break; } return response; }
uint8_t sd_raw_write(const uint64_t offset, const uint8_t* buffer, uint16_t length) { uint32_t blk = (offset / 4); uint16_t n = 0; if ((length > 1) && (length % 4)) return 0; //misaligned access while (length) { /* address card */ SPI_CARD; /* send single block request */ if(sd_raw_send_command(CMD_WRITE_SINGLE_BLOCK, (sd_raw_card_type & (1 << SD_RAW_SPEC_SDHC) ? blk : blk * 512))) { SPI_PERIPH; return 0; } /* send start byte */ sd_raw_send_byte(0xfe); /* read byte block */ for (uint16_t i = 0, j = 0; i < 512; i++) { uint8_t b = 0xFF; //empty Flash cell state if ((i >= img_blk_offset) && (j < 4) && length) { b = buffer[n++]; j++; length--; } sd_raw_send_byte(b); if (j == 4) { sd_raw_hispeed_on(); SD_RAW_HISPEED_WAIT; sd_raw_hispeed_off(); break; } } /* wait while card is busy */ while(sd_raw_rec_byte() != 0xff); sd_raw_rec_byte(); /* deaddress card */ SPI_PERIPH; /* shift block */ blk++; } return 1; }
uint8_t sd_write_block(unsigned long block_address, unsigned char buffer[512]) { //unsigned int block_offset = (block_address*512) & 0x01FF; //block_address = (block_address*512) - block_offset; block_address *= 512; if(sd_raw_locked()) return 0; /* address card */ select_card(); /* send single block request */ #if SD_RAW_SDHC if(sd_raw_send_command(CMD_WRITE_SINGLE_BLOCK, (sd_raw_card_type & (1 << SD_RAW_SPEC_SDHC) ? block_address / 512 : block_address))) #else if(sd_raw_send_command(CMD_WRITE_SINGLE_BLOCK, block_address)) #endif { unselect_card(); return 0; } /* send start byte */ sd_raw_send_byte(0xfe); /* write byte block */ uint16_t i; for(i = 0; i < 512; i++) sd_raw_send_byte(buffer[i]); /* write dummy crc16 */ sd_raw_send_byte(0xff); sd_raw_send_byte(0xff); /* wait while card is busy */ while(sd_raw_rec_byte() != 0xff); sd_raw_rec_byte(); /* deaddress card */ unselect_card(); return 1; }
/** * \ingroup sd_raw * Send a command to the memory card which responses with a R1 response (and possibly others). * * \param[in] command The command to send. * \param[in] arg The argument for command. * \returns The command answer. */ uint8_t sd_raw_send_command(uint8_t command, uint32_t arg) { uint8_t response; /* wait some clock cycles */ sd_raw_rec_byte(); /* send command via SPI */ sd_raw_send_byte(0x40 | command); sd_raw_send_byte((arg >> 24) & 0xff); sd_raw_send_byte((arg >> 16) & 0xff); sd_raw_send_byte((arg >> 8) & 0xff); sd_raw_send_byte((arg >> 0) & 0xff); switch(command) { case CMD_GO_IDLE_STATE: sd_raw_send_byte(0x95); break; case CMD_SEND_IF_COND: sd_raw_send_byte(0x87); break; default: sd_raw_send_byte(0xff); break; } /* receive response */ uint8_t i; for(i = 0; i < 10; ++i) { response = sd_raw_rec_byte(); if(response != 0xff) break; } return response; }
/** * \ingroup sd_raw * Send a command to the memory card which responses with a R1 response (and possibly others). * * \param[in] command The command to send. * \param[in] arg The argument for command. * \returns The command answer. */ uint8_t sd_raw_send_command(uint8_t command, uint32_t arg) { uint8_t response; uint8_t n_try = 0; do { n_try++; // wait before retrying if (n_try > 1) { delay(50); printf("Retry "); } //printf("C %hd %ld\r\n", command, arg); LED_on(); /* interrupt request */ irq_high(); /* send command via SPI */ sd_raw_send_byte(0x40 | command); sd_raw_send_byte((arg >> 24) & 0xff); sd_raw_send_byte((arg >> 16) & 0xff); sd_raw_send_byte((arg >> 8) & 0xff); sd_raw_send_byte((arg >> 0) & 0xff); /* receive response */ response = sd_raw_rec_byte(); /* finish interrupt request */ irq_low(); LED_off(); // after 255 trials, fail if (n_try == 0xff) { response = R1_FAILURE; break; } } while (response == R1_WAIT_RETRY); return response; }
/** * \ingroup sd_raw * Send a command to the memory card which responses with a R1 response (and possibly others). * * \param[in] command The command to send. * \param[in] arg The argument for command. * \returns The command answer. */ uint8_t sd_raw_send_command(uint8_t command, uint32_t arg) { uint8_t response; uint8_t *args = reinterpret_cast<uint8_t *>(&arg); /* wait some clock cycles */ sd_raw_rec_byte(); #if !SD_RAW_SAVE_RAM if ( sd_use_crc ) { uint8_t crc[6] = { command | 0x40, args[3], args[2], args[1], args[0] }; crc[5] = sd_crc7(crc, 5); for (uint8_t i = 0; i < 6; i++) sd_raw_send_byte(crc[i]); } else { #endif /* send command via SPI */ sd_raw_send_byte(0x40 | command); for (int8_t i = 3; i >= 0; i--) sd_raw_send_byte(args[i]); switch(command) { case CMD_GO_IDLE_STATE: sd_raw_send_byte(0x95); break; case CMD_SEND_IF_COND: sd_raw_send_byte(0x87); break; default: sd_raw_send_byte(0xff); break; } #if !SD_RAW_SAVE_RAM } #endif /* receive response */ for(uint8_t i = 0; i < 10; ++i) { response = sd_raw_rec_byte(); if(response != 0xff) break; } return response; }
/** * \ingroup sd_raw * Writes raw data to the card. * * \note If write buffering is enabled, you might have to * call sd_raw_sync() before disconnecting the card * to ensure all remaining data has been written. * * \param[in] offset The offset where to start writing. * \param[in] buffer The buffer containing the data to be written. * \param[in] length The number of bytes to write. * \returns 0 on failure, 1 on success. * \see sd_raw_write_interval, sd_raw_read, sd_raw_read_interval */ uint8_t sd_raw_write(uint32_t offset, const uint8_t* buffer, uint16_t length) { #if SD_RAW_WRITE_SUPPORT if(get_pin_locked()) return 0; uint32_t block_address; uint16_t block_offset; uint16_t write_length; uint16_t i; while(length > 0) { /* determine byte count to write at once */ block_address = offset & 0xfffffe00; block_offset = offset & 0x01ff; write_length = 512 - block_offset; /* write up to block border */ if(write_length > length) write_length = length; /* Merge the data to write with the content of the block. * Use the cached block if available. */ if(block_address != raw_block_address) { #if SD_RAW_WRITE_BUFFERING if(!raw_block_written) { if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) return 0; } #endif if(block_offset || write_length < 512) { if(!sd_raw_read(block_address, raw_block, sizeof(raw_block))) return 0; } raw_block_address = block_address; } if(buffer != raw_block) { memcpy(raw_block + block_offset, buffer, write_length); #if SD_RAW_WRITE_BUFFERING raw_block_written = 0; if(length == write_length) return 1; #endif } buffer += write_length; /* address card */ select_card(); /* send single block request */ if(sd_raw_send_command_r1(CMD_WRITE_SINGLE_BLOCK, block_address)) { unselect_card(); return 0; } /* send start byte */ sd_raw_send_byte(0xfe); /* write byte block */ uint8_t* cache = raw_block; for(i = 0; i < 512; ++i) sd_raw_send_byte(*cache++); /* write dummy crc16 */ sd_raw_send_byte(0xff); sd_raw_send_byte(0xff); /* wait while card is busy */ while(sd_raw_rec_byte() != 0xff); sd_raw_rec_byte(); /* deaddress card */ unselect_card(); length -= write_length; offset += write_length; #if SD_RAW_WRITE_BUFFERING raw_block_written = 1; #endif } return 1; #else return 0; #endif }
/** * \ingroup sd_raw * Writes raw data to the card. * * \note If write buffering is enabled, you might have to * call sd_raw_sync() before disconnecting the card * to ensure all remaining data has been written. * * \param[in] offset The offset where to start writing. * \param[in] buffer The buffer containing the data to be written. * \param[in] length The number of bytes to write. * \returns 0 on failure, 1 on success. * \see sd_raw_write_interval, sd_raw_read, sd_raw_read_interval */ uint8_t sd_raw_write(offset_t offset, const uint8_t* buffer, uintptr_t length) { if(sd_raw_locked()) return 0; offset_t block_address; uint16_t block_offset; uint16_t write_length; while(length > 0) { /* determine byte count to write at once */ block_offset = offset & 0x01ff; block_address = offset - block_offset; write_length = 512 - block_offset; /* write up to block border */ if(write_length > length) write_length = length; /* Merge the data to write with the content of the block. * Use the cached block if available. */ if(block_address != raw_block_address) { #if SD_RAW_WRITE_BUFFERING if(!sd_raw_sync()) return 0; #endif if(block_offset || write_length < 512) { if(!sd_raw_read(block_address, raw_block, sizeof(raw_block))) return 0; } raw_block_address = block_address; } if(buffer != raw_block) { memcpy(raw_block + block_offset, buffer, write_length); #if SD_RAW_WRITE_BUFFERING raw_block_written = 0; if(length == write_length) return 1; #endif } /* address card */ select_card(); /* send single block request */ #if SD_RAW_SDHC if(sd_raw_send_command(CMD_WRITE_SINGLE_BLOCK, (sd_raw_card_type & (1 << SD_RAW_SPEC_SDHC) ? block_address / 512 : block_address))) #else if(sd_raw_send_command(CMD_WRITE_SINGLE_BLOCK, block_address)) #endif { unselect_card(); return 0; } /* send start byte */ sd_raw_send_byte(0xfe); /* write byte block */ uint8_t* cache = raw_block; for(uint16_t i = 0; i < 512; ++i) sd_raw_send_byte(*cache++); /* write dummy crc16 */ sd_raw_send_byte(0xff); sd_raw_send_byte(0xff); uint16_t tries = 0; /* wait while card is busy */ while(sd_raw_rec_byte() != 0xff){ if(tries >= 0x7FFF){ unselect_card(); return 0; } tries++; } sd_raw_rec_byte(); /* deaddress card */ unselect_card(); buffer += write_length; offset += write_length; length -= write_length; #if SD_RAW_WRITE_BUFFERING raw_block_written = 1; #endif } return 1; }
/** * \ingroup sd_raw * Reads raw data from the card. * * \param[in] offset The offset from which to read. * \param[out] buffer The buffer into which to write the data. * \param[in] length The number of bytes to read. * \returns 0 on failure, 1 on success. * \see sd_raw_read_interval, sd_raw_write, sd_raw_write_interval */ uint8_t sd_raw_read(offset_t offset, uint8_t* buffer, uintptr_t length) { offset_t block_address; uint16_t block_offset; uint16_t read_length; while(length > 0) { /* determine byte count to read at once */ block_offset = offset & 0x01ff; block_address = offset - block_offset; read_length = 512 - block_offset; /* read up to block border */ if(read_length > length) read_length = length; /* check if the requested data is cached */ if(block_address != raw_block_address) { #if SD_RAW_WRITE_BUFFERING if(!sd_raw_sync()) return 0; #endif /* send single block request */ #if SD_RAW_SDHC if(sd_raw_send_command(CMD_READ_SINGLE_BLOCK, (sd_raw_card_type & (1 << SD_RAW_SPEC_SDHC) ? block_address / 512 : block_address))) #else if(sd_raw_send_command(CMD_READ_SINGLE_BLOCK, block_address)) #endif { return 0; } /* wait for data block (start byte 0xfe) */ //while(sd_raw_rec_byte() != 0xfe); sd_raw_send_byte(0xef); /* read byte block */ uint8_t* cache = raw_block; for(uint16_t i = 0; i < 512; ++i) { while(!(SPSR & (1<<SPIF))); *cache++ = SPDR; } raw_block_address = block_address; /* read crc16 */ sd_raw_send_byte(0xab); sd_raw_send_byte(0xcd); memcpy(buffer, raw_block + block_offset, read_length); buffer += read_length; } else { /* use cached data */ memcpy(buffer, raw_block + block_offset, read_length); buffer += read_length; } length -= read_length; offset += read_length; } return 1; }