Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

How should I Write data in a SD memory and read it through SPI ?

Status
Not open for further replies.
hello FVM, vinodstanur, doraemon, and mf1364.
i am doing the same project and i read all the posts >>>>>>>>>>> nice
i use ATmega8535 AVR controller
i send CMD0 to the SD and 1 returned, then, i send CMD1 and 0 returned, then i send CMD59 and 0 to turn off the CRC and 0 is returned, then i send CMD16 and 256 to adjust the block size to 256, then my problem occur. my problem is after that i send CMD24 and 5*256(sector five*number of bytes in each sector) to write in the fifth sector then 64 is returned. from r1 response, this means that it is an illegal command and there is an address error and parameter error

note : i use an lcd to show the r1 response of each command
note also that this code is the first code that mf1364 use, but i correct it

my code is:
Code:
#include <mega8535.h>
#include <stdio.h>
#include <delay.h>

#asm
   .equ __lcd_port=0x1B ;PORTA
#endasm
#include <lcd.h>

#define MMC_CS_PORT            PORTB
#define MMC_CS_DDR             DDRB
#define MMC_CS_PIN              4
// MMC commands  (taken from sandisk MMC reference)
#define MMC_GO_IDLE_STATE           0          // initialize card to spi-type access
#define MMC_SEND_OP_COND            1         // set card operational mode 
#define MMC_SEND_IF_COND            8         // For only SDC V2. Check voltage range.
#define MMC_SEND_CSD                9         // get card"s CSD
#define MMC_SEND_CID                10        // get card's CID
#define MMC_SEND_STATE              13
#define MMC_SET_BLOCKLEN            16       //set number of byte to transferblock
#define MMC_READ_SINGLE_BLOCK       17       //read a block
#define MMC_WRITE_BLOCK             24       //write a block
#define MMC_PROGRAM_CSD             27
#define MMC_SET_WRITE_PROT          28
#define MMC_CLR_WRITE_PROT          29
#define MMC_SEND_WRITE_PORT         30
#define MMC_TAG_SECTOR_START        32
#define MMC_TAG_SECTOR_END          33
#define MMC_UNTAG_SECTOR            34
#define MMC_TAG_ERASE_GROUP_START   35       // sets beginning of erase group(mass erase)
#define MMC_TAG_ERASE_GROUP_END     36       //sets end of erase group (mass erase)
#define MMC_UNTAG_ERASE_GROUP       37
#define MMC_ERASE                   38
#define MMC_CRC_ON_OFF              59
#define MMC_R1_BUSY                 0X80
#define MMC_R1_PARAMETER            0X40
#define MMC_R1_ADDRESS              0X20
#define MMC_R1_ERASE_SEQ            0X10
#define MMC_R1_COM_CRC              0X08
#define MMC_R1_ILLEGAL_COM          0X04
#define MMC_R1_ERASE_RESET          0X02
#define MMC_R1_IDLE_STATE           0X01

#define MMC_STARTBLOCK_READ         0XFE
#define MMC_STARTBLOCK_WRITE        0XFE
#define MMC_STARTBLOCK_MWRITE       0XFC
#define MMC_STOPTRAN_WRITE          0XFD
#define MMC_DE_MASK                 0X1F
#define MMC_DE_ERROR                 0X01
#define MMC_DE_CC_ERROR              0X02
#define MMC_DE_ECC_FAIL              0X04

#define MMC_DE_OUT_OF_RANGE          0X04
#define MMC_DE_CARD_LOCKED           0X04

#define MMC_DR_MASK                   0X1F
#define MMC_DR_ACCEPT                 0X05
#define MMC_DR_REJECT_CRC             0X0B
#define MMC_DR_REJECT_WRITE_ERROR     0X0D

 char c[10],y[10];

void spi_write(unsigned char data);
void mmclint(void);
unsigned char mmcreset(void);
unsigned char mmcsendcommand(unsigned char cmd, unsigned long int argument);
unsigned char mmcread(unsigned long int sector, unsigned char* buffer);
unsigned char mmcwrite(unsigned long int sector, unsigned char* buffer);
unsigned char mmccommand(unsigned char cmd, unsigned long int argument);  
//----------------------------------
void spilnit()
{
PORTB.7=1;
DDRB.7=1;
DDRB.6=0;
DDRB.5=1;
DDRB.4=1;
SPCR=0X52;
SPSR=0X00;                                                                                      //kan SPCR=0x00;
}

