Tutorials - PIC

 

HEF


HEF ?

Nei microcontroller, la presenza di EEPROM è molto utile per salvare impostazioni utente, dati di calibrazione e simili. Quanto scritto in EEPROM permane anche se il chip non è alimentato.

Nei PIC più recenti, Microchip ha sostituito EEPROM con HEF, acronimo di High Endurance Flash, ovvero Flash a Lunga Durata. 

Tuttavia, HEF non è uguale a EEPROM e l'unica documentazione specifica su High Endurance Flash (HEF) è l' AN1673 e quanto scritto sui fogli dati dei vari componenti. Anche perchè c'è ancora qualche confusione dovuta al fatto dal fatto che nelle specifiche di alcuni chip si indica EEPROM, mentre poi si tratta di HEF.

Dai fogli dati si rileva che l' area HEF, che corrisponde alle ultime locazioni (typ. 128) della Flash, ha una durata minima garantita di 100K cicli di scrittura, rispetto ai 10K del resto della Flash. Questo porta le caratteristiche di durata (endurance) della HEF ad essere comparabili con quelle della EEPROM.

La differenza essenziale è che la HEF fa parte della memoria programma FLASH: si tratta quindi di scrivere e leggere dati da un'area della Flash, che, negli Enhanced Midrange e nei Midrange, è della stessa ampiezza del bus istruzione, ovvero 14 bit.
Dato che il bus dati è a 8 bit, i fogli dati parrebbero affermare che solamente gli 8 bit più bassi delle locazioni HEF sono validamente utilizzabili. Da questo si dovrebbe affermare che le ultime locazioni della Flash siano composte da memoria di programma in grado di contenere 14 bit (così come il resto della memoria Flash), ma dei quali gli 8 bit LSB sono HEF Flash e i 6 bit MSB sono di flash normale. 

Ne deriva che ogni scrittura dovrà agire in HEF flash sugli 8 bit bassi, scartando i 6 bit alti.

Sia l'area HEF che la Flash normale differiscono da un modulo dati EEPROM in due modi. Nella HEF:

  • I dati devono essere cancellati manualmente prima di una scrittura e questo può essere eseguito solo in blocchi (denominati righe) di una dimensione fissa (tipicamente 32 locazioni)
  • Scrivendo la Flash si manda in stallo la CPU per alcuni millisecondi (param. D123, tipicamente 2-2.5ms)

Per contro, in una EEPROM reale i dati possono essere scritti byte per byte e non c'è stallo nella CPU durante la scrittura, anche se , per ragioni di semplicità costruttiva, la maggior parte delle applicazioni includeranno un ciclo di ritardo per assicurare che la scrittura è stata completata prima del successivo passo.

Le differenze indicate implicano che ci sono differenze nel trattamento dei dati in HEF rispetto a quanto finora visto per EEPROM e che sia necessaria una corretta comprensione dei meccanismi quando si sostituisce HEF a EEPROM.

Vediamo alcuni dettagli.
Per tutti gli esempi seguenti facciamo riferimento a Enhanced Midrange del gruppo 16F150x, ma quanto detto vale anche per gli altri chip dotati di HEF, con l'obbligo di verificare la posizione nella mappa di memoria dell'area HEF, la sua estensione e l' ampiezza della riga, parametri che possono variare a seconda del chip.


Operazioni sulla HEF.

HEF è Flash e quindi le operazioni di lettura e scrittura impiegano le stesse procedure che sono impiegate per la Flash "normale".
L' unica differenza consiste nel fatto che, dei 14 bytes letti, solo i primi 8 (LSB) vanno considerati, mentre i rimaneti 6 sono scartati.

Vediamo nei particolari le varie operazioni.


Lettura della HEF.

Per quanto riguarda la lettura di dati nella HEF, non esistono limitazioni nella dimensione, nè tanto meno è richiesto uno stallo della MPU.
Il problema essenziale è che la lettura della Flash non è la stessa cosa della lettura della RAM, in quanto richiede, analogamente a quanto accede per la EEPROM, una procedura specifica, con l' uso di registri dedicati.

Per gli Enhanced Midrange si tratta dei registri PMADRL e PMADRH per l' indirizzo e dei registri PMDATL e PMDATH per il dato. Inoltre, entra in gioco il registro PMCON1.

Importante considerare che questi chip hanno tipicamente l'area RAM suddivisa in ben 32 banchi e che i registri di gestione delle operazioni in Flash si trovano tipicamente nel banco 3, il che richiede l' uso dello switch dei banchi.
Se gli Enhanced Midrange semplificano questa operazione con l' istruzione bsr, l' uso del classico BANKSEL è la soluzione più pratica, dato che è valida per qualsiasi famiglia di PIC.

