|
|
View previous topic :: View next topic |
Author |
Message |
shinagan
Joined: 15 Mar 2012 Posts: 5
|
PIC18f2580 & EEPROM 25LC1024 |
Posted: Thu Mar 15, 2012 2:46 pm |
|
|
Hi everyone,
I would like to know if it exists an example of code for writing on an EEPROM with a PIC18 using CCS C compiler. I've tried a lot on my own, but i didn't succeed.
If no example is available, i will show what i've written, you might find what's wrong ! |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Thu Mar 15, 2012 4:48 pm |
|
|
Go ahead and post your code. Also, what compiler revision are you using?
If you have time, take a look at the driver folder in your CCS directory and look at the 23k256.c file. Ignore the init function in there as it is totally different from your chip, but the read and write functions there should give you an idea of how it should look.
Mind you, the chip you have might have 24bit addressing, so you would need to add another line for the 3rd address byte if that is the case (the 23k256 has 16bit addressing), as well as update the address parameter from 16bits to 32bits (for enough space for 24bits).
The main difference for your chip aside from that is you need to issue the WREN instruction before writing to the chip. Since the 23k256 doesn't require this, there won't be any example code for that, but you should be able to look at both of the read and write functions to get an idea of how the flow should be to issue a command based on the datasheet and make a write_en() function yourself. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Thu Mar 15, 2012 5:04 pm |
|
|
CCS does supply some examples in their 'examples' and 'drivers' folders that may supply you enough information to write your own 'driver'. Also , check the 'code library' to see if someone else has already done the work. |
|
|
shinagan
Joined: 15 Mar 2012 Posts: 5
|
|
Posted: Mon Mar 19, 2012 10:23 am |
|
|
Hi,
I'm using :
IDE version 4.041
PCM version 4.041
PCB version 4.041
PCH version 4.041
I've looked a lot of docs and examples but i still have the same problem : my EEPROM doesn't respond.
I mean : i ask the EEPROM to store data in a particular adress (for example : 0x00AAAA) and then ask it the value stored at the adress 0x00AAAA. But the EEPROM never responds.
Here is the code i used :
Code: | #include <18F2580.h>
#DEVICE ICD=TRUE
#FUSES XT
#use delay(clock=20M)
#define LED PIN_C7
#define SPI PIN_C5
#define EEPROM_SELECT PIN_B3 //branché sur CS
#define EEPROM_CLK PIN_C3 //branché sur la patte horloge
#define EEPROM_DI PIN_C5 //branche sur la patte SDO
#define EEPROM_DO PIN_C4 //branche sur la patte SDI
#define EEPROM_ADDRESS long int // Les adresses sont un long int (ecrites en binaire)
#define EEPROM_SIZE 1048576 // Taille de l'EEPROM, en bit
/*
***********
*FONCTIONS*
***********
*/
//FAIRE CLIGNOTER LA LED
void blink()
{
output_high(LED);
delay_ms(200);
output_low(LED);
delay_ms(200);
}
//CHECKER L'ETAT DE L'EEPROM
int1 ext_eeprom_ready(void)
{
int8 data ; //variable de capture, 8 bits
output_low(EEPROM_SELECT); // CS = 0
//blink();
spi_write(0x05); //demande l'etat de l'EEPROM
//blink();
data = spi_read(0); //data enregistre la réponse (8bits, cf. section 3)
output_high(EEPROM_SELECT); // CS = 1
return(!bit_test(data, 0)); //renvoie non-(bit 0 de data) <=> 1 dit qu'elle est 10po
}
//ECRIRE SUR l'EEPROM
void write_ext_eeprom(EEPROM_ADDRESS address, BYTE data)
{
while(!ext_eeprom_ready()); //tant que l'EEPROM est occupée, le PIC tourne en boucle
output_low(EEPROM_SELECT); // CS = 0
spi_write(0x06); //dévérouille l'écriture
output_high(EEPROM_SELECT); // CS = 1
output_low(EEPROM_SELECT); // CS = 0
spi_write(0x02); //Mode écriture
spi_write(address >> 16); // envoi du MSB
spi_write(address >> 8); // envoi d'adress
spi_write(address); // envoi du LSB
spi_write(data); //Envoi des données
output_high(EEPROM_SELECT); // CS = 1
}
//LIRE L'EEPROM
BYTE read_ext_eeprom(EEPROM_ADDRESS address)
{
int8 data; //variable de capture, 8 bits
while(!ext_eeprom_ready()); //tant que l'EEPROM est occupée, le PIC tourne en boucle
output_low(EEPROM_SELECT); // CS =0
spi_write(0x03); //Mode lecture
spi_write(address >> 16); // envoi du MSB
spi_write(address >> 8); // envoi d'adress
spi_write(address); // envoi du LSB
delay_us(1);
data = spi_read(0); //data enregistre la réponse
output_high(EEPROM_SELECT); // CS = 1
return(data); //On renvoie la valeur data en octets
}
void main()
{
int8 test;
output_high(EEPROM_SELECT); // CS = 1
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
output_low(EEPROM_SELECT);
write_ext_eeprom(0x00AAAA,0x11);
delay_us(100);
test = spi_read(0x00AAAA);
output_high(EEPROM_SELECT);
if(test == 0x11)
{
while(1)
{
blink();
}
}
else
{
blink();
}
}
|
Comments are in french, sorry, i'm not english ;)
My opinion :
- I'm not sure about this line :
Code: | setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16); | I don't know if this is a clock mode that the EEPROM understands. That's why i often try the four modes...
Can anyone tell mode which mode is the right one ?
- I suspect the clock emitted by the PIC to be the main problem.
If you look at the datasheet of my EEPROM (available here : http://ww1.microchip.com/downloads/en/devicedoc/22064a.pdf) you can see page 7 or 8 that when you write or read on this EEPROM the clock never stops. You always emit a clock from the PIC. BUT i don't know how to do this. When i use the function of CCS C, it clocks 8 times then stops and then clock again.
Here is the evidence :
So the EEPROM may never respond because the clock stops ! How can i force the PIC to always clock ?
Thanks for everything,
shinagan |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Mon Mar 19, 2012 10:36 am |
|
|
The clock stopping shouldn't cause you any issues. SPI devices are driven by the clock. Assuming the normal mode most operate in, they clock data into their own registers on the rising edge of the clock, and change their outgoing data on the falling edge. You could theoretically clock 8 bits, hold the line low for a million years and then clock 8 more bits (well assuming the devices could stay on that long). It's the edge transitions that move the processing along.
EDIT: As a point of interest, I work with the 25LC512 and I stop the clock often and sometimes long with no issues. Unfortunately, I used VHDL, so I don't have any PIC code handy.
Can you probe all 4 lines at once (clock, data in, data out, and CS) and show that in a screen shot?
Also, is there a way for you to show the entire contents of the status register when you ready it? It would be helpful so you could see the write latch and block protect bits as well incase those are causing problems.
EDIT2: You don't need to toggle the CS lines when calling setup_spi(). That just gets the PIC ready to use SPI in the way you desire. It doesn't actually transmit data.
EDIT3: Also, I know you did the ready polling before writing or reading, but could you also insert a 10ms delay between your write call and your read call. You have an older compiler, so we don't know for sure the function doing the ready checking is functioning correctly or not. The EEPROM has a max write time of 6ms, so I figure 10ms would be more than enough. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Mon Mar 19, 2012 10:51 am |
|
|
OK, I'm 'old school'...
It's generally not a good idea to run 5 volt PICs with 3 volt devices unless proper logic level translation is done.
Perhaps others who have this combination can offer their advise. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Mon Mar 19, 2012 11:04 am |
|
|
Also, though this isn't causing your issue (yet), I think this is incorrect:
Code: |
#define EEPROM_ADDRESS long int
|
I don't typically work with PIC18s, but I thought "long int" was a 16bit type.
I would do something like:
Code: |
#define EEPROM_ADDRESS unsigned int32
|
This is what I read from the manual, but I am not 100% sure I have the right one for a PIC18
Quote: |
long int16
long long int32
Note: All types, exceptfloat, by default are un signed; however, may be preceded by unsigned or signed . Short and long may have the keyword INT following them with no effect. Also see #TYPE to change the default size.
|
In general, I find it usually better to stick with the size defined types, int8, int16, int32 |
|
|
shinagan
Joined: 15 Mar 2012 Posts: 5
|
|
Posted: Mon Mar 19, 2012 12:45 pm |
|
|
Let's sum up all this ideas :
- The fact that the clock stops shouldn't be a problem.
- I can't probe the four lines on a single oscilloscope as they only have two channels. But i can take a picture of clock+data in then clock+data out then clock+CS or any other combination...
Oscilloscopes have a kind of "security wire" to avoid people stealing them. So i don't thing i can even gather close enough two of them to have 4 probes on 2 screens...
- I can ask the EEPROM :
It should show the status register. But the EEPROM always responds 0x00 (or doesn't responds !!)
- I've taken into account every modification you told me to do.
Labs are closed now so i will try again tomorrow, during lunch time ! |
|
|
shinagan
Joined: 15 Mar 2012 Posts: 5
|
|
Posted: Tue Mar 20, 2012 7:56 am |
|
|
Here is the code used this time :
Code: | #include <18F2580.h>
#DEVICE ICD=TRUE
#FUSES XT
#use delay(clock=20M)
#define LED PIN_C7
#define SPI PIN_C5
#define EEPROM_SELECT PIN_B3 //branché sur CS
#define EEPROM_CLK PIN_C3 //branché sur la patte horloge
#define EEPROM_DI PIN_C5 //branche sur la patte SDO
#define EEPROM_DO PIN_C4 //branche sur la patte SDI
#define EEPROM_ADDRESS unsigned int32 // Les adresses sont un long int (ecrites en binaire)
#define EEPROM_SIZE 1048576 // Taille de l'EEPROM, en bit
/*
***********
*FONCTIONS*
***********
*/
//FAIRE CLIGNOTER LA LED
void blink()
{
output_high(LED);
delay_ms(200);
output_low(LED);
delay_ms(200);
}
//CHECKER L'ETAT DE L'EEPROM
int1 ext_eeprom_ready(void)
{
int8 data ; //variable de capture, 8 bits
output_low(EEPROM_SELECT); // CS = 0
//blink();
spi_write(0x05); //demande l'etat de l'EEPROM
//blink();
data = spi_read(0); //data enregistre la réponse (8bits, cf. section 3)
output_high(EEPROM_SELECT); // CS = 1
return(!bit_test(data, 0)); //renvoie non-(bit 0 de data) <=> 1 dit qu'elle est 10po
}
//ECRIRE SUR l'EEPROM
void write_ext_eeprom(EEPROM_ADDRESS address, BYTE data)
{
while(!ext_eeprom_ready()); //tant que l'EEPROM est occupée, le PIC tourne en boucle
output_low(EEPROM_SELECT); // CS = 0
spi_write(0x06); //dévérouille l'écriture
output_high(EEPROM_SELECT); // CS = 1
output_low(EEPROM_SELECT); // CS = 0
spi_write(0x02); //Mode écriture
spi_write(address >> 16); // envoi du MSB
spi_write(address >> 8); // envoi d'adress
spi_write(address); // envoi du LSB
spi_write(data); //Envoi des données
output_high(EEPROM_SELECT); // CS = 1
}
//LIRE L'EEPROM
BYTE read_ext_eeprom(EEPROM_ADDRESS address)
{
int8 data; //variable de capture, 8 bits
while(!ext_eeprom_ready()); //tant que l'EEPROM est occupée, le PIC tourne en boucle
output_low(EEPROM_SELECT); // CS =0
spi_write(0x03); //Mode lecture
spi_write(address >> 16); // envoi du MSB
spi_write(address >> 8); // envoi d'adress
spi_write(address); // envoi du LSB
delay_us(1);
data = spi_read(0); //data enregistre la réponse
output_high(EEPROM_SELECT); // CS = 1
return(data); //On renvoie la valeur data en octets
}
void main()
{
int8 test;
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
write_ext_eeprom(0x00AAAA,0x11);
delay_ms(10);
test = spi_read(0x00AAAA);
output_high(EEPROM_SELECT);
if(test == 0x11)
{
while(1)
{
blink();
}
}
else
{
blink();
}
}
|
I took a lot of picture to show what's happening :
Nothing at all :
Clock + Chip Select (CS) :
Clock + data in at 2.5 ms/div (so we can see the delay_ms(10)) :
Clock + Data in at 10us/div :
Clock + Data out :
Clock + Vss :
Any idea of what's wrong ? |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Tue Mar 20, 2012 8:48 am |
|
|
The most likely problem is your code in main() that currently looks like: Code: | test = spi_read(0x00AAAA); | really should look like: Code: | test = read_ext_eeprom(0x00AAAA); | Something else is your #FUSES XT. That should be #FUSES HS if you're using a 20MHz crystal. _________________ Andrew |
|
|
drh
Joined: 12 Jul 2004 Posts: 192 Location: Hemet, California USA
|
|
Posted: Tue Mar 20, 2012 8:53 am |
|
|
It looks like the data out from the eeprom is connected to a uP pin configured as an output (set low) rather than as an input. The version of compiler you are using is really old. Versions before 4.070 are known to be buggy. _________________ David |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Tue Mar 20, 2012 10:38 am |
|
|
As a note, the line;
Code: |
test = spi_read(0x00AAAA);
|
does the following (assuming you had the chipselects, which you don't):
1. writes 0xAA (the byte) to the EEPROM
2. reads back junk
And that is assuming you use the chip selects around it which you don't.
You need to treat the read just like how you did the write (per andrewg suggestion) and make a function that handles chip select, write the read command byte, write the address (all 3 bytes, not just one), reads the byte you wish to see, and then finishes off the chip select. you can't just simply execute an SPI read like you did.
EDIT: You can actually see all of this in the 2nd and 4th pictures you posted (clock +CS and Clock +data). In the second picture, you see the clock going while the chip select is still high. When you look at the data versus the clock, you can clearly see you writing 0xAA during that time, which isn't what the read command looks like. It looks like your write command is working correctly, but you need to work on your read command. it should look almost the same as your write command, except you don't need to do a "read enable" or anything...just need to wait till it is finished writing (the ready() function you wrote) and then the same sequence as your write, but with a read command byte instead of a write and reading the last byte instead of writing it. |
|
|
shinagan
Joined: 15 Mar 2012 Posts: 5
|
|
Posted: Wed Mar 21, 2012 11:06 am |
|
|
Hi,
It works !!!!!!!!!
This code works:
Code: |
#include <18F2580.h>
#DEVICE ICD=TRUE
#FUSES HS
#use delay(clock=20M)
#define LED PIN_C7
#define EEPROM_SELECT PIN_B3 //branché sur la patte CS
#define HOLD PIN_B4 //branché sur la patte HOLD
#define EEPROM_CLK PIN_C3 //branché sur la patte horloge
#define EEPROM_DI PIN_C5 //branche sur la patte SDO
#define EEPROM_DO PIN_C4 //branche sur la patte SDI
#define EEPROM_ADDRESS unsigned int32 // Les adresses sont un long int (ecrites en binaire)
#define EEPROM_SIZE 1048576 // Taille de l'EEPROM, en bit
/*
***********
*FONCTIONS*
***********
*/
//FAIRE CLIGNOTER LA LED
void blink()
{
output_high(LED);
delay_ms(200);
output_low(LED);
delay_ms(200);
}
//CHECKER L'ETAT DE L'EEPROM
int1 ext_eeprom_ready(void)
{
int8 data ; //variable de capture, 8 bits
output_low(EEPROM_SELECT); // CS = 0
//blink();
spi_write(0x05); //demande l'etat de l'EEPROM
//blink();
data = spi_read(0); //data enregistre la réponse (8bits, cf. section 3)
output_high(EEPROM_SELECT); // CS = 1
return(!bit_test(data, 0)); //renvoie non-(bit 0 de data) <=> 1 dit qu'elle est 10po
}
//ECRIRE SUR l'EEPROM
void write_ext_eeprom(EEPROM_ADDRESS address, BYTE data)
{
while(!ext_eeprom_ready()); //tant que l'EEPROM est occupée, le PIC tourne en boucle
output_low(EEPROM_SELECT); // CS = 0
spi_write(0x06); //dévérouille l'écriture
output_high(EEPROM_SELECT); // CS = 1
output_low(EEPROM_SELECT); // CS = 0
spi_write(0x02); //Mode écriture
spi_write(address >> 16); // envoi du MSB
spi_write(address >> 8); // envoi d'adress
spi_write(address); // envoi du LSB
spi_write(data); //Envoi des données
output_high(EEPROM_SELECT); // CS = 1
}
//LIRE L'EEPROM
BYTE read_ext_eeprom(EEPROM_ADDRESS address)
{
int8 data; //variable de capture, 8 bits
while(!ext_eeprom_ready()); //tant que l'EEPROM est occupée, le PIC tourne en boucle
output_low(EEPROM_SELECT); // CS =0
spi_write(0x03); //Mode lecture
spi_write(address >> 16); // envoi du MSB
spi_write(address >> 8); // envoi d'adress
spi_write(address); // envoi du LSB
data = spi_read(0); //data enregistre la réponse
output_high(EEPROM_SELECT); // CS = 1
return(data); //On renvoie la valeur data en octets
}
void main()
{
int8 test;
setup_spi(SPI_MASTER | SPI_L_TO_H |SPI_XMIT_L_TO_H | SPI_CLK_DIV_16);
output_high(HOLD);
write_ext_eeprom(0x00AAAA,0xF7);
delay_ms(10);
test = read_ext_eeprom(0x00AAAA);
delay_us(10);
output_high(EEPROM_SELECT);
if(test == 0xF7)
{
while(1)
{
blink();
}
}
else
{
blink();
}
}
|
The LED is blinking forever, no matter the address I give nor the byte I want to store !
Thanks for everything, after 1 month of unsuccessful tries, it works :D
shinagan |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
|
|
|
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
|