Routines per la copia di blocchi di memoria su AVR

Nelle applicazioni embedded è spesso necessario spostare interi blocchi di memoria dalla FLASH alla SRAM o all’interno della SRAM stessa. Ecco una serie di routine assembler (o assembly) per microcontrollori AVR di Atmel ottimizzate per lo spostamento di blocchi di dimensioni fino a 256 bytes. La routine flash2ram consente la copia di un blocco di  memoria  dalla  FLASH alla  SRAM. Per la copia di un blocco di dati all’interno  della SRAM, verrà illustrata la routine  ram2ram.

LA COPIA DA MEMORIA FLASH A SRAM

I parametri richiesti dalla routine flash2ram sono tre: flashsize,  Z-pointer e Y-pointer.  Il primo specifica la dimensione del blocco di memoria che verrà copiato,  Z-pointer è l’indirizzo della FLASH a partire dal quale ha inizio il blocco interessato nella copia e Y-pointer è l’indirizzo di destinazione in RAM a partire dal quale verrà collocato il blocco dati. La routine fa uso dell’istruzione LPM che opera il trasferimento di un dato dalla FLASH ad un registro. Tale istruzione viene utilizzata per  prelevare dalla FLASH la word puntata dai 15 byte più significativi di Z-pointer. Il byte prelevato viene memorizzato in R0. Il puntatore viene incrementato automaticamente. L’istruzione “ST  Y+,Rs”  consente di scrivere il dato all’indirizzo di destinazione e poiché l’istruzione LPM non supporta l’incremento automatico del puntatore, questo viene fatto utilizzando l’istruzione ADIW. In figura 1 il diagramma di flusso della routine flash2ram e nel listato 1 il relativo codice assembler.

Figura 1. Diagramma di flusso della routine flash2ram

Figura 1. Diagramma di flusso della routine flash2ram

La tabella 1 riassume i registri utilizzati e le caratteristiche della routine in termini di risorse utilizzate.

Tabella 1. Risorse utilizzate dalla routine flash2ram

Tabella 1. Risorse utilizzate dalla routine flash2ram

Il codice assembler (o assembly) riportato nel listato 1 può essere compilato utilizzando AVR studio, l’ambiente di sviluppo dedicato ai microcontrollori Atmel.

.include “8515def.inc”

     rjmp RESET ;reset handle

.def flashsize=r16          ;size of block to be copied

flash2ram:
     lpm               ;get constant
     st     Y+,r0      ;store in SRAM and increment Y-pointer
     adiw   ZL,1       ;increment Z-pointer
     dec    flashsize
     brne   flash2ram  ;if not end of table, loop more
     ret
Listato 1

COPIA DA SRAM A SRAM

I parametri richiesti dall ram2ram sono: ramsize, Z-pointer e Y-pointer. I due puntatori costituiscono rispettivamente l’indirizzo sorgente e destinatario in SRAM, mentre ramsize è la dimensione del blocco dati da copiare. Per spostare un byte ed incrementare i due puntatori sono necessarie solo due  istruzioni,  mentre  altre due  istruzioni  aggiuntive  sono  necessarie per  il decremento  di  ramsize che viene utilizzato come contatore all’interno della routine. Durante il trasferimento i dati vengono temporaneamente memorizzati nella variabile ramtemp. Il diagramma di flusso è riportato  in figura 2, mentre il listato 2 contiene il codice assembler e la tabella 2 le risorse utilizzate.

Figura 2. Diagramma di flusso della ram2ram

Figura 2. Diagramma di flusso della ram2ram

Tabella 2. Risorse utilizzate dalla routine ram2ram

Tabella 2. Risorse utilizzate dalla routine ram2ram

.include “8515def.inc”

rjmp    RESET     ;reset handle

.def    ramtemp   =r1   ;
.def    ramsize   =r16      ;  
ram2ram:
ld      ramtemp,Z+ ;
st      Y+,ramtemp ;
dec     ramsize ;
brne    ram2ram ;
ret
Listato 2

Il listato 3, infine, riporta un piccolo programma di esempio di uso delle routines. Il programma provvede a copiare 20 bytes di dati dalla memoria programma alla SRAM a partire dalla locazione puntata da BLOCK1, quindi  esegue una seconda copia a partire dalla locazione BLOCK2. Anche per il listato 2 e il listato 3 può essere utilizzato AVR studio per la compilazione ed il debugger.

;* Test Program
.equ BLOCK1      =$60        ;start address of SRAM array #1
.equ BLOCK2      =$80        ;start address of SRAM array #2
.def temp   =r16        ;temporary storage variable
RESET:
     ldi   temp,low(RAMEND)
     out   SPL,temp ;init Stack Pointer
     ldi   temp,high(RAMEND)
     out   SPH,temp
;***** Copy 20 bytes ROM -> RAM
    ldi    ZH,high(F_TABLE*2)
    ldi    ZL,low(F_TABLE*2)  ;init Z-pointer
    ldi    YH,high(BLOCK1)
    ldi    YL,low(BLOCK1)     ;init Y-pointer
    ldi    flashsize,20
    rcall  flash2ram          ;copy 20 bytes
;***** Copy 20 bytes RAM -> RAM
    ldi   ZH,high(BLOCK1)
    ldi   ZL,low(BLOCK1)      ;init Z-pointer
    ldi   YH,high(BLOCK2)     ;(not necessary in this specific case)
    ldi   YL,low(BLOCK2)      ;init Y-pointer
    ldi   ramsize,20
    rcall ram2ram             ;copy 20 bytes

forever:rjmp    forever       ;eternal loop
F_TABLE:
      .db 0,1                 ;start of table (20 bytes)
      .db 2,3
      .db 4,5
      .db 6,7
      .db 8,9
      .db 10,11
      .db 12,13
      .db 14,15
      .db 16,17
      .db 18,19
Listato 3

 

Scarica subito una copia gratis

Una risposta

  1. Maurizio 22 Aprile 2016

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend