//**********************************************************
// **** MAIN routine FOR Interfacing microSD/SD CARD ******
//**********************************************************
//Controller: ATmega8 (Clock: 8 Mhz-internal)
//Compiler: AVR-GCC
//Version : 2.1
//Author: CC Dharmani, Chennai (India)
// http://www.dharmanitech.com/

//Date: 26 Feb 2009
//********************************************************

//Link to the Post: http://www.dharmanitech.com/2009/01/sd-card-interfacing-with-atmega8-fat32.html


#define F_CPU 8000000UL       //freq 8 MHz
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "SPI_routines.h"
#include "SD_routines.h"
#include "UART_routines.h"
#include "FAT32.h"

volatile
unsigned long startBlock;
volatile
unsigned long totalBlocks;
volatile
unsigned char buffer[512];
volatile
unsigned long firstDataSector, rootCluster, totalClusters;
volatile
unsigned int  bytesPerSector, sectorPerCluster, reservedSectorCount;

void
port_init(void)
{
PORTB = 0xEF;
DDRB
  = 0xEF;
//MISO line i/p, rest o/p
PORTC = 0x00;
DDRC
  = 0x00;
PORTD = 0x00;
DDRD
  = 0x7F;
}

//UART0 initialize
// desired baud rate: 19200
// actual: baud rate:19231 (0.2%)
// char size: 8 bit
// parity: Disabled
void uart0_init(void)
{
 
UCSRB = 0x00;
//disable while setting baud rate
 UCSRA = 0x00;
 UCSRC = (1 << URSEL) | 0x06;
 UBRRL = 0x19;
//set baud rate lo
 UBRRH = 0x00;
//set baud rate hi
 UCSRB = 0x18;
}

//call this routine to initialize all peripherals
void init_devices(void)
{
 cli();
 port_init();
 spi_init();
 uart0_init();

 MCUCR = 0x00;
 GICR  = 0x00;
 TIMSK = 0x00;
//timer interrupt sources
 
//all peripherals are now initialized

}


