|
|
View previous topic :: View next topic |
Author |
Message |
GG_Louis Guest
|
SPI problem with 18F4620 and EEprom 25C040 |
Posted: Tue Nov 13, 2007 12:40 pm |
|
|
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
|
|
Posted: Tue Nov 13, 2007 1:10 pm |
|
|
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
|
|
Posted: Tue Nov 13, 2007 4:24 pm |
|
|
Thank you very much PCM, I will try this new driver as soon as I can. |
|
|
GG_louis Guest
|
Still not working ! |
Posted: Fri Nov 16, 2007 8:26 pm |
|
|
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
|
|
Posted: Fri Nov 16, 2007 10:57 pm |
|
|
Quote: | #include <18F4620>
//#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000) |
A 20 MHz crystal requires the HS fuse.
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
|
25C040 |
Posted: Thu Nov 25, 2010 2:20 pm |
|
|
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
|
|
Posted: Thu Nov 25, 2010 4:42 pm |
|
|
First, try to make your eeprom work with the CCS driver, 25040.c.
If it works, then you know your hardware is good. |
|
|
|
|
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
|