Impostazione Clock e Word di Configurazione sui microcontrollori PIC® ad 8 bit – il PIC16F18877

I nuovi PIC® hanno un occhio sempre più attento alle performance e ai consumi energetici, com’è giusto che sia. La cura di queste caratteristiche ricade chiaramente nella necessità di parametri di configurazione sempre più articolati. La sola configurazione del clock, ad esempio, ormai vanta un numero sempre maggiore di opzioni che possono rendere un po’ complicato districarsi nel datasheet. Sebbene in MPLABX ci sia la possibilità di utilizzare il Code Configurator che sicuramente facilita il compito, è comunque bene avere chiaro il significato di alcuni parametri dato che comunque il configuratore non li spiega.

Dal momento che è sempre meglio fare esempi concreti ho scelto di fare gli esempi su un PICmicro specifico: il PIC16F18877 (appartenente alla famiglia Enhanced Midrange) che andrà a soppiantare definitivamente il PIC16F887, il quale a sua volta ha già sostituito il caro, vecchio, PIC16F877 (appartenenti entrambi alla famiglia Mid-Range), amico di mille avventure, con il quale abbiamo iniziato il vecchio corso di programmazione microcontrollori PIC® in C.

Della famiglia Enhanced Midrange fanno parte i PIC con la sigla che presenta il numero 1 dopo la lettera F (12F1xxx, 16F1xxx, 16F1xxxx) che, a differenza della famiglia Mid-Range, hanno un numero maggiore di istruzioni assembler (49 vs 35), quantitativi di memoria maggiori, uno stack a 16 livelli (contro 8), svariate funzioni avanzate tra cui quelle di risparmio energetico e altre migliorie.

In questo articolo affronteremo quindi in maniera approfondita sia la circuiteria di Clock che l’impostazione della Config Word.

Anche se mi riferisco nello specifico al PIC16F18877 le nozioni sono valide un po’ per tutti i PICmicro perchè affronto argomenti che fanno capire meglio come funzionano clock e word di configurazione e questo PICmicro ha dentro un po’ di tutto, per cui il peggio (?) che vi può capitare è di avere tra le mani un PICmicro ad 8 bit più semplice di questo, che manca di alcune funzionalità. In aggiunta farò riferimento anche a funzionalità che questo PICmicro non ha o evidenzierò le differenze rispetto ad altri per cui questo articolo tornerà utile in mille occasioni.

Cenni sul Clock Switching e sul Fail Safe Clock Monitor

Questo PICmicro, come tanti altri, ha la possibilità di eseguire il Clock Switching: ovvero la caratteristica di poter cambiare, anche a runtime, la sorgente di clock sia manualmente, agendo in appositi registri, sia automaticamente dopo un malfunzionamento del clock principale nonchè di cambiare a runtime la frequenza dell’oscillatore interno.

La funzione di Clock Switching è presente anche sul predecessore di questo PICmicro: il PIC16F887, ma su esso non prevedeva la possibilità di variare la frequenza di Clock dell’oscillatore interno nè la possibilità di switchare tra i clock interni: prevede unicamente lo switch tra clock interno ed esterno.

In particolare la rilevazione di malfunzionamento del clock esterno è gestita da un modulo apposito chiamato Fail-Safe Clock Monitor che controlla costantemente il clock principale e ne attiva un altro (esegue lo switch) in caso di malfunzionamenti. In particolare questo tipo di Clock Switch è chiaramente automatico, ed è presente anche sul PIC16F887. Il PIC16F18877 invece, oltre a questa funzione, ha anche la possibilità del Clock Switching manuale. Proprio a causa di queste funzionalità il diagramma del clock sul datasheet appare più complesso rispetto a come molti di noi sono abituati, ma prima di piazzarvelo qui, è meglio chiarire prima alcuni concetti perchè spesso i Datasheet (a cui bisogna SEMPRE fare riferimento) contengono sigle e abbreviazioni oscure che non sono facili da interpretare.

COSC, NOSC e RSTOSC

I clock di sistema sui dispositivi Enhanced Midrange (quindi non vale per il 16F887) dotati di Clock Switching manuale vengono idenficati con due sigle: COSC e NOSC. Con la sigla COSC (Current Oscillator – dove current sta per “corrente” nel senso di “attuale”) viene identificato l’oscillatore attualmente in funzione, ovvero quello che a runtime sta fornendo il clock al sistema. Con NOSC (New Oscillator) si indica il nuovo oscillatore: ovvero quello che vogliamo impostare, a runtime, e che andrà a sostituire quello attuale. NOSC è in pratica un oscillatore che abbiamo appena finito di configurare (a runtime) e non è ancora entrato in funzione. C’è anche un’altra sigla: RSTOSC (Reset Oscillator), che rappresenta l’oscillatore definito dalla word di configurazione ed è quello che viene attivato dopo un qualsiasi tipo di reset:

All’avvio, quindi, il sistema utilizza il clock definito nella word di configurazione (RSTOSC) che diventa quindi l’oscillatore attuale (COSC), detto in parole povere, quello che accade è che il valore di RSTOSC (che ricordo: si trova nella word di configurazione) viene automaticamente copiato in un registro apposito che contiene il valore del COSC. Volendo, dopo che il sistema si è avviato, possiamo cambiare l’oscillatore (oppure, nel caso di un oscillatore interno, utilizzare sempre lo stesso ma con parametri differenti) e andiamo quindi a definire il NOSC. Dopo aver definito il NOSC, l’oscillatore corrente diventa quello appena impostato, per cui COSC=NOSC.

Questa funzione può anche essere utile per eseguire una partenza a doppia velocità: si utilizza prima un clock interno a bassa velocità e poi si passa a quello esterno che, normalmente, ha bisogno di più tempo per partire. Questa funzionalità è implementata in automatico in alcuni PICmicro che però non hanno il Clock-Switching manuale. Ne parlo più in basso.

