Stripped down SD-Card Library

Hi

I stripped down the SD-Card Library so it uses less resources:

  • Read and Write of defined (small) Blocks without big overhead (the original library always writes 512 bytes)
  • No 512Byte Buffer needed. Read and Write direcly to the result buffer.
  • Soft SPI with freely configurable pins.
  • Only two files

I left the interrupt driven spi interface intakt but it seems not to work anymore with the fastest speed.
I guess it needs a delay somewhere.

Have Fun

sd_raw.cpp

/*
 * Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de>
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of either the GNU General Public License version 2
 * or the GNU Lesser General Public License version 2.1, both as
 * published by the Free Software Foundation.
 */
 


#include <string.h>
#include <avr/io.h>
#include "sd_raw.h"

/**
 * \addtogroup sd_raw MMC/SD card raw access
 *
 * This module implements read and write access to MMC and
 * SD cards. It serves as a low-level driver for the higher
 * level modules such as partition and file system access.
 *
 * @{
 */
/**
 * \file
 * MMC/SD raw access implementation (license: GPLv2 or LGPLv2.1)
 *
 * \author Roland Riegel
 */
 
  //striped down for small block access for use as large eeprom
 //26.8.2011 Deif Keller

/**
 * \addtogroup sd_raw_config MMC/SD configuration
 * Preprocessor defines to configure the MMC/SD support.
 */

/**
 * @}
 */

/* commands available in SPI mode */

/* CMD0: response R1 */
#define CMD_GO_IDLE_STATE 0x00
/* CMD1: response R1 */
#define CMD_SEND_OP_COND 0x01
/* CMD9: response R1 */
#define CMD_SEND_CSD 0x09
/* CMD10: response R1 */
#define CMD_SEND_CID 0x0a
/* CMD12: response R1 */
#define CMD_STOP_TRANSMISSION 0x0c
/* CMD13: response R2 */
#define CMD_SEND_STATUS 0x0d
/* CMD16: arg0[31:0]: block length, response R1 */
#define CMD_SET_BLOCKLEN 0x10
/* CMD17: arg0[31:0]: data address, response R1 */
#define CMD_READ_SINGLE_BLOCK 0x11
/* CMD18: arg0[31:0]: data address, response R1 */
#define CMD_READ_MULTIPLE_BLOCK 0x12
/* CMD24: arg0[31:0]: data address, response R1 */
#define CMD_WRITE_SINGLE_BLOCK 0x18
/* CMD25: arg0[31:0]: data address, response R1 */
#define CMD_WRITE_MULTIPLE_BLOCK 0x19
/* CMD27: response R1 */
#define CMD_PROGRAM_CSD 0x1b
/* CMD28: arg0[31:0]: data address, response R1b */
#define CMD_SET_WRITE_PROT 0x1c
/* CMD29: arg0[31:0]: data address, response R1b */
#define CMD_CLR_WRITE_PROT 0x1d
/* CMD30: arg0[31:0]: write protect data address, response R1 */
#define CMD_SEND_WRITE_PROT 0x1e
/* CMD32: arg0[31:0]: data address, response R1 */
#define CMD_TAG_SECTOR_START 0x20
/* CMD33: arg0[31:0]: data address, response R1 */
#define CMD_TAG_SECTOR_END 0x21
/* CMD34: arg0[31:0]: data address, response R1 */
#define CMD_UNTAG_SECTOR 0x22
/* CMD35: arg0[31:0]: data address, response R1 */
#define CMD_TAG_ERASE_GROUP_START 0x23
/* CMD36: arg0[31:0]: data address, response R1 */
#define CMD_TAG_ERASE_GROUP_END 0x24
/* CMD37: arg0[31:0]: data address, response R1 */
#define CMD_UNTAG_ERASE_GROUP 0x25
/* CMD38: arg0[31:0]: stuff bits, response R1b */
#define CMD_ERASE 0x26
/* CMD42: arg0[31:0]: stuff bits, response R1b */
#define CMD_LOCK_UNLOCK 0x2a
/* CMD58: response R3 */
#define CMD_READ_OCR 0x3a
/* CMD59: arg0[31:1]: stuff bits, arg0[0:0]: crc option, response R1 */
#define CMD_CRC_ON_OFF 0x3b