int
main(void)
{
unsigned
char option, error, data, FAT32_active;
unsigned
int i;
unsigned
char fileName[13];

_delay_ms(100);
 
//delay for VCC stabilization

init_devices();

PORTD |= 0x04;
//switching ON the LED (for testing purpose only)

TX_NEWLINE;
TX_NEWLINE;
transmitString_F (PSTR("***********************************"
));
TX_NEWLINE;
transmitString_F (PSTR(" Dharmani's microSD Card Testing.."
));
TX_NEWLINE;
transmitString_F (PSTR("***********************************"
));
TX_NEWLINE;

SD_init();
SPI_HIGH_SPEED;
  
//SCK - 4 MHz

_delay_ms(1);

FAT32_active = 1;
error = getBootSectorData ();
//read boot sector and keep necessary data in global variables
if(error)  
{
 
transmitString_F (PSTR("FAT32 not found!")); 
//FAT32 incompatible drive
  FAT32_active = 0;
}

while(1)
{
TX_NEWLINE;
transmitString_F(PSTR("Press any key..."));
TX_NEWLINE;
option = receiveByte();
TX_NEWLINE;
transmitString_F(PSTR("> 0 : Erase Blocks"));
TX_NEWLINE;
transmitString_F(PSTR("> 1 : Write single Block"));
TX_NEWLINE;
transmitString_F(PSTR("> 2 : Read single Block"));

#ifndef FAT_TESTING_ONLY
TX_NEWLINE;
transmitString_F(PSTR("> 3 : Write multiple Blocks"));
TX_NEWLINE;
transmitString_F(PSTR("> 4 : Read multiple Blocks"));
#endif


TX_NEWLINE;
transmitString_F(PSTR("> 5 : Get file list"));
TX_NEWLINE;
transmitString_F(PSTR("> 6 : Read File"));
TX_NEWLINE;
transmitString_F(PSTR("> 7 : Create File"));
TX_NEWLINE;
transmitString_F(PSTR("> 8 : Delete File"));
TX_NEWLINE;
transmitString_F(PSTR("> 9 : Read SD Memory Capacity (Total/Free)"));

TX_NEWLINE;
TX_NEWLINE;
transmitString_F(PSTR("> Select Option (0-9): "));


/*WARNING: If option 0, 1 or 3 is selected, the card may not be detected by PC/Laptop again,
as it disturbs the FAT format, and you may have to format it again with FAT32.
This options are given for learning the raw data transfer to & from the SD Card*/


option = receiveByte();
transmitByte(option);

if(option >= 0x35 && option <= 0x39) 
//options 5 to 9 disabled if FAT32 not found
{
  if(!FAT32_active)
  {
    TX_NEWLINE;
    TX_NEWLINE;
      transmitString_F(PSTR("FAT32 options disabled!"));
      continue;
  }
}


if((option >= 0x30) && (option <=0x34))
//get starting block address for options 0 to 4

{
TX_NEWLINE;
TX_NEWLINE;
transmitString_F(PSTR("Enter the Block number (0000-9999):"
));
data = receiveByte(); transmitByte(data);
startBlock = (data & 0x0f) * 1000;
data = receiveByte(); transmitByte(data);
startBlock += (data & 0x0f) * 100;
data = receiveByte(); transmitByte(data);
startBlock += (data & 0x0f) * 10;
data = receiveByte(); transmitByte(data);
startBlock += (data & 0x0f);
TX_NEWLINE;
}

totalBlocks = 1;

#ifndef FAT_TESTING_ONLY

if((option == 0x30) || (option == 0x33) || (option == 0x34))
//get total number of blocks for options 0, 3 or 4
{
TX_NEWLINE;
TX_NEWLINE;
transmitString_F(PSTR("How many blocks? (000-999):"
));
data = receiveByte(); transmitByte(data);
totalBlocks = (data & 0x0f) * 100;
data = receiveByte(); transmitByte(data);
totalBlocks += (data & 0x0f) * 10;
data = receiveByte(); transmitByte(data);
totalBlocks += (data & 0x0f);
TX_NEWLINE;
}
#endif

switch
(option)
{
case
'0':
//error = SD_erase (block, totalBlocks);
          error = SD_erase (startBlock, totalBlocks);
          TX_NEWLINE;
          if(error)
              transmitString_F(PSTR("Erase failed.."));
          else
              transmitString_F(PSTR("Erased!"));
          break;

case '1': TX_NEWLINE;
          transmitString_F(PSTR(" Enter text (End with ~):"));
          i=0;
            do
            {
                data = receiveByte();
                transmitByte(data);
                buffer[i++] = data;
                if(data == '\r')    \\append 'newline' character whenevr 'carriage return' is received
                {
                    transmitByte('\n');
                    buffer[i++] = '\n';
                }
                if(i == 512) break;
            }while (data != '~');

            error = SD_writeSingleBlock (startBlock);
            TX_NEWLINE;
            TX_NEWLINE;
            if(error)
                transmitString_F(PSTR("Write failed.."));
            else
                transmitString_F(PSTR("Write successful!"));
            break;

case '2': error = SD_readSingleBlock (startBlock);
          TX_NEWLINE;
          if(error)
            transmitString_F(PSTR("Read failed.."));
          else
          {
            for(i=0;i<512;i++)
            {
                if(buffer[i] == '~') break;
                transmitByte(buffer[i]);
            }
            TX_NEWLINE;
            TX_NEWLINE;
            transmitString_F(PSTR("Read successful!"));
          }

          break;
//next two options will work only if following macro is cleared from SD_routines.h
#ifndef FAT_TESTING_ONLY

case '3':
          error = SD_writeMultipleBlock (startBlock, totalBlocks);
          TX_NEWLINE;
          if(error)
            transmitString_F(PSTR("Write failed.."));
          else
            transmitString_F(PSTR("Write successful!"));
          break;

case '4': error = SD_readMultipleBlock (startBlock, totalBlocks);
          TX_NEWLINE;
          if(error)
            transmitString_F(PSTR("Read failed.."));
          else
            transmitString_F(PSTR("Read successful!"));
          break;
#endif

case '5': TX_NEWLINE;
              findFiles(GET_LIST,0);
          break;

case '6':
case '7':
case '8': TX_NEWLINE;
              TX_NEWLINE;
          transmitString_F(PSTR("Enter file name: "));
          for(i=0; i<13; i++)
                  fileName[i] = 0x00;  
//clearing any previously stored file name
          i=0;
          while(1)
          {
            data = receiveByte();
            if(data == '\r') break
//'ENTER' key pressed
            if(data == 0x08) 
//'Back Space' key pressed
            {
              if(i != 0)
              {
                transmitByte(data);
                transmitByte(' ');
                transmitByte(data);
                i--;
              }
              continue;    
            }
            if(data <0x20 || data > 0x7e) continue
//check for valid English text character
            transmitByte(data);
            fileName[i++] = data;
            if(i==13){transmitString_F(PSTR(" file name too long..")); break;}
          }
          if(i>12) break;
      
          TX_NEWLINE;
          if(option == '6')
            readFile( READ, fileName);
          if(option == '7')
            createFile(fileName);
          if(option == '8')
            deleteFile(fileName);
          break;

case '9': memoryStatistics();
          break;

default: TX_NEWLINE;
         TX_NEWLINE;
         transmitString_F(PSTR(" Invalid option!"));
         TX_NEWLINE;
}

TX_NEWLINE;
}
return 0;
}

 

//********** END *********** http://www.dharmanitech.com/ *************