Riassumendo: RSTOSC è l’oscillatore di default, definito dalla Word di Configurazione e attivato dopo un qualsiasi reset, NOSC è un eventuale nuovo oscillatore che vogliamo impostare dopo la partenza (a runtime, da software, quindi sempre modificabile), e COSC è un valore di sola lettura che contiene le informazioni sull’oscillatore che è attualmente in funzione (COSC=RSTOSC dopo un reset e sucessivamente, se lo vogliamo, eseguiamo un clock-switch e quindi COSC=NOSC). Il sistema prende sempre l’impostazione del clock dal valore definito dal COSC.

Config 1 – Clock

Il PIC16F18877 può essere alimentato da 4 distinte sorgenti di clock le quali possono essere scambiate tra loro a runtime e in particolare quella dell’oscillatore interno ad alta frequenza può anche essere modificata durante il programma:

  • Clock esterno o FEXTOSC (ovvero il quarzo con i condensatori sui pin CLKIN/CLKOUT oppure un generatore di clock su CLKIN)
  • Clock interno ad alta frequenza, HFINTOSC
  • Clock interno a bassa frequenza, LFINTOSC
  • Clock secondario esterno SOSC (il quarzo a bassa frequenza sui pin SOSCO/SOSCI)

Sono inoltre disponibili 2 PLL (in realtà è un solo modulo PLL diviso in due) a valore fisso non configurabile che permettono di moltiplicare il clock. C’è un PLL 4x utilizzabile esclusivamente dall’oscillatore esterno e un PLL 2x utilizzabile esclusivamente dall’oscillatore interno ad alta frequenza.

Per la scrittura della word di configurazione dobbiamo sempre utilizzare il tool apposito incluso in MPLABX come ho spiegato nel primo articolo del nuovo corso di programmazione PICmicro in C oppure il Code Configurator, che inseriscono tutte queste parole chiave in automatico.

L’oscillatore da utilizzare all’avvio (RSTOSC), come dicevo, si imposta nella word di configurazione. In particolare nella Config 1, che è dedicata esclusivamente al Clock. Vediamola insieme e analizziamo i singoli gruppi di bit:

FCMEN serve ad abilitare il Fail-Safe Clock Monitor di cui ho già accennato ad inizio articolo. Questo modulo monitora costantemente il clock esterno e funziona in maniera indipendente da esso sfruttando il clock interno a bassa frequenza diviso 64 (488Hz). Grossolanamente potete immaginare che quando non viene più rilevato segnale sul CLKOUT questo modulo esegue lo switch del Clock e fa entrare in funzione il clock interno ad alta frequenza settato ad 1MHz. Questa condizione alza il bit OSFIF (Oscillator Fault Interrupt Flag) di PIR1 e genera un interrupt se è settato il bit OSFIE di PIE1 per cui possiamo rilevare questo stato e, se vogliamo, impostare un nuovo clock, una nuova frequenza dell’oscillatore esterno o ancora, tentare di riavviare il clock esterno.

CSWEN abilita la possibilità di eseguire il clock-switching manuale. Disabilitando tale funzione l’unico oscillatore impostabile è quello definito dalla word di configurazione e la scrittura nei registri di configurazione manuale non ha effetto.

!CLKOUTEN abilita l’uscita del segnale di clock dal pin RA6/CLKOUT. Questa caratteristica è utilizzabile solo in accoppiata con il clock interno, oppure con quello esterno ma che lasci libero il pin RA6/CLKOUT (ovvero uno dei 3 settaggi EC, perchè i quarzi usano entrambi i pin RA6/CLKOUT e RA7/CLKIN). Con questa impostazione abilitata, sul pin RA6/CLKOUT avremo un segnale con una frequenza pari a FOSC/4. Volendo fare un esempio: se abbiamo impostato un clock a 32MHz, avremo in uscita sul pin RA6 un segnale a 8MHz. Questa funzione, a parte che può essere utile per applicazioni particolari, per sincronizzare dispositivi esterni, io a volte la utilizzo come debug quando non sono sicuro di aver impostato correttamente tutti i registri dell’oscillatore interno: in pratica  vado a controllare RA6 con l’oscilloscopio.

Sui vecchi dispositivi non avevamo un bit apposito per abilitare tale funzione e la funzionalità di Clock-Out sul pin CLKOUT veniva incorporata nella selezione del Clock interno. Ad esempio nella config word c’era il gruppo di bit FOSC (sostituito ora da RSTOSC) che tra i vari settaggi aveva il valore INTOSC (che prevedeva RA6 come clock-out e RA7 come IO) oppure INTOSCIO (che non prevedeva il clock-out e permetteva di usare sia RA6 che RA7 come IO). Su altri PICmicro (come ad esempio il PIC16F1939, il PIC16F1789 ecc), l’utilizzo dell’oscillatore interno prevede una sola configurazione: INTOSC e non è possibile utilizzare anche RA6 come I/O.

RSTOSC è l’oscillatore da utilizzare dopo un reset (ricordo sempre che l’avvio è anch’esso una condizione di “dopo-reset”!). Le impostazioni possibili sono:

  • EXT1X: viene utilizzato un oscillatore esterno che andremo a definire nei gruppi di bit successivi FEXTOSC. C’è 1X nella parola per indicare che viene usato tal quale, senza PLL.
  • HFINT1: oscillatore interno ad alta frequenza settato a 1MHz
  • LFINT: oscillatore interno a bassa frequenza (questo è fisso a 31KHz)
  • SOSC: oscillatore esterno secondario collegato sui pin RC1/SOSCI – RC0/SOSCO (impostazione utilizzata per il quarzo da 32.768KHz per le funzioni di Real Time Clock/Calendar)
  • EXT4X: oscillatore esterno a cui viene applicato il PLL dedicato 4x
  • HFINTPLL: oscillatore interno ad alta frequenza settato a 16MHz a cui viene applicato il PLL dedicato 2x (per cui la frequenza finale di questa modalità è 32MHz)
  • HFINT32: oscillatore interno ad alta frequenza settato a 32MHz (senza PLL!)

