Sunteți pe pagina 1din 79

Arhitecturi de sisteme incorporate

Microcontrolere si sisteme
integrate
Microchip AVR 8 biți:
• Inițializarea hardware (Reset-ul),
• Ceasul de gardă (watchdog timer),
• Intrări-ieşiri numerice (porturile I/O),
• Metode generale pentru a realiza accesul la intrări -
ieșiri (arhitecturi de calcul)
• Sistemul de întreruperi (partea 1)
1
Inițializarea AVR 8 biti (reset)
• După o inițializare hardware (un reset), la fel ca la orice alt
microprocesor/microcontroler, şi cel puţin o parte din resurse au o
stare inițială precizată, astfel:
– Toate registrele I/O sunt setate la anumite valori iniţiale (implicite),
descrise in foaia de catalog/manual
– Prima instrucțiune executată este cea din vectorul de Reset, de la
adresa respectivă- 0x0000; cu alte cuvinte valoarea initiala a
numaratorului program PC este 0x0000
• Instrucțiunea memorată în vectorul de reset este de obicei o instrucțiune de salt absolut
(JMP) la prima instrucțiune din programul propriu-zis.
• Daca vorbim de initializarea hardware, pentru orice
microcontroler exista doua tipuri de baza de reset hardware:
– Un reset generat de conectarea si reconectarea sursei de
alimentare (power down + power up), numit reset la rece (cold
reset)
– Un reset generat de orice altceva (de exemplu prin intermediul
unui pin de reset), numit reset la cald (warm reset)
• După un reset la cald conținutul memoriei SRAM de date
rămâne nemodificat!
• După un reset la rece, conținutul RAM-ului de date (SRAM),
deci si al registrelor de uz general, este neprecizat (SRAM-ul
este o memorie volatila)! 2
Inițializarea AVR 8 biti (reset)

• Valori inițiale (initial value) ale biților unui registru I/O, după reset,
asa cum apar in foaia de catalog.
• Dacă programul nu activează şi nu utilizează întreruperile, vectorii
de întrerupere nu vor fi folosiți, şi codul programului poate scris şi la
aceste adrese- vezi sistemul de intreruperi.
– Acest lucru este, de asemenea, posibil şi în cazul în care vectorul de
reset este în zona de aplicaţie în timp ce vectorii de întrerupere sunt în
zona de bootloader sau invers.
• După ce „sursa externă” care a generat semnalul de reset devine
inactivă, intră în acțiune un numărător intern care va genera o
întârziere (time-out) cu scopul măririi perioadei cât reset-ul, intern
de data aceasta (internal reset), este activ.
– Aceasta va permite, de exemplu, tensiunii de alimentare să ajungă la o
valoare nominală stabilă înainte de se executa instrucţiuni.
– Acest timp de întârziere este definit si poate fi programat de utilizator
prin fuzibilele CKSEL.
3
Schema bloc a sistemului de generare a
reset-ului AVR 8 biti (AVR clasic)

4
Schema bloc a sistemului de generare a
reset-ului AVR 8 biti (AVR modernizat )

Variantele modernizate de Mega si Tiny (seriile 0, 1 si 2 ) introduc un nou asa


zis controler de reset RESCTRL care permite si:
• determinarea originii resetului (cine l-a generat) prin intermediul unui registru
de stare numit RSTFR - Reset Flag Register
• generarea unui reset software - CPU(SW)- prin intermediul registrului de
5
control SWRR- Software Reset Register
Inițializarea AVR 8 biti (reset): sursele

• Tipic, pentru un microcontroler AVR 8 biti (exemplificare ATMega)


există cinci surse de reset, care pot fi descrise astfel:

– Reset la conectarea tensiunii de alimentare (power-up reset): când


tensiunea de alimentare, crescătoare, depășește o anumită valoare de
prag (notată VPOT).
– Reset extern: când un nivel de „0” este prezent pe pinul RESET, pentru
o perioadă mai mare decât o durata minimă.
– Reset prin ceasul de gardă (watchdog reset): când ceasul de gardă
este activat şi perioada de gardă expiră.
– Reset la scăderea temporară a tensiunii de alimentare (Brown-out
reset): când detectorul de Brown-out este activat şi tensiunea de
alimentare VCC coboară sub pragul de brown-out (notată VBOT).
– Reset prin interfața JTAG (pentru variantele care au interfata
JTAG): când registrul de reset al interfeței JTAG este adus în “1”.

6
Reset-ul la conectarea tensiunii de alimentare
(POR)
• Un impuls de reset va fi generat la conectarea tensiunii de alimentare de
un circuit specializat (POR - Power On Reset) atunci când VCC va atinge
nivelul de prag VPOT atât în sens crescător cât şi descrescător.
• Circuitul POR garantează că microcontrolerul va fi resetat corect la
conectarea alimentării (Power-on).
• Atingerea tensiunii de prag în sens crescător declanşează numărătorul de
întârziere care va stabili durata de prelungire a reset-ului intern (tTOUT), după
dispariţia condiţiei.
• Reset-ul intern este activat (si mentinut) fără nici o întârziere atunci când
VCC coboară sub nivelul de detectare.
• Această variantă de reset este valorificată în practică prin conectarea
pinului RESET direct la tensiunea de alimentare Vcc: VPOT=VRST .

7
Reset-ul extern
• Un reset extern este generat practic de un nivel “0” pe pinul /RESET,
impuls care durează mai mult decât o lăţime de impuls minimă (din foaia de
catalog), chiar dacă ceasul CPU este oprit.
• Când semnalul aplicat pe /RESET atinge tensiunea de prag (VRST) pe
frontul crescător, pinul va fi considerat în „1”, condiția a dispărut şi un
numărător intern de întârziere va genera perioada suplimentară de reset
intern tOUT.
• În figuri sunt prezentate cele două situații relevante pentru activarea intrării
RESET: imediat după Power-up şi oricând în timpul funcționării.

8
Dacă nu utilizăm un reset de
Utilizare Reset extern tip extern, pinul respectiv
poate fi folosit ca intrare /ieşire
de uz general (in ex. PA2)

Utilizarea unui circuit extern


dedicat (de ex. DS1233 EconoReset de la
Reset manual – cu un buton; există/este activată Maxim) pentru generarea
Reset-ului la punerea sub tensiune
o rezistentă internă către Vcc, PA2 ieşire si =1)

9
Reset-ul la scăderea temporară a tensiunii de
alimentare (Brown-out)
• Unele microcontrolere AVR (ATMega, XMEGA si cateva ATTiny) au un circuit de
detecţie numit BOD- Brown Out Detection, pentru a monitoriza nivelul VCC în
timpul funcţionării, comparând-ul cu un nivel fix de declanşare.
• Nivelul de declanşare pentru BOD poate fi selectat cu fuzibilul BODLEVEL la
valoarea 2.7V (BODLEVEL neprogramat), sau la valoarea 4.0V (BODLEVEL
programat), funcţie de valoarea utilizată pentru tensiunea de alimentare.
• Nivelul de declanșare are asociat şi un histerezis VHYST pentru a garanta o detecţie
sigură şi a discerne între evoluţia crescătoare (V+ ) şi cea descrescătoare(V- ):
– VBOT+ = VBOT + VHYST /2 şi VBOT- = VBOT - VHYST /2.
• Circuitul BOD poate fi activat sau dezactivat prin intermediul unui fuzibil numit
BODEN.
• Când BOD este activat (fuzibilul BODEN programat) şi VCC scade la o valoare sub
nivelul de declanșare (VBOT - în figura), reset-ul intern este activat imediat.
– Când VCC crește deasupra nivelului de declanşare (VBOT+ în figura) numărătorul de
întârziere va genera perioada suplimentară de reset intern tOUT.
– Circuitul BOD va detecta o scădere a VCC numai dacă tensiunea se menţine sub nivelul de
declanșare mai mult decât un interval minim tBOD.

Se numeste “Brown-out” prin raportare


la ce inseamna un “Black-out” –
o căderea totala a tensiunii de alimentare

10
Conceptul de ceas de gardă (watchdog) si
utilizarea lui
• Un temporizator de tip ceas de gardă (watchdog timer) este un
subsistem hardware/software al unui sistem de calcul care declanșează
un Reset - o inițializare hardware- (sau o altă acţiune corectivă de aceiași
natură) atunci când programul aplicației, datorită apariției unei stări de
defect temporar sau permanent (având ca efect tipic gen programul se
“agață”, nu mai răspunde, se “înțepenește”, etc.), nu mai reușește să
“trateze” (tipic să inițializeze) acest temporizator in mod periodic si
regulat (la intervale previzibile de timp)
• Scopul final este de a readuce sistemul într-o stare cunoscută si, dacă
este posibil, o stare de funcționare normală sau sigură
– De regula aceasta stare este starea după reset (inițializare hardware)
• Un temporizator de tip ceas de gardă poate fi de asemenea utilizat pentru a
aduce un sistem de calcul utilizat pentru control (controler) de tip fail-safe
într-o stare sigură, de exemplu, cu motoarele oprite, cu ieșirile de înaltă
tensiune si cu alte sub-sisteme periculoase similare oprite/inactive.
– Un sistem fail-safe este un sistem zis cu securitate incorporată, care in cazul
apariției unui defect ajunge într-o stare sigură, prescrisă anterior
– Utilizarea acestor sisteme fail-safe este esențială in aplicațiile critice din
avionică, transport feroviar, industria automobilului sau domeniul medical

11
Ceasul de gardă (watchdog)
• Pentru toate sisteme incorporate (embedded systems) care nu
pot fi supravegheate in mod constant de un operator uman si
care trebuie să fie auto-suficiente, utilizarea unei astfel de
tehnologii este obligatorie (nu există nimeni care să apese pe
butonul de reset dacă sistemul nu mai reacționează!)
• In mod riguros(si din considerente de fiabilitate), un temporizator de
tip ceas de gardă trebuie să fie exterior sistemului (să nu fie realizat
pe acelaşi microcircuit cu unitatea centrala), reducând probabilitatea
ca același defect să afecteze sistemul de calcul si temporizatorul
simultan
• Atunci când el este inclus ca un periferic dedicat, ca in cazul multor
microcontrolere (inclusiv AVR), soluţia este una de compromis preţ
de cost-siguranţă in funcţionare
• Oricum ar fi implementat, mărimea lui de “ieşire” trebuie să
controleze direct intrarea de reset (iniţializare hardware) a sistemului
de calcul (microcontroler, microprocesor, etc. )
• In varianta sa cea mai simplă el este un temporizator/numărător
care, dacă nu este reîncărcat/resetat/rearmat periodic, ajunge la
depăşire (Overflow, Time-Out), aceasta condiție ducând la Reset-ul
12
CPU
AVR 8 biti: Temporizatorul ceasului de gardă
• Watchdog Timer (WDT) AVR este de fapt un numărător care are un semnal de ceas care
provine de la un oscilator RC separat on-chip (intern, independent de ceasul sistem)
de 128 kHz (asta la ATiny 2313, la alte variante poate avea alte valori).
• WDT va genera un reset sau o întrerupere dacă numărătorul ajunge la valoarea maximă
(la depășire).
• In funcționarea normală utilizatorul (aplicația software) trebuie să folosească
instrucțiunea WDR - Watchdog Timer Reset – pentru a reporni numărătorul de la 0 înainte
ca acesta să ajungă la valoarea maximă, in caz contrar el generând un reset sau o
întrerupere
• Pentru o evita a dezactivare/oprire accidentală a acestui sub-sistem trebuie utilizate
secvențe speciale de operații in momentul in care se lucrează cu biții din registrul
WDTCR- Watchdog Timer Control Register

13
Reset-ul prin ceasul de gardă (Watchdog Reset)
• Cu ajutorul divizorului (watchdog prescaler) se pot programa (alege)
intervale pentru declanșarea ceasului de garda (durată totală a ciclului de
numărare) intre 16msec si 8 sec.
• Dacă se dorește utilizarea acestui sub-sistem fuzibilul WatchDog
always ON (WDTON), trebuie să fie programat (in caz contrar acest
temporizator poate genera doar o cerere de întrerupere)
– Atunci când ceasul de gardă generează o depășire (Time-out, ca urmare a ne
reîncărcării/repornirii lui în timp util), el va genera un impuls scurt de reset cu durata de un
ciclu de ceas (1CK), iar pe frontul căzător al acestuia va fi declanșat numărătorul de
întârziere reset care la rândul lui va genera perioada suplimentară de reset intern tOUT.

14
Fuzibile Reset ATTiny2313-
Proteus VSM

Modelele AVR nu au
toate fuzibilele, de ex.
lipsesc fuzibilele
BODLEVEL!

15
Fuzibilul RSTDSBL si utilizarea pinului
/RESET
• Pentru variantele de microcontrolere AVR 8 biți la care
pinul /RESET poate avea si funcții alternative de intrare-
ieșire (ca parte a unui port), cum ar fi:
– ATTiny2313: /RESET si PA2
– ATMEGA48, ATMEGA88: /RESET si PC6
– ATMEGA329: /RESET si PG5,
– etc.
in setul de fuzibile există un fuzibil numit RSTDSBL
(external Reset Disable) care trebui să fie programat
(Programmed) pentru ca pinul respectiv să poată fi
programat si utilizat ca un pin de intrare/ieșire obișnuit;
altcumva el poate fi utilizat eventual doar ca intrare de
reset extern!
16
Intrările și ieșirile numerice (porturile de
intrare/ieșire)
• Toate microcontrolerele AVR 8 biți au un număr oarecare de intrări- ieșiri
numerice de uz general, grupate din punct de vedere funcțional în “porturi” de
intrare/ ieșire (I/O ports).
• Denumirea lor (Microchip/Atmel) este PORTA, PORTB, PORTC, PORTD, etc.
– Ele permit realizarea de cicluri de acces de tip Read-Modify-Write (citește –
modifică - scrie).
• Toti pinii asociați acestor porturi sunt bidirecționali
• Direcția unui pin (intrare si/sau ieșire) al portului poate fi schimbată individual,
fără a schimba şi direcția oricărui alt pin din același port
– Direcția, adica utilizarea sa ca intrare sau ieșire, este programabilă individual
pentru fiecare pin din port
• Dacă un pin este programat ca fiind de tip ieșire, tipul de ieșire este si el
programabil, prin activarea sau dezactivarea rezistoarelor de sarcină interne
Rpu= x10KOhmi:
– De tip cu drenă în gol (fără rezistență internă de sarcină) sau
– Normală, cu rezistență interna de sarcină, către Vcc(Rpu pull-up)

Dacă un pin este programat ca fiind de tip intrare, comportarea sa depinde de


conectarea sau nu a rezistentei interne de sarcina Rpu:
- daca Rpu e conectat intrarea respectiva are potențialul fixat la “1”, putând fi
eventual trasa la “0”
- daca Rpu nu e conectată intrarea respectiva va fi flotantă, într-o stare de înaltă
impedanță (Hi-Z) 17
Pin-out (conexiunile externe) pentru ATTiny
2313 (capsula DIP20)

Deși par a exista porturile A, B, C, D, etc. ele nu sunt “egale” intre ele:
nu au același număr de pini disponibili (biţi)- la fel ca si in cazul unor alte variante de
AVR cu număr relativ redus de pini, pentru acest tip de AVR anumite porturi sunt
implementate doar parțial, adică nu au toți cei 8 biți
18
Pin-out (conexiunile externe) pentru ATMega
328 (capsula PDIP28)

Deși par a exista porturile A, B, C, D, etc. ele nu sunt “egale” intre ele:
nu au același număr de pini disponibili (biţi)- la fel ca si in cazul unor alte variante de
AVR cu număr relativ redus de pini, pentru acest tip de AVR anumite porturi sunt
implementate doar parțial, adică nu au toți cei 8 biți
Obs. ATMega 328 este microcontrolerul utilizat de Arduino Uno. 19
Pin-out (conexiunile externe) pentru ATMega
2560 (capsula TQFP100)

