Maker Pro
Maker Pro

ATMEGA2560 .ORG Directives for ELPM and other Extended Pgm Memory Instructions


So long, and Thanks for all the Fish!
Aug 27, 2013
Aug 27, 2013
I thought I would share this because I pulled out more than a little hair figuring it out ...

Please NOTE: This concerns AVR Assembler Instructions, No Idea how it is handled in C.

I am working on an Assembler program for the AT2560 that has several large tables, the code itself fits in Page0. No need for a boot loader, so page1, page2 and page3 of Flash are readily available for my large tables ... but I had a heck of a time sorting out how to use them ...

The 2560 is organized as 4 x 8k pages of 16-bit Words. To access any given page (other than Page0) one uses the RAMPZ register as the upper bits of the Address.

    ;Prior to call:
    ;    Load Speed in iTH:L
    ;    TCCR1B in iT0
    ;    ICR1 in iTH:L
                                                   ; 5 for call
            ldi        ZH, High(2*SpdToClksTable)  ; 1
            ldi        ZL, Low(2*SpdToClksTable)   ; 1
            ;Add iTH:L Offset to ZH:L     
            add        ZL, iTL                     ; 1
            adc        ZH, iTH                     ; 1 
            ;Table Begins @ $18000 ... Page3, Address $0000
            ;Set RAMPZ = 3   
            ldi       Temp, 3                      ; 1
            out       RAMPZ, Temp                  ; 1
            ;Load TCCR1B
            elpm        iT0, Z+                    ; 3
            ;Load ICR1
            elpm        iTH, Z+                    ; 3
            elpm        iTL, Z+                    ; 3
            ret                                    ; 5
            ;                                       25

So far very straightforward ... but how do we get the table so that it is only in Page3?

The answer is simple enough:
.org $18000

Which brings me to the "sharing" part.

The ATMEGA2560 documentation about how the Program Memory is organized is terse at best:

ATMEGA2560 Flash Memory.jpg

The first "clue" is that each address is 16 bits .... the next clue is: "0x7FFF/0xFFFF/0x1FFFF" ... the second clue is actually the END of Page1 Address in an ATMEGA640, the END of Page2 Address in an ATMEGA1280 and the END of Page3 Address in an ATMEGA2560.

With these two clues I finally figured out that the appropriate .ORG directives for Pages 1,2,3 are:
;Start of Page1
.org $8000
;Start of Page2:
.org $10000
;Start of Page3:
.org $18000

The salient details are:

Each Page = 32k WORDs = 64k Addressable Bytes
Page0 = 32k Words (32768 * 16 bits) Byte Addressable as 0 to 65535 (0 to $FFFF)
Page1 = 32k Words (32768 * 16 bits) Byte Addressable as 65,536 to 131071 ($10000 to $1FFFF)
Page2 = 32k Words (32768 * 16 bits) Byte Addressable as 131072 to 196,607 ($20000 to $2FFFF)
Page3 = 32k Words (32768 * 16 bits) Byte Addressable as 196,608 to 262,143 ($30000 to $3FFFF)

HOWEVER .... The Address used in the .org Directive is the 16-bit WORD Address:
Start of Page1 = $8000 ($10000/2) (ATMEGA2560|1280|640)
Start of Page2 = $10000 ($20000/2) (ATMEGA2560|1280)
Start of Page3 = $18000 ($30000/2) (ATMEGA2560)

I suspect that the hardware uses Bit.0 of ZL to determine which 8 bits are returned (0-7 or 8-15) ... hence why Program Labels require a logical Left shift for opcodes like ijmp, lpm etc

.macro ldiLPM     ; $Label
    ldi     ZH, High(2*@0)
    ldi     ZL, Low(2*@0)

I am posting this in the hope that it will help clarify how to use the various pages in the ATMEGA2560/1280/640 ... perhaps in C the compiler takes care of this better than the assembler does OR perhaps I am the only person this will help (when I forget how to did it, LoL).




  • 52780-fefb8b40c76304a6b4745da86cd9765f.jpg
    2 KB · Views: 0