Il fatto che si siano due impostazioni con l’oscillatore interno che forniscono un clock di 32MHz è che una ha il PLL e l’altra no: se dopo l’avvio abbiamo bisogno di impostare un altro valore di frequenza dell’oscillatore interno (la config word difatti non prevede tutti i valori possibili, ma solo 1MHz e 32MHz) che necessita del PLL 2x, allora si sceglie HFINTPLL e successivamente si cambia la frequenza. Non è difatti possibile attivare o disattivare il PLL a runtime, per cui si parte con una configurazione che lo prevede per poi cambiare la frequenza.

Qualcuno potrebbe obiettare del perchè c’è un PLL 2x per l’oscillatore interno quando tutte le frequenze possono essere ottenute anche senza PLL (es.: 32MHz è disponibile sia normalmente che come 16+PLL e così anche 8 può essere ottenuto normalmente sia come 4+PLL e così via). In realtà c’è la frequenza di 12MHz che non è un multiplo di una potenza di 2, per cui ci permette di avere anche 24MHz, che senza PLL non è disponibile, la quale, accoppiata al modulo divisore, ci fornisce un altro range di frequenze.

FEXTOSC imposta il tipo di oscillatore esterno. Le modalità che iniziano con EC prevedono una sorgente di clock sul pin CLKIN (RA7) e lasciano libero il pin CLKOUT (RA6) (oscillatori digitali che generano un’onda quadra):

  • ECH: oscillatore esterno alta potenza (da 8MHz non compreso in su. Fino a 32MHz per questo PICmicro)
  • ECM: oscillatore esterno media potenza (da 500KHz a 8MHz)
  • ECL: oscillatore esterno bassa potenza
  • OFF: non è presente nessun oscillatore esterno, per cui sia RA6 che RA7 possono essere utilizzati come normali IO
  • HS: quarzo ad elevato guadagno (da 4MHz non compreso in su)
  • XT: quarzo a medio guadagno (da 100KHz a 4MHz)
  • LP: quarzo a basso guadagno (questa modalità è realizzata per l’utilizzo di un quarzo da 32.768KHz)

Ricapitolando: nella Config1 impostiamo l’oscillatore da utilizzare all’avvio e ovviamente nulla vieta che l’impostazione debba rimanere quella della Config1 per cui possiamo benissimo impostare, ad esempio, l’oscillatore interno a 32MHz e quindi lavorare con quello tralasciando tutte le altre possibilità. Per cui tutto quello che segue alla maggior parte degli utenti potrebbe non interessare. Dopo aver definito la Config Word, infatti, non è necessario definire un NOSC, ma potremmo comunque voler sfruttare la funzione di Fail-Safe del Clock, intercettare l’interrupt che segnala il guasto e quindi cambiare oscillatore (oppure tenere quello interno a 1MHz settato di default dopo un guasto). Capite bene l’importanza di una funzione del genere: aumenta la sicurezza di funzionamento ed è indispensabili in applicazioni critiche.

Two Speed Clock Start-Up

Questo paragrafo non vale per il PICmicro che ho preso ad esempio e l’ho inserito per completezza.

Altri PICmicro (come il PIC16F887) hanno un’altra funzionalità: il Two Speed Clock Start-Up ovvero la partenza a due diverse velocità di clock. A cosa serve? Quando utilizziamo un quarzo esterno, questo necessita di 1024 oscillazioni per essere considerato stabile, per cui il tempo di attesa, a seconda dell’applicazione, può risultare lungo. I PICmicro che hanno questa feature fanno avviare il sistema dall’oscillatore interno e dopo che l’oscillatore esterno  si è stabilizzato, eseguono il clock switching. I PICmicro che hanno questa funzionalità hanno il bit IESO (Internal-External SwitchOver) che deve essere abilitato per poter sfruttare questa funzionalità. E’ chiaramente necessario un clock esterno costituito da un quarzo, altrimenti questa funzione non ha senso. Questi PICmicro hanno il bit SCS (System Clock Select) nel registro OSCCON (unico registro OSCCON) che al reset si trova a zero (valore da usare per sfruttare il two speed clock startup) e che permette di utilizzare il clock definito dalla config word. E’ anche presente un bit di sola lettura OSTS (Oscillator Startup Timer Status) che indica se il sistema sta funzionando col clock definito dalla config word (1) o quello interno (0).

Capirete che la funzionalità del Two-Speed Clock Start-up può anche essere eseguita sul PIC16F18877, che non è dotato di questa funzione automatica, semplicemente a mano: si parte col clock interno definito nella Word di configurazione e poi si esegue lo switch a quello esterno. In questo caso non c’è bisogno di controllare se l’oscillatore esterno è stabile o meno perchè sono tutte operazioni eseguite in automatico.

Schema a blocchi della circuiteria di Clock

Proseguiamo quindi con il clock di questo PICmicro, perchè ci sono altre possibilità. Arrivati a questo punto posso allegare il diagramma del clock preso dal datasheet, che ho evitato di mettere all’inizio per non spaventarvi, ma dato che ora alcune parole chiave dovrebbero essere chiare, così come la maggior parte del funzionamento del clock, diciamo che nel diagramma rimane ben poco da capire:

