Yahoo Groups archive

AVR-Chat

Index last updated: 2026-04-28 22:41 UTC

Thread

was eeprom ? Now about disasm

was eeprom ? Now about disasm

2005-04-26 by arhodes19044

I can not find the source files for the eeprom routines in libc.  I 
want to disable interrupts for the minimum necessary period while 
writing to EEPROM.  I bet that the clear/set should occur in the 
write_byte function, since that is probably called by all the larger 
size write functions.

How do I disasm only the required parts.  How do I even SEE the 
disasm'ed code while running avrsrudio?  I have "accidentally" landed 
in the disasm'd code, I think, while in avr-studio, but I have never 
intentionally found it.

If necessary, I could write my own multi-byte function that clears 
interrupts just before invoking the write_byte function, then resets 
them upon return.  It would not be hard to do, But I'd rather take the 
functioning code and insert a cli and sei in between a couple of lines.

-Tony

Re: [AVR-Chat] was eeprom ? Now about disasm

2005-04-27 by David Kelly

On Apr 26, 2005, at 11:04 AM, arhodes19044 wrote:

> I can not find the source files for the eeprom routines in libc.  I
> want to disable interrupts for the minimum necessary period while
> writing to EEPROM.  I bet that the clear/set should occur in the
> write_byte function, since that is probably called by all the larger
> size write functions.

The sources are:

/* write a byte to EEPROM */
/* void eeprom_write_byte(uint8_t *addr, uint8_t val); */
/* addr = r25:r24, val = r22 */
#define val rP3

         .global _U(eeprom_write_byte)

_U(eeprom_write_byte):
         sbic    _SFR_IO_ADDR(EECR), EEWE
         rjmp    _U(eeprom_write_byte)   /* make sure EEPROM is ready */
#ifdef EEARH
         out     _SFR_IO_ADDR(EEARH), addr_hi
#endif
         out     _SFR_IO_ADDR(EEARL), addr_lo
         out     _SFR_IO_ADDR(EEDR), val
         in      __tmp_reg__, _SFR_IO_ADDR(SREG)
         cli                     ; /* no ints between setting EEMWE and 
EEWE */
         sbi     _SFR_IO_ADDR(EECR), EEMWE
         sbi     _SFR_IO_ADDR(EECR), EEWE
         out     _SFR_IO_ADDR(SREG), __tmp_reg__
         ret
#undef val

/* write a block of bytes to EEPROM */
/* void eeprom_write_block (const void *buf, void *addr, size_t n); */
/* buf = r25:r24, addr = r23:r22, n = r21:r20 */

         .global _U(eeprom_write_block)

_U(eeprom_write_block):
         cp      n_lo, __zero_reg__              ; check if really there 
is something to write
         cpc     n_hi, __zero_reg__
         breq    eeprom_write_block_done
         LOAD_X(buf_lo, buf_hi)
         in      buf_lo, _SFR_IO_ADDR(SREG)      ; reuse buf_lo as the 
SREG temporary storage
eeprom_write_block_busy:
         sbic    _SFR_IO_ADDR(EECR), EEWE
         rjmp    eeprom_write_block_busy         ; make sure EEPROM is 
ready
#ifdef EEARH
         out     _SFR_IO_ADDR(EEARH), addr_hi
#endif
         out     _SFR_IO_ADDR(EEARL), addr_lo
         ld      __tmp_reg__, X+
         out     _SFR_IO_ADDR(EEDR), __tmp_reg__
         cli                                     ; no ints between 
setting EEMWE and EEWE
         sbi     _SFR_IO_ADDR(EECR), EEMWE
         sbi     _SFR_IO_ADDR(EECR), EEWE
         out     _SFR_IO_ADDR(SREG), buf_lo
         subi    addr_lo, lo8(-1)
         sbci    addr_hi, hi8(-1)
         subi    n_lo, lo8(1)
         sbci    n_hi, hi8(1)
         brne    eeprom_write_block_busy
eeprom_write_block_done:
         ret

> How do I disasm only the required parts.