/* command responses */
/* R1: size 1 byte */
#define R1_IDLE_STATE 0
#define R1_ERASE_RESET 1
#define R1_ILL_COMMAND 2
#define R1_COM_CRC_ERR 3
#define R1_ERASE_SEQ_ERR 4
#define R1_ADDR_ERR 5
#define R1_PARAM_ERR 6
/* R1b: equals R1, additional busy bytes */
/* R2: size 2 bytes */
#define R2_CARD_LOCKED 0
#define R2_WP_ERASE_SKIP 1
#define R2_ERR 2
#define R2_CARD_ERR 3
#define R2_CARD_ECC_FAIL 4
#define R2_WP_VIOLATION 5
#define R2_INVAL_ERASE 6
#define R2_OUT_OF_RANGE 7
#define R2_CSD_OVERWRITE 7
#define R2_IDLE_STATE (R1_IDLE_STATE + 8)
#define R2_ERASE_RESET (R1_ERASE_RESET + 8)
#define R2_ILL_COMMAND (R1_ILL_COMMAND + 8)
#define R2_COM_CRC_ERR (R1_COM_CRC_ERR + 8)
#define R2_ERASE_SEQ_ERR (R1_ERASE_SEQ_ERR + 8)
#define R2_ADDR_ERR (R1_ADDR_ERR + 8)
#define R2_PARAM_ERR (R1_PARAM_ERR + 8)
/* R3: size 5 bytes */
#define R3_OCR_MASK (0xffffffffUL)
#define R3_IDLE_STATE (R1_IDLE_STATE + 32)
#define R3_ERASE_RESET (R1_ERASE_RESET + 32)
#define R3_ILL_COMMAND (R1_ILL_COMMAND + 32)
#define R3_COM_CRC_ERR (R1_COM_CRC_ERR + 32)
#define R3_ERASE_SEQ_ERR (R1_ERASE_SEQ_ERR + 32)
#define R3_ADDR_ERR (R1_ADDR_ERR + 32)
#define R3_PARAM_ERR (R1_PARAM_ERR + 32)
/* Data Response: size 1 byte */
#define DR_STATUS_MASK 0x0e
#define DR_STATUS_ACCEPTED 0x05
#define DR_STATUS_CRC_ERR 0x0a
#define DR_STATUS_WRITE_ERR 0x0c



/* private helper functions */
static void sd_raw_send_byte(uint8_t b);
static uint8_t sd_raw_rec_byte();
static uint8_t sd_raw_send_command_r1(uint8_t command, uint32_t arg);
static uint16_t sd_raw_send_command_r2(uint8_t command, uint32_t arg);

/**
 * \ingroup sd_raw
 * Initializes memory card communication.
 *
 * \returns 0 on failure, 1 on success.
 */
