- Il problema dell' R-M-W nei PIC16
- Come evitarlo
- Note
Il problema dell' R-M-W
Agli utilizzatori dei PIC dovrebbe essere noto il problema di latch
indesiderato dello stato di un I/O digitale, chiamato R-M-W Problem.
Esso si manifesta quando si cerca di modificare due o più bit dello stesso
port, agendo con
istruzioni successive, ad esempio:
bsf
PORTB, 1
bsf
PORTB, 2 |
ne risulta la possibilità che il bit 0 sia settato, ma che il bit 2 resti a
zero.
Vediamo di capire perchè questo può succedere.
Per poter avere le idee ben chiare, però, occorre conoscere come funziona un I/O.
Come funziona un I/O
Questa è la struttura semplificata di quanto sta dietro un pin di I/O
digitale nei Baseline e Midrange (PIC10/12/16).
|
Il Data Bus è collegato a:
- un latch dati (Data Latch)
- un latch di direzione (TRIS Latch)
- un gate di lettura (RD Port)
Il Data Latch è collegato al pin attraverso un buffer, costituito
da MOSFET a canale P e N. Il buffer è abilitato dal livello 0 in
uscita dal TRIS Latch ed è disabilitato quando è 1;
quindi questo registro determina se il livello logico scritto nel Data Latch viene
trasferito o meno al pin.
Il valore contenuto nel TRS Latch e nel Data Latch viene prelevato dal
bus dati rispettivamente quando si indirizza una scrittura al port (o
gpio) e al TRIS (segnali WR Port e WR Reg).
Il gate di lettura collega il pin direttamente con il bus dati,
trasferendovi la tensione presente sul pin, la quale deve essere
ovviamente a livello logico 0 o 1 per essere trattata come dato. |
Va considerato che i latch sono memorie di genere RAM, ovvero mantengono il loro contenuto
fino a che è presente la tensione di alimentazione o vengono riscritte.
Osserviamo anche il fatto fondamentale che il contenuto del Data Latch e del
TRIS Latch possono essere
scritti, ma non riletti, in quanto non esiste alcun gate che permette questo.
Si deve osservare, quindi, che:
- una scrittura sul registro PORT scrive il Data Latch,
- una lettura del PORT legge lo stato reale del pin, non il valore conservato nel
latch.
Anche se questa parrebbe una differenza ininfluente, è invece proprio
questa situazione a creare il problema, assieme al meccanismo che i PIC
implementano per modificare un registro di I/O.
Per una comprensione migliore, schematizziamo ulteriormente le
funzioni:
Da qui deriva che l' impostazione dell'I/O come uscita si riferisce al
fatto che il buffer è collegato o meno al pin e che il contenuto del Data
Latch viene riflesso o meno all' esterno.
Ne consegue che possiamo avere diverse situazioni a seconda dello
stato dei bit del Tris Latch:
TRIS |
Funzione |
PORT |
Note |
1 |
Ingresso digitale |
scrittura |
Scrivendo un dato in PORTx o GPIO, il dato resta immagazzinato nel
Data Latch fino a nuova scrittura o a mancanza di alimentazione.
Non c'è nessun effetto sul pin perchè il Tris=1
disabilita il buffer
di uscita |
lettura |
Leggendo PORTx o GPIO, si passa direttamente al bus dati il valore
logico applicato al pin |
0 |
Uscita digitale |
scrittura |
Tris=0 abilita il buffer di uscita. Scrivendo un dato in
PORTx o GPIO, il dato viene immagazzinato nel Data Latch fino a nuova
scrittura o a mancanza di alimentazione e passato al buffer del pin. |
lettura |
Leggendo PORTx o GPIO, si passa direttamente al bus dati il valore
logico applicato al pin |
Ricapitoliamo le conseguenze:
- Posso scrivere qualsiasi valore nel registro PORTx
o GPIO, ma
questo valore viene riflesso sul pin corrispondente solamente se il buffer di
uscita è abilitato da TRIS=0.
Con TRIS=1
è comunque possibile la scrittura del Data Latch, che ha come effetto solamente il
caricamento del dato nel latch; se carico
un dato nel registro GPIO, ad esempio con clrf
GPIO questo valore non va perso, ma resta nel latch fino alla
caduta della tensione di alimentazione o ad una nuova scrittura. Nel momento in cui portassi TRIS=0
questo valore verrebbe riflesso sul
pin fisico.
- Per contro, è molto importante capire che la lettura di PORTx
o GPIO non
legge lo stato del Data Latch, ma il valore effettivo che il pin assume nel
preciso momento della lettura e che, come vedremo, può essere diverso da
quello del Data Latch.
La lettura può essere effettuata indipendentemente dal valore impostato
nel TRIS, dato che, come
abbiamo appena visto, l'operazione consiste nella abilitazione del gate di
lettura e nel trasferimento del dato sul bus.
Come può crearsi il problema R-M-W
Vediamo il meccanismo attraverso cui si forma il problema R-M-W.
Dallo schema di principio qui sopra, vediamo che tra il latch dati e il pin
è interposto un buffer totem pole a MOSFET. Questo buffer è in grado di
fornire una corrente di 25 mA e i semiconduttori hanno una
resistenza interna di conduzione, anche se minima.
25 mA non è una corrente immensa, ma è più che sufficiente per gli scopi per cui
è stato progettato il chip. Però è ben possibile applicare al pin carichi
non proprio ideali, come ad esempio qualcosa di capacitivo.
|
Sappiamo che un condensatore scarico è, al momento dell' applicazione della
tensione, l' equivalente di un corto circuito e che per completarne la
carica occorre un tempo che dipende dall' impedenza della sorgente di
tensione
e delle capacità.
Quindi, portando a livello 1 uno dei pin della figura a fianco, il LED si
accenderà con un ritardo proporzionale alla capacità del condensatore, in
quanto questo, nella sua carica, shunterà gran parte della corrente al
momento iniziale.
Questo fa si che, misurando con uno strumento la tensione sul pin, ci si
troverà con una curva tensione-tempo tipica della carica di un
condensatore. |
Dal momento in cui è applicata tensione al momento in cui il condensatore è
caricato al 100% trascorre un tempo determinato dalla impedenza della
sorgente (in questo caso il buffer del pin) e dalla capacità del
condensatore.
Quanto maggiore è la capacità del condensatore, tanto maggiore sarà
il tempo necessario per la stabilizzazione della tensione. La resistenza R è
quella di conduzione dei MOSFET del buffer.
Può capitare che il carico capacitivo del pin sia tale da richiedere alla
tensione un tempo
maggiore di quello del ciclo delle istruzioni (che, ricordiamo, a 20
MHz è di soli 200 ns, mentre la carica di una capacità potrebbe richiedere micro
o milli secondi) per arrivare a livello 1. |
|
E se le istruzioni si succedono ad una velocità superiore a quella di
variazione della tensione del pin, si verifica una discordanza tra il
valore impostato nel Data Latch e quello reale presente sul pin stesso.
R-M-W
Occorrono ancora due considerazioni.
La prima riguarda questo fatto: eseguendo una istruzione di lettura o
scrittura diretta ad uno specifico bit di un port, come bsf
PORTB,0 oppure btfsc
PORTB,0 non si accede al solo bit indicato, ma a TUTTI i bit che fanno
parte del port.
Quindi, ad esempio, btfsc
PORTB, 0 non legge e verifica il solo bit 0, ma legge
l' intero port a cui appartiene il bit, che poi sarà il solo ad essere
considerato. Questo avviene
perchè non è possibile, data la struttura dei chip, leggere o scrivere un
singolo bit, ma occorre passare attraverso il bus dati, che ha ampiezza di 8 bit,
e che accede a
tutti i bit del port contemporaneamente.
In questo senso gli schemi di principio visti all'inizio, possono essere
fuorvianti; occorre pensare il singolo bit come parte di un port. Questa struttura costruttiva e logica è quella che fa si che gli I/O,
di conseguenza, siano
raccolti in gruppi logici (PORT o GPIO) con ampiezza massima di 8 elementi.
Così, se il microcontroller ha meno di 8 I/O, ad esempio 6 come nei
PIC12Fxxx, il registro GPIO sarà comunque composto da 8 bit, di cui i due
più alti non sono implementati. Per contro, se il chip dispone di più di 8
I/O, essi saranno raggruppati in più PORT, ciascuno di 8 elementi al
massimo. Così, nel 16F84, dove abbiamo disponibili 13 I/O, li troviamo
raccolti in due PORT, uno da 8 e l'altro da 5 (che, comunque, è un byte dati
di 8 bit di cui i tre più alti non sono implementati).
Il secondo punto riguarda il meccanismo di accesso e scrittura dei PORT.
Esso si basa sul clock interno che è pari a 1/4 della frequenza
dell'oscillatore principale.
L' operazione di modifica di un bit (o di un byte) avviene, come tutte
le istruzioni ad un ciclo, utilizzando 4 impulsi del clock primario. Così, se il quarzo dell' oscillatore è 4 MHz, occorreranno 4 impulsi
per completare una istruzione, il cui ciclo effettivo sarà 1/4 del clock,
ovvero 1 MHz (Fosc/4).
Il clock principale (clock interno RC o esterno) è diviso per quattro per generare quattro
impulsi non sovrapposti, cioè Q1, Q2, Q3 e Q4. Il program counter è incrementato
ad ogni Q1. Un ciclo di istruzione è costituito dai quattro cicli:
l'istruzione di viene recuperata ed eseguita in una pipeline che tratta una
istruzione mentre decodifica ed esegue la precedente. Una istruzione che
impegna in esecuzione un solo ciclo, è completata nelle quattro fasi, a cui
si sovrappone nella pilpeline il fetch della istruzione successiva. (Fanno
eccezione istruzioni
che richiedono la modifica del PC, come goto e
return, che richiedono due cicli in
quanto la pipeline, che aveva già immagazzinato l' indirizzo dell' istruzione
successiva, deve essere ricaricata con il giusto valore imposto dall'
istruzione). In
particolare, la memoria dati viene letta durante il Q2 e scritta durante il Q4.
Quindi, dietro alla semplice bsf PORTB,0 troviamo,
non vista, una azione complessa:
- viene abilitato il gate di lettura e tutto lo stato dei pin del gruppo a
cui il pin appartiene (in questo caso PORTB) viene passato al bus dati
- questo byte viene salvato in un registro interno, non accessibile se non
dai meccanismi della CPU
- il bit indicato (in questo caso il bit0) viene modificato nel registro
interno
- il registro viene copiato nel Data Latch
Da qui deriva la dicitura R-M-W:
- R - lettura del port e copia in un registro provvisorio
interno
- M - modifica del valore letto con quello voluto, sempre
nel registro provvisorio
- W - copia del registro provvisorio modificato nel Data
Latch
Facciamo un esempio pratico: vogliamo portare a 1 i bit 4 e 5 di
GPIO.
Ai pin sono collegati carchi esterni, ad esempio due LED, ma al
GP5 è collegata anche una certa
capacità. La cosa che parrebbe più ovvia è:
;
set IOpin
bsf GPIO,
GP5
bsf GPIO,
GP4 |
ma questa può non essere una buona soluzione. Tenendo presente quanto scritto
prima, vediamo perchè.
Immaginiamo per semplicità che GPIO sia inizialmente tutto a 0.
La prima linea:
bsf
GPIO, GP5
esegue queste operazioni
|
-
Q1: l'
istruzione bsf
è decodificata
-
Q2: viene
letto lo stato attuale del
GPIO=
00000000
e questo valore è
salvato in un registro provvisorio
-
Q3: viene
modificato il bit 5 portandolo a 1; il registro provvisorio
conterrà 00100000
-
Q4: il
registro provvisorio viene copiato nel
Data Latch
Questa operazione è
completata in un ciclo, che a 4 MHz dura 1 microsecondo.
Il condensatore esterno
collegato al pin comincia a caricarsi alla
massima corrente erogabile dal pin e richiede un certo numero di
microsecondi, ad esempio 3 us.
Intanto il processore non
si è certo fermato in attesa della carica del condensatore, ma sta
provvedendo all' esecuzione dell' istruzione bsf
successiva: |
bsf
GPIO,
GP4
che è 00000000
, dato che il bit 5 non ha ancora raggiunto il livello1 e questo valore è salvato
nel registro provvisorio che varrà 00000000
Q3: viene modificato il
bit 4 portandolo a 1; il registro provvisorio conterrà 000 10000
Q4: il registro
provvisorio viene copiato nel Data Latch
Il LED collegato a
GP4 si accenderà, mentre il LED a GP 5
resterà spento !!!
Cosa è successo ?
-
Q2 ha letto lo stato reale di GPIO dopo
pochi nano secondi dalla fine dell' istruzione precedente.
-
Il condensatore si sta ancora caricando ed il suo
livello non è ancora arrivato a 1 (vedi curva nel diagramma
precedente).
-
Viene letto non il valore salvato nel Data Latch,
ma il livello logico sul pin in quel preciso istante e questo
livello non è ancora a 1 !!!
-
Di conseguenza, la modifica in Q3 non opera su 001000000,
come ci si aspetterebbe, ma su 00000000
(dato che lo stato di bit 0 non è ancora 1). Quindi modifica
comporta 00010000
e non 00 110000
ed è questo il valore che viene scritto nel
Data Latch
Il pin GP5
ha fatto un tentativo di andare a livello 1, ma il successivo
bsf
lo ha
cancellato: il settaggio del
bit 5 è sparito!!!
Questo accade anche se modifichiamo un solo bit, ad esempio:
;
impulso sul bit 5
bsf GPIO,
GP5
bcf GPIO,
GP5 |
dato che succede quanto segue:
bsf GPIO,
GP5
- viene abilitato il gate di lettura e tutto lo stato dei pin del GPIO
viene passato al bus dati
Dato che il livello logico al pin 5 è a 0, la lettura rende 00000000
- questo byte viene salvato nel registro interno, che contiene ora 0000000
- il bit 5 vene modificato nel registro interno, che ora vale 00100000
- il registro viene copiato nel GPIO,
ovvero scritto nel latch dati che ora viene modificato con il valore 00100000
Se il bit 5 non ha collegato capacità sensibili, il livello al pin sale a
1 in un tempo molto breve (ns).
Se però al pin è collegata una certa capacità che determina un tempo di
oltre 1us, la seconda istruzione produce questo:
bcf GPIO,
GP5
- viene abilitato il gate di lettura e tutto lo stato dei pin del GPIO
viene passato al bus dati
Dato che il livello logico al pin 5 non è ancora arrivato a 1, la lettura
rende 00000000
- questo byte viene salvato nel registro interno, che contiene ora 0000000
- il bit 5 vene azzerato nel registro interno, che ora vale 00000000
- il registro viene copiato nel GPIO,
ovvero scritto nel latch dati che ora viene modificato con il valore 00000000
Il livello logico del pin non cambia!!!
Se si è usata questa sequenza per dare un breve impulso sul pin, ad esempio
per uno strobe di una periferica e la capacità i ingresso di questa e dei
collegamenti genera ' errore, non si avrà alcun impulso in uscita.
Quindi, nei Baseline e nei Midrange, istruzioni consecutive di modifica dello stato degli I/O
di uno stesso port devono essere
evitate ed occorre un approccio diverso.
Alcune considerazioni
R-M-W problem si presenta
solo
nei casi in cui il carico
capacitivo è troppo elevato rispetto alla cadenza di modifica imposta sul
port, o, più
in generale, quando il carico applicato al pin è eccessivo.
Casi possibili sono:
- carico capacitivo, ad esempio
rete RC per eliminare la componente variabile da un segnale
- pilotaggio diretto di gate di
grossi MOSFET
- carico induttivo collegato
direttamente
- corrente eccessiva, ad es. LED senza resistenza di
limitazione
- cablaggi in uscita lunghi e
disordinati
Il problema è proporzionale alla frequenza del clock. A 20MHz una
istruzione è eseguita in 200ns (200 miliardesimi di secondo!) e quindi si
risente l' effetto anche di piccole capacità.
Ovvero, i due fattori chiave sono la capacità del carico e la frequenza di
commutazione.
Quindi, nel classico comando di porte
logiche, basi di transistor per piccoli segnali ,
Logic Level MOSFET, operazionali o buffer del genere
ULN2003 o simili,
usati per pilotare
display o relè o altri carichi pesanti che superano i 25mA della
capacità diretta del pin,
oppure anche comandando
LED direttamente collegati al pin
con la relativa resistenza di limitazione, entro i limiti di corrente
indicati, il problema,
in genere non si verifica
e non occorre applicare modifiche al programma.
Ugualmente è difficile incontrare problemi comandando piccoli relè
reed,
display LCD e simili altri carichi a bassa capacità anche
se collegati con brevi cablaggi ordinati.
Per il pilotaggio di MOSFET è
consigliato comunque l' uso dei buffer specifici (MCP1404 e simili) che elimina completamente ogni possibilità di insorgenza del problema
anche con componenti non Logic Gate.
Da osservare che il comando di MOSFET in PWM con il pin di uscita del
modulo CCP/ECCP non comporta il problema, dato che il pin è
azionato singolarmente dal modulo. Non è detto, però, che una
azione contemporanea di altri bit sullo stesso port non crei
situazioni inaspettate, anche se non
risultano segnalazioni in tal senso.
Si può concludere che, in
generale, onde
evitarsi problemi, è particolarmente opportuno ,
per prima cosa,
collegare ai pin solamente carichi
"regolari", utilizzando quanto possibile buffer, che eliminano il
problema.
Quando ciò non è
possibile per qualsiasi ragione, e, comunque, in ogni caso in cui si
comandino uscite contemporanee di bit sullo stesso port,
è
sempre il caso di verificare sufficientemente il comportamento
del proprio specifico circuito ed agire di conseguenza.
Nel dubbio, meglio
implementare comunque
una soluzione software
piuttosto che rischiare di trovarsi nei guai,
durante il funzionamento, per il mancato comando di un pin.
E questo, non solo per
realizzazioni destinate all' uso al di fuori del laboratorio, ma anche
nelle sperimentazioni, onde abituarsi a considerare ogni aspetto dei
problemi collegati alla gestione di carichi sulle uscite del
microcontroller, dato che,
a parte casi assolutamente straordinari, l' aggiunta delle istruzioni
necessarie alla correzione del problema R-M-W non comporta significativi
rallentamenti del programma, occupando ben pochi cicli di istruzione.
Vediamo allora come agire.
Missione I/O sicuro
Microchip consiglia diverse soluzioni.
Soluzione 1:
Mantenere la capacità del carico sufficientemente bassa da non provocare
l' effetto ritardo.
Il parametro D090 del foglio dati "output-high voltage" dichiara una
tensione minima di uscita di Vdd-0.7V per una corrente di 3 mA e il
parametro D080 "output-low voltage" dà una tensione di 0.6V per
assorbire una corrente di 8.5 mA. Questi livelli di tensione assicurano
un corretto funzionamento delle logiche di ingresso dei pin, indipendentemente
dal fatto che siano TTL o trigger.
Inoltre i parametro D101 limita a 50pF la capacità del carico per poter
rispettare le temporizzazioni corrette. Va notato che questi parametri sono dipendenti dalla temperatura, il che vuol
dire che non vanno considerati come valori di sicurezza generale, ma come limiti dai
quali prendere una distanza di sicurezza.
Se il carico è adeguato, la sequenza di istruzioni:
;
set IOpin
bsf
PORTB, 0
bsf
PORTB, 1 |
funzionerà sicuramente, senza problemi, dato che
il tempo di ritardo del bit 0 sarà molto minore del ciclo di istruzione.
In sostanza, basta collegare ai pin carichi adeguati, non
capacitivi (come possono essere gate di MOSFET, cavi lunghi, ecc.) e, dove
sia richiesto comandare tali carichi, inserire un buffer.
Soluzione 2:
Usare la tecnica dello shadow-register.
Per ogni registro di uscita, si riserva in memoria un registro RAM che serve
da copia e si usa questo registro-ombra per le modifiche.
Ad esempio:
;
set IOpin
bsf
PB_Shadow,RB0
;
set
bit 0 nel
registro copia
movf
PB_Shadow,W
;
copia il registro ombra
movwf PORTB
;
nel PORTB
bsf
PB_Shadow,RB1
;
set bit 1
nel registro copia
movf
PB_Shadow,W
;
copia il registro ombra
movwf PORTB
;
nel PORTB |
Questo funziona in ogni caso ed è la soluzione generalmente usata, ma ha, per contro, l' aumento delle
istruzioni e la necessità di utilizzare più memoria.
Soluzione 3:
Usare un ritardo software.
Questo vuol dire inserire un ritardo con istruzioni in modo che la cadenza
delle azioni sullo stesso port sia tale da permettere la carica di eventuali
capacità collegate.
Ad esempio:
;
set IOpin
bsf
PORTB,
0
;
set
bit 0
call
wait_10US ;
attendi 10
microsecondi
bsf
PORTB,
1
;
set
bit 1
call
wait_10US ;
attendi 10
microsecondi |
Questo funziona, ma ha, per contro molti elementi:
l'
aumento delle istruzioni
il rallentamento dell'
esecuzione
occorre verificare che il wait
introdotto sia realmente in grado di evitare il problema, che dipende dal
carico collegato
il ritardo dipende dalla
frequenza dell' oscillatore e la routine può dover essere modificata
Soluzione 4:
Polling dello stato dell' uscita.
Dopo aver effettuato una modifica al port, attendere che la modifica sia
effettiva prima di avviarne una successiva.
Ad esempio:
;
set IOpin
bsf
PORTB,
0
;
set
bit 0
chk_0
btfss PORTB, 0
; attendi fino a che il pin è
goto
chk_0
; andato a livello 1
bsf
PORTB,
1
;
set
bit 1
chk_1
btfss PORTB, 1
; attendi fino a che il pin è
goto
chk_1
; andato a livello 1 |
Questa soluzione è simile alla precedente, ma il tempo impegnato è
ottimizzato.
Ovviamente, comandando buffer con ingresso a bassa capacità, in generale
si può evitare la correzione del software.
Soluzione 5:
Passare da Baseline e Midrange a Enhanced Midrange e PIC18F. Per questi il
problema R-M-W non esiste, data la diversa struttura del port,
come vediamo nella pagine seguenti.
Note finali
- Il problema R-M-W riguarda i
registri di comando degli I/O e non i registri interni del chip, che non
possono avere carichi irregolari. Quindi, se la sequenza:
;
set bit
bsf GPIO,
GP5
bsf GPIO,
GP4
bsf
GPIO, GP2 |
è a rischio, dato che il successo dipende dal carico collegato ai pin,
questa:
;
set bit
in RAM dati
bsf RAM1,
5
bsf RAM1,
4
bsf
RAM1,
2 |
ha successo, dato che si tratta di un registro interno.
- Va compreso che quanto evidenziato non ha nulla a che fare con il problema
dell
a formazione di glitch a seguito di commutazioni
indesiderate dei pin di uscita e neppure con il problema del debounce per i
segnali in ingresso.
I primi dipendono da come viene gestita l' uscita. Il secondo dipende dalle
caratteristiche della sorgente del segnale in ingresso.
e ancora...
Secondo Microchip, esistono altre forme di R-M-W non sempre considerate, e
pertanto più subdole, che appaiono in altre situazioni critiche,
principalmente riguardanti l' uso di moduli di comunicazione integrati assieme
ad I/O digitali sullo steso port.
Il caso noto riguarda l'uso di MSSP in modo I²C , mentre si vuole modificare
un bit del TRIS dello stesso registro. Il cambio di direzione da ingresso a
uscita e viceversa, a seconda di come è impostato il latch del pin, potrebbe
generare situazioni di mancato comando o di glitch.
In generale, è consigliato di mettere i pin a cui è necessario cambiare dinamicamente la direzione in port diversi da
quello usato dal modulo MSSP, evitandosi così ogni problema.
Se però questo è realmente necessario, per sicurezza occorre modificare il
bit voluto e in ogni caso settare anche i bit usati dall' I²C prima di
scrivere il valore nel TRIS register, oppure usare la tecnica dello
shadow-register.
Inoltre, se si implementa un bit banging come I²C master, emulando la funzione in
software senza l' uso dell' MSSP occorre cura particolare nella gestione dei
bit che vengono modificati dal programma.
I²C utilizza un bus open collector pull-up esterno, e, manovrando i
bit del TRIS
register per cambiare la direzione dei pin, occorre fare attenzione.
Un bus open collector, ovvero sostenuto da una resistenza di pull-up. potrebbe
avere una elevata capacità, il dipendenza dalla sua estensione fisica e dal
numero di periferiche collegate. Microchip dà questo esempio:
;
Initialization
of the port-pin's
(i2c-pins are inputs,
; appropriate
port-bits are cleared)
BANKSEL TRISC ;
select
Bank for accessing the
;
tris-register
bsf TRISC,RC3 ;
C,3 is
input (SCL)
bsf TRISC,RC4 ;
C,4 is input (SDA)
BANKSEL PORTC ;
select
Bank for accessing the
;
port-register
movlw b'11100111'
andwf PORTC,F ;
clear the
i2c-port-register-bits
...
; Generate
Start-Bit
BANKSEL TRISC
bcf TRISC,RC4 ;
C,4 (SDA) is output-now
; as port-register-bit is zero, it will go low
call Delay_4_us ; short
delay of 4 usec (required for
; 100 kHz-bus)
bcf TRISC,RC3 ;
C,3 (SCL) is output-now
; as port-register-bit is zero, it will go low
|
L' azione consecutiva
rapida su due bit dello stesso port, a causa della capacità introdotta dal
bus open collector richiede che sia verificato il raggiungimento del livello
voluto.
Se tra
l' inizializzazione e la generazione dei bit seriali non è stata utilizzata
alcuna istruzione non si può essere sicuri che i bit
PORTC3:
4 siano
ancora a zero (come SDA e SCL, le
linee sono alte, se la comunicazione non è attiva).
Una soluzione proposta è quella
di includere l' inizializzazione
dei pin della
I²C all' inizio del
programma ed evitare
qualsiasi istruzioni RMW su altri bit dello stesso port mentre
la comunicazione I²C
è in corso (tra
cui va considerata anche una eventuale
routine di interrupt, che potrebbe essere ancora attiva).
Vediamo ora come il Problema R-M-W è
stato risolto da Microchip nei PIC18, attraverso una semplice variazione della struttura dei registri dei
PORT.
|