Nel diagramma possiamo individuare facilmente i blocchi che abbiamo già visto, ovvero:

  • l’oscillatore esterno, EXTOSC, che usa uno o due pin esterni
  • l’oscillatore secondario, SOSC, che usa due pin esterni
  • l’oscillatore interno a bassa frequenza (31KHz), LFINTOSC
  • l’oscillatore interno ad alta frequenza, HFINTOSC
  • Il blocco PLL diviso in due: il moltiplicatore 2x che può essere usato solo dall’oscillatore interno ad alta frequenza, e il moltiplicatore 4x che può essere usato solo dall’oscillatore esterno.
  • Il multiplexer costituito da COSC prende il settaggio di RSTOSC dopo un reset o quello impostato da NOSC successivamente all’avvio (e che affronteremo tra un po’) e che esegue la scelta della sorgente di Clock.
  • Il modulo FSCM (Fail-Safe Clock Monitor) che viene alimentato da LFINTOSC e monitora il clock in uscita. Anche se dal diagramma si vede che tale modulo è collegato all’uscita del multiplexer COSC e quindi sembra prendere qualsiasi frequenza, anche generata dai clock interni, in realtà funziona soltanto per il clock esterno (e quindi nemmeno per il SOSC che generalmente viene utilizzato per funzioni accessorie – vedi pag. 118 datasheet per approfondimenti).

Notiamo un altro blocco: MFINTOSC. Questo blocco è l’oscillatore interno a Media Frequenza. Non è in realtà un blocco che funziona in maniera autonoma (non è una vera sorgente di clock) ma solo un modulo divisore a impostazione fissa che prende il clock in uscita da HFINTOSC (qualunque esso sia) e genera in automatico due clock fissi: 500KHz e 31.25KHz che possono essere utilizzati per alimentare determinate periferiche (non viene usato per la CPU).

All’uscita del multiplexer abbiamo infine un postscaler CDIV (Current Divider / divisore attuale) che esegue una eventuale divisione del clock e normalmente si trova nell’impostazione 0000 ovvero clock 1:1 (non diviso, preso tal quale). Questa impostazione difatti non l’abbiamo nella word di configurazione ma può essere settata solo a runtime.

Impostare il Nuovo Oscillatore (NOSC)

Bene, ho detto che per avere un clock “semplice” (quello esterno definito dal quarzo o quello interno a 1MHz o 32MHz) non dobbiamo fare nient’altro che settare la Config1.

Ora mettiamo il caso che abbiamo bisogno di utilizzare l’oscillatore interno, ad esempio, 8 MHz (che non è possibile impostare nella word di configurazione): è a questo punto che viene utilizzato NOSC (New Oscillator). Il settaggio di NOSC si trova nel registro OSCCON1. Tale registro ha due gruppi di bit:

  • NOSC (bit 6,5,4) che serve per richiedere una nuova impostazione dell’oscillatore. I valori impostabili sono praticamente uguali a quello del settaggio dei bit RTOSC di Config1 tranne che per il valore 000 (oscillatore interno a 32MHz). Quest’ultimo difatti è un settaggio inutile a runtime perchè in ogni caso, richiedendo l’oscillatore interno (anche se è già quello corrente) bisognerà poi settare la frequenza in un altro registro, ed è quindi li che andremo ad impostare 32MHz se vogliamo. In aggiunta il settaggio 0b110 in NOSC, che in  RTOSC significa “oscillatore interno ad alta frequenza settato a 1MHz” qui invece assume il significato di “Oscillatore interno ad alta frequenza” e basta, senza 1MHz per quanto detto poc’anzi: è implicito che se stavamo utilizzando l’oscillatore interno ad alta frequenza e richiediamo un NOSC per lo stesso oscillatore, vogliamo cambiare la frequenza.
  • NDIV (bit 3,2,1,0 – sta per New Divider): imposta il postscaler, ovvero il divisore di frequenza (per maggiori informazioni sui valori impostabili vedete tabella 6-2 a pag. 121 del datasheet). Impostando, ad esempio, il valore 1:2, il clock subirà una divisione per 2. Dato che il divisore viene applicato prima di inviare il clock a CPU e periferiche capite che può servire per ottenere valori particolari necessari in determinate applicazioni.

Dopo aver impostato OSCCON1, se il nuovo settaggio prevede l’utilizzo dell’oscillatore interno ad alta frequenza, dobbiamo impostarne la frequenza nel registro OSCFRQ.

Tutto questo è fattibile soltanto nel caso in cui nella Config1 abbiamo abilitato il bit CSWEN che ci da la possibilità di poter scrivere nel registro OSCCON1 e quindi eseguire il clock-switching manuale.

Il registro OSCFRQ ha soltanto un gruppo di 3 bit chiamato HFFRQ la cui impostazione è la seguente:

quindi, nel caso in cui vogliamo utilizzare il clock interno ad 8MHz, indipendentemente da quello che abbiamo scritto nella Config1, nel nostro programma, all’avvio (ad esempio quando impostiamo gli IO) andremo ad impostare OSCCON1 e OSCFREQ.

Giusto per completezza: il valore di default dei bit HFFRQ in OSCFREQ all’avvio non è fisso ma vale 010 (4MHz) nel caso in cui nella config abbiamo settato come sorgente di clock HFINTOSC a 1MHz, oppure vale 110 (32MHz) nel caso in cui nella config 1 abbiamo scelto HFINTOSC a 32MHz.

Altri registri legati all’oscillatore

OSCCON2 : è un registro a sola lettura, contiene i bit COSC e CDIV che servono a vedere, rispettivamente, quali sono i settaggi attuali dell’oscillatore e del postscaler, il significato è uguale a quello di OSCCON1. In particolare quando entra in funzione il nuovo oscillatore, il valore di questo registro diventa uguale a quello di OSCCON1.

OSCCON3 : contiene vari bit:

  • CSWHOLD : se settato, fa in modo che quando il nuovo oscillatore definito da NOSC è pronto, di non farlo ancora entrare in funzione: quando questo accade si genere un’interrupt e via software dobbiamo intercettarlo, impostare a zero questo bit e copiare il contenuto di COSC in NOSC, a questo punto lo switch avrà effetto. Di default questa funzione non è impostata e lo switch avviene in automatico dopo che abbiamo finito di impostare il nuovo oscillatore e questo è pronto.
  • SOSCPWR : oscillatore secondario in alta (1) o bassa (0) potenza. Sul datasheet non è purtroppo specificato quali valori del quarzo esterno sui pin SOSCO/SOSCI sono ammessi per l’alta e bassa potenza. Posso solo dire che di default tale bit è zero e che in genere l’oscillatore esterno secondario è un quarzo da 32.768KHz utilizzato per le funzioni di Real Time Clock/Calendar o associato al Timer1 per contare appunto il tempo che passa.
  • ORDY : bit in sola lettura segnala se c’è uno switch dell’oscillatore in corso (0) oppure se OSCCON1=OSCCON2 ovvero il nuovo oscillatore sta già alimentando il sistema (e quindi COSC=NOSC e CDIV=NDIV).
  • NOSCR : bit in sola lettura. Un valore di 0 può indicare che non c’è uno switch di oscillatore in corso oppure che il nuovo oscillatore non è ancora pronto. Un valore di 1 indica che il nuovo oscillatore è pronto e c’è uno switch in corso.

OSCSTAT : (Oscillator Status) contiene lo stato di funzionamento (1=pronto, 0=non pronto) delle varie sorgenti di Clock. Ogni bit indica lo stato di un oscillatore (la parte finale della sigla, OR sta per Oscillator Ready):

  • EXTOR : Oscillatore esterno
  • HFOR : Oscillatore interno ad alta frequenza
  • MFOR : Oscillatore interno a media frequenza
  • LFOR : Oscillatore interno a bassa frequenza
  • SOR : Oscillatore esterno secondario
  • ADOR : Oscillatore RC che è possibile utilizzare esclusivamente col modulo di conversione Analogico/Digitale
  • PLLR : quando questo bit è zero vuol dire che o il PLL non è stato abilitato nella word di configurazione oppure che semplicemente non è ancora pronto

OSCEN : (Oscillator Manual Enable). Il contenuto di questo registro è zero di default: permette di abilitare manualmente (mettendo a 1 i singoli bit) i vari oscillatori. I bit a zero indicano che i vari oscillatori vengono messi in funzione automaticamente a seconda delle esigenze (ad esempio il NOSC entra in funzione quando lo settiamo), per cui nella gran parte dei casi non c’è l’esigenza di toccare questo registro.

OSCTUNE : (Oscillator Tuning). Contiene un unico gruppo di 6 bit (HFTUN) che serve a modificare leggermente verso l’alto (>32) o verso il basso (<32) il valore di calibrazione dell’oscillatore interno. E’ possibile quindi regolare l’oscillatore interno in un range del ±12% rispetto al valore centrale. La funzione è praticamente uguale a quella di cui abbiamo già parlato nel caso di OSCCAL. A meno che non abbiamo la necessità di ricalibrare il valore di fabbrica, generalmente questo registro non viene modificato e si lascia al valore centrale di default  0b00100000 (32) che corrisponde a: “utilizza il valore di calibrazione di fabbrica”. C’è un AppNote della Microchip (AN2030) che spiega come ricalibrare l’oscillatore interno utilizzando il modulo SMT (Signal Measurement Timer) e un oscillatore esterno calibrato.

Dato che la funzionalità è la stessa, azzardo dicendo che forse il nome di questo registro è stato cambiato rispetto ad altri picmicro (OSCTUNE anzichè OSCCAL) perchè “CAL” fa pensare ad una calibrazione vera e propria (ovvero un valore che in fabbrica si regola e rimane fisso: immaginate di regolare uno strumento a lancetta girando una vite per fare in modo che con un campione standard legga il suo valore preciso dopodichè blocchiamo la vite con della cera), mentre “TUNE/tuning” presuppone un aggiustamento fine di un valore già calibrato.

Active Clock Tuning

Questo paragrafo non vale per il PICmicro che ho preso ad esempio e l’ho inserito per completezza.

Sempre riguardo ad OSCTUNE, alcuni PICmicro possiedono l’Active Clock Tuning (ACT). Questo modulo esegue una regolazione continua del Clock interno prendendo possesso del registro OSCTUNE. La funzionalità viene gestita dal registro ACTCON e per eseguire la calibrazione continua viene utilizzato un quarzo esterno da 32.768KHz sui pin SOSCO/SOSCI oppure, sui PIC che lo permettono, il clock degli eventi sulla porta USB full-speed.

Abbiamo quindi finito di analizzare la parte dell’oscillatore. Adesso analizziamo la restante parte della Word di configurazione.

La word di configurazione

Abbiamo già visto la Config 1, che contiene esclusivamente i settaggi dell’oscillatore da utilizzare dopo un reset. Sul PIC16F18877 (e tanti altri) ci sono altre 4 Config Words.

Config 2 – Sistemi di supervisione

Contiene i flag dei sistemi di supervisione:

  • !DEBUG: Abilita (0) lo strumento di debug sui pin RB6/RB7. Normalmente questa funzione non è attiva e non è nemmeno impostabile dal tool integrato di MPLABX che genera la word. Viene gestita in automatico dalla toolchain di sviluppo.
  • STVREN: Abilita (1) il reset della CPU nel caso in cui si verifica uno Stack Overflow/Underflow. Se il sistema viene resettato per stack overflow, a parte che sicuramente abbiamo combinato un pasticcio nel programma, viene posto a 1 il bit STKOVF di PCON0. Il bit dello Stack Underflow  è STKUNF.
  • PPS1WAY: Questo picmicro ha la funzionalità PPS (Peripheral Pin Select) che permette a molte periferiche di utilizzare dei pin piuttosto che altri. Ne abbiamo già parlato tempo fa relativamente ai PICmicro a 16bit. Mettendo a 1 tale bit è possibile assegnare i pin alle periferiche una volta soltanto (normalmente è così che si fa: all’avvio impostiamo le periferiche e li rimangono). Se viene resettato è possibile riassegnare i pin alle periferiche e viceversa più di una volta durante il programma.
  • ZCDDIS: Serve a disabilitare (1) il circuito di Zero-Cross Detect, utilizzato dal modulo omonimo per funzioni analogiche. Se serve, si può comunque abilitare con il bit EN del registro ZCDCON. Altrimenti si può lasciare sempre attivo impostando ZCDDIS a zero (ma consuma corrente).
  • BORV: Serve a selezionare la tensione di Brown-Out (calo di tensione) che deve causare il reset (1=bassa: tipicamente 2.45V per questo particolare PIC, 0=alta: tipicamente 2.70V). Questa funzionalità serve ad evitare che i cali di tensione possano causare comportamenti anomali nel circuito/nel programma e quindi a mettere il dispositivo in uno stato conosciuto (reset). Quando il BOR è attivo, il POR (Power-On Reset) viene disabilitato.

    Il POR è il circuito di default su tutti i PICmicro che serve a tenere il sistema in stato di Reset quando la Vdd scende al di sotto di una certa soglia (più bassa di quella del BOR).

    Se un reset è stato causato da un calo di tensione rilevato dal BOR, tale evento può essere riconosciuto attraverso il bit !BOR del registro PCON0 (se invece il BOR non è attivo, entra in funzione il POR e l’evento è registrato dal bit !POR). E’ quindi possibile distinguere un reset causato dalla circuiteria di  POR (Power-On Reset, determinato dalla soglia di tensione minima ammissibile) e un reset BOR (Brown-Out Reset, determinato da una soglia un po’ più alta della minima e impostabile via software). Alcuni PIC (18F, 24F, dsPIC) hanno la possibilità di ulteriori settaggi per il BOR (è possibile scegliere tra più soglie di tensione). 

  • BOREN: serve ad abilitare o meno il reset per Brown-Out oppure a farlo controllare via software a seconda delle esigenze con il bit SBOREN del registro BORCON.
  • !LPBOREN: Serve per abilitare (0) il Brown-Out Reset a bassa potenza (LPBOR). Su alcuni PICmicro viene anche chiamato Deep Sleep BOR (DSBOR). E’ anche questa una modalità di reset per calo di tensione come il BOR. A differenza del BOR non ha più soglie impostabili ma solo una e generalmente più bassa, ha una tolleranza maggiore e reagisce in maniera più lenta. Ha il vantaggio che è utilizzabile anche in modalità Deep Sleep e che la sua circuiteria consuma un quantitativo di corrente molto basso (dai 5 ai 50nA) ed è quindi l’ideale per i sistemi a batteria.

Maggiori informazioni sulla circuiteria di Reset, il BOR e il LPBOR sono disponibili su MicrochipDeveloper nel capitolo dedicato al reset. Ci sono anche alcuni vecchi documenti che parlano del Brown-Out: Comparing PIC microcontroller Brown-Out Reset options e dei tipi di reset: PICmicro mid-range MCU family – Section 3: Reset ma a mio avviso meglio consultare il sito MicrochipDeveloper perchè è più aggiornato.

  • !PWRTE: serve ad abilitare (o) il Power-Up Timer. Questo Timer serve a consentire alla Vdd di stabilizzarsi dopo l’avvio (POR) o dopo un Brown-Out Reset (BOR). Se abilitato, all’avvio o dopo un BOR mantiene la CPU in stato di Reset per 64mS. E’ quindi un ritardo aggiuntivo che viene applicato dopo l’uscita da una condizione POR o BOR.
  • MCLRE: se 0 fa in modo che il pin RE3, in genere utilizzato per la funzione di Master Clear (MCLR), sia utilizzato come ingresso digitale (ricordo: RE3 può essere utilizzato esclusivamente come input, difatti anche il relativo bit del registro tristato, TRISE3, non è implementato e viene letto sempre come 1). Nel caso in cui sia abilitata la funzionalità di programmazione a bassa tensione (LVP) questo settaggio è ininfluente: RE3 funziona sempre come MCLR. Utilizzando il pic di MCLR come ingresso perdiamo in pratica la funzionalità di Reset manuale dall’esterno (che generalmente eseguiamo col pulsante).

 

Config 3 – Windowed Watchdog

Contiene i flag di impostazione del “Watchdog con finestra” (Windowed Watchdog). Di cosa si tratta? Conosciamo il Watchdog Timer: è un timer che, se abilitato, esegue di continuo un conteggio indipendemente dal resto del programma e ogni tanto, all’interno del programma, con l’istruzione assembler CLRWDT dobbiamo resettarlo perchè se giunge al termine del conteggio (overflow) causa il reset del dispositivo (controllabile dal flag !RWDT di PCON0).

E’ una funzione di sicurezza che serve ad impedire che errori sconosciuti nel nostro software mandino il programma in loop tenendolo bloccato: in questo caso l’istruzione CLRWDT non viene eseguita (perchè chiaramente l’abbiamo messa al di fuori di un ciclo o comunque in un posto “sicuro”) e il Watchdog Timer termina il conteggio (condizione di Time-Out). Il Windowed Watchdog Timer aggiunge un ulteriore livello di sicurezza: l’istruzione CLRWDT viene accettata esclusivamente in condizione di TimeOut entro un certo tempo (determinato dalla finestra: la finestra si “apre” in condizione di timeout). Nella Config 3 si sceglie quindi la sorgente di clock del Watchdog Timer (WDTCCS), il tempo percentuale di apertura della finestra (WDTCWS), la modalità operativa (WDTE) e il periodo/prescaler (WDTCPS). Per disabilitare il Watchdog Timer basta mettere a zero i bit WDTE: le altre impostazioni del Watchdog Timer saranno chiaramente ininfluenti.

Config 4 – Gestione Memoria Flash – Il Flag LVP e il pin PGM

