📄 sdraw.c
字号:
#include "config.h"
#include <string.h>
static uint8_t raw_block[512];
static uint8_t raw_block_written;
static uint32_t raw_block_address;
uint8_t sdraw_card_detected()
{
return ((get_pin_cd() == 0x00) ? 1 : 0);
}
uint8_t sdraw_card_wp()
{
return((get_pin_wp() == 0x00) ? 1 : 0);
}
uint8_t sdraw_recv_byte()
{
/* send dummy data for receiving some */
return SPI_recv_byte();
}
void sdraw_send_byte(uint8_t data)
{
SPI_send_byte(data);
}
uint8_t sdraw_send_command_r1(uint8_t command, uint32_t arg)
{
uint8_t i;
uint8_t response;
/* wait some clock cycles */
sdraw_recv_byte();
/* send command via SPI */
sdraw_send_byte(0x40 | command);
sdraw_send_byte((arg >> 24) & 0xFF);
sdraw_send_byte((arg >> 16) & 0xFF);
sdraw_send_byte((arg >> 8) & 0xFF);
sdraw_send_byte((arg >> 0) & 0xFF);
sdraw_send_byte(command == CMD_GO_IDLE_STATE ? 0x95 : 0xFF);
/* receive response */
for(i = 0; i < 10; ++i)
{
response = sdraw_recv_byte();
if(response != 0xFF)
break;
}
return response;
}
uint8_t sdraw_sync()
{
if(raw_block_written)
return 1;
if(!sdraw_write(raw_block_address, raw_block, sizeof(raw_block)))
return 0;
raw_block_written = 1;
return 1;
}
uint8_t sdraw_read(uint32_t offset, uint8_t* buffer, uint16_t length)
{
uint32_t block_address;
uint16_t block_offset;
uint16_t read_length;
uint16_t read_to;
uint16_t i;
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(!sdraw_sync())
return 0;
/* address card */
select_card();
/* send single block request */
if(sdraw_send_command_r1(CMD_READ_SINGLE_BLOCK, block_address))
{
unselect_card();
return 0;
}
/* wait for data block (start byte 0xfe) */
while(sdraw_recv_byte() != 0xFE);
/* read byte block */
read_to = block_offset + read_length;
for(i = 0; i < 512; ++i)
{
uint8_t b = sdraw_recv_byte();
if(i >= block_offset && i < read_to)
*buffer++ = b;
}
/* read crc16 */
sdraw_recv_byte();
sdraw_recv_byte();
/* deaddress card */
unselect_card();
/* let card some time to finish */
sdraw_recv_byte();
length -= read_length;
offset += read_length;
}
return 1;
}
uint8_t sdraw_write(uint32_t offset, const uint8_t* buffer, uint16_t length)
{
uint32_t block_address;
uint16_t block_offset;
uint16_t write_length;
uint8_t* cache;
uint16_t i;
if(sdraw_card_wp())
return 0;
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(!sdraw_sync())
return 0;
if(block_offset || write_length < 512)
{
if(!sdraw_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);
raw_block_written = 0;
if(length == write_length)
return 1;
}
/* address card */
select_card();
/* send single block request */
if(sdraw_send_command_r1(CMD_WRITE_SINGLE_BLOCK, block_address))
{
unselect_card();
return 0;
}
/* send start byte */
sdraw_send_byte(0xFE);
/* write byte block */
cache = raw_block;
for(i = 0; i < 512; ++i)
sdraw_send_byte(*cache++);
/* write dummy crc16 */
sdraw_send_byte(0xFF);
sdraw_send_byte(0xFF);
/* wait while card is busy */
while(sdraw_recv_byte() != 0xFF);
sdraw_recv_byte();
/* deaddress card */
unselect_card();
buffer += write_length;
offset += write_length;
length -= write_length;
raw_block_written = 1;
}
return 1;
}
uint8_t sdraw_init()
{
uint8_t i;
uint16_t j;
uint8_t response;
/* enable inputs for reading card status */
configure_pin_cd();
configure_pin_wp();
/* enable outputs for MOSI, SCK, SS, input for MISO */
configure_pin_mosi();
configure_pin_sck();
configure_pin_ss();
configure_pin_miso();
unselect_card();
/* initialize SPI with lowest frequency; max. 400kHz during identification mode of card */
// SPI_init();
/* initialization procedure */
if(!sdraw_card_detected())
{ UART_puts("ERROR : CARD NOT FOUND\n");
return 0;
}
UART_puts("CARD DETECTED\n");
/* card needs 74 cycles minimum to start up */
for(i = 0; i < 10; ++i)
{
/* byte recv : 8 cycles */
sdraw_recv_byte();
}
/* address card */
select_card();
/* reset card */
for(j = 0; ; ++j)
{
response = sdraw_send_command_r1(CMD_GO_IDLE_STATE, 0);
if(response == (1 << R1_IDLE_STATE))
break;
if(j == 0x1ff)
{
unselect_card();
UART_puts("ERROR : RESET TIMEOVER\n");
return 0;
}
}
UART_puts("RESET OK\n");
/* wait for card to get ready */
for(j = 0; ; ++j)
{
response = sdraw_send_command_r1(CMD_SEND_OP_COND, 0);
if(!(response & (1 << R1_IDLE_STATE)))
break;
if(j == 0x7fff)
{
unselect_card();
UART_puts("ERROR : CARD NOT READY\n");
return 0;
}
}
UART_puts("CARD READY\n");
/* set block size to 512 bytes */
if(sdraw_send_command_r1(CMD_SET_BLOCKLEN, 512))
{
unselect_card();
UART_puts("ERROR : UNABLE TO BLOCK SIZE\n");
return 0;
}
UART_puts("SET BLOCK SIZE TO 512\n");
/* deaddress card */
unselect_card();
/* switch to highest SPI frequency possible */
SPI_set_speed(SPI_SPEED_FOSC_DIV_4, SPI_2X_ENABLE);
return 1;
}
uint8_t sdraw_get_info(struct sdraw_info* info)
{
uint8_t i, b;
uint8_t csd_read_bl_len = 0;
uint8_t csd_c_size_mult = 0;
uint16_t csd_c_size = 0;
if(!info || !sdraw_card_detected())
return 0;
memset(info, 0, sizeof(*info));
select_card();
/* read cid register */
if(sdraw_send_command_r1(CMD_SEND_CID, 0))
{
unselect_card();
return 0;
}
while(sdraw_recv_byte() != 0xFE);
for(i = 0; i < 18; ++i)
{
b = sdraw_recv_byte();
switch(i)
{
case 0:
info->manufacturer = b;
break;
case 1:
case 2:
info->oem[i - 1] = b;
break;
case 3:
case 4:
case 5:
case 6:
case 7:
info->product[i - 3] = b;
break;
case 8:
info->revision = b;
break;
case 9:
case 10:
case 11:
case 12:
info->serial |= (uint32_t) b << ((12 - i) * 8);
break;
case 13:
info->manufacturing_year = b << 4;
break;
case 14:
info->manufacturing_year |= b >> 4;
info->manufacturing_month = b & 0x0f;
break;
}
}
/* read csd register */
if(sdraw_send_command_r1(CMD_SEND_CSD, 0))
{
unselect_card();
return 0;
}
while(sdraw_recv_byte() != 0xfe);
for(i = 0; i < 18; ++i)
{
b = sdraw_recv_byte();
switch(i)
{
case 5:
csd_read_bl_len = b & 0x0f;
break;
case 6:
csd_c_size = (uint16_t) (b & 0x03) << 8;
break;
case 7:
csd_c_size |= b;
csd_c_size <<= 2;
break;
case 8:
csd_c_size |= b >> 6;
++csd_c_size;
break;
case 9:
csd_c_size_mult = (b & 0x03) << 1;
break;
case 10:
csd_c_size_mult |= b >> 7;
info->capacity = (uint32_t) csd_c_size << (csd_c_size_mult + csd_read_bl_len + 2);
break;
case 14:
if(b & 0x40)
info->flag_copy = 1;
if(b & 0x20)
info->flag_write_protect = 1;
if(b & 0x10)
info->flag_write_protect_temp = 1;
info->format = (b & 0x0c) >> 2;
break;
}
}
unselect_card();
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -