Tutorials - PIC

 

Come passare un programma Assembler scritto per 16F84 al 16F628


Questa pagina NON intende fornire un tutorial per l' uso del PIC16F628, ma piuttosto una serie di informazioni per sostituire pin-to-pin un PIC16F84/84A con un PIC più recente, a partire dal PIC16F628.

Innanzitutto, va detto che PIC 16F628 è perfettamente pin compatibile con 16F84, per cui, non volendo utilizzare nessuna delle nuove funzioni hardware, 628 può essere installato sullo stesso zoccolo del 16F84A senza cambiare alcuna parte esterna o cablaggio.
Sarà tuttavia possibile, con una minima modifica al CONFIG, eliminare quarzo e condensatori relativi per un funzionamento a  MHz, avendo PIC16F628 la possibilità di funzionare con un oscillatore interno.

Le altre differenti prestazioni addizionali di 628 NON saranno considerate in questa sede, proprio per ottenere una sostituzione totatle del vecchio 84. Se poi si desidera utilizzare la maggiore Program Memory o EEPROM o RAM o i comparatori, oppure l' UART, i timer, LVP o altro, queste non sono da intendersi come semplici modifiche al sorgente e vanno viste in un' ottica diversa.


 


Prima di iniziare la conversione di un vecchio sorgente per F84 o C84 e adattarlo ad un F628/F88/F1827, è opportuno considerare i seguenti punti:

  1. Non impegnarsi in un lavoro superiore alle proprie possibilità. E' probabile che un sorgente complesso sia afflitto dal problema della mancanza di documentazione e di commenti che potrebbero essere indispensabili per chiarire e risolvere punti oscuri, dove non è facile interpretare la logica di chi lo ha scritto.
    Iniziate con cose semplici, per poi passare a quelle più complesse quando avete un minimo di esperienza
     

  2. Alla larga dai programmi scritti con la parte opposta alla testa, ovvero quelli in cui sono utilizzati solamente valori assoluti e $.
    Programmi del genere sono portabili solo con grande fatica. Se proprio non potete farne a meno, probabilmente è meglio prima aggiustare la situazione sostituendo gli assoluti con label, quindi convertire.

  3. Attenzione ai programmi complessi, scritti senza un minimo di forma (template) o senza commenti: si può rivelare difficile capire cosa il programmatore originale intendesse fare e come.

 

Detto questo e limitandoci ad una sostituzione pari pari, occorrerà apportare al sorgente almeno le seguenti  sei correzioni :


1. - Tipo di processore

Per prima cosa, ovviamente, in testa al listato Assembly, la direttiva PROCESSOR deve contenere il nome del nuovo processore, sostituendo 16F84 con 16F628.
Listato originario 16F84 Modifica per 16F628
 
; Definizione del processore

   LIST P=16F84
   #INCLUDE "P16F84.INC"

 
; Definizione del processore

    LIST P=16F628
    #INCLUDE "P16F628.INC"
   


Azione 1: sostituire la definizione e il file .inc con quello del processore scelto


2. - __CONFIG

  1. La più complessa struttura hardware di 628 richiede una stringa  __CONFIG più lunga.
    Essa dovrà comprendere:
    • il comando _LVP_OFF, che rende RB4 compatibile con quello di 16F84
    • il comando _BODEN_OFF , che disabilita il BrownOut detector, rendendo il generatore del reset compatibile con quello del 16F84.
    • il comando _MCLRE_OFF per disabilitare la funzione di GPIO sul pin di MCLR e renderlo compatibile con il 16F84.
    Listato originario 16F84 Modifica per 16F628
        ; configuratore

       __CONFIG _CP_OFF & _HS_OSC & _WDT_OFF & _PWRTE_ON
       ; configuratore

      __CONFIG   _CP_OFF & _HS_OSC & _WDT_OFF & _PWRTE_ON &
    _BODEN_OFF & _LVP_OFF & _MCLRE_O

    La riga di CONFIG indicata NON sfrutta le possibilità di F628, ma semplicemente lo porta ad essere compatibile con F84. Per utilizzare altre risorse, occorrerà consultare il foglio dati per il CONFIG adeguato.

    Qui occorre insistere decisamente sulla critica alla pessima abitudine di utilizzare valori assoluti e non label.
     
    Nel caso del CONFIG la differenza tra questo modo stupido di procedere e l' impiego della corretta tecnica per indicare i valori da assemblare e fin troppo evidente.

    Listato originario 16F84 Modifica per 16F628
      
     ; configuratore

       __CONFIG 0x3FF1
        ; configuratore

      __CONFIG 0x3D21 

    Ora, sarebbe interessante conoscere chi, dal valore esadecimale impostato, sa risalire alle condizioni di configurazione senza consultare il foglio dati !!!
    Chi usa questo sistema o non è a conoscenza di altri modi più intelligenti o semplicemente copia da lavori altrui senza porsi minimamente il problema del significato di quanto scrive.

    Se utilizziamo una riga di CONFIG che abbia come oggetto un numero esadecimale (o binario):
    - il suo significato è criptico: occorre andare a scartabellare il foglio dati e combinare i bit per capire in quale modo lo sciocco autore del programma intendeva configurare il processore
    - il valore cambia tra PIC e PIC e quindi la riga NON E' PORTABILE e deve essere modificata

    Invece, utilizzando la corretta modalità che fa uso dei simbolici:
    - si comprende a prima vista cosa si vuole ottenere
    - il passaggio ad un altro micro consiste solo in aggiunte (o eliminazioni) di queste label
    Sarà l' Assembler a combinare le label e a generare il corretto settaggio dei bit dei registri di CONFIG.