Contiene i flag di impostazione della memoria flash:

    • LVP: Se 1 abilita la modalità di programmazione a bassa tensione e di conseguenza il pin RE3/MCLR/VPP non può essere usato come ingresso digitale. La modalità di programmazione a bassa tensione prevede che sul pin VPP sia inviata una tensione di 5V piuttosto che 13V. E’ importante sapere che se è attiva la modalità di programmazione a bassa tensione (cioè abbiamo già programmato un PICmicro con questo flag settato), non è possibile azzerare questo flag continuando ad utilizzare questa modalità di programmazione: per cancellarlo dobbiamo mandare la tensione di 13V su VPP (la modalità ad alta tensione è difatti comunque sempre attiva).

La nota interessante è che, su questi PIC, non è più presente il pin PGM (che era una condizione di AND per abilitare la modalità di programmazione LVP): il programmatore invece deve inviare una sequenza-chiave di 32 bit che, una volta riconosciuta dal PIC, abilita la programmazione a bassa tensione. (La chiave è la parola “MCHP” in ASCII).

  • SCANE: disabilita (0) il Memory Scanner. Questi PICmicro hanno a bordo un modulo CRC (Cyclic Redundancy Check) che implementa in hardware un generatore di Checksum configurabile via software. Per accelerare il processo viene utilizzato il Memory Scanner che ha la funzione di fornire i dati su cui eseguire il Checksum al modulo CRC. Tale modulo può anche essere utilizzato per rilevare errori nella memoria flash del dispositivo.
  • WRT: disabilita (11) la protezione da auto-scrittura della memoria Flash oppure protegge determinate aree. L’autoscrittura è una funzione, ad esempio, utilizzata dai bootloader che sono piccoli programmi che risiedono nella memoria flash che riprogrammano altre parti di memoria flash.

 

Config 5 – Protezione

contiene i flag per la protezione del codice:

  • !CPD : se 1 disabilita la protezione della memoria dati EEprom (sui datasheet viene anche chiamata anche NVM che sta per Non-Volatile Memory). E’ l’area dati in cui normalmente salviamo le variabili che vogliamo non vadano via dopo una mancanza di alimentazione: impostazioni, salvataggi ecc
  • !CP : se 1 disabilita la protezione della memoria Flash. E’ l’area di memoria dove risiede il programma. Serve ad evitare che quando sviluppiamo un’applicazione e la distribuiamo, possano clonare il circuito e quindi scaricare il programma dal PICmicro.

A questo punto, dato che siamo in tema di approfondimenti e stiamo parlando di protezione… :

Come sproteggere un PICmicro protetto da lettura per leggerne l’HEX

L’abilitazione delle protezione non implica che il PICmicro non possa più essere riscritto, come molti credono: può essere sempre cancellato e riscritto. Quando sono attive le protezioni, il programmatore piuttosto non è in grado di eseguire il download del firmware dal PICmicro verso il PC (ovvero ottenere l’HEX dal PICmicro protetto). Dato che in tantissime persone mi chiedono come poter leggere il firmware di un PIC protetto ho pensato di aggiungere questo paragrafo all’articolo come chiarimento definitivo.

L’unico sistema realmente valido in questi casi, che può portare a qualche risultato ma è alla portata di pochissimi, è quello di eseguire un decapping del chip (ovvero rimuovere la plastica dal circuito integrato per portare alla luce il Die), mascherare l’area flash/eeprom con qualcosa di impenetrabile dalla luce e applicare una luce UV per cancellare la sola area di configurazione (si usano gli UV per le vecchie Eprom, che sono UV-C e quindi che hanno una lunghezza d’onda di ∼250nm, gli stessi normalmente utilizzati per sterilizzazione).

PIC12C508 decappato – Immagine dalla pagina del Dottor Sergei P. Skorobogatov

Attualmente (intendo con i PICmicro prodotti da una decina, o forse più, di anni a questa parte) questa operazione non è facilissima perchè internamente l’area di configurazione è coperta da protezioni metalliche. Perchè mai proteggono quest’area? Appunto per evitare (diciamo piuttosto: rendere più difficoltosa) questa operazione estrema dato che sui PIC molto vecchi (come quelli con memoria Cmos) non pensarono a mettere questa protezione e l’operazione risultava leggermente più semplice.

Gli UV riportano le eprom in condizione di bit tutti settati a 1, e quindi i bit di protezione vengono disabilitati. Solo a questo punto è possibile agganciare il programmatore e leggere il programma senza problemi.

Questa è chiaramente un’operazione alla portata di pochissimi esperti nel mondo perchè richiede strumentazione particolare sia per eseguire il decapping senza rovinare il Die, sia per eseguire tutte le operazioni successive che , tra le altre cose, richiedono un buon microscopio elettronico. E io, anche se adoro questi dispositivi, mi dispiace non posso farlo, non chiedetemelo più.

Pare esistano alcune ditte che eseguono questa operazione ma i costi sono davvero eccessivi (si parla di $1000 a chip senza nemmeno la certezza di riuscire a recuperare il programma e hanno anche bisogno di più di un circuito integrato con lo stesso programma). E no, non conosco queste ditte e non so darvi indicazioni più approfondite.

Altri dicono di essere riusciti a cancellare la word di configurazione, e quindi successivamente leggere il programma, mediante sistemi non invasivi fornendo spike ad alta tensione, controllati, sul pin VPP. Anche se questa modalità può funzionare, dubito che poi il PICmicro sarebbe riutilizzabile e in aggiunta è più facile che venga danneggiato prima di riuscire a leggerlo: non c’è una scienza esatta che dice quale tensione fornire, per quanto tempo. Sono più convinto che chi ci è riuscito è stato solo molto fortunato.

A questo link c’è una pagina con gli esperimenti fatti da un certo Dottor Sergei P. Skorobogatov dell’università di Cambridge che sarebbe riuscito molti anni fa ad eseguire attacchi invasivi e non sui PICmicro riuscendo a leggere il codice. Nella pagina fa anche riferimento ad un dispositivo da lui progettato appositamente per crackare i PICmicro in maniera non invasiva, di cui non ci sono informazioni nè foto dettagliate. Ad ogni modo stiamo parlando di dispositivi ed esperimenti di 20 anni fa, quando non c’era tutta questa attenzione verso i sistemi di protezione anche perchè mancava la disponibilità odierna di programmatori e strumentazione cinese a basso costo e soprattutto la facilità con cui procurarseli.

C’è un altro post, più interessante del precedente, che spiega in dettaglio l’operazione di cui vi ho parlato prima (il decapping seguito dalla cancellazione tramite UV della word di configurazione): è possibile trovarlo qui. Consiglio di leggere la pagina che ho linkato perchè è davvero molto intessante soprattutto perchè sono presenti delle fotografie al microscopio elettronico del Die del PIC18F1320 su cui è stato eseguito l’esperimento. Stiamo comunque parlando di un dispositivo di una decina di anni fa anche se, stranamente, è ancora in produzione.

Maggiori informazioni sulla modalità di programmazione dei PIC sono contenute nei documenti appositi relativi alle specifiche di programmazione, disponibili in questa pagina e divisi per famiglia. In particolare, per il PIC16F18877 che ho preso ad esempio, il documento è questo. Per le specifiche della programmazione ICSP c’è un altro documento che si chiama In-Circuit Serial programming guide che, anche se vecchio (fa riferimento a dispositivi non più esistenti) è comunque valido.

Esempi

Alla fine di questo articolo è possibile scaricare un esempio per PIC16F18877 che illustra l’impostazione del Clock. Da config word viene abilitato il clock-out, per cui l’esempio è realizzato per chi ha un oscilloscopio. Bisogna collegare una sonda su RA6 per osservare la forma d’onda che, ricordo, vale FOSC/4, per cui se impostiamo il clock interno a 8MHz, su RA6 vedremo un segnale a 2MHz. L’esempio è unico, leggete i commenti nel codice. Non ho fatto un esempio col clock esterno perchè è banale: i passaggi sono praticamente identici, basta impostare l’oscillatore esterno da config word. Ho già spiegato come si genera la word di configurazione in un precedente articolo.

Clock interno a 1MHz

E’ l’esempio di default: non dovete modificare nulla. Il clock interno è definito a 1MHz da config word:

18
#pragma config RSTOSC = HFINT1

Dato che nell’esempio faccio anche lampeggiare un led collegato su RA0 e utilizzo i delay inclusi in XC8, bisogna definire la macro _XTAL_FREQ impostandola al valore dell’oscillatore utilizzato espresso in Hertz:

59
#define _XTAL_FREQ 1000000

In questo esempio non viene definito un nuovo oscillatore. Su RA6 dobbiamo osservare un’onda quadra a 1MHz/4=250KHz:

Clock interno a 32MHz

Cambiate la riga 18 per avere il clock interno a 32MHz:

18
#pragma config RSTOSC = HFINT32

Questa impostazione è quella che genera i 32MHz senza l’utilizzo del PLL. Dovete modificare anche l’impostazione di _XTAL_FREQ per definirla come 32MHz:

65
#define _XTAL_FREQ 32000000

su RA6 dobbiamo osservare un’onda quadra a 32MHz/4 = 8MHz:

Come vedete l’onda non verrà fuori proprio quadra: è molto disturbata. Inizialmente pensavo fosse un effetto induttivo derivante dal PCB, ma anche con i pin in aria libera è lo stesso. In aggiunta la forma d’onda mi viene fuori praticamente uguale sia con 32MHz che con 16MHz+PLL 2x, con varie sonde, attenuazioni ecc. E’ quindi probabilmente un difetto di tutta la struttura del PICmicro, ma potrei sbagliarmi, se qualcuno fa altre prove e ha risposte, sono graditi commenti. Potete osservare che man mano che si sale con la frequenza dell’oscillatore interno, l’onda da quadra assume sempre di più questa forma.

Clock interno a 8MHz

La config word possiamo impostarla come vogliamo dato che 8MHz non è ottenibile allo start-up e dovremo ricorrere al nuovo oscillatore. Modifichiamo la macro _XTAL_FREQ solo per ottenere i delay corretti:

#define _XTAL_FREQ 8000000

e ora abilitiamo il nuovo oscillatore (togliete il commento alle righe 87,88,89):

87
88
89
OSCCON1bits.NOSC=0b110; // nuovo oscillatore: interno HF, poi dovrò usare OSCFRQ per impostare la frequenza
OSCCON1bits.NDIV=0; // non voglio dividere la frequenza (1:1)
OSCFRQ=0b011; // Oscillatore interno a 8MHz

su RA6 osserveremo:

Come vedete il segnale comincia a deformarsi, non è più un’onda quadra come con FOSC=1MHz ma assume una forma quasi trapezoidale, sebbene non sia ancora come quella a 32MHz. Le impostazioni che ho scritto nell’esempio chiaramente valgono solo con il PLL disattivato. Se abilitiamo il PLL per l’oscillatore interno (con RSTOSC = HFINTPLL), allora per ottenere gli 8MHz dobbiamo selezionare 4MHz. Potete provare voi gli altri valori di frequenza per l’oscillatore interno. Nella config non importa cosa impostiamo dato che poi andremo a definire un nuovo oscillatore. Possiamo anche divertirci a definire il divisore (OSCCON1.NDIV) per ottenere altri valori di frequenza.

Downloads

Nell’esempio allegato c’è solo il main. Dovete definire voi il progetto in MPLABX come ho spiegato nel primo articolo del Nuovo corso di programmazione PICmicro in C scegliendo il PIC16F18877 e quindi includere questo file oppure fare  copia/incolla.

Esempio Clock PIC16F18877 (493 download)
Se questo articolo ti è piaciuto, condividilo su un social:
Se l'articolo ti è piaciuto o ti è stato utile, potresti dedicare un minuto a leggere questa pagina, dove ho elencato alcune cose che potrebbero farmi contento? Grazie :)