L'operazione non è complessa ed è divisibile in tre fasi:

  • piazzare nei registri PMADRL e PMADRH l' indirizzo voluto
  • selezionare nel registro  la modalità di lettura dell' area Flash
  • recuperare il dato nei registri PMDATL e PMDATH

L'indirizzo può essere uno qualsiasi all' interno dell' area HEF.

Se l' uso di una coppia di registri per l' indirizzo è evidente, diventa meno immediata la necessità di una coppia di registri per il dato in lettura. Però, se ricordiamo come la Flash sia una memoria programma a 14 bit, ne deriva che l'uso di questi come dati ne prevede la suddivisione in un byte basso a 8 bit ed in uno alto a 6 bit. 

In effetti, vediamo nella routine più sotto, analoga a quella della lettura di un dato in una locazione generica della Flash, come il byte alto venga scartato, anche perchè, come indicato inizialmente, non è HEF e quindi inadatto a sostenere con sicurezza un numero elevato di cicli di scrittura.

Osservare la necessità di introdurre due nop una volta iniziata l' operazione di lettura: questo tempo extra è necessario in quanto il processore ha due fetch di istruzione che ignorerà; inserendo due nop si risolve il problema.

Ecco un esempio di come si può trasformare la cosa in istruzioni:

; Legge 1 byte dall'indirizzo HEF_ADDR
Read_HEF
  BANKSEL PMADRL        ; Select Bank for PMCON registers
  movlw   low(HEF_ADDR) ; Load initial address
  movwf   PMADRL
  movlw   high(HEF_ADDR)
  movwf   PMADRH
  bcf     PMCON1,CFGS   ; select flash Space
  bsf     PMCON1,RD     ; Initiate read
  nop
  nop

; get only LSB - 8 bit HEF
  movf    PMDATL,W      ; Get LSB of word
  return

Il trasferimento del dato dalla cella Flash al bus dati è immediato, ma l' operazione per arrivare a questo dato, come si vede, richiede numerose istruzioni. Ne deriva che, necessitando di leggere dati in HEF la procedura più sensata è quella effettuare, ad esempio ad inizio programma, il trasferimento del contenuto di blocco e copiarlo in una delle aree RAM dati disponibili, dalla quale i dati saranno accessibili immediatamente.
 
La routine seguente utilizza l' indirizzamento indiretto post indicizzato FSR0++ e l' istruzione  movwi specifica del set degli Enhanced Midrange per spostare una riga di HEF una una area RAM dati.
L' indirizzo HEF_ADDR dovrà essere quello di inizio della riga che si vuole copiare.

; Copia 32 bytes dall'indirizzo HEF_ADDR alla RAM all'indirizzzo hefdata
; Scarta MSB delle word

Read_HEF32:
       BANKSEL PMADRL        ; Select Bank for PMCON registers
       movlw   low(HEF_ADDR) ; Load initial HEF address
       movwf   PMADRL
       movlw   high(HEF_ADDR)
       movwf   PMADRH
       movlw   LOW hefdata   ; Load initial data address
       movwf   FSR0L
       movlw   HIGH hefdata  
       movwf   FSR0H
RdH_lp bcf     PMCON1,CFGS   ; select flash Space
       bsf     PMCON1,RD     ; Initiate read
       nop
       nop

; get only LSB - 8 bit HEF
       movf    PMDATL,W      ; Get LSB of word
       movwi   FSR0++        ; Store in user location
; i byte alti vengono scartati
;movf PMDATH,W               
;movwf data_hi 

       movf    PMADRL,W      ; Check lower bits of address
       xorlw   0x1F          ; Check if we're on the last of 32 addresses
       andlw   0x1F
       skpnz
        goto   RdH_end
       incf    PMADRL,f
       bra     RdH_lp
RdH_end:
       return

 


L'indirizzo della HEF.

Abbiamo accennato al fatto che la HEF occupa l' ultima parte della Flash e quindi il suo indirizzo di partenza dipende dal processore considerato. Sfortunatamente i fogli dati sono oscuri e confusi sull'argomento, in modo molto irritante. Occorre ricercare con certosina pazienza quanto serve per definire l' area HEF.
Troviamo parte delle informazioni nella sezione  e parte dove si descrivono le operazioni in Flash, ma possiamo benissimo trovarci davanti a fogli dati reticenti o del tutto sballati.
Ad esempio, per 10F320 il foglio dati DS40001585C-page 2 indica una Program Memory Flash da 512 words, il che equivarrebbe ad una zona tra 000 e 1FFh. Purtroppo lo stesso documento, a pagina 9 riporta la TABLE 2.1:

che è evidentemente contiene un errore nell' Address Range di entrambe le aree HEF, che il Silicon Errata and Data Sheet Clarification DS80000529F  non corregge, nè tanto meno "chiarifica".

Non è secondario, poichè il foglio dati non specifica la dimensione della HEF, che invece troviamo indicata chiaramente solo nella descrizione generale del componente , dove vengono dichiarati 128 bytes.

Ora, se la Flash di 10F320 è di 256, inizia a 00 e termina a FFh. Se 128 sono HEF, questa occupa metà della Flash: inizia a 80h e finisce a FFh!

In compenso, abbiamo l' indicazione "spot" che solo il low byte è HEF.

Bisogna poi passare al capitolo relativo alla Flash, pag.91, per arrivare a sapere che la riga ha una ampiezza di 16 word.

Abbastanza analoga la situazione delle informazioni per altri chip; piuttosto desolante per quella che dovrebbe essere una documentazione tecnica di un componente complesso.

Comunque, ecco le caratteristiche di alcuni:

PIC Flash Inizio HEF Dimensione Riga
16F1507 2k 0780h 128 32
16F1508 4k 0F80h 128 32
16F1509 8k 1F80h 128 32
16F1516/7 8k 1F80h 128 32
16F1518/9 16k 3F80h 128 32
10F320 256 80h 128 16
10F322 512 180h 128 16

Questi elementi serviranno per le definizioni nel sorgente. Ad esempio, volendo pre caricare una riga:

; HEF memory preload
   #ifdef __16F1508
HEFDATA CODE 0F80h
   #endif
   #ifdef
__16F1509
HEFDATA CODE 1F80h
   #endif
   #ifdef
__16F1507
HEFDATA CODE 0780h
   #endif

DA 60h, 0, 99h, 9, 40h, 03h, 0, 0 ;8 bytes
DA "MICROCONTROLLER.IT@ 2015"     ;24 bytes - tot 32 bytes

 


Stallo della MCU

In contrasto con il comportamento di una EEPROM , la MCU non è in grado di recuperare nuove istruzioni dalla Flash durante un ciclo di auto-scrittura ed è, pertanto, in fase di stallo fino a che l' operazione di scrittura (o cancellazione) non è conclusa: dobbiamo aver ben chiaro che la scrittura nella Flash implica il fatto che la Flash stessa è l' area che contiene i codici delle istruzioni: se stiamo scrivendoci dentro, non possiamo contemporaneamente leggere opcodes....
Questo significa che nessuna  altra azione può essere eseguita durante una cancellazione o scrittura, né è possibile rispondere ad interrupt, che va disabilitato.

Al termine della scrittura, l' esecuzione del codice riprende automaticamente. Il progettista deve, quindi, tener
conto del jitter aggiuntivo introdotto o del congelamento momentaneo dell'applicazione durante gli aggiornamenti di memoria non volatile.
Va notato che la durata dello stallo è indipendente dalla quantità di dati scritti in una riga, operazione eseguita in una sola azione.

Il problema dello stallo della MCU ,nonostante quello che si possa temere, normalmente non è per nulla un evento critico. Basta semplicemente considerare la presenza di questo tempo ed effettuare gli aggiornamenti della Flash in momenti del programma in cui esso non è causa di problemi. In pratica, trattandosi di un tempo limitato (max. 2.5ms), non è percepibile dall' utente (ad esempio, non disturba neppure il multiplex di un gruppo di display a sette segmenti, anche se sospende l' interrupt). Solo nel caso in cui la gestione dell' interrupt sia critica, occorrerà definire con precisione il momento delle operazioni sulla HEF, ad esempio all' accensione e allo spegnimento.


Cancellazione di una riga

Se non esistono limitazioni sulla lettura dei dati dall'area HEF, quando si scrive o cancella un dato occorre garantirne l' allineamento corretto nella matrice, ovvero all' interno di un blocco, o riga.

Questo vuol dire che non è possibile scrivere (cancellare) un singolo byte, ma occorre riscrivere o cancellare l' intera riga.

Pertanto, una operazione di aggiornamento della HEF, anche per un solo elemento, deve considerare le seguenti azioni:

  • copia in RAM della riga che contiene il dato
  • modifica del dato
  • cancellazione della riga in HEF 
  • scrittura della riga

Da osservare che la cancellazione è necessaria, di per se, solamente per i bit che si trovano a livello 0: la Flash "cancellata" ha i bit a livello 1.  Comunque, se anche un solo bit della riga contiene uno 0, la cancellazione riguarda l' intera riga. 

Fortunatamente vedremo subito che Microchip ha implementato un sistema alquanto efficiente per cui la cancellazione o la scrittura della riga è effettuata in una sola operazione.

 

Ecco il flow chart delle operazioni necessarie alla cancellazione di una intera riga.

Per prima cosa, se l'interrupt è abilitato, occorre disabilitarlo.

Come per la lettura, ci si appoggia ai registri speciali PMADRL e PMADRH che, ricordiamo, non sono in banco 0.
La cancellazione avviene a partire dall' indirizzo di inizio della riga, ma, in effetti, basta fornire un indirizzo della riga e la cancellazione avviene per tutta la riga corrispondente.

Il registro  dovrà essere inizializzato selezionando il bit di memoria CFGS.

Come per le EEPROM, occorre una "chiave" di accesso alle operazioni di cancellazione e scrittura e questa è costituita da una ben precisa sequenza di istruzioni.

Dopo aver programmato i bit FREE e WREN per abilitare la cancellazione, occorreà scrivere la "chiave" AAh e 55h.

A questo punto si avvia la cancellazione e la MPU va in stallo per 2-2.5ms. In questo periodo il processore è l'I/O sono congelati.

Esaurito il tempo di stallo, il programma riprende automaticamente dall'opcode successivo.

Occorrerà ora disabilitare la scrittura con il bit WREN e riabilitare, se richiesto, l' interrupt.

Come si vede, una procedura del tutto simile a quella usata per la EEPROM.

Ed ecco le istruzioni:

; Cancella una riga di HEF (32 word)
Erase_HEF
    bcf     INTCON,GIE     ; Disable int
    BANKSEL PMADRL
    movlw   low(HEF_ADDR)  ; lower address
    movwf   PMADRL
    movlw   high(HEF_ADDR) ; upper address
    movwf   PMADRH
    bcf     PMCON1,CFGS    ; Not configuration space
    bsf     PMCON1,FREE    ; Specify an erase operation
    bsf     PMCON1,WREN    ; Enable writes
    movlw   055h           ; Start erase sequence 
    movwf   PMCON2
    movlw   0AAh
    movwf   PMCON2
    bsf     PMCON1,WR      ; Set WR bit to begin erase
    nop
    nop

; The processor stalls until the erase process is complete
; after erase processor continues with 3rd instruction

    bcf     PMCON1,WREN    ; Disable writes
    bsf     INTCON,GIE     ; Enable interrupts
    return

Osserviamo che non servono "dati" per la cancellazione; cancellare una locazione significa semplicemente portare il livello elettrico dei bit a 1. Di conseguenza una locazione cancella a 14-bit conterrà 3FFh.
Per chiarezza, questa è struttura della "chiave":

Viene utilizzato uno specifico SFR, PMCON2, nel quale occorre scrivere, nella sequenza indicata, le chiavi AAh e 55h.

Da osservare la necessità dei due nop già visti per la lettura.

Se non si utilizza questo algoritmo, non è possibile cancellare o scrivere nella Flash.

La sua necessità è evidente, in quanto la Flash contiene il firmware, che non deve rischiare di essere danneggiato da eventi casuali, ma che può essere modificato solamente a seguito di una azione volontaria del programma.

 


Scrittura di una riga

Analogamente alla cancellazione, la scrittura richiede una "chiave", ma, questa volta, anche dei dati.
Dovendo scrive una intera riga per volta, occorre un sistema per evitare il ripetersi di 16 o 32 stalli alla scrittura di ogni byte. Il meccanismo implementato dal costruttore è quello di un buffer, ampio come la riga, che viene scritto in Flash in una unica azione, riducendo lo stallo ai già visti 2-2.5ms.

Ovviamente il buffer deve essere caricato con word a 14 bit e questo richiede un certo numero di istruzioni: ecco il flowchart consigliato dal foglio dati

Osserviamo che nella scrittura dei latches non occorre alcun ritardo.

In istruzioni. Copiamo una riga da 32 bytes dalla RAM alla HEF.

Osserviamo che la Flash è composta da due "bytes", uno di 8 e uno di 6 bit. A noi interessa, trattandosi di HEF, solo la parte a 8bit e si scarterà quella a 6, caricandola con un valore dummy.

; Copia 32 bytes da RAM dall' indirizzo hefdata all'indirizzo
; HEF_ADDR della HEF
; Dati immagazzinati in formato little endian
; L'MSB delle word è il valore dummy 3Fh

