Defines | Functions

sddisk.c File Reference

interface functions between FATFS and SD card I/O functions More...

#include "config.h"
#include <stdio.h>
#include <avr/pgmspace.h>
#include <diskio.h>
#include <sdcmd.h>

Defines

#define SDCARD_MINVOLTAGE   (2800)
 minimum voltage for SD access
#define CHK_POWER   do {} while (0)
#define MAXMULTSECT   (0 ? 8 : 1)
 maximum number of sectors to handle in one SD command (read or write)

Functions

DSTATUS disk_initialize (BYTE drv)
 initialize disk
DSTATUS disk_status (BYTE drv)
 check disk status
DRESULT disk_read (BYTE drv, BYTE *buf, DWORD sect, BYTE count)
 read data from disk
DRESULT disk_write (BYTE drv, const BYTE *buf, DWORD sect, BYTE count)
 write data to disk
DRESULT disk_ioctl (BYTE drv, BYTE ctrl, void *buf)
 special operations with disk

Detailed Description

interface functions between FATFS and SD card I/O functions


Define Documentation

#define MAXMULTSECT   (0 ? 8 : 1)

maximum number of sectors to handle in one SD command (read or write)

MAXMULTSECT currently is set to 1, because more does not seem to work for me and I don't have documentation at hand.

#define SDCARD_MINVOLTAGE   (2800)

minimum voltage for SD access

The minimum safe voltage for SD card operation is 2.7 Volt according to specification. Require somewhat more to account for measuring error


Function Documentation

DSTATUS disk_initialize ( BYTE  drv  ) 

initialize disk

disk_initialize() initializes the SD card if necessary (power-on or after battery low level indication).

Parameters:
drv which drive to initialize (0=SD card)
Returns:
status (0=successful)

{
  uint16_t result;

  if (drv == 0) {
    CHK_POWER;
    if (!sd_is_initialized) {
      result = sd_init_card (1);
      if (result != 0) {
        /* failure on init */
        return STA_NOINIT;
      }
      sd_is_initialized = 1;
    }
    return 0;
  }
  return STA_NOINIT;
}

DRESULT disk_read ( BYTE  drv,
BYTE *  buf,
DWORD  sect,
BYTE  count 
)

read data from disk

disk_read() reads the specified number of sectors from disk into RAM.

Parameters:
drv which drive to read the data from
buf pointer to RAM buffer to put read data into
sect starting sector number
count number of sectors to read
Returns:
status (0=successful)

For reading a single sector just do a sd_read_block().

When there is more than one sector left to read, use sd_read_block_multi(), but read at most MAXMULTSECT sectors per iteration.

{
  uint8_t result;
  uint32_t addr;

  if (drv != 0)
    return RES_NOTRDY;

  CHK_POWER;

  if (count == 0) return RES_PARERR;

  while (count) {
    uint8_t n;
    if (count == 1) {
      addr = sd_block2addr (sect);
      result = sd_read_block (buf, addr);
      if (result) {
        printf_P (PSTR("sd_read_block(%p,%lx)"), buf, addr);
        printf_P (PSTR("=%02x\r\n"), result);
      }
      return result ? RES_ERROR : RES_OK;
    }
    
    /* count > 1 => use multiple access if enabled */
    n = MAXMULTSECT;
    if (count < n) n = count;

    if (MAXMULTSECT > 1) {
      sd_rd_mult_block_data_t desc;
      /* fill data pointers */
      desc.buffer = buf;
      desc.num_blocks = n;

      buf += SECTOR_SIZE * n; /* prepare for next iteration */

      addr = sd_block2addr(sect);
      printf_P (PSTR("sd_read_block_mult2(%p,%lx,%hu)"), buf, addr, n);
      result = sd_read_multiple_block2 (&desc, n, addr);
    } else {
      addr = sd_block2addr (sect);
#if 0
      printf_P (PSTR("sd_read_block(%p,%lx)"), buf, addr);
#endif
      result = sd_read_block (buf, addr);
      buf += SECTOR_SIZE;
    }
    sect += n;
    count -= n;

    if (result) return RES_ERROR;
  }

  return RES_OK;
}

DSTATUS disk_status ( BYTE  drv  ) 

check disk status

Parameters:
drv drive to check
Returns:
status (0=successful)

{
  if (drv == 0) {
    CHK_POWER;
    return 0;
    return STA_NODISK;
  }
  return STA_NOINIT;
}

DRESULT disk_write ( BYTE  drv,
const BYTE *  buf,
DWORD  sect,
BYTE  count 
)

write data to disk

disk_write() writes the specified number of sectors from RAM to the disk.

Parameters:
drv which drive to write the data to
buf pointer to RAM buffer to read data from
sect starting sector number
count number of sectors to write
Returns:
status (0=successful)

For writing a single sector just do a sd_write_block().

When there is more than one sector left to write, use sd_write_block_multi(), but write at most MAXMULTSECT sectors per iteration.

{
  uint32_t result;
  uint32_t addr;

  if (drv != 0)
    return RES_NOTRDY;

  CHK_POWER;

  if (count == 0) return RES_PARERR;

  while (count) {
    uint8_t n;
    if (count == 1) {
      uint8_t retries = 4;
      uint8_t reset_retries = 5;
      uint8_t reset_done = 0;

      addr = sd_block2addr (sect);
      do {
        result = sd_write_block (buf, addr);
        if (result || reset_done) {
          printf_P (PSTR("sd_write_block(%p,%lx)"), buf, addr);
          printf_P (PSTR("=%06lx\r\n"), result);
        }
        if (result) {
          if (--retries == 0) {
            /* give up */
            if (--reset_retries == 0) {
              /* really give up */
              return RES_ERROR;
            }
            /* - reset card and try again */
            printf_P (PSTR("resetting SD card\r\n"));
            sd_init_card (0);
            reset_done = 1;
          }
        }
      } while (result);
      return RES_OK;
    }
    
    /* count > 1 => use multiple access if enabled */
    n = MAXMULTSECT;
    if (count < n) n = count;

    if (MAXMULTSECT > 1) {
      sd_wr_mult_block_data_t desc;
      /* fill data pointers */
      desc.buffer = buf;
      desc.num_blocks = n;

      buf += SECTOR_SIZE * n; /* prepare for next iteration */

      result = sd_write_multiple_block2 (&desc, n, sd_block2addr(sect));
    } else {
      addr = sd_block2addr (sect);
      printf_P (PSTR("sd_write_block(%p,%lx)"), buf, addr);
      result = sd_write_block (buf, addr);
      buf += SECTOR_SIZE;
    }
    sect += n;
    count -= n;
    
    if (result) return RES_ERROR;
  }
  
  return RES_OK;
}