Path:
Home =>
AVR-Übersicht =>
Software => LPM-Befehl
(Diese Seite in Deutsch:
)
The LPM instruction and its special properties
The LPM instruction reads content from the flash program memory to a register. Its
mnemonic stems from Load from Program Memory.
The program memory in AVRs is, different from all other internal memories like the
port registers, the static RAM (SRAM) and the EEPROM, not as 8-bit memory organized
but as 16-bit-memory. All instructions at any address location (0x0000, 0x0001, 0x0002,
etc.) consist of 16 bits each: a lower and an upper byte.
Because, when reading from a certain flash memory location, it has to be decided
whether to read the lower (L) or the upper (U) byte, an additional bit
is necessary for that. This additional bit is placed to bit 0 of the pointer address
in the register pair Z, which consists of the upper register ZH (R31) and the lower
register ZL (R30). To create space for this additional bit, the memory address has to
be shifted once left. If the U/L bit is zero, the lower byte at the address in bits
1 to 15 in Z is to be read, if it is one, the upper byte is meant.
Let us take an example: a table (Tabelle) in program memory at the address Tabelle:
shall consist of the bytes zero to seven. We'll get the assembler to write a table to
program memory with the following source code:
; Table with the values zero to seven in program memory
Tabelle:
.db 0, 1, 2, 3, 4, 5, 6, 7
Here, the assembler has the same problem: each byte that he writes to the program
memory has 8 bits only, while the program memory has 16 bits at each location. The
assembler does the following: he places the first byte (zero) to the lower byte
and the second byte (one) to the upper byte at the location Tabelle:. Always
two bytes at one location. The table therefor has a length of four 16-bit-words:
Tabelle: points to zero and one, Tabelle + 1: to two and three,
Tabelle + 2: to four and five and Tabelle + 3: to six and seven.
If the pointer Z shall be placed onto the zero, we'll have to write:
ldi ZH,High(2 * Tabelle + 0) ; The MSB of the pointer to the table
ldi ZL,Low(2 * Tabelle + 0) ; The LSB of that pointer
lpm ; Read the byte at address in Z to the register R0
After assembling the listing of the table shows the following:
25: ; Die Tabelle
26: Tabelle:
27: .db 0, 1, 2, 3, 4, 5, 6, 7
000004 0100 0302 0504 0706
The table starts at address 0x000004 and consists of four 16-bit-words. The even numbers
0, 2, 4 and 6 are located in the lower bytes, the uneven ones in the upper bytes of the
four words.
Multiplying the address Tabelle: by two in the upper source code accessing the
table's content has created the necessary space for the least significant bit in Z
to select the upper or lower byte. + 0 points to the lower byte, while + 1
would point to the upper byte (the one).
If we simulate this with avr_sim, the table
access program looks like this in the beginning. I have set R0 manually to 0xFF to
demonstrate that it is changed by the program execution.
After executing the three instructions, we see that:
- The register pair ZH:ZL (R31:R30) points to the address 0x0008, double the
table's address.
- R0 is zero, the byte has been read and placed there.
If we reformulate this program by replacing LPM by the instruction LPM R0,Z+,
and we place two of these there. The Z+ increases the pointer in Z automatically
after reading from program memory. The table is now at address 0x0005 of the program
memory. Now the programm has executed the following in four steps:
- first the table addresse 0x0005 has been doubled and written to Z,
- then the zero has been read from the program memory and the pointer in Z has been
increased, 0x000B.
- following that the one was read from program memory, written to R0 and the pointer
was again increased, 0x000C.
We see that placing the U/L selection bit to bit 0 of Z has the advantage that a bytewise
table is read in the correct row as placed by the assembler. This eases table creation
and access also when text is placed to a table. Text to a table
Text:
.db "This is a Text.",0x0D,0x0A
is easily placed, together with a final carriage return and line feed character. When
assembling this we'll get the warning that the number of bytes in this line is uneven.
There are not enough bytes to fill the last instruction word, so the assembler adds
a zero at the end.
Repeated LPM R0,Z+ from this table brings the characters in the correct row to the
register R0.
Placing the extra bit for U/L selection into Z has the additional effect that the
address of the table can only have a 15-bit address, because the 16th bit is lost.
In AVRs with a large memory tables can only be placed to the lower 32 kWords. But
this is rarely the case.
And note that this speciality only concerns accesses to the program memory, any other
memories are 8 bit only and do not require this extra U/L bit in their pointer address.
; Uses the LPM-command for reading bytes from a table
; located in the code segment
;
; Reads the keys on the STK200 board and translates
; the position of the key to the number
of LEDs by use
; of a table in the code segment and
displays these
; LEDs (switch 0: 8 LEDs, switch 1: 1 LED, switch 2:
; 2 LEDs, etc.).
; A rather useless program, but it demonstrates the use
; of the LPM command to access the code
segment and
; some ROLling and JUMPing.
;
.NOLIST
.INCLUDE "8515def.inc"
.LIST
;
; Registers
;
.DEF erg=R0 ; The
LPM-command uses R0
.DEF mpr=R16 ;
Multi-funktion-register
;
; Registers ZL (R30) and ZH (R31) are also
used but are already
; defined in 8515def.inc, so we don't need
to do it here.
;
;
RJMP main
;
main: CLR mpr
; Load 0 to register mpr
OUT DDRD,mpr
; all D-Ports are Input switches
DEC mpr
; Load FF to Register B
OUT DDRB,mpr
; All B-Ports are outputs to LEDs
OUT PORTD,mpr
; All Pullups Port D on
loop: LDI ZL,LOW(liste2)
; Register pair Z points to
LDI ZH,HIGH(liste2)
; first Byte (FF) in
the list
IN mpr,PIND
; Read switches
CPI mpr,0xFF
; All switches off? All LEDs off!
BREQ ;read
incp: INC ZL
;Point LSB to next byte on list
BRNE rolle
;overflow to MSB?
INC ZH
;MSB overflow, increment
rolle: ROR mpr
;shift Bit
0 to carry
BRLO incp
; Carry=1, switch is off, next list element
lesen: LPM ; Read
byte on which Z points to, to R0
OUT PORTB,erg
; Output to LEDs
RJMP loop
; Loop
;
; The list with the LED combinations, each byte
refers to a switch
; The values must be defined word-wise to avoid addition of a zero Byte.
; Use of .DB xx always adds a zero Byte. To
define a word, you can also use
; .DB xx,yy, which are linked to a word. The
same applies to text input
; using .DB "abcd...". Even number
of bytes or
characters are linked, odd
; numbers receive a zero byte at the end
of the list.
;
liste:
.DW 0xFEFF ; 1 LED, 0 LED
(0 ist second, 1 first!)
.DW 0xF8FC ; 3 LEDs,
2 LEDs
.DW 0xE0F0 ; 5 LEDs,
4 LEDs
.DW 0x80C0 ; 7 LEDs,
6 LEDs
;
.EQU liste2=liste*2 ;
This is needed, because adresses
; of the list are wordwise, access is bytewise
©2002/2021 by http://www.avr-asm-tutorial.net