Path: Home => AVR-Übersicht => Software => LPM-Befehl    (Diese Seite in Deutsch: Flag DE) Logo

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.

Organization of the program memory in AVRs 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.

The U/L-bit in the pointer address 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).

Start of the LPM program 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.

Executed LPM program After executing the three instructions, we see that:

Ausgeführtes doppeltes LPM-Programm 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: 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.
;

; Reset-/Interrupt-Vector

;
   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