📄 sd_raw.c
字号:
uint16_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); sd_raw_send_byte(command == CMD_GO_IDLE_STATE ? 0x95 : 0xff); /* receive response */ for(int i = 0; i < 10; ++i) { response = sd_raw_rec_byte(); if(response != 0xff) break; } response <<= 8; response |= sd_raw_rec_byte(); /* the card internally needs eight further clock cycles */ sd_raw_rec_byte(); return response;}/** * \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 */uint8_t sd_raw_read(uint32_t offset, uint8_t* buffer, uint16_t length){ /* address card */ select_card(); uint32_t block_address; uint16_t block_offset; uint16_t read_length; while(length > 0) { /* determine byte count to read at once */ block_address = offset & 0xfffffe00; block_offset = offset & 0x01ff; read_length = 512 - block_offset; /* read up to block border */ if(read_length > length) read_length = length; #if !SD_RAW_SAVE_RAM /* check if the requested data is cached */ if(block_address != raw_block_address)#endif { /* send single block request */ if(sd_raw_send_command_r1(CMD_READ_SINGLE_BLOCK, block_address)) { unselect_card(); return 0; } /* wait for data block (start byte 0xfe) */ while(sd_raw_rec_byte() != 0xfe);#if SD_RAW_SAVE_RAM /* read byte block */ uint16_t read_to = block_offset + read_length; for(uint16_t i = 0; i < 512; ++i) { uint8_t b = sd_raw_rec_byte(); if(i >= block_offset && i < read_to) *buffer++ = b; }#else /* read byte block */ uint8_t* cache = raw_block; for(uint16_t i = 0; i < 512; ++i) *cache++ = sd_raw_rec_byte(); raw_block_address = block_address; memcpy(buffer, raw_block + block_offset, read_length); buffer += read_length;#endif /* read crc16 */ sd_raw_rec_byte(); sd_raw_rec_byte(); }#if !SD_RAW_SAVE_RAM else { /* use cached data */ memcpy(buffer, raw_block + block_offset, read_length); }#endif length -= read_length; offset += read_length; } /* deaddress card */ unselect_card(); /* let card some time to finish */ sd_raw_rec_byte(); return 1;}/** * \ingroup sd_raw * Continuously reads units of \c interval bytes and calls a callback function. * * This function starts reading at the specified offset. Every \c interval bytes, * it calls the callback function with the associated data buffer. * * By returning zero, the callback may stop reading. * * \note Within the callback function, you can not start another read or * write operation. * \note This function only works if the following conditions are met: * - (offset - (offset % 512)) % interval == 0 * - length % interval == 0 * * \param[in] offset Offset from which to start reading. * \param[in] buffer Pointer to a buffer which is at least interval bytes in size. * \param[in] interval Number of bytes to read before calling the callback function. * \param[in] length Number of bytes to read altogether. * \param[in] callback The function to call every interval bytes. * \param[in] p An opaque pointer directly passed to the callback function. * \returns 0 on failure, 1 on success * \see sd_raw_read, sd_raw_write */uint8_t sd_raw_read_interval(uint32_t offset, uint8_t* buffer, uint16_t interval, uint16_t length, sd_raw_interval_handler callback, void* p){ if(!buffer || interval == 0 || length < interval || !callback) return 0;#if !SD_RAW_SAVE_RAM while(length >= interval) { /* as reading is now buffered, we directly * hand over the request to sd_raw_read() */ if(!sd_raw_read(offset, buffer, interval)) return 0; if(!callback(buffer, offset, p)) break; offset += interval; length -= interval; } return 1;#else /* address card */ select_card(); uint16_t block_offset; uint16_t read_length; uint8_t* buffer_cur; uint8_t finished = 0; do { /* determine byte count to read at once */ block_offset = offset & 0x01ff; read_length = 512 - block_offset; /* send single block request */ if(sd_raw_send_command_r1(CMD_READ_SINGLE_BLOCK, offset & 0xfffffe00)) { unselect_card(); return 0; } /* wait for data block (start byte 0xfe) */ while(sd_raw_rec_byte() != 0xfe); /* read up to the data of interest */ for(uint16_t i = 0; i < block_offset; ++i) sd_raw_rec_byte(); /* read interval bytes of data and execute the callback */ do { if(read_length < interval || length < interval) break; buffer_cur = buffer; for(uint16_t i = 0; i < interval; ++i) *buffer_cur++ = sd_raw_rec_byte(); if(!callback(buffer, offset + (512 - read_length), p)) { finished = 1; break; } read_length -= interval; length -= interval; } while(read_length > 0 && length > 0); /* read rest of data block */ while(read_length-- > 0) sd_raw_rec_byte(); /* read crc16 */ sd_raw_rec_byte(); sd_raw_rec_byte(); if(length < interval) break; offset = (offset & 0xfffffe00) + 512; } while(!finished); /* deaddress card */ unselect_card(); /* let card some time to finish */ sd_raw_rec_byte(); return 1;#endif}/** * \ingroup sd_raw * Writes raw data to the card. * * \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_read */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; while(length > 0) { /* determine byte count to read at once */ block_address = offset & 0xfffffe00; block_offset = offset & 0x01ff; write_length = 512 - block_offset; /* read 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(block_offset || write_length < 512) { if(!sd_raw_read(block_address, raw_block, sizeof(raw_block))) return 0; } } raw_block_address = block_address; memcpy(raw_block + block_offset, buffer, write_length); 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(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); /* 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; } return 1;#else return 0;#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -