CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

SPI problem with 18F4620 and EEprom 25C040

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
GG_Louis
Guest







SPI problem with 18F4620 and EEprom 25C040
PostPosted: Tue Nov 13, 2007 12:40 pm     Reply with quote

Here is my problem. I was about to begin my project of end of studies in college by building a SD-card mp3 player, working with the VS1001 DSP chip. Since I'm forced to use SPI, which I've never used before, me and my teachers agreed it would be a great idea to try it out with a simple SPI EEprom from Microchip (only 4K of memory, it's really basic.)

So, I read the entire 25C040 datasheet, the MSSP chapter in the 18F4620 and a lot of documents about SPI. I did my simple PIC-EEprom setup on breadboard (5V, 20MHz quartz, SDI (RC4) to SO, SCK (RC3) to SCK, SDO (RC5) to SI, VCC, /WP, /HOLD connected to pull-up resistors). This is for the hardware part.

For the software part, I used the 0,0 SPI mode (clock idle = 0, transition from idle to active - rising edge). It is only a simple program to test the SPI and the writing and reading on the EEprom :

- Activate TRISC register for SPI mode (SDO and SCK as output, SDI as input)
- Setup_SPI in mode 0,0 (CKE=1, CKP = 0)
- Chip select = 1, SDO and SCK = 0;

(main)

- CS low, RDSR (read status register in eeprom), CS high.
- CS low, WREN (write enable on eeprom), CS high, delay.
- CS low, write instruction (0x02), adress, word (0x6A), CS high, delay (min = 5 ms).
- CS low, read instruction (0x03), adress, spi_read(0);, CS high.

And that's pretty much the whole tiny program reformulated into a few lines. Now, here's what I really wrote in the main routine :


Code:

#include "18f4620.h"
#use delay(clock = 20000000)

#bit GIE = 0xFF2.7
#bit SSPIF = 0xF9E.3

#byte SSPBUF = 0xFC9

#byte SSPSTAT = 0xFC7
#bit SMP = SSPSTAT.7 
#bit CKE = SSPSTAT.6
#bit BF = SSPSTAT.0

#byte SSPCON1 = 0xFC6
#bit WCOL = SSPCON1.7
#bit SSPOV = SSPCON1.6
#bit SSPEN = SSPCON1.5
#bit CKP = SSPCON1.4
#bit SSPM3 = SSPCON1.3 // mode
#bit SSPM2 = SSPCON1.2 // mode
#bit SSPM1 = SSPCON1.1 // mode
#bit SSPM0 = SSPCON1.0 // mode

#byte TRISC = 0xF94 // adresse du set_tris_c()

#byte PORTC = 0xF82
#bit CS = PORTC.2
#bit SCK = PORTC.3
#bit SDI = PORTC.4
#bit SDO = PORTC.5

#define WRDI   0x04 // Disable write operations
#define WREN   0x06 // Enable write operations
#define RDSR   0x05 // Read STATUS register
#define WRSR   0x01 // Write STATUS register
#define READ0   0x03 // Read between 0x000 et 0x0FF
#define READ1   0x0B // Read between 0x100 et 0x1FF
#define WRITE0   0x02 // Write between 0x000 et 0x0FF
#define WRITE1   0x0A // Write between0x100 et 0x1FF

void main(void)
{
   TRISC = 0b00010000;

   SETUP_SPI(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);

   CKE = 1; //mode 0
   CKP = 0;
   
   CS = 1;
   SDO = 0;
   SCK = 0;


while(1)
{

   CS = 0;
   spi_write(RDSR);
   popo = spi_read(0);
   CS=1;      

   CS = 0;
   spi_write(WREN);
   CS=1;
   delay_ms(500);
   
   CS=0;
   spi_write(0x02);
   spi_write(0x00);
   spi_write(0x6A);
   CS = 1;
   delay_ms(500);

   CS=0;
   spi_write(0x03);
   spi_write(0x00);
   popo = spi_read(0);
   CS = 1;

   if(popo==0x6a)
   {
      LUM = 1;  // witness LED
   }

}
   
}


The problem is when I read from the oscilloscope, I can clearly see the SCK pin the proper clock for the eeprom device and also the hex number on the SDO pin given to the SI pin of the eeprom. But When I synchronize the clock and the SDI, I get a signal but it seems too small to be read from the PIC. Maybe it's the dummy data or some crap. When I use the spi_read(0); to give the eeprom the clock to receive data I always get 0x00.In the program that I wrote above, I was supposed to get 0x6A from the eeprom. I looked in other forums and posts, I found out that many people had problems with the SPI. Is that normal? I really will appreciate any kind of help. THANK YOU!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Nov 13, 2007 1:10 pm     Reply with quote

Quote:
So, I read the entire 25C040 datasheet


CCS has a driver for that eeprom. It's in this directory:
Quote:
c:\Program Files\PICC\Drivers\25040.c



I just realized that the CCS driver is a software SPI driver
and you want a hardware SPI driver. I've posted an example
of a hardware driver for the 25LC640 in the following link:
http://www.ccsinfo.com/forum/viewtopic.php?t=28199&start=1
GG_louis
Guest







PostPosted: Tue Nov 13, 2007 4:24 pm     Reply with quote

Thank you very much PCM, I will try this new driver as soon as I can.
GG_louis
Guest







Still not working !
PostPosted: Fri Nov 16, 2007 8:26 pm     Reply with quote

Now there is exactly the same problem that is happening to this test circuit. I keep sending data to the EEprom (which I cannot be sure that this data is really written or not IN the EEprom...), random bytes, but when I read the same adresses I supposively wrote microseconds ago, I get 0x00. Nothing is comming out of this damn EEprom !!

Also, when I'm trying to use the eeprom_ready() function, I instantly get a 0 from the status register bit 0 (which means the eeprom is ready to read/write), because all I'm reading from the SO of the EE are zeros !

That dosen't help really much... I'm starting to be desperate.

So here is the modified C code I'm using for this, inspired by the hardware SPI driver for the 25LC640 (if i'm not mistaken) made by PCM Programmer.

Code:
#include <18F4620>
//#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000)
#include <STDLIB>

#define SPI_MODE_0_0 0x4000
#define SPI_MODE_0_1 0x0000
#define SPI_MODE_1_0 0x0010
#define SPI_MODE_1_1 0x4010
#define EEPROM_SIZE    10 // ten adresses will do for now...
#define EEPROM_SELECT PIN_C2

#byte TRISC = 0xF94 // address of set_tris_c()

void init_ext_eeprom(void);
int1 ext_eeprom_ready(void);
void write_ext_eeprom(int8 address, int8 data);
int8 read_ext_eeprom(int8 address);

//========================
void main()
{
int8 word[EEPROM_SIZE]={0};
int8 wrote[EEPROM_SIZE]={0};
int8 addr;
     
init_ext_eeprom(); 

srand(0x55);

for(addr = 0; addr < EEPROM_SIZE; addr++)
   {
    write_ext_eeprom(addr, (int8)rand());
   word[addr] = (int8)rand();
   }

srand(0x55);

for(addr = 0; addr < EEPROM_SIZE; addr++)
   {
    wrote[addr] = read_ext_eeprom(addr);
   }

while(1);
}






void init_ext_eeprom(void)
{
TRISC = 0b00010000;
output_high(EEPROM_SELECT);   
setup_spi(SPI_MASTER | SPI_MODE_0_0 | SPI_CLK_DIV_16 );
}

//--------------------------------
int1 ext_eeprom_ready(void)
{
int8 data;

output_low(EEPROM_SELECT);
spi_write(0x05); //RDSR
data = spi_read(0);
output_high(EEPROM_SELECT);
return(!bit_test(data, 0));
}

//--------------------------------
void write_ext_eeprom(int8 address, int8 data)
{
//while(!ext_eeprom_ready());

output_low(EEPROM_SELECT);
spi_write(0x06);
output_high(EEPROM_SELECT);

output_low(EEPROM_SELECT);
spi_write(0x02); //instruction write
spi_write(address);
spi_write(data);
output_high(EEPROM_SELECT);

delay_ms(5);
}
//--------------------------------

int8 read_ext_eeprom(int8 address)
{
int8 data;

//while(!ext_eeprom_ready()); // not working

output_low(EEPROM_SELECT);
spi_write(0x03);
spi_write(address);

data = spi_read(0);
output_high(EEPROM_SELECT);

return(data);
}



I would really like to be helped out on this one... Nobody I know can make this work... and now I beginning to consider using SPI with a Cypress PSoC.... that's how lame I am right now.

Thank you everyone,
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Nov 16, 2007 10:57 pm     Reply with quote

Quote:
#include <18F4620>
//#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000)

A 20 MHz crystal requires the HS fuse.

Quote:
#include <STDLIB>

This line is missing the ".H". This means you didn't select the tickbox
to "Disable HTML in this post". It's just below the posting window and
should always be selected.

