|
|
View previous topic :: View next topic |
Author |
Message |
arunkish
Joined: 23 Dec 2008 Posts: 83
|
MMC Read Block Issue |
Posted: Wed Feb 20, 2013 9:58 pm |
|
|
Hello,
I have found the following code from forum and modified to write 1024 bytes to MMC, For testing purpose I have written it within the main function calling twice to execute command 0x58. I can see that all the 1024 bytes are written to the MMC, but I do get "Write Error 2" in hyperterminal when the i call command 0x58 for the second time. Why do i get the error and what mistake am i making ?
Code: |
#include <16F877.H>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use fast_io(C)
#byte SSPBUF = 0x13
#byte SSPCON = 0x14
#byte SSPSTAT = 0x94
#bit BF = SSPSTAT.0
#bit SMP = SSPSTAT.7
#bit CKE = SSPSTAT.6
#bit CKP = SSPCON.4
#bit SSPM1 = SSPCON.1
#bit SSPEN = SSPCON.5
#byte PORTC = 7
#bit CS = PORTC.2
//int mmc_init();
int mmc_response(unsigned char response);
//int mmc_read_block(unsigned long block_number);
int mmc_write_block(unsigned long block_number);
//int mmc_get_status();
//****************************************
// This is the same as the CCS spi_read() function.
char SPI(char d)
{
SSPBUF=d;
while (!BF);
return SSPBUF;
}
//******************************************
char Command(char befF, int16 AdrH, int16 AdrL, char befH)
{
SPI(0xFF);
SPI(befF);
SPI(AdrH >> 8);
SPI(AdrH);
SPI(AdrL >> 8);
SPI(AdrL);
SPI(befH);
SPI(0xFF);
return SPI(0xFF); // Return with the response
}
//********************************************
char MMC_Init()
{
char i;
// Init SPI
SMP=0;
CKE=0;
CKP=1;
SSPM1=1;
//SSPM0=1;
SSPEN=1;
CS=1; // MMC-Disabled
// MMC in SPI Mode -- start and Reset.
for(i=0; i < 10; i++) SPI(0xFF); // 10*8=80 clocks
CS=0; // MMC-Enabled
// CMD0
if (Command(0x40,0,0,0x95) !=1) goto Error; // Reset
st:
// CMD1
if (Command(0x41,0,0,0xFF) !=0) goto st ; // CMD1
return 1;
Error:
return 0;
}
//*********************************************
void main(void)
{
int16 i;
char ar;
setup_port_a(NO_ANALOGS);
set_tris_c(0b11010011); // sck rc3-0, sdo rc5-0, CS rc2-0.
set_tris_b(0b00000010);
puts("Start\n\r");
if(MMC_Init())
puts("MMC ON\n\r"); // MMC Init OK
//*****************************************
// Write Block
OUTPUT_LOW(PIN_C2);
if (Command(0x58,0,512,0xFF) !=0) puts("Write error ");
SPI(0xFF);
SPI(0xFF);
SPI(0xFE);
SPI("Begin\n\r"); // 7 characters
for(i=0; i < 500; i++) // Was 512, but used 12 for text
{
SPI('A');
}
SPI("\n\rEnd"); // 5 characters
SPI(255); // Send two bytes of 0xFF at the end
SPI(255);
//i=SPI(0xFF);
//i &=0b00011111;
//if (i != 0b00000101) puts("Write Error ");
//while(SPI(0xFF) !=0xFF); // Wait for end of Busy condition
if((SPI_READ(0xFF)&0x0F)!=0x05) puts("Write ERROR\n\r");;
puts("Write Ok\n\r");
// Write Block
OUTPUT_LOW(PIN_C2);
if (Command(0x58,0,1024,0xFF) !=0) puts("Write error 2 ");
SPI(0xFF);
SPI(0xFF);
SPI(0xFE);
SPI("Begin\n\r"); // 7 characters
for(i=0; i < 500; i++) // Was 512, but used 12 for text
{
SPI('R');
}
SPI("\n\rEnd"); // 5 characters
SPI(255); // Send two bytes of 0xFF at the end
SPI(255);
if((SPI_READ(0xFF)&0x0F)!=0x05) puts("Write ERROR\n\r");;
puts("Write Ok\n\r");
while(1); // The program stops here.
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Thu Feb 21, 2013 3:09 am |
|
|
Retch. Messy code....
Tidy code is easier for everybody.
However obvious thing is your write. It _needs_ to write the block size of the card. (512bytes). You can't change to 500, or '12bytes for testing'. The command won't complete.
Why use the CCS function in some places, and a replacement function in others?. Use one or the other.
Best Wishes |
|
|
arunkish
Joined: 23 Dec 2008 Posts: 83
|
|
Posted: Thu Feb 21, 2013 5:03 am |
|
|
Thank you for your reply. I know that the code is a mess. I wanted to give a try on it first, anyway as you said it did not work. I am looking for an example code that would work on 16F877A or 18F4620. Write Block and Read Block would be fine. I was searching for the code for a long time and unable to find the right one that is working. Can you please help me with an example if you have. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Thu Feb 21, 2013 5:14 am |
|
|
mmc_spi.c, is a complete driver.
The big problem you are going to have, is that your chip does not have enough RAM for a block buffer. MMC, _requires_ data to be read/written in blocks. You are not going to get very far, unless you have a buffer large enough to hold a block.....
The MMC driver requires a 512byte buffer.
Best Wishes |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1635 Location: Perth, Australia
|
|
Posted: Thu Feb 21, 2013 9:09 am |
|
|
Ttelmah wrote: | mmc_spi.c, is a complete driver.
The big problem you are going to have, is that your chip does not have enough RAM for a block buffer. MMC, _requires_ data to be read/written in blocks. You are not going to get very far, unless you have a buffer large enough to hold a block.....
The MMC driver requires a 512byte buffer.
Best Wishes |
Slight correction. Writes must be performed in 512 byte blocks. It is possible to read as little as a single byte at a time. When modifying even a single byte on the media, you must read the appropriate block into RAM, modify the byte of interest, then write out the 512 byte block to the media.
Don't wast you time on a PIC16F processor for this type of application, use a PIC18F4620 or similar. _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Thu Feb 21, 2013 9:45 am |
|
|
Agreed.
Use the 4620, if this is available, and the standard drivers.
Best Wishes |
|
|
arunkish
Joined: 23 Dec 2008 Posts: 83
|
|
Posted: Thu Feb 21, 2013 8:04 pm |
|
|
Thank you all again. I am going to give a try with 18F4620 with mmc_spi.c . I will keep you updated. |
|
|
arunkish
Joined: 23 Dec 2008 Posts: 83
|
|
Posted: Thu Feb 21, 2013 8:28 pm |
|
|
I am working with mmc_spi.c, but it is failing to initialize. Changed PIC to 18F4620.
Code: |
#include <18f4620.h>
#fuses HS, NOLVP, NOPROTECT, NOWDT, BROWNOUT, NOPUT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
//#use fast_io(C)
//#use fast_io(A)
//#define MMC_CLK PIN_C3 //o
//#define MMC_DI PIN_C4 //i
//#define MMC_DO PIN_C5 //o
//#define MMC_CS PIN_C2 //o
#include "mmc_Spi.c"
#byte TRISC = 0xf94
#byte PORTC = 0xf82
#byte TRISA = 0xf92
#byte PORTA = 0xf80
void main(void)
{
byte testchar;
printf("\n\rStarting CARD\n\r");
set_tris_c(0b11010011);
output_high(MMC_CS);
if(mmc_init()==0)puts ("all ok");
else
puts("error");
while(1);
}
|
|
|
|
arunkish
Joined: 23 Dec 2008 Posts: 83
|
|
Posted: Thu Feb 21, 2013 8:53 pm |
|
|
Sorry for writing again... Still no luck with what I am trying. Kindly help on this.
Code: |
#include <18f4620.h>
#fuses HS, NOLVP, NOPROTECT, NOWDT, BROWNOUT, NOPUT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use fast_io(C)
#use fast_io(A)
#define MMC_CLK PIN_C3
#define MMC_DI PIN_C5
#define MMC_DO PIN_C4
#define MMC_CS PIN_C2
#include "mmc_Spi.c"
#byte TRISC = 0xf94
#byte PORTC = 0xf82
#byte TRISA = 0xf92
#byte PORTA = 0xf80
void main(void)
{
byte testchar;
printf("\n\rStarting CARD\n\r");
set_tris_c(0b11010011);
output_high(MMC_CS);
if(mmc_init()==0)puts ("all ok");
else
puts("error");
while(1);
}
|
MMC_SPI.C declarations:
Code: |
//SanDisk’s MultiMediaCards clock data in on the rising edge and out on the falling edge.
#ifndef MMC_CLK
#define MMC_CLK PIN_C3
#endif
#ifndef MMC_DI
#define MMC_DI PIN_C5
#endif
#ifndef MMC_DO
#define MMC_DO PIN_C4
#endif
#ifndef MMC_CS
#define MMC_CS PIN_C2
#endif
|
Connections made between PIC and MMC CARD PINS are as follows:
MMC_CLK >> PIN_C3
MMC_DI >> PIN_C5
MMC_DO >> PIN_C4
MMC_CS >> PIN_C2
Voltage Conversion from 5V to 3.3 has also been done for the required PINS. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri Feb 22, 2013 2:11 am |
|
|
How?.....
On the 'voltage conversion'?.
This is the commonest problem. A _lot_ of the example layouts, posted on the web, _do not work_.
If using resistive dividers, these need quite low values to work successfully at SPI clock rates.
Going the other way, a lot of people show signals fed from 3.3v SPI directly into PIC inputs. This will _only_ work if you are using a pin on the PIC that supports TTL input thresholds. An increasing number of pins don't. The hardware SPI pins don't. You need a buffer chip otherwise.
Remember the pull-up connections. These are _required_ for the chip to wake up correctly (it takes more time for a PIC to wake than the SPI I/O circuitry, and the clock line in particular _must_ be high when the chip wakes).
You need a really good decoupling capacitor close to the card. The current surges from these can be 'surprising'.
Asmallri on the Brush electronics site, has some example circuit layouts.
Seriously, the 5 to 3.3v conversion, is the part that is wrong 99.9% of the time.
Best Wishes |
|
|
arunkish
Joined: 23 Dec 2008 Posts: 83
|
|
Posted: Fri Feb 22, 2013 9:43 pm |
|
|
Agreed with you 100%. I will work accordingly. But before that, I was trying to make it work and Initialized successfully. Read and Write blocks also works without problem. But I am facing a little difficulty with the write block function. The problem is that I am able to write only up to 0 - 63 blocks. ie. 32765 bytes and cannot go more than that.
Code: |
void write_block(int32 block_num)
{
unsigned long int varl,varh;
unsigned long int i,varh1,varh2,varl1,varl2;
OUTPUT_LOW(PIN_C2);
varl=((block_num & 0x003F)<<9);
varh=((block_num & 0xFFC0)>>7);
varh1=varh>>0x08;
varh2=varh &0xFF;
varl1=varl>>0x08;
varl2=varl&0xFF;
if(mmc_send_cmd(0x58, varh1,varh2,varl1, varl2, 0xFF)!=0) puts("Write Command error ");
SPI(0xFF);
SPI(0xFF);
SPI(0xFE);
for(i=0; i < 512; i++)
{
SPI('Q');
}
SPI(0xFF);
SPI(0xFF);
i=SPI(0xFF);
i &=0b00011111;
if (i != 0b00000101) puts("Write Error ");
while(SPI(0xFF) !=0xFF); // Wait for end of Busy condition
OUTPUT_HIGH(PIN_C2);
puts("Write Ok\n\r");
}
char mmc_send_cmd(int8 cmd, int8 arg1, int8 arg2, int8 arg3, int8 arg4, int8 crc)
{
SPI(0xFF);
SPI(cmd);
SPI(arg1);
SPI(arg2);
SPI(arg3);
SPI(arg4);
SPI(crc);
SPI(0xFF);
return SPI(0xFF);
}
|
and the code I call to write blocks ......... If i set the max value to anything greater than 63, it never goes beyond the 63 blocks.
Code: |
for(l=1;l<=127;l++)
{
write_block(l);
}
|
Please advice on what I am missing..... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Sat Feb 23, 2013 2:08 am |
|
|
Variable size......
A 'long int', in CCS, is an int16. You need to be using int32 values to hold the address. You are in the function declaration, but then the internal variables are int16.
Always be explicit in CCS (and every other C!). It is much safer to use declarations like 'unsigned int32', rather than 'unsigned long'. The latter will have different meanings on different chips. The declaration for an int32 (if you must use the 'long' naming), is 'unsigned long long'.
Best Wishes |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|