⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdraw.c

📁 TFT-LCD Atmega128 Source Code
💻 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 + -