If you still have the Makefile I sent a while back, posted to the list, 
it creates "object.elf" which is loaded into AVRStudio for debugging, 
but also generates a text file named "object.list". I add object.list 
to my PN2 project for quick access. Then text search (control-F) for 
the string of interest.

> How do I even SEE the disasm'ed code while running avrsrudio?

Right mouse click on the source window, "view disassembly" or something 
obvious to that effect. I have problems with AVRStudio getting out of 
sync with the C source lines, stopping in mid-statement, and 
automagically opening a disassembly window.

One advantage of using object.list described above is that the line of 
C source code is inserted as comments immediately prior to the 
generated code. AVRStudio does not insert the C source, but does 
provide verbose descriptions of each assembly instruction.

Believe the command line to generate object.list is:

avr-objdump -DS object.elf > object.list

--
David Kelly N4HHE, dkelly@HiWAAY.net
========================================================================
Whom computers would destroy, they must first drive mad.

Re: was eeprom ? Now about disasm

2005-04-27 by arhodes19044

AHA!  That sourfce does it.  I see that the interrupts are ALREADY 
cleared in the source you gave me.  I also get the disasm version of 
my code and I see that the libc looks to be identical.

In the Disasm, I can see that the interrupts are cleared.  I could 
not see where they were set again, but in the original source you 
include, I see that a register is used to store SREG, and then to 
restore it.

So, it seeme to me that the interrupts ARE suspended in the libc 
versions.  I was under the impression that they did not suspend 
interrupts, but I can see the cli.

So, I do not need to hand-tune the library eeprom handlers to 
suspend interrupts.  I forget what made me think that the library 
routines did not clear interrupts....

THANKS!  You helped me a lot, and also saved me some time trying to 
write my own stuff.

-Tony

--- In AVR-Chat@yahoogroups.com, David Kelly <dkelly@h...> wrote:
> 
> On Apr 26, 2005, at 11:04 AM, arhodes19044 wrote:
> 
> > I can not find the source files for the eeprom routines in 
libc.  I
> > want to disable interrupts for the minimum necessary period while
> > writing to EEPROM.  I bet that the clear/set should occur in the
> > write_byte function, since that is probably called by all the 
larger
> > size write functions.
> 
> The sources are:
> 
> /* write a byte to EEPROM */
> /* void eeprom_write_byte(uint8_t *addr, uint8_t val); */
> /* addr = r25:r24, val = r22 */
> #define val rP3
> 
>          .global _U(eeprom_write_byte)
> 
> _U(eeprom_write_byte):
>          sbic    _SFR_IO_ADDR(EECR), EEWE
>          rjmp    _U(eeprom_write_byte)   /* make sure EEPROM is 
ready */
> #ifdef EEARH
>          out     _SFR_IO_ADDR(EEARH), addr_hi
> #endif
>          out     _SFR_IO_ADDR(EEARL), addr_lo
>          out     _SFR_IO_ADDR(EEDR), val
>          in      __tmp_reg__, _SFR_IO_ADDR(SREG)
>          cli                     ; /* no ints between setting 
EEMWE and 
> EEWE */
>          sbi     _SFR_IO_ADDR(EECR), EEMWE
>          sbi     _SFR_IO_ADDR(EECR), EEWE
>          out     _SFR_IO_ADDR(SREG), __tmp_reg__
>          ret
> #undef val
> 
> /* write a block of bytes to EEPROM */
> /* void eeprom_write_block (const void *buf, void *addr, size_t 
n); */
> /* buf = r25:r24, addr = r23:r22, n = r21:r20 */
> 
>          .global _U(eeprom_write_block)
> 
> _U(eeprom_write_block):
>          cp      n_lo, __zero_reg__              ; check if really 
there 
> is something to write
>          cpc     n_hi, __zero_reg__
>          breq    eeprom_write_block_done
>          LOAD_X(buf_lo, buf_hi)
>          in      buf_lo, _SFR_IO_ADDR(SREG)      ; reuse buf_lo as 
the 
> SREG temporary storage
> eeprom_write_block_busy:
>          sbic    _SFR_IO_ADDR(EECR), EEWE
>          rjmp    eeprom_write_block_busy         ; make sure 
EEPROM is 
> ready
> #ifdef EEARH
>          out     _SFR_IO_ADDR(EEARH), addr_hi
> #endif
>          out     _SFR_IO_ADDR(EEARL), addr_lo
>          ld      __tmp_reg__, X+
>          out     _SFR_IO_ADDR(EEDR), __tmp_reg__
>          cli                                     ; no ints between 
> setting EEMWE and EEWE
>          sbi     _SFR_IO_ADDR(EECR), EEMWE
>          sbi     _SFR_IO_ADDR(EECR), EEWE
>          out     _SFR_IO_ADDR(SREG), buf_lo
>          subi    addr_lo, lo8(-1)
>          sbci    addr_hi, hi8(-1)
>          subi    n_lo, lo8(1)
>          sbci    n_hi, hi8(1)
>          brne    eeprom_write_block_busy
> eeprom_write_block_done:
>          ret
> 
> > How do I disasm only the required parts.
> 
> If you still have the Makefile I sent a while back, posted to the 
list, 
> it creates "object.elf" which is loaded into AVRStudio for 
debugging, 
> but also generates a text file named "object.list". I add 
object.list 
> to my PN2 project for quick access. Then text search (control-F) 
for 
> the string of interest.
> 
> > How do I even SEE the disasm'ed code while running avrsrudio?
> 
> Right mouse click on the source window, "view disassembly" or 
something 
> obvious to that effect. I have problems with AVRStudio getting out 
of 
> sync with the C source lines, stopping in mid-statement, and 
> automagically opening a disassembly window.
> 
> One advantage of using object.list described above is that the 
line of 
> C source code is inserted as comments immediately prior to the 
> generated code. AVRStudio does not insert the C source, but does 
> provide verbose descriptions of each assembly instruction.
> 
> Believe the command line to generate object.list is:
> 
> avr-objdump -DS object.elf > object.list
> 
> --
> David Kelly N4HHE, dkelly@H...
> 
=====================================================================
===
> Whom computers would destroy, they must first drive mad.

