View previous topic :: View next topic |
Author |
Message |
tranjimmysd
Joined: 05 May 2005 Posts: 9
|
Need help with the MMC code |
Posted: Tue May 10, 2005 8:54 pm |
|
|
Hi,
I have the CCS 16F877A Proto-board. I connect it with 256 MB MMC card( brand new one, I got it from Fry's Electronic). I use SPI.
RC5 to MOSI(MMC pin2)
RC4 to MISO(MMC pin7)
RC3 to CLK (MMC pin 5)
RC1 to CS (MMC pin1)
the MMC is powered by 3.3 volt. The PIC is powered by 5.0 volt. Since the voltage level for RC1, RC4 and RC3 is 5.0 volt. So I use voltage divider 3.3 K and 1.8 K Ohm in MOSI, CS, CLK to make sure that those MMC pins will have 3.3 volt level.
I use this code from the internet to test it. Based on the debug output to rs232, i can tell that I got some responses from MMC when I write to it. But when it comes to the read function. I get nothing when trying to read back the test pattern ( a bunch of number 7). Here is the code. Can anyone tell me if I am missing anything:
*******************************************
#include <16f877a.h>
#device ICD=TRUE
#fuses HS, NOPROTECT, PUT, NOWDT, BROWNOUT, NOLVP, NOCPD
#use delay(clock=20000000)
#use rs232 (baud=9600, xmit=PIN_C6,rcv=PIN_C7)
#include <stdlib.h>
#include <input.c>
#define LOW(var) (var & 0xFF)
#define HIGH(var) (var>>8)
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();
/************************** MMC Init **************************************/
/* Initialises the MMC into SPI mode and sets block size, returns 0 on success */
int mmc_init()
{
int i;
SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_SS_DISABLED);
*0x94 |= 0x40; // set CKE = 1 - clock idle low
*0x14 &= 0xEF; // set CKP = 0 - data valid on rising edge
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
for(i=0;i<10;i++) // initialise the MMC card into SPI mode by sending clks on
{
SPI_WRITE(0xFF);
}
OUTPUT_LOW(PIN_C2); // set SS = 0 (on) tells card to go to spi mode when it receives reset
SPI_WRITE(0x40); // send reset command
SPI_WRITE(0x00); // all the arguments are 0x00 for the reset command
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x95); // precalculated checksum as we are still in MMC mode
printf("Sent go to SPI\n\r");
if(mmc_response(0x01)==1) return 1; // if = 1 then there was a timeout waiting for 0x01 from the mmc
printf("Got response from MMC\n\r");
i = 0;
while((i < 255) && (mmc_response(0x00)==1)) // must keep sending command if response
{
SPI_WRITE(0x41); // send mmc command one to bring out of idle state
SPI_WRITE(0x00); // all the arguments are 0x00 for command one
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
i++;
}
if(i >= 254) return 1; // if >= 254 then there was a timeout waiting for 0x00 from the mmc
printf("Got out of idle response from MMC\n\r");
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
SPI_WRITE(0xFF); // extra clocks to allow mmc to finish off what it is doing
OUTPUT_LOW(PIN_C2); // set SS = 0 (on)
SPI_WRITE(0x50); // send mmc command one to bring out of idle state
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x02); // high block length bits - 512 bytes
SPI_WRITE(0x00); // low block length bits
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
if((mmc_response(0x00))==1) return 1;
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
printf("Got set block length response from MMC\n\r");
return 0;
}
/************************** MMC Get Status **************************************/
/* Get the status register of the MMC, for debugging purposes */
int mmc_get_status()
{
OUTPUT_LOW(PIN_C2); // set SS = 0 (on)
SPI_WRITE(0x58); // send mmc command one to bring out of idle state
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00); //
SPI_WRITE(0x00); // always zero as mulitples of 512
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
return 0;
}
/************************** MMC Write Block **************************************/
int mmc_write_block(unsigned long block_number)
{
unsigned long i;
unsigned long varh,varl;
varl=((block_number&0x003F)<<9);
varh=((block_number&0xFFC0)>>7);
printf("Write block\n\r"); // block size has been set in mmc_init()
OUTPUT_LOW(PIN_C2); // set SS = 0 (on)
SPI_WRITE(0x58); // send mmc write block
SPI_WRITE(HIGH(varh));
SPI_WRITE(LOW(varh));
SPI_WRITE(HIGH(varl));
SPI_WRITE(0x00); // always zero as mulitples of 512
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
if((mmc_response(0x00))==1) return 1;
printf("Got response to write block\n\r");
SPI_WRITE(0xFE); // send data token
for(i=0;i<512;i++)
{
SPI_WRITE(7 + '0'); // send data
}
SPI_WRITE(0xFF); // dummy CRC
SPI_WRITE(0xFF);
if((SPI_READ(0xFF)&0x0F)!=0x05) return 1;
printf("Got data response to write block\n\r");
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
return 0;
}
/************************** MMC Read Block **************************************/
/**** Reads a 512 Byte block from the MMC and outputs each byte to RS232 ****/
int mmc_read_block(unsigned long block_number)
{
unsigned long i;
unsigned long varh,varl;
varl=((block_number&0x003F)<<9);
varh=((block_number&0xFFC0)>>7);
OUTPUT_LOW(PIN_C2); // set SS = 0 (on)
SPI_WRITE(0x51); // send mmc read single block command
SPI_WRITE(HIGH(varh)); // arguments are address
SPI_WRITE(LOW(varh));
SPI_WRITE(HIGH(varl));
SPI_WRITE(0x00);
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
if((mmc_response(0x00))==1) return 1; // if mmc_response returns 1 then we failed to get a 0x00 response (affirmative)
printf("Got response to read block command\n\r");
if((mmc_response(0xFE))==1) return 1; // wait for data token
printf("Got data token\n\r");
for(i=0;i<512;i++)
{
putc(SPI_READ(0xFF)); // we should now receive 512 bytes
}
SPI_READ(0xFF); // CRC bytes that are not needed
SPI_READ(0xFF);
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
SPI_WRITE(0xFF); // give mmc the clocks it needs to finish off
printf("\n\rEnd of read block\n\r");
return 0;
}
/************************** MMC get response **************************************/
/**** Repeatedly reads the MMC until we get the response we want or timeout ****/
int mmc_response(unsigned char response)
{
unsigned long count = 0xFFFF; // 16bit repeat, it may be possible to shrink this to 8 bit but there is not much point
while(SPI_READ(0xFF) != response && --count > 0);
if(count==0) return 1; // loop was exited due to timeout
else return 0; // loop was exited before timeout
}
void main(void)
{
printf("testing for MMC");
mmc_init();
mmc_write_block(0);
if (mmc_read_block(0) == 1)
{
printf("MMC not response for reading \r\n");
}
while(1)
{
}
} |
|
|
icefield
Joined: 09 May 2005 Posts: 20 Location: Canada
|
Re: Need help with the MMC code |
Posted: Wed May 11, 2005 4:07 am |
|
|
tranjimmysd wrote: | Hi,
the MMC is powered by 3.3 volt. The PIC is powered by 5.0 volt. Since the voltage level for RC1, RC4 and RC3 is 5.0 volt. So I use voltage divider 3.3 K and 1.8 K Ohm in MOSI, CS, CLK to make sure that those MMC pins will have 3.3 volt level.
|
The trouble might be that MISO is only getting 3.3V signals. Check the electrical specs of the PIC. MISO is probably a Schmitt trigger input (see the Port Spec), in which case minimum logic high is usually 0.7 or 0.8Vdd (i.e., 3.5-4V). So, you need a proper level converting chip or some MML to complement that resistor network.
For newbies: MML is Mickey Mouse Logic - usually a transitor or MOSFET with some resistors hanging off. As opposed to TTL or CMOS.
Cheers,
Erik |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1907
|
|
|
tranjimmysd
Joined: 05 May 2005 Posts: 9
|
|
Posted: Wed May 11, 2005 10:44 am |
|
|
Many thanks Icefield and Newguy. Good suggestions. I will give it a try and let you guys know how it goes. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed May 11, 2005 1:39 pm |
|
|
There are some serious problems with your level translation,
and with the MMC specification's requirement for pull-ups, etc.
But before considering that, the code that you posted uses
Pin C2 for the CS (or slave select). But in your pin list,
you're using pin C1.
You must either change your hardware to use Pin C2,
or you must modify the driver so it uses pin C1. |
|
|
tranjimmysd
Joined: 05 May 2005 Posts: 9
|
|
Posted: Wed May 11, 2005 7:26 pm |
|
|
Hi,
Sorry for the typo. I did use C2 for the chip select.
I put this circuit( the first part) in between MISO and RC4 to make sure that the RC4/SDI pin on the pic will receive proper 5 volt level.
http://www.circuitcellar.com/pastissues/articles/Tom99/figure1.htm
with that circuit, I can go little further in the read function until where the function asks for the data token(if((mmc_response(0xFE))==1) return 1; // wait for data token). Asking for 0xFE, the MMC returns 0xFF.
I stuck. Any suggestion will be appreciated.
Jim |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed May 11, 2005 8:58 pm |
|
|
What is your version of the compiler ? |
|
|
tranjimmysd
Joined: 05 May 2005 Posts: 9
|
|
Posted: Wed May 11, 2005 9:35 pm |
|
|
Hi,
The compiler version 3.224
PCWH compiler
IDE version 3.224
PCB Version 3.224
PCM version 3.224
PCH version 3.224
Thanks |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 12, 2005 12:51 am |
|
|
His SPI setup has got some problems. I can see at least two problems.
I don't have time to finish writing it all up tonight. I'll do it tomorrow
morning and then post it.
Also, I'm curious as the manufacturer and part number of your MMC card.
I'd like to download the data sheet for it. |
|
|
tranjimmysd
Joined: 05 May 2005 Posts: 9
|
|
Posted: Thu May 12, 2005 1:17 am |
|
|
Hi,
The MMC card made by Power Quotient International Co., Ltd
www.pqi.com.tw
It called Reduced Size MMC
Thank you very much for all your helps
Jim |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 12, 2005 3:31 pm |
|
|
Actually, I thought I had found two bugs, but I've only found one so far.
This line of code has a bug.
Code: | SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_SS_DISABLED); |
The SPI_SS_DISABLED parameter is only supposed to be used with
the SPI_SLAVE parameter. If it's used with SPI_MASTER, then it
affects the SPI clock frequency. In this case, it changes the divisor
from 1/4 to 1/16. So the SCLK is running not at 5 MHz as he intends,
but actually at 1.25 MHz.
So the correct code should look like this:
Code: | SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4);
|
I don't know if this is going to affect your problem. I'll keep looking
at it on Friday and over the weekend. If I see anything else, I'll post it.
Of course, anyone else who sees a problem should post it as well. |
|
|
tranjimmysd
Joined: 05 May 2005 Posts: 9
|
|
Posted: Thu May 12, 2005 10:24 pm |
|
|
Hi,
I tried that but it did not work. :-(
I made my circuit based on this
http://www.captain.at/electronics/pic-mmc/
I aslo added in the volt level shifter in between the MMC output pin to the PIC SPI input .
I made my volt level shifter by using some of the resistors and transitors( I got them from Radioshack, the NPN high speed switching transistors).
Jim |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 12, 2005 11:00 pm |
|
|
CCS has a driver. It's called MMC_SPI.C, and it's in this folder:
c:\Program Files\Picc\Drivers
Have you tried that one ? |
|
|
tranjimmysd
Joined: 05 May 2005 Posts: 9
|
|
Posted: Fri May 13, 2005 12:42 am |
|
|
Hi,
I tried the CCS driver, but it did not work too.
Have anyone in this forum ever tried this MMC code? http://www.microchipc.com/sourcecode/#mmc
if the code is working on for others, then there must be something wrong with my hardware connection.
Do you know any simple MMC/PIC development platform( PIC on 5 volts and MMC on 3.3 volts and support CCS ICD-U40) out there that I can purchase?
I like to test that MMC code with the surely-working-hardware.
Many thanks for all your helps
Jim |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1907
|
|
Posted: Fri May 13, 2005 1:03 am |
|
|
I could be wrong, but I was under the impression that the ICD-U40 could program the low-voltage (LF) pics. Why don't you try to get an LF pic, run/program it at 3.3V, and then you can directly connect it to the 3.3V MMC card? |
|
|
|