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 support@ccsinfo.com

Does read_eeprom need a delay?

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



Joined: 04 Jun 2009
Posts: 107

View user's profile Send private message

Does read_eeprom need a delay?
PostPosted: Thu Oct 15, 2009 2:33 pm     Reply with quote

I'm trying to introduce code that will allow users of my device to modify certain variable values by sending messages via CANBUS to the device, which the device stores in EEPROM to be read when it powers on. Everything appears to work, except that I get very erratic behavior since introducing the "get" function below. It is behaving as though at least some of the variables are getting zeros instead of their expected values. When I comment this function out (it runs in main() before the while()) everything operates just fine on the default values, which are declared at the beginning of the script.

Either I have some flawed logic and the defaults are getting wiped by this function... or read_eeprom needs a delay? or ??? I've looked at it a hundred times, so perhaps some fresh eyes can help.

Thanks in advance:

PIC 18F4480

Code:


So to reiterate/clarify... if I DONT use this function, then the defaults are used and everything works great. If I DO use this function with a BLANKED eeprom (all values 0xFF) it behaves as though the values are not the defaults and like they are probably zeros. I can't confirm what they are as there is no output on this device. I have confirmed, by bringing the device back in and reading the eeprom, that all values are in fact 0xFF.


Last edited by s_mack on Thu Oct 15, 2009 3:36 pm; edited 1 time in total
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Oct 15, 2009 3:02 pm     Reply with quote

Your test program is too complicated. Strip it down to a few lines
of code. Add the #include, #fuses, #use delay(), main(), variable
declarations and #defines. Add some printf statements to show
the output, to show if it's working or failing. You don't need any
CAN bus stuff for this test. The code in main can be less than 10 lines,
I would guess. Also post your compiler version.


The reason I make this kind of post is:
Sometimes a problem can be solved by inspection. This is made more
difficult by having to read tons of code.

If it can't be solved by inspection, and requires either reading the .LST
file or doing an actual hardware test, it's much easier if the code is short.

In both cases, a complete test program (with fuses) is best, because
quite often the problem is in the fuses or #use statements.
s_mack



Joined: 04 Jun 2009
Posts: 107

View user's profile Send private message

PostPosted: Thu Oct 15, 2009 3:12 pm     Reply with quote

The code is mostly irrelevant anyway. At least to answer the question in the title: "Does read_eeprom need a delay". The code was there to show how read_eeprom gets called in rapid fashion and I wondered if there was a problem with doing that.

Do I need to put in a delay_ms(?) after each one or does it wait until it has the value. I guess I'm wondering if "val" is being presumed to be zero upon initialization and staying that way for some reason as its not getting valid reads?

I suppose its easy enough for me to test... but an arbitrary ms delay seems... clumsy. I'll start there.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Oct 15, 2009 3:32 pm     Reply with quote

Look in the 18F4480 data sheet, in this section:
Quote:
7.3 Reading the Data EEPROM Memory

To read a data memory location, the user must write the
address to the EEADR register, clear the EEPGD
control bit (EECON1<7>) and then set control bit, RD
(EECON1<0>). The data is available on the very next
instruction cycle; therefore, the EEDATA register can
be read by the next instruction.

Answer: No delay is required.

To investigate the compiler's generated code, make a test program
with one line in main() that reads the eeprom:
Code:
.................... result = read_eeprom(0);
0018:  MOVFF  INTCON,@@07
001C:  BCF    INTCON.GIE
001E:  CLRF   EEADR
0020:  BCF    EECON1.CFGS
0022:  BCF    EECON1.EEPGD
0024:  BSF    EECON1.RD
0026:  MOVF   EEDATA,W
0028:  BTFSC  @@07.7
002A:  BSF    INTCON.GIE
002C:  MOVWF  result

Answer: The compiler does not put in any delay loop after reading
the EEDATA register.
s_mack



Joined: 04 Jun 2009
Posts: 107

View user's profile Send private message

PostPosted: Thu Oct 15, 2009 3:37 pm     Reply with quote

Thanks for that. It must be something else then. I'll figure it out, thanks.
s_mack



Joined: 04 Jun 2009
Posts: 107

View user's profile Send private message

PostPosted: Fri Oct 16, 2009 4:44 pm     Reply with quote

Thanks again for your help. I just wanted to follow up in case it helps anyone else.

The code I showed above actually wasn't the problem. It certainly seemed like it because when I commented it out, the problems went away. However it was the code immediately preceding that was the problem... and that was a function full of eeprom_write calls. THOSE need a delay! I wasn't aware they were causing a problem because there wasn't an issue until I subsequently read them.

Essentially (this is over-simplifying) the routine went like this:

Code:
int8 setting = 0x09;  //set a default value
...
write_eeprom( 0x00, 0xFF );  //write a new value to the eeprom
var = read_eeprom( 0x00 ); //retrieve that value
if ( var < 0xFF) setting = var;


The "oops" in there is that write_eeprom ERASES the eeprom THEN writes to it, and in the meantime the code keeps executing. So sometimes what is happening is the eeprom is cleared giving var a null value (interpreted as a zero?) and that is less than 0xFF so setting gets a zero value.

To fix:

I'm sure an arbitrary delay_ms would work but I hate doing that. Make use of the INT_EEPROM interrupt instead. I replace write_eeprom with write_eeprom_wait and add the function to my code:

Code:
void write_eeprom_wait( int8 _id, int8 _val )
{
   eeprom_is_busy = true;
   write_eeprom( _id, _val );
   while( eeprom_is_busy )
   {
      //loop until eeprom_write has finished (see INT_EEPROM interrupt)
   }
}


And the interrupt as well:

Code:
#INT_EEPROM
void EEPROMIsr()
{
   eeprom_is_busy = false;
}


and of course declare the global boolean at the top of my code:
Code:
bool eeprom_is_busy = false;



That cleared up my issue entirely.

- Steven
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