EmbeddedRelated.com
Forums

AVR Assembler - Data from a table in program memory (ATMega8)

Started by Mike Warren March 19, 2008
I have a table in program memory and want to store a byte at a given
location into register R16.

(This is just example data for testing)

MyTable: ; 256 bytes
.db $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F
.db $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F
    <snip>
.db $F0,$F1,$F2,$F3,$F4,$F5,$F6,$F7,$F8,$F9,$FA,$FB,$FC,$FD,$FE,$FF
    
R17 contains a number between $00 and $FF which represents the offset
from MyTable.

Can someone please show me a nice way of doing this?

-- 
-Mike
On Mar 19, 7:25=A0am, "Mike Warren" <miwa-not-this-...@or-this-
csas.net.au> wrote:
> I have a table in program memory and want to store a byte at a given > location into register R16. > > (This is just example data for testing) > > MyTable: ; 256 bytes > .db $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F > .db $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F > =A0 =A0 <snip> > .db $F0,$F1,$F2,$F3,$F4,$F5,$F6,$F7,$F8,$F9,$FA,$FB,$FC,$FD,$FE,$FF > > R17 contains a number between $00 and $FF which represents the offset > from MyTable. > > Can someone please show me a nice way of doing this?
You need to use the LPM instruction, which uses the Z register pair (R31:R30). Something like (no guarantees on the syntax) ldi r31, (high) MyTable ldi r30, (low) MyTable ;load base of table into Z pair add r30,r17 adc r31,#0 ;address of desired value now in Z pair lpm r16,Z ;fetch desired value
On Mar 19, 8:25=A0am, Mike Silva <snarflem...@yahoo.com> wrote:
> On Mar 19, 7:25=A0am, "Mike Warren" <miwa-not-this-...@or-this- > > > > > > csas.net.au> wrote: > > I have a table in program memory and want to store a byte at a given > > location into register R16. > > > (This is just example data for testing) > > > MyTable: ; 256 bytes > > .db $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F > > .db $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F > > =A0 =A0 <snip> > > .db $F0,$F1,$F2,$F3,$F4,$F5,$F6,$F7,$F8,$F9,$FA,$FB,$FC,$FD,$FE,$FF > > > R17 contains a number between $00 and $FF which represents the offset > > from MyTable. > > > Can someone please show me a nice way of doing this? > > You need to use the LPM instruction, which uses the Z register pair > (R31:R30). =A0Something like (no guarantees on the syntax) > > ldi =A0r31, (high) MyTable > ldi =A0r30, (low) MyTable =A0;load base of table into Z pair > add =A0r30,r17 > adc =A0r31,#0 =A0;address of desired value now in Z pair > lpm =A0r16,Z =A0 ;fetch desired value- Hide quoted text - > > - Show quoted text -
OK, looks like "adc r31,#0" isn't allowed. I suppose the alternative is ldi r16,0 adc r31,r16 AVR assembly programmers, is there a better way here? BTW, I know avr-gcc sets up a zero register (r1 IIRC). If you set one up in your program it would be useful to use here for the adc instruction (and many other places, presumably).
Mike Silva wrote:

> You need to use the LPM instruction, which uses the Z register pair > (R31:R30). Something like (no guarantees on the syntax)
Thanks for the reply Mike.
> ldi r31, (high) MyTable > ldi r30, (low) MyTable ;load base of table into Z pair > add r30,r17
Ok, I wasn't sure add(ing) to ZL (R30) would work on all 16 bits of the Z register.
> adc r31,#0 ;address of desired value now in Z pair
I don't understand this. What's supposed to happen here?
> lpm r16,Z ;fetch desired value
-- -Mike
Mike Silva wrote:

> OK, looks like "adc r31,#0" isn't allowed. I suppose the > alternative is > > ldi r16,0 > adc r31,r16
I see now. These three together work on the 16 bits.
> AVR assembly programmers, is there a better way here? > > BTW, I know avr-gcc sets up a zero register (r1 IIRC). If you set > one up in your program it would be useful to use here for the adc > instruction (and many other places, presumably).
Sounds like a good idea. I'll keep that in mind. Thanks. -- -Mike
On Mar 19, 9:03=A0am, "Mike Warren" <miwa-not-this-...@or-this-
csas.net.au> wrote:
> Mike Silva wrote: > > You need to use the LPM instruction, which uses the Z register pair > > (R31:R30). =A0Something like (no guarantees on the syntax) > > Thanks for the reply Mike. > > > ldi =A0r31, (high) MyTable > > ldi =A0r30, (low) MyTable =A0;load base of table into Z pair > > add =A0r30,r17 > > Ok, I wasn't sure add(ing) to ZL (R30) would work on all 16 bits of > the Z register.
No, it doesn't. We're adding an 8 bit value to the low 8 bits of Z (r30), which may or may not result in a carry out. If there is a carry we need to add it to the high 8 bits of Z (r31).
> > adc =A0r31,r1 =A0;address of desired value now in Z pair > > I don't understand this. What's supposed to happen here?
First of all, I replaced "#0" with "r1", assuming that r1 contains 0. This instruction is then adding the carry bit from the "add r30,r17" to r31. Two examples, one without carry and one with: Z =3D MyTable =3D 0x380 (r31 =3D 0x3, r30 =3D 0x80) r17 =3D 0x40 add r30,r17 =3D 0xC0 (no carry) adc r31,r1 =3D 3+0+C(=3D0) =3D 3 (no carry added to r31) r31:r30 =3D 0x3C0 2nd example, same MyTable base address r17 =3D 0xA0 add r30,r17 =3D 0x20 (with carry) adc r31,r1 =3D 3+0+C(=3D1) =3D 4 (adding the carry to r31) r31:r30 =3D 0x420
Mike Silva wrote:

> Two examples, one without carry and one with: > > Z = MyTable = 0x380 (r31 = 0x3, r30 = 0x80) > r17 = 0x40 > add r30,r17 = 0xC0 (no carry) > adc r31,r1 = 3+0+C(=0) = 3 (no carry added to r31) > r31:r30 = 0x3C0 > > 2nd example, same MyTable base address > r17 = 0xA0 > add r30,r17 = 0x20 (with carry) > adc r31,r1 = 3+0+C(=1) = 4 (adding the carry to r31) > r31:r30 = 0x420
All very clear now. Thank you. -- -Mike