Quindi, abolite, evitate, rifuggite, condannate quanto possibile la perfida abitudine di esprimere il valore di configurazione attraverso un numero esadecimale ed utilizzate esclusivamente la modalità corretta.


Azione 2: modificare la riga di CONFIG con quella
corretta


3. -  RAM

La memoria RAM utente parte da 20H anziché da 0CH.
Pertanto l' assegnazione della RAM dovrà tenerne conto. Ad esempio,:

Listato originario 16F84 Modifica per 16F628
 
   ; RAM start
Inizioram equ 0CH
  
  
 ; RAM start
Inizioram equ 20H
  


Fortunatamente un Assembler come MPASM consente di utilizzare statemente condizionali per generare liste assemblate dipendenti dall' ambiente voluto, attraverso comandi come:

  • #define
  • #ifdef / #ifndef
  • #if / #else / #endif

Quindi è una buona idea per scrivere una fase di inizio adatta per entrambi o più processori:

; processor switch - processore selezionabile
; porre come commento la linea che definisce il processore non usato
; (in questo esempio è definito 16F628)

;#define 16F84

#define 16F628

; definizione del processore
  #ifdef 16F628
            list p = 16F628
            #INCLUDE "P16F628.INC"

 __config _BODEN_OFF & _CP_OFF & _LVP_OFF & _MCLRE_OFF & _HS_OSC & _WDT_OFF & _PWRTE_ON
  #endif

  #ifdef 16F84
            list p=16F84
            #INCLUDE "P16F84A.INC"
 __config _CP_OFF & _HS_OSC & _WDT_OFF & _PWRTE_ON
  #endif

; RAM start
  #ifdef 16F628

StartRAM   EQU 0x20   ; inizio area RAM per 16F628

  #endif

  #ifdef 16F84        

StartRAM   EQU 0x0C   ; inizio area RAM per 16F84

  #endif

......

; riserva memoria RAM

    CBLOCK StartRAM       ; inizio RAM dipendente dal processore scelto

    ; qui le label di assegnazione della RAM

    ENDC

  


Azione 3: modificare l' indirizzo di inizio RAM e, se possibile, utilizzare un template adeguato


4. - I Banchi

Va ricordato che la memoria è suddivisa in più banchi, accessibili con i bit RP dello STATUS.  
  • in16F84 i banchi erano solo due, in F628 i banchi sono quattro;
  • in F84 i registri SFR erano in numero molto limitato, dato il numero altrettanto limitato di periferiche disponibili; in F628 i registri SFR sono distribuiti su tutti e quattro i banchi.

Questa condizione fa si che nel 16F628, come per la gran parte dei mid-range, si debba sguazzare in questi banchi alla ricerca del registro desiderato e si debba tenere sempre sott' occhio la situazione, modificando il banco di lavoro quando è necessario.
Questo non accadeva in F84 che, pur avendo due banchi, replicava pari pari i registri in entrambi. Quindi, in qualsiasi banco di RAM si stesse lavorando, l' accesso agli SFR era sempre assicurato senza necessità di azioni speciali. 

16F84 16F628


Per contro, si nota che in F628, per comodità e funzionalità, 16 bytes sono stati resi accessibili in modo comune a tutti i banchi (access), dovunque ci si trovi nell' esecuzione del programma, senza ricorrere agli RP. 
Questi bytes si trovano tra 70H e7FH. Sono particolarmente utili per condividere dati durante le routines di interrupt (save e restore dei registri principali).Se si usa tutta la RAM, va tassativamente ricordato di aggiungere le linee di programma necessarie per commutare i banchi.

Se si trasla solamente il programma F84 su F628 senza alcun uso della memoria addizionale, ovvero si usa solo la memoria in BANK 0, non occorrono modifiche al listato per quanto riguarda la RAM.
  
Però, come detto, 16F84 ha tutti i registri in un solo banco, 16F628 ha i registri suddivisi in due banchi. Quindi, dove per 84 era sufficiente scrivere:

 

Listato originario 16F84

  ; RB0 = 1

   movlw  0x00, W     ; Set PORTB come uscita
   movwf  TRISB
   movlw  b'00000001' ; RB0 = 1
   movwf  PORTB

   


per 628, dato che i registri PORT si trovano in Banco 0 e i registri TRS in banco 1, deve diventare:

 

Modifica per 16F628

  ; Set PORTB come uscita

   banksel TRISB       ; banco 1
   movf    0x00
, W  
   ; Set PORTB come uscita
   movwf   TRISB
   banksel PORTB
  
     ; banco 0
   movlw   b'00000001' ; RB0 = 1
   movwf   PORTB

   