uint8_t sd_raw_init()
{
  
#ifndef SD_RAW_SOFTSPI
  

    /* 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 */
    SPCR = (0 << SPIE) | /* SPI Interrupt Enable */
           (1 << SPE)  | /* SPI Enable */
           (0 << DORD) | /* Data Order: MSB first */
           (1 << MSTR) | /* Master mode */
           (0 << CPOL) | /* Clock Polarity: SCK low when idle */
           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
           (1 << SPR1) | /* Clock Frequency: f_OSC / 128 */
           (1 << SPR0);
    SPSR &= ~(1 << SPI2X); /* No doubled clock frequency */

#else
    
    pinMode(pinClk,OUTPUT);
    pinMode(pinDataOut,OUTPUT);
    pinMode(pinDataIn,INPUT);
    pinMode(pinSdCs, OUTPUT);

 
    
#endif

    /* initialization procedure */
    
    /* card needs 74 cycles minimum to start up */
    for(uint8_t i = 0; i < 10; ++i)
    {
        /* wait 8 clock cycles */
        sd_raw_rec_byte();
    }

    /* address card */
    select_card();

    /* reset card */
    uint8_t response;
    for(uint16_t i = 0; ; ++i)
    {
        response = sd_raw_send_command_r1(CMD_GO_IDLE_STATE, 0);
        if(response == (1 << R1_IDLE_STATE))
            break;

        if(i == 0x1ff)
        {
            unselect_card();
            Serial.println("init error");
            return 0;
        }
    }
    
    /* wait for card to get ready */
    for(uint16_t i = 0; ; ++i)
    {
        response = sd_raw_send_command_r1(CMD_SEND_OP_COND, 0);
        if(!(response & (1 << R1_IDLE_STATE)))
            break;

        if(i == 0x7fff)
        {
            unselect_card();
            return 0;
        }
    }

    /* set block size to 512 bytes */
    if(sd_raw_send_command_r1(CMD_SET_BLOCKLEN, BLOCK_SIZE))
    {
        unselect_card();
        Serial.println("block size error");
        return 0;
    }

    /* deaddress card */
    unselect_card();


#ifndef SD_RAW_SOFTSPI
  // it seems not to work on highest spi frequency... a delay somewhere could help....
    /* switch to highest SPI frequency possible */
    //SPCR &= ~((1 << SPR1) | (1 << SPR0)); /* Clock Frequency: f_OSC / 4 */
    //SPSR |= (1 << SPI2X); /* Doubled Clock Frequency: f_OSC / 2 */
#endif


    return 1;
}



/**
 * \ingroup sd_raw
 * Sends a raw byte to the memory card.
 *
 * \param[in] b The byte to sent.
 * \see sd_raw_rec_byte
 */
void sd_raw_send_byte(uint8_t b)
{
  
#ifndef SD_RAW_SOFTSPI
  
    SPDR = b;
    /* wait for byte to be shifted out */
    while(!(SPSR & (1 << SPIF)));
    SPSR &= ~(1 << SPIF);

#else

	int i = 0;
	digitalWrite(pinClk,LOW);
	for (i=0x80; i > 0; i=i >> 1){
		digitalWrite(pinDataOut, ((b & i) == 0)?LOW:HIGH);
		
		digitalWrite(pinClk,HIGH);
		digitalWrite(pinClk,LOW);
	};

#endif
    
    
    
}

/**
 * \ingroup sd_raw
 * Receives a raw byte from the memory card.
 *
 * \returns The byte which should be read.
 * \see sd_raw_send_byte
 */
uint8_t sd_raw_rec_byte()
{
#ifndef SD_RAW_SOFTSPI

    /* send dummy data for receiving some */
    SPDR = 0xff;
    while(!(SPSR & (1 << SPIF)));
    SPSR &= ~(1 << SPIF);

    return SPDR;
    
   
#else


	unsigned char res = 0;
	int i;

	for (i=0; i < 8; i ++){
		res = res << 1;
		res |= digitalRead(pinDataIn) & 0x01;
		digitalWrite(pinClk,HIGH);
		digitalWrite(pinClk,LOW);
	}

	return res;


#endif
    
    
}

/**
 * \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;

    /* 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(uint8_t i = 0; i < 10; ++i)
    {
        response = sd_raw_rec_byte();
        if(response != 0xff)
            break;
    }

    return response;
}

sd_raw.cpp second part

/**
 * \ingroup sd_raw
 * Send a command to the memory card which responses with a R2 response.
 *
 * \param[in] command The command to send.
 * \param[in] arg The argument for command.
 * \returns The command answer.
 */