In capsula de mai sus (TQFP100) sau in cea de tip CBGA100 de mai sus are 10 porturi:
PA…PL, din care doar portul PG este implementat incomplet (are doar 6 biti). 20
Obs. ATMega 2560 este microcontrolerul utilizat de Arduino 2560.
Intrările și ieșirile numerice (porturile I/O) –
caracteristici electrice
• Intrările sau ieșirile AVR 8 biti sunt compatibile TTL sau LVTTL (funcție si de
tensiunea de alimentare Vcc)
• Buffer-ele de ieșire au capacitatea de a absorbi/debita un curent IOL/IOH de
până la 20mA (la Vcc=5V) putând comanda astfel direct un LED sau optocuplor
• Capacitatea de a absorbi/debita curent depinde însă de tensiunea de
alimentare, de exemplu la Vcc= 3 V curentul maxim absorbit/debitat scade la
10mA.
• Toți pinii de port pot avea rezistoare de sarcină individuale interne, cu o
rezistență care nu depinde de tensiunea de alimentare (Rpu=20..50kOhmi).
• De asemenea toți pinii au diode de protecție atât către Vcc cât și către masă
după cum se observă în figură
– In figura de mai jos Cpin (xpF) este capacitatea parazită asociată pinului, are
conteaza in regim dinamic

Schema electrică
echivalentă a unui “pin”

21
Intrările şi ieșirile numerice AVR 8 biti
(porturile I/O) - caracteristici electrice (de cc)

Tiny2313

Mega32

Sunt specificate ca la orice familie standardizata de circuite integrate numerice


(aceleasi notatii)!

Atenție: Suma dintre IOL si/sau IOH de pe toate porturile existente nu trebuie să
depășească 200mA, iar de pe un singur port (de exemplu portul A) 100mA (valorile
depind însă si de tipul de încapsulare)

22
Intrările şi ieșirile numerice AVR 8 biti
(porturile I/O)- configurarea
• Referitor la notațiile utilizate în continuare (notatii Microchip/Atmel):
cu “x” s-a notat litera care identifică portul de 8 biţi (x= A, B, C, …), şi
cu “n” numărul bitului din port (n=0..7).
• Notația generala ar fi PORTxn, iar ca un exemplu particular bitul 6
din portul A va fi notat cu PORTA6 sau PA6
• Pentru fiecare din porturile existente sunt alocate trei locații de
memorie (trei registre) în spațiul I/O:
– registrul de date de ieşire – notat PORTx,
– registrul pentru stabilirea direcţiei datelor – notat DDRx (Data
Direction Register),
– şi pinii portului (registrul de date de intrare) – notat PINx.
• Locațiile corespunzătoare pinilor de intrare ai portului PINx pot fi
numai citite, în timp ce registrul de date PORTx şi registrul pentru
direcția datelor DDRx pot fi scrise şi citite.
• Majoritatea acestor pini de port au şi funcții alternative relevante
pentru perifericele microcontrolerului, existând un mecanism de
multiplexare adecvat.
– Activarea şi utilizarea funcțiilor alternative pe unii dintre pinii portului nu
influențează folosirea celorlalţi pini din port ca intrări/ieşiri de uz general.
23
Bitul PUD: exemplu ATTiny2313 si ATMega
328

ATTiny2313

ATMega 328

Un bit de comanda particular este bitul de dezactivare a rezistoarelor de


sarcină PUD (Pull Up Disable) din registrul MCUCR (MCU Control
Register) bit care atunci când este setat dezactivează simultan
rezistențele de sarcină interne Rpu pentru toți pinii, pentru toate
porturile.

Ceilalți biti din registrul MCUCR depind de varianta de


microcontroler AVR (au functionaliatati diferite functie de varianta) 24
AVR 8 biți: porturile I/O utilizate ca intrări/ieşiri de
uz general, programarea lor.
• Prima operație care trebuie realizată de utilizatorul intrărilor şi ieșirilor numerice ale unui
microcontroler AVR este cea de “configurare” a pinilor.
• Din punct de vedere al programatorului fiecare pin al portului se compune din trei biţi:
– DDxn,
– PORTxn şi
– PINxn.
• Biţii DDxn sunt accesați la adresa I/O DDRx, biții PORTxn la adresa I/O PORTx şi biţii
PINxn la adresa I/O PINx.
• Bitul DDxn în registrul DDRx selectează direcția acestui pin:
– Dacă DDxn este “1” logic, Pxn este configurat ca pin de ieșire.
– Dacă DDxn este “0” logic, Pxn este configurat ca pin de intrare.
• Dacă PORTxn este programat “1” logic când pinul a fost configurat ca pin de intrare,
rezistorul de sarcină este activat şi va „trage” în „1” intrarea neconectată (nu mai este
nevoie de o rezistenta externă către Vcc dacă ar fi cazul).
• Pentru a dezactiva acest rezistor, PORTxn trebuie să fie “0” logic
• Atâta timp cât reset-ul este activ pinii portului sunt într-o stare similară de înaltă
impedanță High-Z (tri-state), chiar dacă ceasul I/O nu este activ.
• După un reset, toti pinii sunt configurați ca intrări (DDRx=0) fără rezistențe interne
către Vcc (PORTx=0), fiind într-o stare similară High-Z (stare de înaltă impedanță)

• OBSERVATIE: Pentru familia XMEGA si pentru seriile Mega si Tiny modernizate


acest model de programare s-a modificat, devenind mult mai complex (cu 11 + 8 =
19 registre per port!) dar si mai flexibil! 25
Registrele aferente porturilor I/O pentru ATtiny
2313
Pentru Tiny2313
portul A are
doar 3 pini
accesibili si doar
3 biţi
implementaţi

Portul B
este
complet -
8 pini/biţi

