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.
Example:
So far very straightforward ... but how do we get the table so that it is only in Page3?
The answer is simple enough:
Which brings me to the "sharing" part.
The ATMEGA2560 documentation about how the Program Memory is organized is terse at best:
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:
The salient details are:
Each Page = 32k WORDs = 64k Addressable Bytes
So:
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
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).
Cheers!
Fish
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.
Example:
Code:
SpeedToClocks:
;Prior to call:
; Load Speed in iTH:L
;Returns:
; 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:
Code:
.org $18000
SpdToClksTable:
.
.
.
Which brings me to the "sharing" part.
The ATMEGA2560 documentation about how the Program Memory is organized is terse at best:

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:
Code:
;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
So:
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
Code:
.macro ldiLPM ; $Label
ldi ZH, High(2*@0)
ldi ZL, Low(2*@0)
.endmacro
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).
Cheers!
Fish