PDA

View Full Version : Will Interrupts affect on chip eeprom writing?



Art
- 4th March 2012, 14:04
Hi Guys,
No more to say really.. that is the question :)

HenrikOlsson
- 4th March 2012, 17:19
Hi Art,
Here's a quote from the manual on the WRITE command:

If interrupts are used in a program, they must be turned off (masked, not DISABLEd) before executing a WRITE, and turned back on (if desired) after the write instruction is complete. An interrupt occurring during a WRITE may cause it to fail.

And here's a quote from the datasheet on the PIC18F25K22

To write an EEPROM data location, the address must first be written to the EEADR register and the data written to the EEDATA register. The sequence in Example 7-2 must be followed to initiate the write cycle.
The write will not begin if this sequence is not exactly followed (write 55h to EECON2, write 0AAh to EECON2, then set WR bit) for each byte. It is strongly recommended that interrupts be disabled during this
code segment.

So, I think the answer is Yes - Interrupts can interfere with writes to the EEPROM.

/Henrik.

Art
- 4th March 2012, 23:58
Thanks :)
The datasheet for 16F87X is not so clear for on chip eeprom,
but it does say you can write to program memory with interrupts enabled.

What does it mean to say "(masked, not DISABLEd)" ??

HenrikOlsson
- 5th March 2012, 06:15
Didn't know which PIC you're using so I just picked a datasheet I had available.
Not sure but I think that the note about masking and not disabling the interrupts must apply specifically for when using ON INTERRUPT. Ie, they are telling us to clear the interrupt enable flags instead of inserting the DISABLE directive.

/Henrik.

MOUNTAIN747
- 6th March 2012, 22:14
Masked interrupts!

Art, Henrik,
If interrupts are enabled in INTCON Control Register with Global GIE, all individual interrupts are masked if the item/items of interest are cleared and not in use. let us say RBIE Port B interrupt-on-change, RBIE is set to 1, RBIE is now unmasked and ready for use.

If we look at the 18F25K22 as Henrik has used for an example, GIE=1 Enables all unmasked interrupts, PEIE=1 Peripheral Interrupt Enable bit, RBIE=1 unmasked the PortB interrupt-on-change interrupt, it is now ready for use. All other interrupts are masked and not in use. If we look at page 161 para 11.5 Timer0 Interrupt, “The interrupt can be masked by clearing the TMR0IE bit of the INTCON register.
At least that’s the way I understand it.
Wayne

MOUNTAIN747
- 6th March 2012, 22:31
Art, I would add one more thing,

@ BCF INTCON, GIE
Write EEPROM...................................
@ BSF INTCON, GIE

should do the trick if using interrupts durring a Write to EEPROM.
Wayne

Art
- 10th March 2012, 11:53
Art, I would add one more thing,

@ BCF INTCON, GIE
Write EEPROM...................................
@ BSF INTCON, GIE

should do the trick if using interrupts durring a Write to EEPROM.
Wayne

I tried this, and all appears ok so far :)

Darrel Taylor
- 10th March 2012, 17:42
With all the quotes from the manual and datasheet, I thought for sure someone would have seen ...



The following DEFINE turns interrupts off and then back on within a
WRITE command. Do not use this DEFINE if interrupts are not used in the
program.

DEFINE WRITE_INT 1

The difference being that it is built-in to the WRITE command.

Interrupts only need to be disabled during the "unlock" sequence written to EECON2 which takes 5 instructions.
@ 4Mhz, that's only 5uS, @ 20Mhz it's 1uS.

By wrapping the WRITE command with GIE=0 / GIE=1, you are disabling interrupts for the full time it takes to complete the WRITE to EEPROM.
@ any OSC, that's 4-6mS.

Many interrupts can be lost in that much time.

sayzer
- 19th March 2012, 06:21
Just for the note.

I also had same issue as Art.
DEFINE WRITE_INT 1 did not solve the issue, but GIE solved.

BTW; I am also using
@ INT_DISABLE RX_INT
before the write command and then enable it.
Only by itself it did not work, DEFINE WRITE_INT 1 also did not work.
Disabling GIE worked.

Darrel Taylor
- 19th March 2012, 17:48
Sayzer,

How long ago was your issue?
And was your issue with WRITE or WRITECODE?

WRITE_INT was introduced in PBP 2.50, but it was only for the WRITE command.
In 2.60, WRITE_INT was extended to the WRITECODE command.

I've done many interrupt programs as you can imagine.
WRITE_INT has always worked for me.

If you have code that demonstrates a problem with WRITE_INT, no less than 3 people will be involved in fixing it immediately.

EDIT: Using WRITE or WRITECODE inside a PBP type INT_Handler doesn't count.

sayzer
- 20th March 2012, 07:33
EDIT: Using WRITE or WRITECODE inside a PBP type INT_Handler doesn't count.

Does that mean that PBP type INT_Handler causes the problem that I and Art faced ?

If yes, it does not solve the problem anyway, am I right? (if we call this as a problem though)