Quote:

for(addr = 0; addr < EEPROM_SIZE; addr++)
{
write_ext_eeprom(addr, (int8)rand());
word[addr] = (int8)rand();
}

There is no reason for the line in bold to be there. It's calling the
random number generator a 2nd time in every iteration. Therefore
it's skipping every 2nd byte that comes from the RNG.

Quote:
#byte TRISC = 0xF94 // address of set_tris_c()

You're not using #fast_io(), so you don't need to set the TRIS. The
CCS function, setup_spi(), will automatically set the correct TRIS for
the hardware SPI pins (C3, C4, and C5). In standard i/o mode,
the compiler will automatically set the TRIS for the output_low(PIN_C2)
and output_high(PIN_C2) functions. Standard i/o mode is the default
mode of the compiler. You don't have to do anything to enable it.

Quote:
for(addr = 0; addr < EEPROM_SIZE; addr++)
{
wrote[addr] = read_ext_eeprom(addr);
}

I don't see any printf() code to display the data that's read from the
eeprom. How do you know you're getting 0's back ?


Quote:
void init_ext_eeprom(void)
{
TRISC = 0b00010000;
output_high(EEPROM_SELECT);
setup_spi(SPI_MASTER | SPI_MODE_0_0 | SPI_CLK_DIV_16 );
}

Again, there's no need to set the TRIS in standard i/o mode.


Quote:
void write_ext_eeprom(int8 address, int8 data)
{
//while(!ext_eeprom_ready());

output_low(EEPROM_SELECT);
spi_write(0x06);
output_high(EEPROM_SELECT);

output_low(EEPROM_SELECT);
spi_write(0x02); //instruction write
spi_write(address);
spi_write(data);
output_high(EEPROM_SELECT);

delay_ms(5); }

The ready routine should work. If it doesn't work, it means there's
something wrong, possibly with the hardware connections to the EEPROM.
They should be checked.

This eeprom has 512 bytes in it, and therefore it uses 9 bits of address.
So the address parameter should be declared as an int16 variable.
Also, the code inside the routine above should test bit 8 of the address,
If it's set, the code should set bit 3 in the "0x02" instruction to a '1'. The
eeprom data sheet shows that this is how bit A8 is sent to the eeprom.

Quote:
int8 read_ext_eeprom(int8 address)
{
int8 data;

//while(!ext_eeprom_ready()); // not working
output_low(EEPROM_SELECT);
spi_write(0x03);
spi_write(address);

data = spi_read(0);
output_high(EEPROM_SELECT);

return(data);
}

The same things apply to the read routine.

However, for the initial testing, you don't need to put in the code to
set address bit A8 in the command byte. It will be 0, and you're only
testing the first 10 bytes anyway, so it will work OK for now.

Check your connections between the PIC and the EEPROM.
They should look like this:
Code:

PIC     EEPROM
----   --------
SDO       SI   
SDI       SO
SCK       SCK
Pin C2    \CS

The \HOLD and \WP pins on the eeprom should be connected to Vdd.
There must be a ground connection between the PIC and the eeprom.
Rijiru



Joined: 07 Sep 2010
Posts: 3

View user's profile Send private message

25C040
PostPosted: Thu Nov 25, 2010 2:20 pm     Reply with quote

Hi, I have troubles to write and read EEPROM. My trouble is when I put the low address in SPI bus, DO (EEPROM) set high, and write the data. When I read the data stored, it isn't the data I expect, but reads 0xFF.
This is the routine used:
Code:

int1 eeprom_ready()
{
 BYTE data;

 output_low(CS);
 spi_write(0x05);
 data=spi_read(0);
 output_high(CS);
 return(!bit_test(data, 0));
}

void eeprom_write(BYTE addh, BYTE addl, BYTE data)
{
 while(!eeprom_ready());

 output_low(CS);
 spi_write(0x06);
 output_high(CS);
 output_low(CS);
 spi_write((0x02)|((addh)&(0x08)));
 spi_write(addl);
 spi_write(data);
 output_high(CS);
 delay_ms(5);
}

BYTE eeprom_read(BYTE addh, BYTE addl)
{
 int8 data;

 while(!eeprom_ready());

 output_low(CS);
 spi_write((0x03)|((addh)&0x08));
 spi_write(addl);
 data=spi_read(0);
 output_high(CS);

 return(data);
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Nov 25, 2010 4:42 pm     Reply with quote

First, try to make your eeprom work with the CCS driver, 25040.c.
If it works, then you know your hardware is good.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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