Re: [AVR-Chat] Re: was eeprom ? Now about disasm

2005-04-27 by David Kelly

On Wed, Apr 27, 2005 at 05:31:13PM -0000, arhodes19044 wrote:
> 
> In the Disasm, I can see that the interrupts are cleared.  I could 
> not see where they were set again, but in the original source you 
> include, I see that a register is used to store SREG, and then to 
> restore it.

Thats how its done. In a generic library such as avr-libc one does not
want the global interrupt flag to be different on exit than on entry. So
SREG is stashed, cli, bits twiddled, and SREG restored to return to
whatever was originally in effect.

> THANKS!  You helped me a lot, and also saved me some time trying to 
> write my own stuff.

Its more fun to write your own.  :-)

Spent some time playing and my C routines are only a couple of bytes
larger than the handcrafted assembly. I'll keep my C versions in my
project, partly because everything one uses in a library becomes a risk
5, 10, or 20 years down the road. Partly because I want a wdt_reset().
Partly because I also want an ee_compare() to verify the contents of
SRAM and EEPROM match:

//
//	Compare EEPROM contents against SRAM
//		addr is the address within the EEPROM
//		cp is what to compare in RAM
//		n is the number of 8 bit octets to compare
//
//	Returns 0 if contents match, following memcmp() precedent.
//	(this code is almost exactly ee_reads().
//
int
ee_compare(void *addr, const void *cp, uint16_t n)
{
	int tmp;
	
	for( ; n ; n-- ) {
		wdt_reset();
		while( EECR & (1<<EEWE) )	//  wait until ready
			;
			
		EEAR = (uint16_t)addr;		
		EECR |= (1<<EERE);	//  start the read
		tmp = *((uint8_t*)(cp)++) - EEDR; //  read
		if( tmp )
			return(tmp);	//  fail, difference between
		addr++;
	}
	return(0);	//  pass
}


-- 
David Kelly N4HHE, dkelly@HiWAAY.net
========================================================================
Whom computers would destroy, they must first drive mad.

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.