uint16_t sd_raw_send_command_r2(uint8_t command, uint32_t arg)
{
    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(uint8_t i = 0; i < 10; ++i)
    {
        response = sd_raw_rec_byte();
        if(response != 0xff)
            break;
    }
    response <<= 8;
    response |= sd_raw_rec_byte();

    return response;
}



uint8_t sd_raw_read_block(uint32_t block, uint8_t* buffer){

	select_card();
	
	if(sd_raw_send_command_r1(CMD_READ_SINGLE_BLOCK, BLOCK_SIZE * block ))
	{
		unselect_card();
		Serial.println("read command error");
		return 0;
	}
	/* wait for data block (start byte 0xfe) */
	while(sd_raw_rec_byte() != 0xfe);

	/* read byte block */
	for(uint16_t i = 0; i < BLOCK_SIZE; ++i)
		*buffer++ = sd_raw_rec_byte();

	/* read crc16 */
	sd_raw_rec_byte();
	sd_raw_rec_byte();

	/* deaddress card */
	unselect_card();

	/* let card some time to finish */
	sd_raw_rec_byte(); 
  
}





uint8_t sd_raw_write_block(uint32_t block, const uint8_t* buffer)
{  
	/* address card */
	select_card();

	/* send single block request */
	if(sd_raw_send_command_r1(CMD_WRITE_SINGLE_BLOCK, BLOCK_SIZE * block))
	{
		unselect_card();
		Serial.println("write command error");
		return 0;
	}

	/* send start byte */
	sd_raw_send_byte(0xfe);

	/* write byte block */
	for(uint16_t i = 0; i < BLOCK_SIZE; ++i)
		sd_raw_send_byte(*buffer++);

	/* 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();
}















/**
 * \ingroup sd_raw
 * Reads informational data from the card.
 *
 * This function reads and returns the card's registers
 * containing manufacturing and status information.
 *
 * \note: The information retrieved by this function is
 *        not required in any way to operate on the card,
 *        but it might be nice to display some of the data
 *        to the user.
 *
 * \param[in] info A pointer to the structure into which to save the information.
 * \returns 0 on failure, 1 on success.
 */
uint8_t sd_raw_get_info(struct sd_raw_info* info)
{
    //if(!info || !sd_raw_available())
   //     return 0;

    memset(info, 0, sizeof(*info));

    select_card();

    /* read cid register */
    if(sd_raw_send_command_r1(CMD_SEND_CID, 0))
    {
        unselect_card();
        return 0;
    }
    while(sd_raw_rec_byte() != 0xfe);
    for(uint8_t i = 0; i < 18; ++i)
    {
        uint8_t b = sd_raw_rec_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 */
    uint8_t csd_read_bl_len = 0;
    uint8_t csd_c_size_mult = 0;
    uint16_t csd_c_size = 0;
    if(sd_raw_send_command_r1(CMD_SEND_CSD, 0))
    {
        unselect_card();
        return 0;
    }
    while(sd_raw_rec_byte() != 0xfe);
    for(uint8_t i = 0; i < 18; ++i)
    {
        uint8_t b = sd_raw_rec_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;
}

sd_raw.h

/*
 * Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de>
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of either the GNU General Public License version 2
 * or the GNU Lesser General Public License version 2.1, both as
 * published by the Free Software Foundation.
 */
 
  //striped down for small block access for use as large eeprom
 //26.8.2011 Deif Keller

#ifndef SD_RAW_H
#define SD_RAW_H

#include "WProgram.h"

#include <stdint.h>
//#include "sd_raw_config.h"

//use software spi 
#define SD_RAW_SOFTSPI

//use atmega 328... did not work automatically for me
//#define __AVR_ATmega328p__

//define the block size to read and write
#define BLOCK_SIZE 32









/* defines for customisation of sd/mmc port access */
#if defined SD_RAW_SOFTSPI
	
	// arduino pins for soft spi
	#define pinClk 13
	#define pinDataOut 11
	#define pinDataIn 12
	#define pinSdCs 10

    #define select_card() digitalWrite(pinSdCs,LOW)
    #define unselect_card() digitalWrite(pinSdCs,HIGH)
#elif defined(__AVR_ATmega8__) || \
    defined(__AVR_ATmega48__) || \
    defined(__AVR_ATmega88__) || \
    defined(__AVR_ATmega328p__) || \
    defined(__AVR_ATmega168__)
    #define configure_pin_mosi() DDRB |= (1 << DDB3)
    #define configure_pin_sck() DDRB |= (1 << DDB5)
    #define configure_pin_ss() DDRB |= (1 << DDB2)
    #define configure_pin_miso() DDRB &= ~(1 << DDB4)

    #define select_card() PORTB &= ~(1 << PB2)
    #define unselect_card() PORTB |= (1 << PB2)
#elif defined(__AVR_ATmega16__) || \
      defined(__AVR_ATmega32__)
    #define configure_pin_mosi() DDRB |= (1 << DDB5)
    #define configure_pin_sck() DDRB |= (1 << DDB7)
    #define configure_pin_ss() DDRB |= (1 << DDB4)
    #define configure_pin_miso() DDRB &= ~(1 << DDB6)

    #define select_card() PORTB &= ~(1 << PB4)
    #define unselect_card() PORTB |= (1 << PB4)
#elif defined(__AVR_ATmega64__) || \
      defined(__AVR_ATmega128__) || \
      defined(__AVR_ATmega169__)
    #define configure_pin_mosi() DDRB |= (1 << DDB2)
    #define configure_pin_sck() DDRB |= (1 << DDB1)
    #define configure_pin_ss() DDRB |= (1 << DDB0)
    #define configure_pin_miso() DDRB &= ~(1 << DDB3)

    #define select_card() PORTB &= ~(1 << PB0)
    #define unselect_card() PORTB |= (1 << PB0)
#else
    #error "no sd/mmc pin mapping available!"
#endif







/**
 * This struct is used by sd_raw_get_info() to return
 * manufacturing and status information of the card.
 */
struct sd_raw_info
{
    /**
     * A manufacturer code globally assigned by the SD card organization.
     */
    uint8_t manufacturer;
    /**
     * A string describing the card's OEM or content, globally assigned by the SD card organization.
     */
    uint8_t oem[3];
    /**
     * A product name.
     */
    uint8_t product[6];
    /**
     * The card's revision, coded in packed BCD.
     *
     * For example, the revision value \c 0x32 means "3.2".
     */
    uint8_t revision;
    /**
     * A serial number assigned by the manufacturer.
     */
    uint32_t serial;
    /**
     * The year of manufacturing.
     *
     * A value of zero means year 2000.
     */
    uint8_t manufacturing_year;
    /**
     * The month of manufacturing.
     */
    uint8_t manufacturing_month;
    /**
     * The card's total capacity in bytes.
     */
    uint32_t capacity;
    /**
     * Defines wether the card's content is original or copied.
     *
     * A value of \c 0 means original, \c 1 means copied.
     */
    uint8_t flag_copy;
    /**
     * Defines wether the card's content is write-protected.
     *
     * \note This is an internal flag and does not represent the
     *       state of the card's mechanical write-protect switch.
     */
    uint8_t flag_write_protect;
    /**
     * Defines wether the card's content is temporarily write-protected.
     *
     * \note This is an internal flag and does not represent the
     *       state of the card's mechanical write-protect switch.
     */
    uint8_t flag_write_protect_temp;
    /**
     * The card's data layout.
     *
     * See the \c SD_RAW_FORMAT_* constants for details.
     *
     * \note This value is not guaranteed to match reality.
     */
    uint8_t format;
};



uint8_t sd_raw_init();
uint8_t sd_raw_get_info(struct sd_raw_info* info);
uint8_t sd_raw_read_block(uint32_t block, uint8_t* buffer);
uint8_t sd_raw_write_block(uint32_t block, const uint8_t* buffer);
/**
 * @}
 */

#endif

sd_raw_test.pde

//#include "sd-reader_config.h"
#include "sd_raw.h"





int print_disk_info();
int sample();
int readDisk();

byte incomingByte;
void printWelcome();
long int address;
byte tempBytes[2];


void setup()
{
  
  Serial.begin(9600);
  delay(1000);

  if(!sd_raw_init())
  {
     Serial.println("MMC/SD initialization failed");    
   while (true);  
  }
  print_disk_info();
  Serial.println("");
  Serial.println("");
  
  
  #define len 32
  
  unsigned char data[len];
  

  
  
  
  int i;
  for (i=0; i< len; i++){
   data[i] = i + 20; 
    
  }
  Serial.println("--------- write -----------");
  sd_raw_write_block(0,data);
  
  for (i=0; i< len; i++){
   data[i] = i + 100; 
    
  }
  Serial.println("--------- write -----------");
  sd_raw_write_block(512,data);
  
  for (i=0; i< len; i++){
   data[i] = 0; 
  }
  
  Serial.println("--------- read -----------");
  sd_raw_read_block(0,data);
  for (i=0; i< len; i++){
   Serial.println(data[i],DEC);
  }
  
   Serial.println("--------- read -----------");
  
   sd_raw_read_block(1,data);
  for (i=0; i< len; i++){
   Serial.println(data[i],DEC);
  }
  
  while (true);
  
  
  
  
}



void loop()
{

}




int print_disk_info()
{
 

    struct sd_raw_info disk_info;
    if(!sd_raw_get_info(&disk_info))
    {
        return 0;
    }

    
    Serial.println();
    Serial.print("rev:    "); 
    Serial.print(disk_info.revision,HEX); 
    Serial.println();
    Serial.print("serial: 0x"); 
    Serial.print(disk_info.serial,HEX); 
    Serial.println();
    Serial.print("date:   "); 
    Serial.print(disk_info.manufacturing_month,DEC); 
    Serial.println();
    Serial.print(disk_info.manufacturing_year,DEC); 
    Serial.println();
    Serial.print("size:   "); 
    Serial.print(disk_info.capacity,DEC); 
    Serial.println();
    Serial.print("copy:   "); 
    Serial.print(disk_info.flag_copy,DEC); 
    Serial.println();
    Serial.print("wr.pr.: ");
    Serial.print(disk_info.flag_write_protect_temp,DEC); 
    Serial.print('/');
    Serial.print(disk_info.flag_write_protect,DEC); 
    Serial.println();
    Serial.print("format: "); 
    Serial.print(disk_info.format,DEC); 
    Serial.println();
    Serial.print("free:   "); 
   
    return 1;
}

Does it work?

I am tired of optimizing my long sketch for more free RAM... the problem was with SD library and after some experiments with a test function the result was that SD library eat ~500 bytes RAM. (Madness)

Steps you have done sounds promising! I need SD for logging data (slow speed) and manual upload the file via serial to PC (weekly). Can you explain what should I do to start using your library? Where to copy files?

sorry for my slow reply rate....
I dont check this site verry often.

actually it does not.
I noticed that most sd cards do not support smaler block sizes than 512bytes.
I changed the code so it always uses 512 byte blocks but does not fill them up.
if you use smaler blocks it just wastes the remaining sd space but since those cards are verry large I dont care.

all you need to use the code are the functions
uint8_t sd_raw_init()
uint8_t sd_raw_read_block(uint32_t block, uint8_t* buffer, int len)
uint8_t sd_raw_write_block(uint32_t block, const uint8_t* buffer, int len)
block is the block address (not the byte address: 1 means the block starting at byte 512)
buffer the databuffer to write / read and len the length of the buffer.

the functions
uint8_t sd_raw_get_info(struct sd_raw_info* info) (commented out for lower memory consumption)
void decodeResponse1(char response)
are practical for debuging purposes

sd_raw.h (4.63 KB)

sd_raw.cpp (15.8 KB)