Saving settings in PIC memory.

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
I have a project coming up using a 16F886.
I can do all the necessary coding but one part.

The part consists of a variable that will be set up during a setup mode. Set up mode is done by the customer end and setting is input via an encoder. Once set up, I need to retain the value .

I believe I can do the setting routine but saving the value to the EEPROM is something I haven't done yet.

I believe I will be asked about the value. I cannot disclose what the program does cause it is not mine once I make it.
The variable is a preset time delay counter. It can be set up at 30 minute increment up to 12 Hrs. So 24 Increments. Once set up the timer uses that value to time an output. I know I can use that value indefinitely as long there is no power outage. An unexpected reset like a brown out is my concern as will reset the value to initial value (30 minutes).
I like some pointers on how to save the variable in to the memory. Continued writing to EEPROM won't be there, cause once set up it will remain like that for months.
 

jpanhalt

Joined Jan 18, 2008
11,087
That chip has High Endurance Flash (HEF) and EEPROM. You can use either and the routines for using them are similar. Unfortunately, I do only assembly so sharing code probably won't help you.

Both durable memories have limited writes. HEF is less. In the code where I use HEF, it is a calibration that is run at the user's demand, so I didn't think the write limitation would matter. That is a question only you can answer.

John
 

JohnInTX

Joined Jun 26, 2012
4,787
For setup parameters that are written infrequently I'd do something like this:
Write the setup to EE using MikroC's library routines (I assume still MikroC?)
Don't reset the PIC until the EE write time (a few mSec) has elapsed.
On power up, read the EE into a variable and access that variable rather than EE - its just easier.
I create a multi-byte record of setup variables that is checksum-protected and update setup value(s) as a record. Read the record into RAM on power up and check the checksum. Use safe defaults if it's bad (indicating a corrupt EEPROM or non-calibrated system).
Use the brownout detector to avoid clobbering the EE during power down - it happened once to me.
Park EEADDR when done reading/writing by setting it to a value that points away from your good data to avoid clobbering your data if it goes nuts.
Good luck!
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
I am using MikroC Pro.
Looks Simple enough...I will try it.
I making proto on vero, once finished I will start with the code and get back.
TTFN.
Thanks again guys.
 

jpanhalt

Joined Jan 18, 2008
11,087
The wait that JohninTx refers to is the time it takes to write HEF or EEPROM, which is quite long in MCU terms (2 ms) . You want to turn off interrupts while writing too. If turning off at the wrong time is an issue, you could toggle an LED to show when the write was done.

John
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
Aah !
It can wait while saving. Since it is only done during the initial setup. Once set up, there is no more writing taking place. From there it just reads that data any time a brown out or power failure occurs.
 

JohnInTX

Joined Jun 26, 2012
4,787
The wait that JohninTx refers to is the time it takes to write HEF or EEPROM, which is quite long in MCU terms (2 ms) . You want to turn off interrupts while writing too. If turning off at the wrong time is an issue, you could toggle an LED to show when the write was done.

John
Indeed. Hopefully the library routines take the delay into account and the method remains consistent over compiler versions. I had a problem with restarting the PIC after storing new setup structures when the compiler moved the delay / check for done operation from after the write to before the write. With the new version, the PIC reset fouled the write since it occurred while the EE was busy. Checking busy before the write is a better construct but it took a bit to figure that out.

To clarify a bit, interrupts need to be disabled only during the writing of the 55h AAh sequence unless both foreground and background processes write the EE - not recommended for a lot of reasons.

Finally, turning off the interrupts in this dog are not as simple as clearing GIE. You have to retest GIE and ensure that an interrupt did not occur during the bcf INTCON,GIE instruction. If it did, the RETFIE after interrupt service will set GIE=1 and your code sequence will not have disabled the interrupt. Its a known problem in early midrange and noted in the sample code in Example 10-2: DATA EEPROM WRITE in the datasheet. Again, look at the compiled assembler output to see that it includes the retest.

Just one of many reasons why I won't use midrange if I can help it.
 

JohnInTX

Joined Jun 26, 2012
4,787
What if I have the interrupt (all of em) completely disabled during set up.
That's fine but not required. You just need to be aware of those potential gotcha things.
Write a little EE write code, compile and look at the assembler output. We can help you there but I'll bet that MikroC has it covered.
 

John P

Joined Oct 14, 2008
2,026
For what it's worth, here is my "MYEEPROM_write" routine, which I can easily give you because I have a window open for the project I'm working on. Written in MikroC for a PIC16F690.

Incidentally, I made a stupid mistake in this program where I ignored the fact that once a write to the EEPROM begins, the EEPROM is locked until the write ends, and the nature of the lock is that you can't load a new value to EEADR in that time. I was going crazy trying to figure out why reads from the memory were failing (as I thought) randomly. A big "duh" on that one, but to be fair to myself, the manual doesn't mention it.

Code:
#define GLOBAL_INT_ENABLE  intcon.GIE = 1
#define GLOBAL_INT_DISABLE  intcon.GIE = 0

void my_eeprom_write(char addrr, char dataa)
{
  while (eecon1.WR)                  // EEPROM is available?
      ;                              // Wait till previous write completes, if necessary
  eeadr = addrr;
  eedata = dataa;
  eecon1.WREN = 1;
  while(eecon1.WREN == 0)            // Make sure it actually sets
    ;
  GLOBAL_INT_DISABLE;
  while(intcon.GIE)                   // Make sure it actually clears
    ;
  eecon2 = 0x55;
  eecon2 = 0xAA;
  eecon1.WR = 1;                     // Start the write operation
  GLOBAL_INT_ENABLE;
  eecon1.WREN = 0;
}
 

JohnInTX

Joined Jun 26, 2012
4,787
Hi John. I'm pretty sure you need to put GLOBAL_INT_DISABLE within your while(intcon.GIE) loop. If for some reason you get caught in the problem I described it will hang.
Best,
J
 

John P

Joined Oct 14, 2008
2,026
Thank you John, now you point that out, I'm certain that you're right. I put that test in the code with some vague idea that clearing the GIE bit might be delayed somehow, but the point is really that I could clear it and then it might be reset by an interrupt, and my test wouldn't catch that. I'd set up the worst kind of bug, the sort that only appears very occasionally.

I think the right way to do it is (with a new #define to be consistent):
Code:
#define TEST_GIE intcon.GIE

   do {
       GLOBAL_INT_DISABLE;
   }  while(TEST_GIE);
Always clear it once, maybe clear it more than once.
 

jpanhalt

Joined Jan 18, 2008
11,087
@Moderators: If this needs a new thread, please move.

@JohnInTX (post#9)
Thank you for that very informative comment on clearing GIE. That potential problem is clearly defined for the 16C-aged chips, see: AN576b(1997):http://www.t-es-t.hu/download/microchip/an576b.pdf

Summary:
However, there is conflicting information as to whether and when it disappeared with other mid-range chips. Assuming it has been resolved in the extended mid-range chips, I cannot find any discussion of how that was done or tested.

Search details (with comments):

1) Old (1997) Microchip recommendation (AN576b): http://www.t-es-t.hu/download/microchip/an576b.pdf
I don't see how methods 3-6 address the problem of an interrupt occurring during the single instruction cycle that "bcf INTCON,GIE" takes.

2) Describes problem as affecting some newer chips, but does not mention enhanced-mid-range chips:
http://www.microchip.com/forums/m150379.aspx

3) This discussion of enhanced mid-range chips doesn't mention the problem. Has it been fixed (how?) or is that simply an error of omission?
http://microchip.wikidot.com/8bit:emr-interrupts

4) PICLIST discusses several gotcha's and a comment is made that the problem with disabling global interrupts is was fixed with the 16F84 (http://www.piclist.com/techref/microchip/gotchas.htm?key=mode?? ):
Michael Rigby-Jones [mrjones at NORTELNETWORKS.COM] says:

...this was a known problem with the 16C6X and 16C7X devices. The datasheet says:
"If an interrupt occurs while the Global Interrupt Enable (GIE) bit isbeing cleared, the GIE bit may unintentionaly be re-enabled by the users Interrupt Service Routine (the RETFIE instruction)." It then goes on to describe the work around which is as per the macro's above.

Roman Black points out that as per the 16C84 datasheet, this is fixed in the 16F84 and presumably any later chips.
Edit: Link to 16C84 chip: http://ww1.microchip.com/downloads/en/DeviceDoc/30445D.pdf
Problem is defined, but in Example 7-1, the solution is not used! Nevertheless RB's comment is validated in the Microchip table of differences between the two chips (Appendix E):
upload_2016-10-8_10-54-23.png

Question:

I am anxious for your or anyone else's take on the current situation, particularly with enhanced mid-range chips. And as JohnP suggests, why not just clear GIE twice rather than do a loop with btfsc? Never mind.

Regards, John
 
Last edited:

AlbertHall

Joined Jun 4, 2014
12,346
Would you expect that a more complicated chip would have less gotchas. No, they are just different. Keep an eye on the errata.
 
Top