Write_HEF
     bcf     INTCON,GIE     ; Disable ints
     BANKSEL PMADRH         ; Bank 3
     movlw   low(HEF_ADDR)  ; Load initial address
     movwf   PMADRH
     movlw   high(HEF_ADDR)
     movwf   PMADRL
     movlw   LOW hefdata    ; Load initial data address
     movwf   FSR0L
     movlw   HIGH hefdata
     movwf   FSR0H
     bcf     PMCON1,CFGS    ; Not configuration space
     bsf     PMCON1,WREN    ; Enable writes
     bsf     PMCON1,LWLO    ; Only Load Write Latches
WHlp moviw   FSR0++         ; Load first data byte into lower
     movwf   PMDATL
;moviw FSR0++ ; discard second data byte
     movlw   3Fh            ; and use dummy value for MSB
     movwf   PMDATH
     movf    PMADRL,W       ; Check if lower address 
     xorlw   0x1F           
     andlw   0x1F
     skpnz                  ; Exit if last of 32 words
      bra    WHstart        ; otherwise re loop
     movlw   055h           ; write sequence
     movwf   PMCON2         
     movlw   0AAh
     movwf   PMCON2
     bsf     PMCON1,WR      ; Set WR bit to begin write
     nop
     nop
     incf
    PMADRL,F       ; latches Increment address
     bra     WHlp           ; Write next latches
WHstart
     bcf     PMCON1,LWLO    ; memory write
     movlw   055h           ; write sequence
     movwf   PMCON2
     movlw   0AAh
     movwf   PMCON2
     bsf     PMCON1,WR      ; Set WR bit to begin write
     nop                    ; all latches simultaneously
     nop                    ; to program memory.
; the processor stalls until the self-write process complete. ; After write processor continues

     bcf     PMCON1,WREN    ; Disable writes
     bsf     INTCON,GIE     ; Enable interrupts
     return

Osserviamo come l' uso dell'indirizzamento indiretto post incrementato e l'opcode moviw facilitino l'operazione. 
L'MSB (i 6 bit non HEF) è caricato con un valore che ha tutti i bit a 1 ed evita una in utile scrittura.

 


Modifica della HEF.


La modifica del contenuto della HEF è realizzabile semplicemente organizzando quanto detto finora.

Dobbiamo partire sempre dal concetto base che è l' operazione su una intera riga, sia che si debba modificare un solo byte o più bytes.

Il contenuto della riga ha posto come immagine in RAM: in una area adeguata posso copiare il contenuto della riga.

Le modifiche verranno effettuate su questa immagine in RAM.

Quindi si provvederà a cancellare la riga e a riscriverla con il contenuto desiderato.

Le operazioni di blocchi di dati sono facilmente realizzabili con l' uso dell'indirizzamento indiretto e delle nuove istruzioni relative.

Ecco un esempio di macro per movimentare un c erto numero di byte da un'area RAM ad un'altra.

; Copy n bytes da source a target
COPYMEM MACRO source, target, nbyte
  local c_0
    movlw  nbyte
    movwf  temp
    movlw  low(source)
    movwf  FSR0L
    movlw  high(source)
    movwf  FSR0H
    movlw  low(target)
    movwf  FSR1L
    movlw  high(target)
    movwf  FSR1H
c_0 moviw  FSR0++
    movwi  FSR1++
    decfsz temp,f
     bra   c_0
        ENDM

Osserviamo l'impiego di due puntatori indiretti e della coppia di istruzion moviw - movwi
Sorgente e destinazione possono essere in qualsiasi banco, dato che, attraverso gli FSR possiamo raggiungere qualsiasi punto della RAM. Il post incremento riduce il numero delle istruzioni necessarie al loop.

 


Verifica.


Una volta effettuata una scrittura, può essere utile verificare che i dati siano stati correttamente copiati in HEF.

Il procedimento è semplice.

Consideriamo come riferimento la serie di dati che abbiamo copiato dalla RAM nei buffer per la scrittura della Flash.

Leggiamo uno alla volta gli elementi della riga appena scritta e li compariamo con la copia in RAM. Se ci sono differenze, la scrittura non è riuscita e si dovranno prendere le conseguenti decisioni.

Se abbiamo avuto cura di realizzare le varie funzioni come subroutines o macro, il loro riutilizzo è immediato e consente un sensibile risparmio di tempo e risorse.

 


E con il C?

L' AN1673 tratta il problema dal punto di vista del compilatore C, per il quale esiste una libreria specifica per la scrittura della Flash.

 


 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 19/06/15.