I am trying to write to the eeprom in a 16F876, but although using the
procedure detailed in the datasheet (DS30292C page 43) my routine will not
write. I am attempting to have a 10 bit number in two adjacent locations,
and have default values specified in my source code, which get written by
the programmer, and I can read ok. However any attempt at writing to these
locations fails in my code, and seems to set the corresponding locations to
all ones.
Source code below for the write routine, using Olin's macros
;* Subroutine "a2d_write_default"
;* Write a default value into the correct EEPROM location for
;* the a2d channel and upper or lower limit selected.
;*
;* Inputs
;* Reg1 - 0 for low limit, non-zero for high limit value
;* Req3(high byte)/Reg2(low byte) - value to save
;* Reg4 - a2d channel address (becomes eeprom offset)
;*
;* Outputs
;* Reg1 - 0 good save, non-zero save failed or invalid channel
;* Req4 - corrupted
a2d_write
; start by ensuring a write is not in progress
dbankif EECON1
a2d_write_check
btfsc EECON1,WR
goto a2d_write_check
; get channel address *4 into REG4
; This will overflow if warning above is not heeded
bcf status,c ; clear carry before rotate
rlf Reg4,F ; move up by three bits (*2)
rlf Reg4,F ; (*4 ready here for eeprom access)
dbankif EEADR
getf Reg4 ; mov offset into EEADR
movwf EEADR
movlw a2d0_high ; now allow for address to be adjusted
testfz Reg1 ; check to see which it is
skip_z
addlw 2 ; adjust address for low limit to be set
addwf EEADR,F
dbankif EEADRH
clrf EEADRH ; clear high address for safety.
dbankif EEDATA
getf Reg3 ; load high byte
movwf EEDATA ; into the data register
intr_off ; disallow interrupts through critical portion
movlw 0x55 ; see data sheet for machinations performed here
movwf EECON2
movlw 0xAA
movwf EECON2
bsf EECON1,WR
intr_on ; and allow interrupts again
a2d_wr_wait1
btfsc EECON1,WR ; allow write to complete
goto a2d_wr_wait1
bcf EECON1,WREN ; remove write enable to stop corruption
dbankif EECON2
intr_off ; disallow interrupts through critical portion
movlw 0x55 ; see data sheet for machinations performed here
movwf EECON2
movlw 0xAA
movwf EECON2
bsf EECON1,WR
intr_on ; and allow interrupts again
a2d_wr_wait2
btfsc EECON1,WR ; allow write to complete
goto a2d_wr_wait2
bcf EECON1,WREN ; remove write enable to stop corruption
; Now we check that the write happened OK.
; first check that the second byte wrote
clrf EECON1
bsf EECON1,RD ; start read operation
dbankif EEDATA
getf EEDATA ; get the byte
subwf Reg2,W ; compare with what should have been written
movwf Reg0 ; and save result as a flag
dbankif EEADR
decf EEADR,F ; now do other byte
dbankif EECON1
clrf EECON1
bsf EECON1,RD ; start the read
dbankif EEDATA
getf EEDATA ; get this byte
subwf Reg3,W ; compare with what should have been written
iorwf Reg0,F ; and OR it with previous result
a2d_wr_exit ; and exit
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
> dbankif EEDATA
> getf Reg3 ; load high byte
> movwf EEDATA ; into the data register
I'm not familiar with these macros, but is this correct? This
looks like it would set the bank for EEDATA, but then get Reg3.
So if Reg3 is not in the same bank as EEDATA, it would get the
wrong data. On the other hand, I'm not sure what getf is!
Just a thought.
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
>> dbankif EEDATA
>> getf Reg3 ; load high byte
>> movwf EEDATA ; into the data register
>
>I'm not familiar with these macros, but is this correct? This
>looks like it would set the bank for EEDATA, but then get Reg3.
>So if Reg3 is not in the same bank as EEDATA, it would get the
>wrong data. On the other hand, I'm not sure what getf is!
>Just a thought.
Reg3 is in the "unbanked" RAM area from 70 to 7f.
getf is a macro that resolves to Movf %1,W
but thanks for the thought anyway.
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
> > dbankif EEDATA
> > getf Reg3 ; load high byte
> > movwf EEDATA ; into the data register
>
> I'm not familiar with these macros, but is this correct? This
> looks like it would set the bank for EEDATA, but then get Reg3.
> So if Reg3 is not in the same bank as EEDATA, it would get the
> wrong data. On the other hand, I'm not sure what getf is!
> Just a thought.
This code looks like it's using my macros. If so, REG3 is one of the
"general registers" which are implemented in the memory that is common to
all banks. Many of the 16 family PICs have the last 16 bytes of each bank
mapped to the same physical RAM, and can therefore be accessed with any bank
setting.
If these assumptions are correct, then this snippet is correct. The only
gotcha I can think of is if the assembly time bank assumptions were
incorrect before the DBANKIF EEDATA. That can happen when multiple code
fragments with different bank settings jump to the same point. In that case
you should invalidate the bank assumptions by using the UNBANK macro.
*****************************************************************
Embed Inc, embedded system specialists in Littleton Massachusetts
(978) 742-9014, http://www.embedinc.com
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
>In that case you should invalidate the bank assumptions by using the UNBANK
macro
The banking is being done correctly. Only a handful of lines above the code
I quoted in my original post is a GLBSUB heading, with appropriate banking
macros.
I can single step through the code, and have gone to the extent of putting a
breakpoint at the end of the writing portion, to ensure that I am not
violating any conditions within the 5 instruction loop listed in the data
sheet, but still it does not write to the eeprom. All examples I have found
seem to be using the same code, so I cannot explain why this does not work
as expected.
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
Hi Alan - I fought with the same situation earlier this year - below you
will find the software I ended up with (and it works). It seems that asking
people to review software on this list will as often as not lead to you
getting a nasty email about not having time, not making money blah blah
blah. So I offer you my software to review - with no nasty comments!
Alan B. Pearce wrote:
> I am trying to write to the eeprom in a 16F876, but although
> using the procedure detailed in the datasheet (DS30292C
> page 43) my routine will not write. I am attempting to have
> a 10 bit number in two adjacent locations...
Olin Lathrop wrote(RE: [PIC]: Using NVRAM with a PIC):
> ...There are more steps after that. I won't bother with the
> details, but the point is to test each thing incrementally
> until eventually everything works.
According to Olin, may be firstly you should debug writing
only one byte. You repeated the same code for the second
byte, why not get it to subroutine?
Anyway try significant delay between writes.
Mike.
PS: I successfully used to wrote two bytes one after one
to a 16F874, but with the delay.
-- http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads
OK, I found my problem. I was writing two words (each of two bytes) to the
eeprom, and both writes were working, but the second was overwriting the
first. As the second write was 0x3ff, that was what I was reading out.
And then of course to confuse matters, it seems that the "read eeprom"
functions in MPLAB only ever read what is in the "eeprom memory" local to
MPLAB, that is written to when you load the memory from a hex file. It never
goes out through the ICD to read actual eeprom !!!! Microchip take note.