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

PIC18f2580 & EEPROM 25LC1024

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



Joined: 15 Mar 2012
Posts: 5

View user's profile Send private message

PIC18f2580 & EEPROM 25LC1024
PostPosted: Thu Mar 15, 2012 2:46 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 15, 2012 4:48 pm     Reply with quote

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: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Mar 15, 2012 5:04 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Mar 19, 2012 10:23 am     Reply with quote

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
Code:
spi_write
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

View user's profile Send private message

PostPosted: Mon Mar 19, 2012 10:36 am     Reply with quote

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: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Mar 19, 2012 10:51 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Mar 19, 2012 11:04 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Mar 19, 2012 12:45 pm     Reply with quote

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 :
Code:
spi_write(0x05);

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

View user's profile Send private message

PostPosted: Tue Mar 20, 2012 7:56 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Tue Mar 20, 2012 8:48 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Mar 20, 2012 8:53 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Mar 20, 2012 10:38 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Mar 21, 2012 11:06 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Thu Mar 22, 2012 12:12 am     Reply with quote

Not related to this topic, but I thought I'd mention your use of 1X probes in your 'scope screenshots. If possible, use 10X probes as they impose less of a load on the signal you're measuring.

http://answers.yahoo.com/question/index?qid=20081019141222AAeokCJ
http://www.radio-electronics.com/info/t_and_m/oscilloscope/oscilloscope_probes.php
_________________
Andrew
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