unsigned char spitransferbyte(unsigned char data)
{
unsigned char received =0;
 SPDR = data;
 while(!(SPSR&(1<<7)));
received = SPDR;
return (received);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void mmclint(void)
{
spilnit();
MMC_CS_DDR.MMC_CS_PIN=1;
MMC_CS_PORT.MMC_CS_PIN=1; 
lcd_clear();
lcd_putsf(" MMC  initiated ");
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void spi_write(unsigned char data){
//MMC_CS_PORT.MMC_CS_PIN=0; 
SPDR=data;   
while(!(SPSR&(1<<7)));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
unsigned char mmcreset(void){
unsigned char i;
unsigned char retry;
unsigned char r1=0;
retry=0;

do{
for(i=0;i<10;i++)   spitransferbyte(0xff);        // send dummy byte with CS high before accessing
r1= mmcsendcommand(MMC_GO_IDLE_STATE,0);                   //resetting card go to spi mode     r1=?????  0x95
retry++;  
 if(retry>10)  return-1;
}while(r1 != 0X01);
retry=0;
lcd_clear();
sprintf(y,"CMD0  r1= %d",r1);
lcd_puts(y);
spitransferbyte(0xff); 

do
{
r1= mmcsendcommand(MMC_SEND_OP_COND,0);                // initializing card for operation
retry++;    
if(retry>10)return-1;
}while(r1); 
sprintf(y,"\nCMD1  r1= %d",r1);
lcd_puts(y);
delay_ms(500);

r1= mmcsendcommand(MMC_CRC_ON_OFF,0);              //turn off CRC checking to simplify communication  
lcd_clear();
sprintf(y,"CMD59  r1= %d",r1);
lcd_puts(y);

r1=mmcsendcommand(MMC_SET_BLOCKLEN,256);
sprintf(y,"\nCMD16  r1= %d",r1);
lcd_puts(y);      
delay_ms(500);
return 0;

}
//-------------------------------------------------
unsigned char mmcsendcommand(unsigned char cmd, unsigned long argument){
unsigned char r1;
MMC_CS_PORT.MMC_CS_PIN=0; //MMC_CS_DDR.MMC_CS_PIN=0;                               //assert chip select          ??
r1= mmccommand(cmd,argument);              //issue the command
MMC_CS_PORT.MMC_CS_PIN=1;
return r1;

}
//-----------------------------------------------
 char mmcread(unsigned long int sector,unsigned char* buffer )
{
unsigned char r1;
unsigned i;

MMC_CS_DDR.MMC_CS_PIN=0;
 r1= mmccommand(MMC_READ_SINGLE_BLOCK,sector<<9);
if (r1!=0X00)
return r1;
 while(spitransferbyte(0xff)!=MMC_STARTBLOCK_READ);
for (i=0;i<0X200;i++)
 *buffer++ = spitransferbyte(0xff);
spitransferbyte(0xff);
spitransferbyte(0xff);
MMC_CS_PORT.MMC_CS_PIN=1;
return 0;


}  
///-------------------------------------------------------
unsigned char mmcwrite(unsigned long int sector,unsigned char* buffer ){
unsigned char r1;
unsigned int i; 

MMC_CS_PORT.MMC_CS_PIN=0;               //issue command
r1=mmccommand(MMC_WRITE_BLOCK,sector<<8);         //multiply sector by 256
if(r1 != 0x00)
{/*lcd_clear();  
sprintf(y,"CMD24  r1= %d",r1);
lcd_puts(y);*/
return r1;}
lcd_clear();  
sprintf(y,"CMD24  r1= %d",r1);
lcd_puts(y);

spitransferbyte(0xff);                         // send dummy

spitransferbyte(MMC_STARTBLOCK_WRITE);                      //send data start token
for (i=0; i<256; i++)
spitransferbyte(*buffer++);
spitransferbyte(0xff);
spitransferbyte(0xff);
r1=spitransferbyte(0xff);                        // write 16-bit crc (dummy values)

                                                 // read data response token
if((r1&MMC_DR_MASK)!= MMC_DR_ACCEPT)
return r1;
while(!spitransferbyte(0xff));                   //wait for busy period
sprintf(y,"\nDatares = %d",r1);
lcd_puts(y);
MMC_CS_PORT.MMC_CS_PIN=1;                           //CS
return 0;                                // return succes
}
//////////////////////////////////////////
unsigned char mmccommand(unsigned char cmd,unsigned long int argument){
char r1;
char retry=0;
//send command
spi_write(cmd |0x40);
spi_write(argument>>24); 
spi_write(argument>>16);
spi_write(argument>>8);
spi_write(argument);    
if(cmd==MMC_GO_IDLE_STATE)
spi_write(0x95);                            //crc valid only for mmc_go_idle_state

while((r1 = spitransferbyte(0xff))==0xff)
if(retry++ > 8) break;
return r1;
}
///-------------------------------------------------

char write_buf[256]; //read_buf[10]; 


void main(void) {
unsigned int i;
unsigned long int sector;  

// LCD module initialization
lcd_init(16);
lcd_putsf("    wellcome    "); 
delay_ms(500);
  mmclint();     
  delay_ms(10);
  mmcreset();
for (i=0;i<256;i++)
write_buf[i]=i;
sector=5;
delay_ms(10);              

mmcwrite(sector,write_buf);      // write to sector 5
/*
delay_ms(1);
mmcread(sector,read_buf);   */     // read of sector 5
while(1){}
}

my sd is as shown :
DSC01271.JPG

thanks in advance
 

Debugging faulty codes can be most effectively done with your hands on the hardware and probably a good debugger. I also don't expect others to find well hidden bugs in my code from a distance.

In the present case, it looks like CS stays high during read and write, a successful operation would be surprizing.
 

thank u FvM
but it is not the problem , i correct it (i set PORTB.4 to one before write function)
i have a question
the data direction of the ss is output or input ??
 

Output on the master side of course. I thought, you did it right so far.
 

hello FvM
i found my mistake ............. it is in the size of sector
it must be 512 ......... and if i change it by cmd16 to any value rather than 512 , i cannot read from my sd (cmd17 is responded by 0x64)

now i can read and write to my sd

then,,,
i check if my sd is FAT16 or not by a function, and i found it is not FAT16
my question is >> can i make it FAT16 ??

the function is
void fat16_init() //BOOT SECTOR SCANNING//
{
mmc_read_sector(0);
clear();
LINE1;
if((mmc_buf[0x36] == 'F') && (mmc_buf[0x39] == '1') && (mmc_buf[0x3a] == '6'))
string("FAT16 DETECTED",1);
else {
string("NOT A FAT16",1);
while(1);
}
_delay_ms(500);
fat_start = mmc_buf[0x0e];
dir_start = (fat_start + (((mmc_buf[0x17] << 8) + mmc_buf[0x16]) * 2));
data_start = (dir_start + ((((mmc_buf[0x12] << 8) + (mmc_buf[0x11])) * 32) / 512));
sect_per_clust = mmc_buf[0x0d];
}

thank u in advance
 

i found my mistake ............. it is in the size of sector
it must be 512
Right, sector size is a media hardware property. Seriously speaking, I hadn't expecting anyone to use a different sector size.
i check if my sd is FAT16 or not by a function, and i found it is not FAT16
my question is >> can i make it FAT16 ??
There are two points.
- Assumed the media uses a MBR, sector 0 won't have an ASCII designator for the FAT type, instead there's a partition type byte in the partition table
- Generally, partitions above 2 GB must be FAT32. You can best see it by reading the card on a PC. On larger cards, you can basically up to 2 GB partitions, up to 4.
 

well
my sd card is 1G card ......... i could format it to be FAT16 "FAT"
After googling
now i can read the sd card through HxD software
i read the MBR and the partitions entries
only the first partition entry has a values on it and the other entries have zeros
my problem is that the current state of first partition is 00h so it is not active "it must to be active"
HxD.png

how can i make it active and what is the next step

i want also to get the first sector in the first partition (FAT16 boot record), then i can easily read the Disk Parameter Block (DPB) which contain the useful data about byte per sector,sectors per cluster , etc.

another problem is >>> How to convert the address of the beginning and the end of Partition (which are in the partition entry in the MBR) from CHS addressing to a useful sector number

thanks in advance
 
Last edited:

yes, but how??
Following the known MBR and FAT specifications...

To get an idea, how it works, review the code of an embedded FDISK tool appended below.

Alternatively, you can use Windows (diskpart) or Linux administration tools to partition the SD card.
 

Attachments

  • fdisk.zip
    6.5 KB · Views: 104

I believe the code (FAT16 detection) you[Hz2020] shown is a part of my wav player code, and there I didn't used any MBR parser because there I didn't made any partition in the MMC and the sector 0 itself is the boot sector of the MMC.

Now in your case,
To get the starting sector of partition 1(partition 1 boot sector) from the master boot record (MBR), you can try this.
Code:
void PARSE_MBR()
{
	mmc_read_sector(0);
	p1_bootsect = mmc_buf[0x1be + 8] | mmc_buf[0x1be + 9]<<8; //assuming that 1 partition will start with in range of 0xffff sector, otherwise modify it..
	filesystem_type = mmc_buf[0x1be + 4]; 
}


Now, in the function to read sector, you may be providing sector number as argument, is it?
Then inside the sector read function, add the sector number with the p1_bootsect.
ie
sector = sector + p1_bootsect;

So, you will be accessing the partition 1...
 
Last edited:

thank u
i found the FAT boot record with function like this using a function I made
i was doing a serious fault >>>>>>> and that is the reason that i cannot find the FAT boot record
my fault was that i did not know that the low byte (LSB) is written first in the HxD page then the High byte (MSB) is written
so i should read the data and arrange it.

my function is as shown
Code:
     mmcread(0);
    
    LBA1=read_buf[0x1C9];
    LBA2=read_buf[0x1C8];
    LBA3=read_buf[0x1C7];
    LBA4=read_buf[0x1C6];
    
    first_partition_boot_record=(LBA1<<24) + (LBA2<<16) + (LBA3<<8) + (LBA4);

    mmcread(first_partition_boot_record);

now i continue on trying reading the wave file
thank u all friends

please vinodstanur, I want to understand the meaning of the long if condition in the scan_root_dir function
Code:
if ((mmc_buf[1] != 0) && (mmc_buf[base_count + 2] != 0) && (mmc_buf[base_count] != 0xe5) && (mmc_buf[base_count] != 0x00) && ((mmc_buf[base_count + 11] & 0b00011110) == 0) && (strncmp(mmc_buf + base_count + 8, FILE_EXTENSION, 3) == 0))
i understand the last condition (strncmp(mmc_buf + base_count + 8, FILE_EXTENSION, 3) == 0), it for being sure that the file has a WAV extention
but i do not understand all the other conditions

thank u in advance
 
Last edited:

please vinodstanur
i want to understand what the function (check_bitrate_and_stereo) do:
Code:
char check_bitrate_and_stereo(unsigned int cluster)
{
    int i;
    mmc_read_sector(((unsigned long int)(cluster -2) * sect_per_clust) + data_start);
    if(mmc_buf[34] != 8) return 1;
    for (i = 31; i > 27; i--) {
        bitrate <<= 8;
        bitrate |= mmc_buf[i];
    }
    STEREO = mmc_buf[22] - 1;
    print_num(bitrate,2);
    OCR1A_BACKUP = ((F_CPU *(STEREO + 1))/bitrate);
    OCR1A = OCR1A_ADJUST = OCR1A_BACKUP;
    return 0;
}
 

Now I think the discussion is deviating from the thread topic. So it will be better to make another thread with a proper title...

Okay,
It just extract the bitrate and the no of channel information from the wave header and it sets the compare match interrupt intervel accordingly...
 

hello vinodstanur
now i can understand the code except the find_next_cluster function
Code:
unsigned int find_next_cluster(unsigned int cluster)
{
    static unsigned int cluster_index_in_buff;
    static unsigned int return_cluster;
    if((return_cluster + 1) == cluster)
    {
        if(cluster_index_in_buff+=2 < 512)
	{
            return_cluster += 1;
            return return_cluster;
        } 
	
	else {
            cluster_index_in_buff-=2;
        }
    }
    cluster_index_in_buff = (2 * (cluster % 256));
    mmc_read_sector(fat_start + cluster/256);
    return_cluster = ((mmc_buf[cluster_index_in_buff + 1] << 8) + mmc_buf[cluster_index_in_buff]);
}
the first if condition will never be right
and why this formula??
cluster_index_in_buff = (2 * (cluster % 256));
mmc_read_sector(fat_start + cluster/256);

please i need a help
thank u
 
hello vinodstanur
now i can understand the code except the find_next_cluster function
Code:
unsigned int find_next_cluster(unsigned int cluster)
{
    static unsigned int cluster_index_in_buff;
    static unsigned int return_cluster;
    if((return_cluster + 1) == cluster)
    {
        if(cluster_index_in_buff+=2 < 512)
	{
            return_cluster += 1;
            return return_cluster;
        } 
	
	else {
            cluster_index_in_buff-=2;
        }
    }
    cluster_index_in_buff = (2 * (cluster % 256));
    mmc_read_sector(fat_start + cluster/256);
    return_cluster = ((mmc_buf[cluster_index_in_buff + 1] << 8) + mmc_buf[cluster_index_in_buff]);
}
the first if condition will never be right
and why this formula??
cluster_index_in_buff = (2 * (cluster % 256));
mmc_read_sector(fat_start + cluster/256);

please i need a help
thank u

This function finds the next cluster number of a current playing file from the FAT table if we provide the current cluster number. So we can continue the stream.
Hope you have read about the FAT table....
 

I must admit, that I have also problems to understand the shown implementation of the function find_next_cluster(). As a simple point, it doesn't always return a value, in other words the return value is undefined. It looks like either part of the function got lost or some lines are mixed up.
 
Oh yes I missed the return... Now only I noticed this! Also the first if condition will never become true... Thanks for pointing this mistake....
r
Actually after writing this function at the first attempt, I tested it and got the next cluster without any problem!! So there after I didn't looked into this code... That is what happened... So now I assume the reason for this code worked in my case is because in my case, the expected return value carrying registers (say r24, r25 or any other) may be handling the real return values while calculating inside the function.. Think so...

Thanks for showing this error...

hope this below code is enough;
Code:
unsigned int find_next_cluster(unsigned int cluster)
{
	unsigned int cluster_index_in_buff;
    cluster_index_in_buff = (2 * (cluster % 256));
    mmc_read_sector(fat_start + cluster/256);
    return   ((mmc_buf[cluster_index_in_buff + 1] << 8) + mmc_buf[cluster_index_in_buff]);	
}

Also I think we can make this process little more fast. Because in most case the next cluster value will be there in the adjacent cluster location in the linked list. When there is no deleted files and if it is a new formatted memory chip, sure all the 'next cluster' will be the adjacent one in the FAT.... So I think we can check for it in the previous buffered bytes before doing the "%" and then loading a new 512 bytes of FAT containing our required cluster .... Hope it will save some processor time.
What is your opinion about this? Also, if you have a better idea, pls share it...
 
Last edited:

hello all
now i can play only small wav files with low byte rate (11025)
when i play wav files with high byte rate (44100) the output sound is slow and noisy
please i need a help

another question
in some wav files the bits per sample are 16 bits per sample and the code is only for 8 bits per sample
can i convert from 16 bits per sample files to 8 bits per sample files

now my working code is
Code:
/*****************************************************
This program was produced by the
CodeWizardAVR V1.24.8d Professional
Automatic Program Generator
© Copyright 1998-2006 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : 
Version : 
Date    : 5/1/2012
Author  : F4CG                            
Company : F4CG                            
Comments: 


Chip type           : ATmega32
Program type        : Application
Clock frequency     : 12.000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 512
*****************************************************/

#include <mega32.h>
#include <stdio.h>
#include <delay.h>
#include <string.h>
#asm
   .equ __lcd_port=0x1B ;PORTA
#endasm
#include <lcd.h>

#define MMC_CS_PORT            PORTB
#define MMC_CS_DDR             DDRB
#define MMC_CS_PIN              4
// MMC commands  (taken from sandisk MMC reference)
#define MMC_GO_IDLE_STATE           0          // initialize card to spi-type access
#define MMC_SEND_OP_COND            1         // set card operational mode 
#define MMC_SEND_IF_COND            8         // For only SDC V2. Check voltage range.
#define MMC_SEND_CSD                9         // get card"s CSD
#define MMC_SEND_CID                10        // get card's CID
#define MMC_SEND_STATE              13
#define MMC_SET_BLOCKLEN            16       //set number of byte to transferblock
#define MMC_READ_SINGLE_BLOCK       17       //read a block
#define MMC_WRITE_BLOCK             24       //write a block
#define MMC_PROGRAM_CSD             27
#define MMC_SET_WRITE_PROT          28
#define MMC_CLR_WRITE_PROT          29
#define MMC_SEND_WRITE_PORT         30
#define MMC_TAG_SECTOR_START        32
#define MMC_TAG_SECTOR_END          33
#define MMC_UNTAG_SECTOR            34
#define MMC_TAG_ERASE_GROUP_START   35       // sets beginning of erase group(mass erase)
#define MMC_TAG_ERASE_GROUP_END     36       //sets end of erase group (mass erase)
#define MMC_UNTAG_ERASE_GROUP       37
#define MMC_ERASE                   38
#define MMC_CRC_ON_OFF              59
#define MMC_R1_BUSY                 0X80
#define MMC_R1_PARAMETER            0X40
#define MMC_R1_ADDRESS              0X20
#define MMC_R1_ERASE_SEQ            0X10
#define MMC_R1_COM_CRC              0X08
#define MMC_R1_ILLEGAL_COM          0X04
#define MMC_R1_ERASE_RESET          0X02
#define MMC_R1_IDLE_STATE           0X01

#define MMC_STARTBLOCK_READ         0XFE
#define MMC_STARTBLOCK_WRITE        0XFE
#define MMC_STARTBLOCK_MWRITE       0XFC
#define MMC_STOPTRAN_WRITE          0XFD
#define MMC_DE_MASK                 0X1F
#define MMC_DE_ERROR                 0X01
#define MMC_DE_CC_ERROR              0X02
#define MMC_DE_ECC_FAIL              0X04

#define MMC_DE_OUT_OF_RANGE          0X04
#define MMC_DE_CARD_LOCKED           0X04

#define MMC_DR_MASK                   0X1F
#define MMC_DR_ACCEPT                 0X05
#define MMC_DR_REJECT_CRC             0X0B
#define MMC_DR_REJECT_WRITE_ERROR     0X0D
                               
#define F_CPU 12000000
#define LEFT_SWITCH  PIND&(1<<2)
#define RIGHT_SWITCH PIND&(1<<3)
#define SWITCH_EVENT PIND&((1<<3)|(1<<2))
 
register int  ISR_i @ 2;
register int STEREO @ 4;
register char TOGGLE_BUFFER @ 6;

char y[20];
unsigned int fat_start, dir_start, data_start,Max_RooT_Direc_Entry_L,Max_RooT_Direc_Entry_H,Sectors_per_FAT_L,Sectors_per_FAT_H,
first_partition_boot_record,LBA3,LBA4; 
unsigned long int LBA1,LBA2;
unsigned char sect_per_clust; 
//unsigned char TOGGLE_BUFFER;
unsigned int STARTING_CLUSTER;
unsigned int STARTING_CLUSTER_LOW,STARTING_CLUSTER_HIGH;
volatile unsigned char BUF1_EMPTY, BUF0_EMPTY = 0;
unsigned long int OCR1A_BACKUP;
unsigned int OCR1A_ADJUST;
unsigned long int bitrate;
//unsigned int ISR_i,STEREO;
//unsigned int cluster_index_in_buff;
//unsigned int return_cluster;
//unsigned  int ret_cluster_H;
//unsigned  int ret_cluster_L;    
unsigned char mmc_buf0[512],mmc_buf1[512]; 
unsigned char read_buf[512];
/*
eeprom unsigned  char read_buf[512]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};*/                        
void mmc_read_double_buffer(unsigned long int, unsigned char []);
void spi_write(unsigned char data);
void mmclint(void);
void fat16_init(void);
unsigned char mmcreset(void);
unsigned char mmcsendcommand(unsigned char cmd, unsigned long int argument);
unsigned char mmcread(unsigned long int sector);            //unsigned char mmcread(unsigned long int sector, unsigned char* buffer);
//unsigned char mmcwrite(unsigned long int sector);         //unsigned char mmcwrite(unsigned long int sector, unsigned char* buffer);
unsigned char mmccommand(unsigned char cmd, unsigned long int argument); 
char check_bitrate_and_stereo(unsigned int);
unsigned int scan_root_dir(char [], char);
void play_cluster(unsigned int);
unsigned int find_next_cluster(unsigned int);
void pwm_init();
void timer1_init(); 
//----------------------------------
void spilnit()
{
PORTB.7=1;
DDRB.7=1;
DDRB.6=0;
PORTB.6=0;
DDRB.5=1;
PORTB.5=0;
DDRB.4=1;
PORTB.4=0;
SPCR=0x52;
SPSR=0x01;                                                                                      //kan SPCR=0x00;
}

unsigned char spitransferbyte(unsigned char data)
{
unsigned char received =0;
 SPDR = data;
 while(!(SPSR&(1<<7)));
received = SPDR;
return (received);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void mmclint(void)
{
spilnit();
MMC_CS_DDR.MMC_CS_PIN=1;
MMC_CS_PORT.MMC_CS_PIN=1; 

}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void spi_write(unsigned char data){
//MMC_CS_PORT.MMC_CS_PIN=0; 
SPDR=data;   
while(!(SPSR&(1<<7)));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
unsigned char mmcreset(void){
unsigned char i;
unsigned char retry;
unsigned char r1=0;
retry=0;

do{
for(i=0;i<10;i++)   spitransferbyte(0xFF);        // send dummy byte with CS high before accessing
MMC_CS_PORT.MMC_CS_PIN=0;
for(i=0; i < 2; i++) spitransferbyte(0xFF);
r1= mmcsendcommand(MMC_GO_IDLE_STATE,0);                   //resetting card go to spi mode     r1=?????  0x95
retry++;  
 if(retry>10)  return -1;      //was -1
}while(r1 != 0X01);
retry=0;
lcd_clear();
sprintf(y,"CMD0  r1= %d",r1);
lcd_puts(y);
delay_ms(500);
spitransferbyte(0xff);   



do
{
r1= mmcsendcommand(MMC_SEND_OP_COND,0);                // initializing card for operation
retry++;    
if(retry>10)return-1;
}while(r1);
lcd_clear(); 
sprintf(y,"CMD1  r1= %d",r1);
lcd_puts(y);
delay_ms(500);



r1= mmcsendcommand(MMC_CRC_ON_OFF,0);              //turn off CRC checking to simplify communication  
lcd_clear();
sprintf(y,"CMD59  r1= %d",r1);
lcd_puts(y);
delay_ms(500);



r1=mmcsendcommand(MMC_SET_BLOCKLEN,512);
lcd_clear();
sprintf(y,"CMD16  r1= %d",r1);
lcd_puts(y);      
delay_ms(500);

lcd_clear();
lcd_putsf(" MMC  initiated ");
return 0;

}
//-------------------------------------------------
unsigned char mmcsendcommand(unsigned char cmd, unsigned long argument){
unsigned char r1;
MMC_CS_PORT.MMC_CS_PIN=0;                  //assert chip select          
r1= mmccommand(cmd,argument);              //issue the command
MMC_CS_PORT.MMC_CS_PIN=1;
return r1;

}
//-----------------------------------------------
 char mmcread(unsigned long int sector)   //char mmcread(unsigned long int sector,unsigned char* buffer )
{
unsigned char r1;
unsigned i;

MMC_CS_PORT.MMC_CS_PIN=0;    //MMC_CS_DDR.MMC_CS_PIN=0;
 r1= mmccommand(MMC_READ_SINGLE_BLOCK,sector<<9);
if (r1!=0x00)
{return r1;}
/*lcd_clear();  
sprintf(y,"CMD17  r1= %d",r1);
lcd_puts(y);
delay_ms(500);*/
 while(spitransferbyte(0xff)!=MMC_STARTBLOCK_READ);
for (i=0;i<512;i++)                        //(i=0;i<0x200;i++)
read_buf[i] = spitransferbyte(0xff);                //*buffer++ = spitransferbyte(0xff);    //haaaaaaaam
spitransferbyte(0xff);
spitransferbyte(0xff);
MMC_CS_PORT.MMC_CS_PIN=1; 
/*
lcd_clear();
lcd_putsf("  Data is read  ");
delay_ms(1000);

for (i=0;i<512;i++)
{
lcd_clear();
sprintf(y,"buf[%x]=0x%x",i,read_buf[i]); 
lcd_puts(y);
delay_ms(250);
}           
*/
return 0;


}  
///-------------------------------------------------------
/*unsigned char mmcwrite(unsigned long int sector)                //unsigned char mmcwrite(unsigned long int sector,unsigned char* buffer )
{
unsigned char r1;
unsigned int i; 

MMC_CS_PORT.MMC_CS_PIN=0;                         //issue command
for(i=0; i < 8; i++) spitransferbyte(0xFF);               
r1=mmccommand(MMC_WRITE_BLOCK,sector<<9);         //multiply sector by 512       
if(r1 != 0x00)
{return r1;}
lcd_clear();  
sprintf(y,"CMD24  r1= %d",r1);
lcd_puts(y);

spitransferbyte(0xff);                         // send dummy

spitransferbyte(MMC_STARTBLOCK_WRITE);                      //send data start token
for (i=0; i<512; i++)
spitransferbyte(write_buf[i]);                //spitransferbyte(*buffer++);
spitransferbyte(0xff);                         // write 16-bit crc (dummy values)
spitransferbyte(0xff);


r1=spitransferbyte(0xff);                    // read data response token   
if((r1&MMC_DR_MASK)!= MMC_DR_ACCEPT)
return r1;
while(!spitransferbyte(0xff));                   //wait for busy period
lcd_clear();
sprintf(y,"Datares = %d",r1);
lcd_puts(y);
delay_ms(500);
MMC_CS_PORT.MMC_CS_PIN=1;                           //CS 
lcd_clear();
lcd_putsf(" Data is writen ");
return 0;                                // return succes
} */
//////////////////////////////////////////
unsigned char mmccommand(unsigned char cmd,unsigned long int argument){
unsigned char r1;
char retry=0;
//send command
spi_write(cmd |0x40);
spi_write(argument>>24); 
spi_write(argument>>16);
spi_write(argument>>8);
spi_write(argument);    
if((cmd==MMC_GO_IDLE_STATE)||(cmd==8))
spi_write(0x95);                            //crc valid only for mmc_go_idle_state

while((r1 = spitransferbyte(0xff))==0xff)
if(retry++ > 8) break;
return r1;
}
///-------------------------------------------------                                  

void fat16_init()            //BOOT SECTOR SCANNING//
{
    mmcread(0);
    
    LBA1=read_buf[0x1C9];
    LBA2=read_buf[0x1C8];
    LBA3=read_buf[0x1C7];
    LBA4=read_buf[0x1C6];
    
    first_partition_boot_record=(LBA1<<24) + (LBA2<<16) + (LBA3<<8) + (LBA4);

    mmcread(first_partition_boot_record);
    
    lcd_clear();
    if((read_buf[0x36] == 'F') && (read_buf[0x39] == '1') && (read_buf[0x3a] == '6'))
    lcd_putsf(" FAT16 DETECTED ");
    else {
        lcd_putsf("   NOT  FAT16   ");
        while(1);
    }    
    
    Sectors_per_FAT_L=read_buf[0x16];
    Sectors_per_FAT_H=read_buf[0x17];
    Max_RooT_Direc_Entry_L=read_buf[0x11];
    Max_RooT_Direc_Entry_H=read_buf[0x12];
    
    delay_ms(500);
    fat_start = read_buf[0x0e]+first_partition_boot_record;                   //in sectors
    dir_start = (fat_start + (((Sectors_per_FAT_H << 8) + Sectors_per_FAT_L) * 2));            //in sectors
    data_start = (dir_start + ((((Max_RooT_Direc_Entry_H << 8) + (Max_RooT_Direc_Entry_L)) * 32) / 512));          //in sectors
    sect_per_clust = read_buf[0x0d];               //in sectors
    
    lcd_clear();
    sprintf(y,"fat_start=\n%d sectors",fat_start);
    lcd_puts(y); 
    delay_ms(500);
    lcd_clear();
    sprintf(y,"dir_start=\n%d sectors",dir_start);
    lcd_puts(y); 
    delay_ms(500);
    lcd_clear();
    sprintf(y,"data_start=\n%d sectors",data_start);
    lcd_puts(y); 
    delay_ms(500);
    lcd_clear();
    sprintf(y,"sect_per_clust=\n%d sectors",sect_per_clust);
    lcd_puts(y); 
    delay_ms(500);
    
} 
//------------------------------------------------------------------------------------
unsigned int scan_root_dir(char FNAME[], char UP_DOWN)
{
    while(1) {
        unsigned int i;
        static unsigned char read_end = 0;
        static int base_count = -32, sect_plus = 0;
        if(UP_DOWN == 1) 
		{
            	base_count += 32;
            	if(base_count == 512) {base_count = 0; sect_plus += 1;};
            	} 
	else {
            	base_count -= 32;
            	if(base_count == -32) {base_count = (512 - 32); sect_plus -= 1;}
            	if(sect_plus < 0) {sect_plus = 0; base_count = 0;}
        	}
        while(1) {
            mmcread(dir_start + sect_plus);
            while(base_count < 512) {
                if(read_buf[base_count] == 0) { read_end = 1; break;}
                if ((read_buf[1] != 0) && (read_buf[base_count + 2] != 0) && (read_buf[base_count] != 0xe5) 
                && (read_buf[base_count] != 0x00) && ((read_buf[base_count + 11] & 0b00011110) == 0) 
                && (read_buf[base_count+8]=='W')&& (read_buf[base_count+9]=='A')&& (read_buf[base_count+10]=='V')) {
                    for(i = 0; i < 11; i++)
                    FNAME[i] = read_buf[base_count + i];
                    FNAME[11] = 0;  
                    STARTING_CLUSTER_HIGH=read_buf[27 + base_count];
                    STARTING_CLUSTER_LOW=read_buf[26 + base_count];
                    
                    return (STARTING_CLUSTER = (unsigned int)((STARTING_CLUSTER_HIGH << 8) + STARTING_CLUSTER_LOW));
                }
                if(UP_DOWN) base_count += 32;
                else base_count -= 32;
            }
            base_count = 0;
            sect_plus++;
            if(read_end) { base_count = -32; sect_plus = 0; read_end = 0; return 0;}
        }
    
}}
//------------------------------------------------------------------------------------

char check_bitrate_and_stereo(unsigned int cluster)
{
    int i;
    mmcread(((unsigned long int)(cluster -2) * sect_per_clust) + data_start);
    if(read_buf[34] != 8) return 1;                //in our case if(read_buf[34] != 8) return 1;
    for (i = 31; i > 27; i--) {
        bitrate <<= 8;
        bitrate |= read_buf[i];
    }
    STEREO = read_buf[22] - 1;  
    sprintf(y,"\n bitrate:%lu",bitrate);
    lcd_puts(y);
    delay_ms(500);
    OCR1A_BACKUP = ((F_CPU  *(STEREO + 1))/bitrate);
    OCR1A = OCR1A_ADJUST = OCR1A_BACKUP;
    return 0;
}
//------------------------------------------------------------------------------------
void play_cluster(unsigned int cluster)
{
    unsigned long int sector;
    int i;
    sector = ((unsigned long int)(cluster -2) * sect_per_clust);
    sector += data_start;
    for(i = 0; i < sect_per_clust; i++) {
        while((!BUF1_EMPTY) && (!BUF0_EMPTY));       //////////////////-***********
        if(BUF0_EMPTY) {
            mmc_read_double_buffer(sector, mmc_buf0);
            BUF0_EMPTY = 0;
            } 
            else if(BUF1_EMPTY) {
            mmc_read_double_buffer(sector, mmc_buf1);
            BUF1_EMPTY = 0;
            }
        sector += 1;
    }
} 
//------------------------------------------------------------------------------------
unsigned int find_next_cluster(unsigned int cluster)
{
    unsigned int cluster_index_in_buff;
    unsigned int return_cluster;
    
    cluster_index_in_buff = (2 * (cluster % 256));
    mmcread(fat_start + cluster/256);
    return_cluster = (((unsigned int)read_buf[cluster_index_in_buff + 1] << 8) + (unsigned int)read_buf[cluster_index_in_buff]); 
    return return_cluster;
}
//------------------------------------------------------------------------------------
void timer1_init()
{
    TCCR1B=0x09;    //TCCR1B |= (1 << WGM12)|(1 << CS10);
    TCNT1 = 0;
    OCR1A = 10000;
    TIMSK=0x10;    //TIMSK |= (1 << OCIE1A);
}
//------------------------------------------------------------------------------------
void pwm_init()
{
    TCCR0=0x69;    //TCCR0|=(1<<WGM00)|(1<<WGM01)|(1<<COM01)|(1<<CS00);
    TCCR2=0x69;    //TCCR2|=(1<<WGM20)|(1<<WGM21)|(1<<COM21)|(1<<CS20);
    DDRB.3=1;    //DDRB|=(1<<PB3);
    DDRD.7=1;    //DDRD|=(1<<PD7);
}
//------------------------------------------------------------------------------------
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{//PORTC=1; 
    if(STEREO) {
        if(TOGGLE_BUFFER == 0) {
            /*mmc_buf_H=mmc_buf0[ISR_i+1];
            mmc_buf_L=mmc_buf0[ISR_i];  
            OCR0 = (mmc_buf_H<<8+mmc_buf_L)/256;
            ISR_i=ISR_i+2; 
            mmc_buf_H=mmc_buf0[ISR_i+1];
            mmc_buf_L=mmc_buf0[ISR_i]; 
            OCR2 = (mmc_buf_H<<8+mmc_buf_L)/256;*/
            OCR0 =  mmc_buf0[ISR_i++];
            OCR2 =  mmc_buf0[ISR_i++];
            }
	else{
            /*mmc_buf_H=mmc_buf1[ISR_i+1];
            mmc_buf_L=mmc_buf1[ISR_i];  
            OCR0 = (mmc_buf_H<<8+mmc_buf_L)/256;
            ISR_i=ISR_i+2; 
            mmc_buf_H=mmc_buf1[ISR_i+1];
            mmc_buf_L=mmc_buf1[ISR_i]; 
            OCR2 = (mmc_buf_H<<8+mmc_buf_L)/256;*/
            OCR0 =  mmc_buf1[ISR_i++];
            OCR2 =  mmc_buf1[ISR_i++];
            }
        if(ISR_i == 512) {
            if(TOGGLE_BUFFER==0)
            BUF0_EMPTY = 1;
            else
            BUF1_EMPTY = 1;  
            
            TOGGLE_BUFFER ^= 1;
            ISR_i = 0;
            }
        } 
	else {
        	if(TOGGLE_BUFFER == 0)
        	OCR0 = OCR2 = mmc_buf0[ISR_i++];
        	else
        	OCR0 = OCR2 = mmc_buf1[ISR_i++];
        	if(ISR_i == 512) {
            	if(TOGGLE_BUFFER==0)
            	BUF0_EMPTY = 1;
            	else
            	BUF1_EMPTY = 1;
            	TOGGLE_BUFFER ^= 1;
            	ISR_i = 0;
        	}
    	}
}
//------------------------------------------------------------------------------------
void mmc_read_double_buffer(unsigned long int sector, unsigned char a[])
{   unsigned char r1;
    unsigned i;
    MMC_CS_PORT.MMC_CS_PIN=0;
    r1=mmccommand(MMC_READ_SINGLE_BLOCK,sector<<9);
    if (r1!=0x00){}
 while(spitransferbyte(0xff)!=MMC_STARTBLOCK_READ);
    for(i = 0; i < 512; i++)
    a[i] = spitransferbyte(0xff);
    spitransferbyte(0xff);
    spitransferbyte(0xff);
    MMC_CS_PORT.MMC_CS_PIN=1;
}
/////////////////////////////////////////////////////////////////////////////////



void main(void) {
unsigned char fname[12];
unsigned int cluster;
char NEXT_OR_PREVIOUS = 1; 
DDRB.0=1;
DDRC=0xFF;
PORTC=0;
// LCD module initialization
lcd_init(16);
lcd_putsf("    wellcome    "); 
delay_ms(2000);    
lcd_clear();

PORTB.0=1;
delay_ms(1);
  mmclint();
delay_ms(100);    
  mmcreset();
delay_ms(100);

pwm_init();
fat16_init();
timer1_init();

delay_ms(200);

while(1){
while((cluster = scan_root_dir(fname, NEXT_OR_PREVIOUS)) == 0)             NEXT_OR_PREVIOUS = 1;
        lcd_clear();
        sprintf(y,"  %s.",fname);
        lcd_puts(y);
        delay_ms(500);
        if(!check_bitrate_and_stereo(cluster)) {
            TOGGLE_BUFFER = 0;
            BUF0_EMPTY = 1;
            BUF1_EMPTY = 1;
            #asm("sei")
            ISR_i = 0;
            while(cluster != 0xFFFF) {               
                lcd_clear();
                sprintf(y,"  cluster = %d",cluster);
                lcd_puts(y);
                play_cluster(cluster);
                cluster = find_next_cluster(cluster);
            if(SWITCH_EVENT) {
                    if(RIGHT_SWITCH) {NEXT_OR_PREVIOUS = 1;break;};
                    if(LEFT_SWITCH) {NEXT_OR_PREVIOUS = 0; break;};
                }
            }
            }
  
}
}
thank u in advance
 

Hi every body
Is there any formula for the amount of hidden sectors ? because as you know the boot sector is at sector 0 but the for some SDs with hidden sector, the boot record sector is at hidden sector so for finding boot record I search from the zero sector and increase it till can find it. I searched a lot but I couldn't find any rule or formula for hidden sectors, what's your idea ?
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top