Interrupt-driven EEPROM writing...

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Trying to get my head round interrupt driven EEPROM writing on a Mega16.

AVR104 says...

In the interrupt driven approach, there is no need to poll the EEWE status bit to verify whether the previous write cycle has completed. The EEPROM Ready Interrupt is constantly triggered when the EEWE status bit is cleared. It is however still necessary to poll the SPMEN status bit if Self-Programming is used, to make sure a Self-Programming operation is not currently active. The primary advantage of an interrupt driven approach is that dedicated hardware can request processing power when needed; this decreases the processor load.

The confusion is around

The EEPROM Ready Interrupt is constantly triggered when the EEWE status bit is cleared.

Constantly triggerred? Does it really meant that - surely not? Triggered once I could understand...

AVR104 only has C code examples for writing a SRAM buffer to EEPROM - does anyone have any example/reference code in ASM before I have to sort out my confusion and then code it from scratch?

TIA, Martin

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Constantly triggerred? Does it really meant that - surely not?

I don't use interrupt-driven EEPROM, but I'll wager that the "constantly triggered" is correct--just like UDRE or level-triggerred external interrupt. Typically, you service the first pertinent hit then disable the interrupt.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So in my Mega16 code...

...where I've declared all interrupt vectors and have a 'reti' after each currently unused one, including EE_RDY...

...and done a global 'sei' at the start of the main loop...

...as soon as I've set the first EEWE for my current, polled, EEPROM writes...

....and the hardware has cleared it for the first time...

....I'm getting constant EE_RDY interrupts for the rest of my run time????

If that's the case, then Ouch!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As Lee points out... It's no more of an "ouch" than the UDRE interrupt source.

Look at it this way... say you have to update a huge block of EEPROM (say, 24 bytes). With polling, the ATmega16 can do it in a typical period of 8.5 milliseconds per byte. That is 204 milliseconds in which the AVR isn't doing anything except for writing to the EEPROM. It is conceivable that you may allow interrupts for most of that time. But at a minimum, the couple of clock cycles that are consumed between setting the EEMWE bit and then subsequently setting the EEWE bit must be done with interrupts inhibited.

If you have some cooperative tasks that require rapid servicing within the mainline during those 204 milliseconds, then that's just too bad.

That's where EEPROM interrupts can come in handy. You'd structure it in much the same way as you'd structure using the UDRE interrupt for buffered USART communication. Except, each "packet" of information being sent to EEPROM would require three pieces of information: The starting address to write to, the length of the buffer being written, and the actual data to write.

EEPROM interrupts would initially be disabled by clearing the EERIE interrupt

You might have a list of EEPROM datagrams, each consisting of the three components: Destination address, buffer length, and buffer content.

When you want to write some data to EEPROM, you'd create and populate an entry in the datagram list. Then, you'd enable the EERIE interrupt mask.

- If EEPROM was previously busy servicing another datagram, then it will continue servicing it as though nothing had happened.
- If EEPROM was previously idle, then the EE_RDY interrupt will immediately fire. This step is the point at which allowing the EE_RDY interrupt to be "continually triggered" rather than "one-off triggered" becomes critically important. If they were "one-off" triggered, then extra run-time and code would need to be spent "kick-starting" the EEPROM writing mechanism if it had been previously idle. Since it is "continually triggered", there is no need for special cases here.

Inside the EE_RDY ISR, you'll check to see if you're currently busy servicing one datagram. If so, you would check to see how much of the datagram has been stored.
- If there are still bytes left in the datagram, then you'd store the "next" byte and exit.
- If there aren't any bytes left to store, then you'd discard the datagram and then check to see if there are any other datagrams waiting.
- If there are other datagrams, then you'd fetch the next one in the list, and start storing the first byte from that datagram, then exit.
- If there are no other datagrams, then you'd disable the EE_RDY interrupt by clearing the EERIE mask. Then exit. The EEPROM will now sit idle until the next datagram needs to be stored.

In this scheme, the EEPROM will only eat up a few microseconds out of every 8.5 milliseconds of CPU time (worst case), leaving the rest of the time for the mainline to do its job.

While the EEPROM is idle, the EERIE mask is cleared. Even though the EE_RDY interrupt is constantly being triggered, it is being masked out by the EERIE mask, so you aren't actually spending any time servicing the interrupt.

Last Edited: Mon. Apr 3, 2006 - 02:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

So in my Mega16 code...

...where I've declared all interrupt vectors and have a 'reti' after each currently unused one, including EE_RDY...

...and done a global 'sei' at the start of the main loop...

...as soon as I've set the first EEWE for my current, polled, EEPROM writes...

....and the hardware has cleared it for the first time...

....I'm getting constant EE_RDY interrupts for the rest of my run time????

If that's the case, then Ouch!

Not exactly. The flag bit will be set; true. But the ISR will only be invoked if enabled -- EERIE set. As I mentioned, this is the same as with UDRIE & GICR/INTx with the external interrupt set for low-level.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

George - this looks like polled EEPROM writing to me :-(

;-------------------------------------------------------------------------------
EEPROM_Write:		; Write EEPROM the  Data byte
;-------------------------------------------------------------------------------
		out	EEARH,AddrH	; Load EEPROM the Address
		 out	EEARL,AddrL
		 out	EEDR,tmp1	; Load EEPROM the Data byte
		; Write the EEPROM byte
		cli
		sbi	EECR,EEMWE	; Enable EEPROM writting; Write the data.
		 sbi	EECR,EEWE	; [–,–,–,–,EERIE,EEMWE,EEWE,EERE]
		 sei
		sbi	EECR,EERIE	; Enable the EERPOM-ready interrupt
		 sbi	GPIOR0,wEr	; Preset the EEPROM Ready wait flag
		; Wait for the EEPROM to be ready
		sleep			; Wait for the EEPROM
		 sbic	GPIOR0,wEr	; Ready?
		 rjmp	PC-2		;  Not yet. Else:
		cbi	EECR,EERIE	; Disable the EERPOM-ready interrupt
		; Update the EEPROM Address & exit
		adiw	AddrL,1		; Next EEPROM Address
		ret

..and I don't understand what your EE_RDY ISR does in conjunction with it

.org	BootStart+0x28;	rjmp	EE_RDY		; EEPROM Ready Handler
			cbi	GPIOR0,wEr	; Ready!
			 reti

Lee and lfm - thanks, but my my head hurts about this!

My SRAM buffer, when having been completely and asynchronously collected by the UART from an external system, is of the order of 500 bytes and has to be written as soon as possible whilst not compromising ANY of the other interrupts that are happening every 2ms - 10ms, so I'm pretty sure I need interrupt driven EEPROM writing. So I'm still hurting and looking for example reference ASM code...[/code]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

George's code demonstrates a hybrid of polling and interrupts. The objective there is apparently to achieve minimum possible power consumption during the EEPROM writing. So he puts the AVR to SLEEP while waiting for the operation to complete.

He uses the EEPROM ready interrupt to wake the AVR up once the EEPROM write is finished. The ISR itself doesn't do anything except ensure that the AVR wakes up in a meaningful state.

(I might suggest to George that a possible improvement to his code might be to disable the EERIE interrupt source inside the EE_RDY ISR itself... otherwise, the continuous triggering property of the EE_RDY interrupt that got Martin's attention in the first place will significantly slow down the runtime performance of the bootloader for the first few instructions after each EEPROM write finishes.

Maybe use another unused segment of the interrupt vector table to hold the body of such an expanded ISR without increasing the overall size of the bootloader, since it will not fit inline as your existing ISR does.)