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:
-
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
-
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.
-
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
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_ON |
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, W
; 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
|
|