Edit: How should I decide which type should I use? when, why? based on what criteria? Please.

Darrel Taylor
- 20th March 2012, 14:07
No, that's not what it means at all...

You cannot use the WRITE command in an ASM type interrupt, because it's a PBP statement.

When you use DEFINE WRITE_INT, GIE is turned back on during the WRITE command.
If you have a WRITE command inside a PBP type ISR, GIE is turned on in the middle of the ISR, the stack hasn't been popped by a retfie, and the chip immediately interrupts again, quickly overflowing the stack.

If you are using DEFINE WRITE_INT, you should never have a WRITE command inside the ISR.
If you are using WRITE in your ISR, you should not use DEFINE WRITE_INT.

Since interrupts cannot be interrupted (except low priority on 18F's), interrupts don't need to be disabled during a WRITE in the ISR anyhow.

If you only have WRITE statements in your your main program, it's best to use DEFINE WRITE_INT, not wrap it with GIE=0/GIE=1.

sayzer
- 21st March 2012, 18:18
Thank you for the information Darrel.

Here is a sample code for me to understand it better.



CLEAR

@ __config _HS_OSC & _WDT_OFF & _PWRTE_OFF & _BODEN_OFF & _LVP_OFF & _CP_ON & _WRT_OFF

DEFINE OSC 20

Number1Adr data word 0

'DEFINE WRITE_INT 1

DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_SPBRG 64 ' 19200 Baud @ 20MHz, 0,16%
DEFINE HSER_CLROERR 1 ' Clear overflow automatically

CMCON = 7 ' Disable Comps.
PAUSEUS 10
CVRCON = 0 ' Turn off VRCON.
PAUSEUS 10

ADCON0 = 0
ADCON1 = %00001111 ' All digital.

TRISA = 0
TRISB = 0
TRISC = %10000000 ' RC7 RS232 RX pin.

PORTA = 0
PORTB = 0
PORTC = 0

RXLED var PORTC.4

' ========= RS232 RX ===========
Header1 var byte
Header2 var byte
Komut var byte
Kimlik var byte
DataInLow var byte
DataInHigh var byte
WriteFlag var byte
OldNumber var word
Number var word

INCLUDE "DT_INTS-14_F873A.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP.bas" ; Include if using PBP interrupts

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _RS232RX, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM


Pause 10

Begin:
header1 = 254
header2 = 252
WriteFlag = 0

@ INT_ENABLE RX_INT ; enable external (INT) interrupts

Start:


if writeflag > 0 then
; disable interrupts
@ INT_DISABLE RX_INT
@ BCF INTCON, GIE

read Number1Adr, word oldnumber ' Read old value first.
if oldnumber <> number then write Number1Adr,word number
' If the incoming value changed, then write. Otherwise, do not write.

; enable interrupts
@ BSF INTCON, GIE
@ INT_ENABLE RX_INT

writeflag = 0 ' Clear write flag.

endif



goto start


RS232RX:
rxled = 1
hserin 50,Jump,[WAIT(header1,header2),komut,datainLow,DatainHigh]

if komut = 100 then
WriteFlag = 1
number.lowbyte = datainlow
number.highbyte = datainhigh
endif



Jump:

RXLED = 0
@ INT_RETURN


END






If I remove GIE, and use WRITE_INT, eeprom does not write right.

Darrel Taylor
- 21st March 2012, 22:13
Sayzer,

I'm running your program here on a 16F873 @20Mhz in a LAB-X2 (I don't have an 873A).
And I cannot make it write incorrect values due to interrupts during a WRITE.

The only way to generate an interrupt during the write in that program is to send more serial data after the 254,252,100,xx,xx command.
I can send any amount of data after it without any problems, as long as it's not another 254,252,100,xx,xx command.

If I do send two commands in a row without giving it time to finish the first WRITE, then the datainLow,DatainHigh variables are overwritten in the middle of the write, and you get the lowbyte from the first command and the highbyte from the second command.

I'm using the Serial Communicator in MicroCode Studio with the following data ...

This works fine ...
#254#252#100$12$34,Mary had a little lamb, it's fleece was white as snow.
http://support.melabs.com/DT/SayzerGood.jpg

This writes bad data...
#254#252#100$12$34#254#252#100$56$78,Mary had a little lamb, it's fleece was white as snow.

http://support.melabs.com/DT/SayzerBad.jpg

So it seems to be the way the received data is being handled, instead of a problem with WRITE_INT.
When you do GIE = 0 before the write, it will not service the interrupt during the entire write, which protects it from being improperly overwritten in the ISR. But then that causes missed interrupts, and the second command is never received.

I also added a 10Khz interrupt from Timer1 ... No problems writing to EEPROM.

sayzer
- 25th March 2012, 10:25
Thank you Darrel.

Playing with the TX side, each packet has 30ms pause at its end now.
I removed GIE, and now using WRITE_INT.

All seems ok.

Thanks again.