Che può essere scritto, seppure meno chiaramente, con: 

 

Modifica per 16F628

  ; Set PORTB come uscita

   bsf     STATUS, RP0 ; banco 1
   movf    0x00
, W  
   ; Set PORTB come uscita
   movwf   TRISB
   bcf     STATUS, RP0
; banco 0
   movlw   b'00000001' ; RB0 = 1
   movwf   PORTB

   



La differenza tra la pseudo istruzione
banksel e il classico bsf STATUS, RP0  è che  banksel si adatta al numero di banchi del processore e agisce sugli switch di banco (RP) in modo tale da poter puntare con sicurezza al banco in cui sta la label oggetto.
In questo caso, su entrambi gli RP, per cui è equivalente a: 

banksel

assemblato

 ; Set PORTB come uscita

   banksel TRISB    ; banco 1
   movf    0x00
,
; Set PORTB uscita
   movwf   TRISB
   banksel PORTB
  
     ; banco 0
   movlw   b'00000001' ; RB0 = 1
   movwf   PORTB

; Set PORTB come uscita

   bsf     STATUS, RP0 ; banco 1
  
bcf     STATUS, RP1 ; banco 1

   movf    0x00
, W  
   ; Set PORTB uscita
   movwf   TRISB
   bcf     STATUS, RP0
; banco 0
   bcf     STATUS, RP1 ; banco 1
   movlw   b'00000001' ; RB0 = 1
   movwf   PORTB

 

Certamente se, durante il programma, non si è mai toccato RP1, che è a 0 per default al reset, non c'è necessità di applicare un bcf STATUS, RP1 ogni volta che si cambia banco.

Però bisogna essere sicuri di non averlo mai toccato; e in un programma che utilizza tutti i banchi, tenere presente dove ci si trova per agire solo ed esclusivamente sullo switch necessario per passare al banco voluto può non essere così immediato. banksel, agendo su tutti gli switch, sacrifica qualche istruzione in più, ma evita tante grane.

Quindi, anche se banksel dà origine a due istruzioni, è auto esplicativa a livello di listato sorgente ed è da preferire, a meno che ci siano limiti stretti di memoria o di velocità (cosa che capita molto, molto raramente in listati semplici per vecchi PIC).

Un aiuto viene da MPASM che genera un warning, il [302] che avviasa il programmatore ogni volta il sorgente richiama un registro non in Bank 0, consentendo di tenere sotto controllo la situazione.

 

Azione 4: utilizzare banksel o comunque prestare attenzione alla posizione dei registri nei banchi


5. - CMCON

Assolutamente importante iniziare le operazioni con il settaggio del registro di configurazione del modulo comparatore CMCON con il valore 07H  

Questo perchè i 3 bit inferiori di PA (da RA0 a RA3) sono collegati, dopo ogni reset, per default, alla funzione dei comparatori, che in F84 non era presente.

Occorre quindi agire sul registro CMCON (COMparator CONtrol register) per disabilitarli, altrimenti questi pin non si potranno usare come I/O General Purpose.

Listato originario 16F84 Modifica per 16F628
; Program start

 

  clrf   PORTA  ; clear PA

 

; Program  start

   
   clrf     PORTA   ; clear PA
   movlw    0x07
   movwf    CMCON   ; disable comparators

  

 

Azione 5: inserire le due righe per disabilitare i comparatori


6. - EEPROM

Particolare attenzione si dovrà usare nel caso in cui il programma da convertire faccia uso della EEPROM, in quanto qui la questione è più complessa.

Se si usa la EEPROM interna:

  • i registri EEADR e EEDATA non si trovano più nel BANK0 , ma nel BANK 1, quindi sarà necessario agire sullo STATUS per commutare i banchi.
  • Inoltre, tanto per fare un poco di confusione, i progettisti di Microchip hanno spostato 
    -
    il bit
    EEIE (enable per l’interrupt della EEPROM) dal registro INTCON al registro  PIE1 , che è accessibile in BANK1.
    - Anche il bit
    EEIF è stato spostato
    dal registro EECON1, che era in BANK1, al registro PIR1, che è in BANK0
16F84 16F628

 

 

Questo è dovuto al fatto che F628 ha un numero molto maggiore di sorgenti di interrupt ed è stata necessaria una completa revisone dell' area relativa.

Quindi la conversione di un sorgente che utilizza la EEPROM dovrà  tenere presente la necessità di modificare i riferimenti ai registri indicati e di inserire le linee di controllo per lo switch dei banchi. 
 

Azione 6: modificare la posizione dei registri


Per riassumere

Per riassumere i punti principali da osservare per convertire un sorgente da 16F84 a 16F128 sono solo questi:

 

  • sostituire la definizione e il file .inc con quello del processore scelto

  • modificare la riga di CONFIG con quella corretta

  • modificare l' indirizzo di inizio RAM e, se possibile, utilizzare un template adeguato

  • utilizzare banksel o comunque prestare attenzione alla posizione dei registri nei banchi

  • inserire le due righe per disabilitare i comparatori

  • se usata la EEPROM, modificare la posizione dei registri

 

 


 

 

 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 21/10/10.