26
Porturile I/O ca intrări/ieșiri de uz general –
comutarea intrare-ieșire si invers
• Dacă PORTxn este =“1” când pinul este configurat (cu DDRxn) ca
ieșire, pinul portului va fi şi el în “1”.
• Dacă PORTxn este =“0” când pinul este configurat ca ieșire, pinul
portului va fi şi el în “0” .
– Când se trece de la o stare tip intrare High-Z ({DDxn, PORTxn} = 0b00)
la o stare tip ieşire în „1” ({DDxn, PORTxn} = 0b11), apare o stare
intermediară, fie cu rezistoarele de sarcină activate ({DDxn, PORTxn}
= 0b01) fie cu ieşirea in „0” ({DDxn, PORTxn} = 0b10).
• În mod normal, starea cu rezistoarele de sarcină activate este
complet acceptabilă, deoarece in cazul unei intrări având o
impedanță mare nu se va observa diferența între un pin in starea “1”
şi prezența rezistoarelor de sarcină.
– Dacă este însă cazul ieşirii „0”, bitul PUD din registrul SFIOR poate fi
setat pentru a dezactiva toate rezistoarele de sarcină .
• Când se trece de la o stare cu intrarea cu rezistoare de sarcină la o
ieșire în „0” apare aceeași problemă.
– Utilizatorul trebuie să folosească starea tri-state ({DDxn, PORTxn} =
0b00) sau ieșire “1” ({DDxn, PORTxn = 0b11) ca un pas intermediar.

27
Porturi I/O: configurația implicită (după
reset), intrare, fără Rpull-up
Vcc
DDx

0 R Pull-Up

PORTx

PINx Pinul fizic

? ?

Direcţia: INTRARE
R Pull-Up: DECONECTATA (OFF)
Porturi I/O: intrare, cu RPull-Up conectat

DDx Vcc

0 RPull-Up

PORTx

PINx Pinul fizic

? 1

Direcţie: INTRARE
RPull-Up: CONECTATA (ON)
Porturi I/O: ieşire, in “1”

Vcc
DDx

1 RPull-Up

PORTx

PINx Pinul fizic

1 1

Direcţie: IEŞIRE
RPull-Up: DECONECTATA (OFF)
Exemple elementare de cod, porturi I/O

• Următorul exemplul de cod (în limbaj de


asamblare şi apoi în C) arată cum se pot
programa pentru portul B:
– în “1” pinii 0 şi 1 ca ieşiri ,
– în “0” pinii 2 şi 3 tot ca ieşiri şi cum
– se definesc pinii de la 4 la 7 ca intrări,
• cu rezistenţe de sarcină doar pentru pinii 6 şi 7.
– Valorile setate şi rezultate pentru pini sunt citite
înapoi, dar o instrucţiune NOP este inserată înainte
pentru a face posibilă citirea corectă a valorilor recent
asignate pinilor (ea introduce o mică întârziere).

31
Exemple de cod: programare porturi
In limbaj de asamblare AVR (asamblor AVR Studio 4):

;Definirea rezistenţelor şi setarea ieşirii in 1.


;Definirea direcţiei pentru pinii portului
ldi R16,(1 << PB7) | ( 1 <<PB6) | (1 << PB1) | (1 << PB0)
ldi R17,(1 << DDB3) | ( 1 <<DDB2) | (1 < <DDB1) | (1 << DDB0)
out PORTB, R16
out DDRB, R17
nop ; Inserarea unei instrucţiuni NOP
; Citirea pinilor portului
in R16, PINB

Pentru codul în asamblare sunt utilizate două registre temporare R16 şi


R17 pentru a minimiza timpul de când rezistenţele de sarcină sunt
activate pe pinii 0, 1, 6, şi 7 şi până când direcţia biţilor este corect
setată, definind biţii 2 şi 3 ca “0” şi redefinind biţii 0 şi 1 ca ieşiri în “1”.

Operatorul “<<” este cel de deplasare (shift) stânga, iar “ | “ este un SAU
logic la nivel de bit, identici cu operatorii bitwise din C 32
Exemple de cod: programare porturi
In limbaj C (WinAVR):

unsigned char i;
/* Definirea rezistenţelor de sarcina şi setarea ieşirii
in 1. */
/* Definirea direcţiei pentru pinii portului */
PORTB =(1 << PB7) | (1 << PB6) | (1 << PB1) | (1 << PB0);
DDRB = (1 << DDB3) | (1 << DDB2) | (1 << DDB1) | (1 <<
DDB0);
/* Inserarea unei instrucţiuni NOP */
_nop();
/* Citirea pinilor portului */
i = PINB

Operatorul “<<” este cel de deplasare (shift) stânga, iar “ | “


este un SAU logic la nivel de bit (bitwise)

VEZI SI PREZENTAREA MM0 ! 33


Exemple de cod, ce înseamnă PORTB sau
PB2.. (WinAVR)
• In fişierul header notat ioyXXXX.h, (de ex. iotn2313.h) cu ajutorul unor directive
#define sunt (pre)definite valorile pentru porturi si biţi.
• De exemplu, pentru portul B avem:

/*Data Register, Port B */


#define PORTB _SFR_IO8(0x18)//adresa din RAM-ul de date
…..

/*Port B Data Register – PORTB */


#define PB7 7 //practic doar numarul bitului
#define PB6 6
#define PB5 5
#define PB4 4
#define PB3 3
#define PB2 2
#define PB1 1
#define PB0 0

34
Exemple de cod, manipulare biţi

• Prin folosirea de operatorilor logici la nivel de bit (bitwise) de tip AND,


OR, XOR si NOT se pot manipula biţii individuali

/* XOR comutam starea bitului 5 */


PORTB = PORTB ^ 0x20; /* adica il inversam */
PORTB ^= 0x20; /* mai inversam odata, dar altfel */

/* OR setam biti 7 si 2, ceilalti nu ne intereseaza!*/


PORTB = PORTB | 0x84;
PORTB |= (1<<PB7)|(1<<PB2) ; /*acelasi lucru dar mai
portabil*/

/* AND stergem biti 0 si 1, dar numai pe ei! */


PORTB = PORTB & 0xFC;
PORTB &= ~((1<<PB0)|(1<<PB1)); /* acelasi lucru dar mai
portabil, folosim si un NOT */

35
Exemple de cod, măşti

• Prin utilizarea unei “măşti” (constante) putem testa


starea unor biţi individuali:
/*ne intereseaza daca bitul 0 din Portul D este 1*/
if(PIND & 0x01){facem_ceva();}
• Valoarea constanta 0x01 utilizată aici este numită
“mască” (mask).
• Ne permite să “anulăm” ceilalți biţi (fara insa a le
modifica valoarea din registru) si să determinăm dacă un
bit particular este in 1.
• O filozofie asemănătoare se poate aplica dacă ne
interesează să testăm dacă un bit in 0:

/* ne intereseaza daca bitul 5 din Portul B este 0*/


if(~PIND & 0x20){facem_ceva();}
36
Exemple de cod, o aplicație cu intrări/ieșiri
elementare
• Să presupunem (de altfel in mod corect) că după
inițializare (reset) starea registrelor asociate porturilor B si
D este:
– DDRD = 0x00 (intrare..)
– DDRB = 0x00 (intrare..)

• Pe pinul corespunzător bitului 0 din portul D este conectat


un comutator normal deschis.
– Atunci când comutatorul se va închide pinul va fi conectat la masă
(“0”).
• O să citim starea bitului 0 din portul D, o să o inversăm si
valoarea rezultată va oferita ca ieşire pe pinul (bitul) 0 din
portul B- acesta va trebui deci sa fie (re)configurat ca
iesire
• Valoarea/starea tuturor celorlalți biți si pini din
porturile utilizate nu trebuie să fie afectată!
37
Exemple de cod, o aplicaţie I/O
Hardware-ul..
Vcc
Atenţie: aici nu există rezistentă externă
către Vcc, obligatoriu trebuie activată
(conectată) cea internă R

PB0 IF
“0” LED
PD0
Comutator
LED-ul se va aprinde când
PB0=“0”, pinul PB0 absorbind
Masa (Gnd) curentul de conducţie directă
IF al LED-ului

Evident, bornele de alimentare ale microcontrolerului Vcc si Masa (GND)


38
nu au mai fost figurate!
Exemple de cod, o aplicație..
si software-ul ..
#include <avr/io.h>
int main()
{
DDRD &= 0xFE; /*ne asiguram ca numai bitul 0 din portul
D este definit ca intrare */
PORTD |= 0x01; /*conectam rezistenta interna de pull-up
pentru bitul bitul 0*/
DDRB |= 0x01; /*configuram numai bitul 0 din Portul B
este iesire */

while (1) /*o bucla fara sfarsit */


{
if(PIND & 0x01){PORTB &= 0xFE;} // daca bitul este 1
else {PORTB |= 0x01;} // daca bitul este 0
}
}

39
Ce facem cu pinii I/O neutilizați / “neconectați”

• Dacă unii dintre pinii de intrare/ieşire rămân neutilizaţi,


este bine să se garanteze că aceşti pini au o stare
definită şi nu rămân flotanţi (in gol)
• Metoda cea mai simplă pentru a garanta o stare definită
(“1”) pentru un pin neutilizat, este definirea lui ca
intrare şi activarea rezistenţelor de sarcină.
• Trebuie ţinut cont că în cazul unei reiniţializări (reset)
rezistenţele de sarcină vor fi (re)activate
• Dacă un consum scăzut de energie este important în
timpul (re)iniţializării, este recomandat să se folosească
rezistoare externe de sarcină către VCC („1”) sau
rezistoare externe către masă („0”).
• Nu este recomandată conectarea pinilor neutilizați
direct la VCC sau la masă, deoarece aceasta poate
duce la apariția unor curenți excesivi dacă pinul este
configurat din greșeală ca ieşire. 40
Ce facem când numărul de pini I/O este insuficient?
Cum putem eventual “multiplica” numărul de intrări?
Prin utilizarea unui registru de deplasare extern
de tip paralel -> serie (74HC165 in exemplu):
aici cu ajutorul a 3 pini putem citi 8 intrări
8 intrări numerice
Algoritm:
-PB5(ieșire) = intrare /LOAD registru =“0”
încarcă datele paralel
-PB6 (ieşire) = intrare CLK registru este
ceasul de deplasare
- PB6 (intrare) = iesire Qh registru
-Se generează 8 cicluri de ceas (impulsuri)
-La fiecare ciclu se citește in bitul PB7=Qh
data de ieşire (serială, bit cu bit) din registru
-Microcontrolerul (aplicația) “asamblează”
cei 8 biţi citiți secvențial intr-un octet
Registrul de deplasare poate avea o
dimensiune mult mai mare (obținută de
exemplu prin cascadarea a mai multe registre)
Conectarea cu microcontrolerul utilizează
doar 3 pini (si 3 fire) si o masa comuna.
Putem avea, de exemplu, 64 de intrări numerice 41
citite doar cu ajutorul a 3 pini!
Ce facem când numărul de pini I/O este
insuficient?
Cum putem eventual “multiplica” numărul de ieșiri?
8 ieşiri numerice Prin utilizarea unui registru de deplasare extern
(CD 4094 in exemplu) de tip serie -> paralel
Algoritm:
-PB6 (ieșire) = intrare CLK registru, este ceasul de
deplasare
-Se generează 8 cicluri de ceas (“0”,”1”, “0”..,)
-La fiecare ciclu se scrie bitul PB7 (ieșire) = intrare
DATA registru care este data de intrare (serială) in
registru
- Cei 8 biți, scriși secvențial de microcontroler
(de aplicație), sunt asamblați intern
(sunt desocializați de registru) intr-un octet
- La final PB5 (ieșire) = intrare Strobe registru = “1” si
datele sunt transferate la ieșirile registrului , acestea
fiind actualizate (vezi si foaia de catalog a lui CD4094!)

Soluția de mai sus poate fi utilizata si pentru mai multe


ieșiri prin cascadarea mai multor registre
42
Ce mai putem face când numărul de pini I/O este
insuficient?
Utilizarea unor dispozitive
periferice dedicate, cu magistrală
serială de tip I2C care necesită
doar 3 fire (folosesc doar 3 biţi,
conexiuni I/O)
Interfaţa I2C poate fi implementată
software pentru ATTiny 2313, sau se poate
utiliza un ATMega care are si o
interfaţă TWI (I2C) hardware

PCF 8574 este un exemplu de


circuit I/O expander (8 biţi intrări
si/sau ieşiri), cu interfaţă serială de
tip I2C
Există soluţii similare si pentru
Magistrala serială SPI (disponibilă si
ea la ATMega).
Vezi capitolele despre interfeţele seriale
sincrone TWI si I2C ! 43
Care sunt metodele pentru a realiza accesul la
intrări/ ieşiri (I/O) pentru o unitate centrala
(CPU)?
• Cum ar trebui să procedeze unitatea centrală (CPU)
a unui microcontroler / microprocesor pentru a
comunica cu si a controla dispozitivele de intrare si
ieșire (I/O)?
– Transferul de date înseamnă o relație intre două entități: un
producător de date si un consumator de date
• Dispozitivele I/O sunt “văzute” de CPU prin intermediul
unei interfețe I/O care înseamnă un set de registre sau
locații de memorie specifice
• Tipic putem spune că ea este alcătuită (exemplu
generic):
– registre de date (un set de biți utilizați pentru transferul de
date, atât pentru intrări cat si ieșiri),
– registre de stare si control (un set de bit utilizați pentru
sincronizarea intre cele două entități, care permit citirea stării
si implementarea controlului prin comenzi)
• Interfața I/O face parte din modelul de programare
pentru dispozitivele de intrare si ieșire 44
Metode pentru a realiza accesul
la intrări/ieșiri ( I/O)
• Câteva întrebări (relevante):
• Ce fel de date trebuie să fie transferate?
– Aceasta depinde de natura specifica a intrării / ieșirii, a dispozitivelor respective
de I/O
– O imprimanta este diferita de o tastatura si ambele sunt diferite de un robot
industrial sau un sistem de achiziții de date..
• Cine produce si cine consumă informația/datele?
– Avem, contextual, diverse tipuri de producători de date si consumatori de date
– Unitatea centrala poate fi producător de date si dispozitivul I/O consumator de
date (operație de ieșire)
– Unitatea centrala poate fi consumator de date si dispozitivul I/O producător de
date (operație de intrare)
• Care este viteza cu care un producător produce datele si care este
viteza cu care un consumator poate să le consume?
• Care este volumul de date care trebuie transferat per unitatea de timp?
• Ținând cont de viteza si volumul datelor, care sunt modalitățile prin care
se poate obține un schimb de date fiabil (a.i. sa nu se piardă date!) si
eficient (din punct de vedere al timpului de calcul utilizat) intre
producători si consumatori, cum anume se pot “sincroniza” cei doi
parteneri de dialog ?
45
Transferul programat (bazat pe interogare in
buclă)
• Cu ajutorul celor două seturi de registre I/O (date si stare/ control) se
poate realiza o “tranzacție” de date intre cele două părți
(producător si consumator) pe baza unei bucle de așteptare:
fiecare parte va aștepta un timp nedefinit într-o buclă in care testează
starea indicatorului înainte de produce/consuma.
– Starea poate fi citita si pe baza ei se poate elabora o comanda de transfer de date
– Pe baza comenzii se realizează transferul efectiv de date si se elaborează
informația de stare (care spune ca transferul s-a finalizat) si eventual una de eroare
(transfer finalizat corect)
• Acest gen de gestionare a intrărilor/ieșirilor se numește transfer
programat sau transfer bazat pe interogare (polling) printr-o bucla
de așteptare (busy waiting loop)
• Acest mod de transfer de date are un mare dezavantaj: consumă
inutil puterea de calcul si timpul de prelucrare al CPU:
– Când CPU execută bucla de așteptare el nu face nimic util in afara de
aceasta așteptare.
– Ca să aveți idee de cat timp CPU se pierde, pentru acest exemplu
comparați viteza de calcul a oricărui CPU cu viteza cu care un operator
uman poate introduce datele (poate apăsa tastele unei tastaturi)!

46
Întreruperi si rutine de tratare a
întreruperilor
• Modalitatea programată de intrare/ieșire este afectată in primul
rând de faptul ca participanții la o astfel de tranzacție I/O pot avea
viteze de acces la informație mult diferite si diverse
– Luând ca exemplu tastatura, bănuim că un sistem de calcul (un CPU)
poate citi de mii si mii de ori mai rapid decât un operator poate tasta
(fie el si un Speedy Gonzalez…)
• Astfel, “partenerul” rapid va trebui să aștepte după “partenerul”
lent, ducând la o irosire masivă de resurse (de exemplu putere
computațională): astfel intre 2 prelucrări succesive nu se face
nimic, doar se așteaptă, irosindu-se timpul unității centrale

• Asincronismul dintre un sistem de calcul, sincron prin natura
lui, si lumea exterioară lui, cu care interacționează, necesită
de cel mai multe ori soluții mai eficiente.

• Utilizarea întreruperilor reprezintă o astfel de soluție


47
Principii de bază pentru utilizarea
întreruperilor
• Pentru un sistem de calcul o întrerupere este un “semnal” care
provine de la un sub-sistem hardware (întreruperi hardware) sau in
urma execuției unor instrucțiuni (întreruperi software) si care indica
necesitatea tratării unui eveniment de unitatea centrală
• Dacă evenimentul respectiv este legat de necesitatea realizării unei
operații de intrare/ieșire atunci întreruperile reprezintă o modalitate
de a le trata
– In cazul unei astfel de întreruperi (si nu numai) unitatea centrala va
presupune că pentru a trata intrarea sau ieșirea respectivă activitățile
de intrare/ieşire sunt temporar suspendate (cum ar fi situația in care
operatorul uman nu a apăsat încă următoarea tastă) si își va planifica
singur (adică automat sau cvasi-automat) execuția unei alte sarcini
computaționale legata de prelucrarea acestei intrări sau ieșiri
• O întrerupere este o discontinuitate, o “ruptură” (trap) in derularea
secvențială (normală) a fluxului program, forțând CPU să își
întrerupă/suspende programul curent si să transfere controlul unei
(sub)rutine de tratare a întreruperii.
– Este echivalentul unui apel de subrutină/funcţie sau de salt dar care
este realizat in mod “automat” de un sub-sistem hardware dedicat: 48
sistemul de întreruperi
Exemplu de tratare al unei întreruperi provenind de la
o tastatură

Re-activează introducerea datelor


de la tastatura si întreruperile
Activează introducerea datelor
de la tastatura si întreruperile

Întoarcere din
întrerupere

Citeşte/prelucrează
Face tot felul de
datele provenind
lucruri utile.. de la tastatura
Întrerupere
Programul “principal”:
Alte activităţi ale CPU DA
Am terminat?

NU

(Sub)rutina de tratare a
întreruperilor 49
Observații cheie legate de utilizarea
întreruperilor
• Deoarece unitatea centrală nu mai trebuie să execute
bucla/buclele de așteptare, ea poate realiza, in marea
majoritate a timpului, alte sarcini utile, până când va fi
întreruptă din nou.
• Aceasta îmbunătățește utilizarea resurselor CPU si
a sistemului/timpului de calcul in ansamblu, având
ca efect si un timp mai bun de răspuns pentru toți
“utilizatorii”
• Prelucrarea I/O se poate realiza astfel intr-un mod
total asincron, fără a face nici o ipoteză legată de
momentul apariției evenimentelor legate de
intrări/ieșiri
• Orice microprocesor sau microcontroler modern are
un sub-sistem de întreruperi hardware, care la
rândul lui are si propria interfață de programare, cu
registre de stare si control / comanda
50
Multiplicitatea surselor de întreruperi
• Întreruperile pot proveni de la mai multe dispozitive de intrare/ieșire (de la mai
multe surse de întreruperi )
• Intr-un sistem tipic de calcul cereri de întrerupere ar putea fi cauzate de (doar
câteva exemple):
– Defecte ale surselor de alimentare: cădere iminenta a sursei de alimentare
– Sisteme de temporizare/numărare: depășiri
– Dispozitive de intrare/ieșire, convertor analog - numeric, interfață serială
asincronă: terminarea operațiilor de conversie sau transfer
– Apariția unor erori de natura hardware: eroare de paritate memorie, etc.
– Apariția unor erori de natura software: împărțire la zero, etc.
• In acest context rezulta probleme specifice:
– Care sunt prioritățile acestor întreruperi: dacă mai multe cereri de
întreruperi apar simultan care va fi procesata prima, o întrerupere poate fi la
rândul ei întreruptă?
– Cum se face identificarea (individualizarea) întreruperilor: funcție de
natura specifică a întreruperii vor exista rutine de tratare diferite, care din
ele se va fi selectată si se va executa?
• Cum știm de fapt cine a generat de fapt cererea de întrerupere?

51
Prioritățile întreruperilor
• Când putem să-i permitem unei întreruperi să întrerupă la rândul
ei rutina de tratare a unei alte întreruperi? De ce? Care
întrerupere va fi tratată următoarea?
– In mod tipic prioritățile pot fi asignate de proiectant si programator
diverselor surse de întreruperi conform unor criterii funcționale cum ar
fi: care sunt penalitățile dacă nu se reacționează in timp util, utilitatea
valorilor returnate de rutina de tratare a unei întreruperi specifice, etc.
– Astfel următoarea ordonare a priorităților, de la mai mare la mai mic, ar
putea fi tipică:
• Defect sursă alimentare; Temporizări; Erori; I/O;
• Alocarea priorităților se poate face de programator prin
intermediul unor biți dintr-un registru de comanda sau este
impusă de arhitectura sistemului de întreruperi
• Eventual fiecare sub-clasă de priorități ar putea avea drept
corespondent un bit intr-un registru de stare al unui semnal
transmis către CPU.
– Aceasta ar fi o cerere de întrerupere specifică pentru această sub-clasă
de priorități.

52
Identificarea întreruperilor
• Selecția rutinei de tratare a întreruperii adecvate poate fi
rezolvată in mai multe feluri
• In general, CPU trebuie să identifice sursa întreruperii
(eventual începând cu cea având mai mare prioritate)
pentru a o trata corespunzător
• Identificarea poate fi realizată folosind o interogare
software (software polling) a întreruperilor: rutina de
tratare a întreruperii este cea care “caută” prin interfeţele
de intrare/ieșire (registrele de stare asociate), începând cu
cea mai prioritară interfață
• Odată ce a ajuns la prima interfață care are o cerere de
întrerupere activă, va selecta rutina de tratare a
întreruperii corespunzătoare acelui dispozitiv (interfețe)
• Sincronizarea cu dispozitivul care a generat întreruperea
este facuta pe baza un semnal / unei condiții provenind de
la CPU indicând ca CPU este gata să proceseze
întreruperea (Interrupt Acknowledge ), astfel încât
acesta să o identifice, eventual sub forma unui vector de
întrerupere (interrupt vector).

53
Vectorii de întrerupere
• Un vector de întreruperi face parte dintr-o tabela de
vectori de întrerupere care este o structură de date
care asociază o listă de rutine de tratare a întreruperilor
cu o listă de cereri de întreruperi
– Vectorul de întrerupere este primit de CPU care îl va utiliza ca un
pointer (indicator)/ sau adresa a punctului de început a rutinei de
tratare a întreruperilor, funcție de natura si sursa întreruperii.
• O tabelă de vectori de întrerupere, o tabelă care conține
mai mulți vectori de întrerupere, reprezintă modalitatea
tipică de a asocia fiecare sursă de întrerupere cu o
(sub)rutină de tratare specifică a întreruperii (RTI)
• Conținutul/valoarea acestor vectori indică (direct -
adresa sau indirect - adresa adresei, funcție de familia
concretă de microcontrolere/ microprocesoare) adresa
de început a rutinei de tratare a întreruperii dorite (de
unde se execută prima instrucțiune a RTI)
• Si AVR 8 biți folosește o astfel de tabelă de vectori de
întrerupere
54
Activarea si dezactivarea
întreruperilor (interrupt enable/disable)
• Deși utilizarea priorităților, intr-un anume sens, deja
dezactivează întreruperile de priorități mai mici
nepermițându-le să întrerupă o rutină de tratare a
întreruperii a unei întreruperi mai prioritare, de multe ori este
necesară si o dezactivare dinamică (pe parcursul
execuției programului) sau statică (de la începutul
execuției programului in cazul in care întreruperile
respective nu sunt utilizate )
• Un exemplu activare/dezactivare dinamica ar fi existenţa a
două procese, unul de intrare si unul de ieşire, de exemplu:
– Procesul de intrare citește un caracter de la tastatură si procesul de
citire afișează acest caracter pe o consolă.
– Intrarea si ieșirea trebuie realizate aici in secvență, alternativ
– Pentru a sincroniza cele doua procese s-ar putea utiliza activarea/
dezactivarea întreruperilor pentru cele două surse asociate celor
doua procese.
55
Activarea si dezactivarea întreruperilor(2)

• Activarea/dezactivarea întreruperilor poate fi realizată prin procedeul


generic numit “mascare” (masking)
• Un indicator (un bit) de “mascare” este asociat fiecărei surse de
întrerupere.
• Indicatorii respectivi sunt grupați in cadrul unor registre “de control” al
întreruperilor
– Similar pot fi controlate si prioritățile
• O cerere de întrerupere va ajunge la CPU doar dacă nu este mascată,
adică doar dacă are bitul mască asociat =1.
– In acest exemplu generic “mascarea” înseamnă bit=0, “demascarea” bit=1
(valorile măștii sunt convenționale)
• Dacă o întrerupere poate fi astfel dezactivată prin “mascare” ea este
denumită întrerupere mascabilă: ea poate fi dezactivată/activată
individual de programator
• Exista însă si întreruperi pe care proiectantul arhitecturii de calcul le-a
socotit drept critice, care nu pot fi dezactivate de programator, ele fiind
tot timpul active: ele sunt întreruperi nemascabile
– De exemplu reset-ul (inițializarea hardware) poate fi considerat si o întrerupere
nemascabila, de prioritate maxima! 56
“Comutarea” contextului
• O rutină de tratare a întreruperilor utilizează resurse ale CPU
(registre de uz general, registrul de stare, etc.) si, mai mult,
poate modifica starea acestor resurse
• Este iarăși esențial să se cunoască adresa la care se va
face întoarcerea din RTI (este de fapt o valoare a
registrului numărător program)
• Starea acestor resurse in momentul inițierii procesării
întreruperii alcătuiește cea ce se numește contextul in care
programul a fost întrerupt
• Acest context trebuie salvat înainte de execuția rutinei de
tratare a întreruperii si trebuie restaurat după
întoarcerea din rutina de tratare a întreruperii, astfel încât
după întoarcere contextul original să fie disponibil si intact
• Salvarea si restaurarea contextului este descrisă si ca o
comutare (înainte/înapoi) a contextului (context switching)
• Salvarea/restaurarea contextului este realizată tipic de
compilatoare cu ajutorul uneia sau mai multor structuri
de date de tip stiva, in memorie: se scrie si se citește in/din
aceste structuri de date din memorie
– Aceste scrieri / citiri multiple pot reprezenta eventual penalități din
punct de vedere al timpului de execuție si al efortului
computațional

57
Care ar fi dezavantajele utilizării
întreruperilor?
• Întreruperile sunt asincrone si “eliberează” CPU de alte sarcini, dar
numai dacă este realizată comutarea corectă si eficientă a contextului
• Comutarea contextului este prețul plătit (ca timp de calcul si resurse
de memorie) la fiecare procesare a unei întreruperi: trebuie sa se
scrie si sa se citească informație in/din memorie
• Dacă întreruperile sunt foarte “dese” aceasta comutare a
contextului s-ar putea să consume mai mult timp decât
activitățile utile!
• Ce alternative avem:
– De ce nu am putea elibera (aproape) total CPU de activitatea de tratare a
intrărilor/ieșirilor efectuată de rutinele de tratare a întreruperilor?
– In practică aceasta se poate realiza cu ajutorul unui mecanism
(hardware) de acces direct la memorie (DMA- Direct Memory Acces)
– DMA este utilizat tipic când se dorește un transfer masiv de date de
intrare/ieșire
– Un subsistem DMA este prezent la majoritatea microcontrolerelor de 32 de
biti
– In cadrul familiilor AVR de 8 biți un astfel de mecanism este disponibil la
familia AVR XMEGA si la noile variante AVR Microchip (seriile 0,1,2)
– Daca va interesează subiectul DMA:
https://en.wikipedia.org/wiki/Direct_memory_access
58
Exemplu de interogare cu bucla de așteptare.. In
limbaj C
Cum s-ar realiza interogarea: Dacă programul mai are si alte sarcini de
realizat:
main () main ()
{ {
while(1){/*bucla fara sarcina1();
sfarsit*/ Interogheaza_Tast
Interogheaza_Tast(); sarcina2();
Interogheaza_Tast ();
} …
}
Cum s-ar realiza interogarea tastaturii: Efortul de calcul suplimentar:
• Citim registrul de stare ca să vedem • Efort = “cat de des trebuie să
dacă o tastă e apăsată, dacă este o interogăm” × “ce presupune
citim din registrul de date interogarea ca prelucrări”
• Trebuie să o facem la fiecare N Cat este de uşor de programat? :
msec, intervalul minim de timp in • Este dificil de “combinat” codul pentru
care o tastă poate fi apăsată, interogare/bucla de aşteptare cu
altcumva apăsarea de tastă de către sarcinile normale de prelucrare:
utilizator poate fi pierdută! depinde de cate bucle avem, de
natura sarcinilor de prelucrare normale

59
Întreruperi…. in C
char input_buffer[1024]; void
rutina_tratare_intrerupere_tas
main() tatura(void)
{ {
initializeaza_intreruperi (); Interogheaza_Tast ();
/* scrie in input_buffer*/
while (1){ …….
sarcina1(); }
sarcina2();
Detaliile depind si de natura sistemului de
calcul:
/* prelucreaza ce gasesc in • PC: Tipic sistemul de operare gestionează
input_buffer */ întreruperile
………. • Sisteme incorporate, controlere: daca nu
/* multe alte sarcini..*/ există un sistem de operare, aplicaţia
…….. trebuie să trateze întreruperile
}
}

60
Un model generic de programare utilizând
întreruperile

start Întrerupere Întrerupere Întrerupere

RTI pentru RTI pentru RTI pentru


Iniţializare
sarcina 1 sarcina 2 sarcina 3

Aşteaptă
Întoarcere -I Întoarcere -I Întoarcere -I
evenimente

Procesare
Memorie

61
Sistemul de întreruperi la AVR 8
biți
• Arhitectura AVR 8 biți permite tratarea cererilor de întrerupere
provenind de la mai multe surse diferite, acestea fiind tipic
asociate unor periferice, cu ajutorul unor vectori de
întrerupere care aici sunt adrese fixe de tratare.
– De exemplu, pentru ATMega64 există 34 de surse potențiale de
întrerupere, ATTiny2313 are “doar” 19.
• Există şi posibilitatea ca un eveniment extern să declanșeze
o cerere de întrerupere: exista posibilitatea tratării unor
întreruperi externe.
• În mod convențional si reset-ul (iniţializarea) hardware pentru
un AVR 8 biti poate fi descris ca fiind o întrerupere specială,
cea mai prioritară şi, datorită faptului că ea nu poate fi
dezactivată, numită şi nemascabilă.
– Toate celelalte întreruperi sunt descrise ca mascabile putând fi
dezactivate/activate individual si global

62
Sistemul de întreruperi AVR 8 biți: Întreruperi
externe si Reset pentru ATTiny2313

Întreruperile externe INT0, INT1


pot fi programate ca active pe nivel (L sau H) sau front (L->H sau H->L)

63
Sistemul de întreruperi AVR 8 biți :
vectorii de întrerupere
• ATENŢIE:
• Funcție de varianta de AVR, același tip periferic poate avea
vectori (adrese) diferite de tratare
• Mai mult, pentru variantele MEGA si XMEGA care au si o
zona de Bootloader in memoria program, tabela de vectori
poate fi relocata corespunzător prin programarea unui fuzibil
sau a unui bit dintr-un registru (de exemplu IVSEL din
MCUCR) astfel încât Bootloaderul să poată si el utiliza
întreruperile
• Trebuie consultată neapărat tabela de vectori si eventual
facilitățile de relocare a lor din foaia de catalog a variantei
respective!
– De exemplu pentru ATTiny2313 comparatorul analogic are
vectorul 11 (la adresa 0x000A), iar pentru un anumit ATMega
același periferic are vectorul 19 (0x0024), s.a.m.d

64
Cea mai prioritară

Prioritate
descrescătoare

Cea mai puţin prioritară 65


Iniţializarea vectorilor de întrerupere pentru un ATTiny2313
(exemplu in limbaj de asamblare)
Adresa Eticheta/Cod Comentarii
0x0000 rjmp RESET ; Tratare Reset
0x0001 rjmp INT0 ; Tratare intrerupere externa 0 Prima instrucţiune se execută
0x0002 rjmp INT1 ; Tratare intrerupere externa 1
0x0003 rjmp TIM1_CAPT ; Tratare Timer1 Capture
de aici, de la adresa 0x0000
0x0004 rjmp TIM1_COMPA ; Tratare Timer1 CompareA De fapt este un salt aici..
0x0005 rjmp TIM1_OVF ; Tratare depasire Timer1
0x0006 rjmp TIM0_OVF ; Tratare depasire Timer0
Vectorul este un cuvânt (2 octeti)
0x0007 rjmp USART0_RXC ; Tratare USART0 RX Complete
0x0008 rjmp USART0_DRE ; Tratare USART0,UDR Empty care aici conţine opcodul instrucţiunii
0x0009 rjmp USART0_TXC ; Tratare USART0 TX Complete rjmp INT0 (salt la subrutina de tratare
0x000A rjmp ANA_COMP ; Tratare Comparator Analogic a întreruperii “numita” INT0)
0x000B rjmp PCINT ; Tratare modificare stare Pin
0x000C rjmp TIMER1_COMPB ; Tratare Timer1 Compare B
0x000D rjmp TIMER0_COMPA ; Tratare Timer0 Compare A
0x000E rjmp TIMER0_COMPB ; Tratare Timer0 Compare B
0x000F rjmp USI_START ; Tratare start USI rjmp este o instrucţiune de salt
0x0010 rjmp USI_OVERFLOW ; Tratare depasire USI la adresa de început a subrutinei
0x0011 rjmp EE_READY ; Tratare EEPROM gata (in acest caz, una de tratare a
0x0012 rjmp WDT_OVERFLOW ; Tratare depasire Watchdog
; unei întreruperii)
0x0013 RESET: ……………. ; Inceput program principal
Pentru o aplicaţie in limbaj C, compilatorul va realiza completarea
tabelei de vectori, prin intermediul unor funcţii si directive specifice 66
Se va reveni cu un exemplu complet de utilizare întreruperi (in C)..
Întreruperi externe si Reset la ATMega16

Întreruperea externă INT2


poate fi programată ca activă
doar pe front (L->H sau H->L)

Reset

Întreruperile externe INT0, INT1


pot fi programate ca active pe nivel (L sau H) sau front (L->H sau H->L)
67
Cea mai prioritară

Prioritate
descrescătoare

68
Cea mai puţin prioritară
Tabela de vectori pentru ATMega32

69
Întreruperi externe si Reset la ATMega 328
(capsula PDIP28)

Pe langa INT0 si INT1 mai exista (tot ca functii alternative ale pinilor) PCINT0
la PCINT23: aproape toti pinii pot fi utilizati pentru intreruperi externe!

70
Tabela de vectori pentru ATMega 328

71
Sistemul de întreruperi AVR 8 biți
• Schema utilizată este una vectorială, cu adrese (vectori) de tratare fixe, la fel
ca la multe alte familii de microcontrolere.
• Pentru fiecare întrerupere există rezervat un vector separat, având
dimensiunea fixă de 2 octeți (1 cuvânt), la fel ca și pentru reset, în zona
de început a memoriei de program.
• Toate întreruperile (mai puțin reset-ul) au asignat un bit de activare
individuală care trebuie să fie “1” logic, împreună cu bitul I de activare
globală al întreruperilor în registrul de stare, pentru a se putea utiliza/trata
întreruperea respectivă.
– Prin intermediul acestui bit se spune ca întreruperile pot fi mascate (bit in “0”) sau nu (bit in “1”)
• Bitul I din registrul de stare SREG acționează ca o mască globală (pentru
toate întreruperile) si este controlat de instrucțiunile (limbaj de asamblare)
dedicate SEI (I=“1”) si CLI (I=“0”)
• Întoarcerea dintr-o subrutina de tratare a întreruperii se face cu
instrucțiunea dedicata RETI
– Funcție de valoarea curentă a numărătorului program PC, întreruperile mai pot fi în mod
automat dezactivate atunci când biții (fuzibilele) “Boot Lock” BLB02 sau BLB12 sunt programați
(la un ATMEGA).
• Aceasta caracteristică poate eventual îmbunătăți “protecția” software-ului la copieri neautorizate.

72
Sistemul de întreruperi AVR 8 biți
• Cele mai joase adrese în spațiul de memorie de program, în zona de aplicaţie, sunt
implicit definite ca vectorii de reset şi întrerupere.
• Această listă definește şi nivelele de prioritate ale diferitelor întreruperi.
• Adresa cea mai de jos are nivelul de prioritate cel mai înalt.
– Astfel reset-ul are cea mai mare prioritate, urmat de INT0 – cererea de întrerupere externă 0,
ş.a.m.d.
• Deși vectorii de întrerupere sunt la adrese fixe, ei pot să fie “mutaţi” de la începutul
zonei de aplicație la începutul zonei de Bootloader setând bitul IVSEL în registrul de
control general al întreruperilor GICR (General Interrupt Control Register) – doar la
variantele cu Zona Boot (ATmega).
– Vectorul de reset poate fi, de asemenea, mutat la începutul zonei de Bootloader programând fuzibilul BOOTRST
– doar la ATMega sau Xmega.
• Când o întrerupere este recunoscută şi tratată, bitul I din SREG este
șters şi toate întreruperile sunt dezactivate.
• Utilizatorul poate eventual, in rutina de tratare a întreruperii, să scrie bitul I în “1” logic
pentru a (re)activa întreruperile.
– Toate întreruperile active pot atunci să întrerupă rutina de tratare a întreruperii curente: aşa se
pot imbrica întreruperile (întreruperea întreruperii..)
– Bitul I este în mod automat setat când are loc execuția unei instrucțiuni de revenire
(întoarcere) din rutina de tratare a întreruperii (RETI), făcând posibilă tratarea unei
noi întreruperi: aceasta este diferența esențială intre instrucțiunile RETI si RET
(întoarcerea dintr-o subrutină obișnuită)

73
Exemple: bitul I, biţi de activare întrerupere
- Interrupt enable

74
Tipuri de întreruperi AVR 8 biți: întreruperi
bazate pe un eveniment memorat
• Există în două tipuri de întreruperi din punct de vedere al
comportării/utilizării cererii de întrerupere.
• Acest prim tip de întrerupere este declanșat de un eveniment care
setează un bit (un flag) asociat unei anume întreruperi: cererea de
întrerupere este deci memorata
• La tratarea întreruperii în numărătorul program PC se aduce automat
vectorul corespunzător pentru a se putea executa rutina de tratare a
întreruperii, iar bitul corespondent întreruperii este setat.
• Acești biți asociați întreruperilor pot să fie însă șterși de utilizator
scriind un “1” logic în poziția bitului respectiv.
• Dacă apare o cerere de întrerupere în timp ce bitul corespondent
activării întreruperii este șters, bitul va fi setat şi memorat până când
întreruperea este activată sau bitul este şters prin soft.
• Similar, dacă una sau mai multe cereri de întrerupere apar în timp ce
bitul I este șters, bitul corespondent întreruperii va fi setat şi memorat
până când bitul I este setat din nou, şi atunci cererile vor fi executate în
ordinea priorității.
• Exemple (AVR 8 biti): depășirile in cazul sistemului de temporizare
/numărare

75
Tipuri de întreruperi AVR 8 biți: întreruperi bazate
pe o condiție (nememorată)
• Acest al doilea tip de întrerupere va declanșa o întrerupere doar
atât timp cât condiția de întrerupere este activă (adevărată) si
întreruperea poate fi tratată.
– Aceste întreruperi nu au biți asociați cererii de întrerupere (nu există
fizic o memorare a ei) dar tratarea ei (dacă are loc) este similară
primului tip
– Dacă este posibilă tratarea întreruperii, atunci în numărătorul
program PC se aduce automat vectorul corespunzător pentru a se
putea executa rutina de tratare a întreruperii
– Dacă însă condiția de întrerupere dispare înainte ca
întreruperea (cererea) să fie recunoscută de unitatea centrala,
întreruperea nu va fi luata in considerare şi nu va fi tratată
(informația asociată ei va fi pierdută!).
• La întoarcerea (cu instrucțiunea RETI) dintr-o rutină de tratare a unei
întreruperi în programul principal se vor executa una sau mai multe
instrucțiuni înainte ca orice nouă cerere de întrerupere să poată fi
recunoscută şi tratată.
• Exemple (AVR 8 biți): recepția unui caracter pe portul serial (USART)

76
Întreruperi AVR 8 biți: bitul I din SREG
• Registrul de stare SREG NU este în mod automat
memorat (salvat) când se intră în rutina de tratare a
unei întreruperi şi nici nu este restaurat când se
revine din rutină.
– Această operație trebuie să fie realizată de utilizator
(aplicație), dacă este vorba de limbaj de asamblare
– Pentru limbajul C ea este realizată de compilator
• Când se folosește instrucțiunea CLI pentru a dezactiva
global întreruperile (ștergerea bitului I), ele vor fi imediat
dezactivate.
– Nici o întrerupere nu va fi executată după execuția instrucțiunii
CLI, chiar dacă se ea apare simultan cu instrucțiunea CLI.
• Când se folosește instrucțiunea SEI(setarea bitului I)
pentru a activa global întreruperile, instrucțiunea ce
urmează instrucțiunii SEI va fi executată înaintea de
tratarea oricărei cereri de întrerupere

77
Sistemul de întreruperi AVR 8 biți: timpul de răspuns
al unității centrale la o cerere de întrerupere
Timpul de răspuns la o cerere de întrerupere (numit si
latența întreruperii - interrupt latency ) pentru toate
întreruperile active este de minim patru cicluri (perioade)
de ceas sistem.
• După patru cicluri de ceas rutina de tratare a întreruperii
curente va începe să fie executată.
– În timpul celor patru cicluri de ceas, valoarea PC-ului
corespunzătoare instrucțiunii următoare (doi octeți) este
memorată în stivă, indicatorul de stivă SP este decrementat cu
două unități, şi bitul I din SREG este șters (dezactivare globală a
întreruperilor).
• Tratarea întreruperii presupune un salt la rutina de
tratare a întreruperii şi efectuarea acestui salt durează
încă trei cicluri de ceas.
• Dacă mai apare o cerere de întrerupere în timpul execuției
unor instrucțiuni care durează mai mult de un ciclu (de
exemplu 2 sau 4 cicluri), această instrucțiune multi-ciclu va
fi finalizată înainte ca întreruperea să poată fi tratată.
78
Sistemul de întreruperi AVR 8 biți: timpul de
răspuns in modurile cu putere redusă
• Dacă apare o cerere de întrerupere în timp ce unitatea
centrală este în modul de putere redusa “Sleep”, timpul
de răspuns la cererea de întrerupere este mărit cu încă
patru cicluri de ceas.
– La aceasta se va adăuga și timpul de repornire (de trezire) dintr-
un mod de putere redusa „sleep”.
• Timpul de revenire (întoarcere) din rutina de tratare a
unei întreruperi este de patru cicluri de ceas.
– În timpul acestor patru cicluri ceas, PC-ul (cei doi octeţi) este
extras din stivă, indicatorul de stivă SP este incrementat cu două
unități şi bitul I din SREG este setat (reactivare globală a
întreruperilor)..
• Vom mai reveni asupra descrierii si utilizării
sistemului de întreruperi pentru AVR 8 biți

79

S-ar putea să vă placă și