This shows you the differences between two versions of the page.
cn2:laboratoare:009 [2023/12/17 17:55] george_mircea.grosu [Exerciții] |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Laboratorul 09 - Configurări ===== | ||
- | ==== Cheatsheet ==== | ||
- | |||
- | === GPIO === | ||
- | Folosind GPIO (General-Purpose Input/Output) putem controla un pin al unui circuit integrat. De exemplu, putem aprinde un led folosind instrucțiuni AVR sau putem citi starea unui pin - LOW sau HIGH. Pinii ce suportă GPIO sunt grupați în porturi (grupuri de 8 pini logici numite ''A'' sau ''B'') controlate de registre speciale (pe câte 8 biți): | ||
- | - DDRx: Data Direction Register | ||
- | * un bit setat pe 0 indică faptul ca va fi folosit pentru 'citire' | ||
- | * un bit setat pe 1 indică 'scriere' | ||
- | - PORTx: Data Register: (Stabilesc cum vreau să fie un pin) | ||
- | - Dacă DDRx e setat ca ieșire ('scriere') | ||
- | * dacă un bit n este 0 atunci pinul respectiv va fi legat la LOW (GND) | ||
- | * dacă un bit n este 1 atunci pinul respectiv va fi legat la HIGH (VCC) | ||
- | - Dacă DDRx e setat ca intrare ('citire') | ||
- | - PINx: Data Input Register (Indică starea reală a unui pin) | ||
- | * daca un bit este 0 atunci pinul respectiv are valoarea LOW | ||
- | * daca un bit este 1 atunci pinul are valoare HIGH | ||
- | * **Unde x poate fi A sau B** | ||
- | |||
- | În memoria microcontrollerului de la 0x00 la 0x3F gasim I/O Space. Aici se află toate registrele de lucru cu periferice și, desigur, DDRx, PORTx și PINx. De exemplu registrul PORTA are adresa 0x02. | ||
- | |||
- | Pentru a scrie citi date din I/O Space putem folosi instrucțiunile LDS/STS, însă recomandat este să folosim instrucțiunile speciale pentru lucru de memoria I/O Space ce se execută mai rapid: | ||
- | * ''OUT A, Rr'': Scrie (Store) în I/O Space la adresa A valoarea din registrul Rr | ||
- | * ''IN Rd, A'' : Citește (Load) din I/O Space de la adresa A și pune în registrul Rd | ||
- | |||
- | Pentru a modifica un singur bit dintr-un registru de configurare putem folosi instrucțiunile ''SBI''/''CBI''. | ||
- | |||
- | === TIMER === | ||
- | |||
- | * Un timer este un simplu numărător implementat în hardware | ||
- | * Orice timer trebuie să aibă: | ||
- | * O sursă de ceas | ||
- | * Un registru contor | ||
- | * Trei valori de referință: BOTTOM, MAX și TOP | ||
- | * PWM este o tehnică de generare a unui semnal analogic pornind de la unul digital | ||
- | * Semnalul analogic obtinut depinde de factorul de umplere al semnalului digital | ||
- | * Timerele de pe ATtiny20 conțin 3 registre importante: TCNT0, OCR0A/OCR0B, TCCR0A, TCCR0B | ||
- | * TCNT0 este registrul cu contor | ||
- | * OCR0A/OCR0B definesc valori de comparație iar OCR0A poate fi folosit la TOP | ||
- | * TCCR0A și TCCR0B sunt registre de control pentru modul de funcționare | ||
- | * Moduri de funcționare: | ||
- | * Normal | ||
- | * Timer-ul numără crescător de la 0 la 255, apoi se resetează la 0 | ||
- | * CTC | ||
- | * Timer-ul numără crescător de la 0 la OCR0A, apoi se resetează la 0 | ||
- | * Fast PWM | ||
- | * Timer-ul numără crescător de la 0 la 255 (sau OCR0A), apoi se resetează la 0 | ||
- | * Starea pinilor OC0A/OC0B poate fi schimbată la comparaței și BOTTOM | ||
- | |||
- | === INTRERUPERI === | ||
- | |||
- | * Întreruperile sunt eveniment asincrone execuției programului | ||
- | * Dacă apare o întrerupere, procesorul oprește execuția normală a programului după instrucțiunea curentă și execută o rutină de tratare | ||
- | * Tabela vectorilor de întreruperi conține câte o intrare pentru fiecare întrerupere care duce la rutina ei de tratare | ||
- | * În cadrul rutinei de tratare trebuie să dăm acknowledge la întrerupere | ||
- | * Întreruperile pot fi activate/dezactivate la nivel global și demascate/mascate la nivel individual | ||
- | * Excepție fac NMI | ||
- | * Pe AVR | ||
- | * Activarea/Dezactivarea la nivel global se face cu instrucțiunile SEI/CLI | ||
- | * Demascarea/Mascarea se face prin registrele de control | ||
- | * E.g. TIMSK | ||
- | * Tabela vectorilor de întreruperi se află la adresa 0 | ||
- | * La intrarea într-o rutină de tratare întreruperile sunt dezactivate la nivel global | ||
- | * La ieșirea dintr-o rutină de tratare întreruperile sunt activate la nivel global | ||
- | * O întrerupere este tratată dacă | ||
- | * Întreruperile sunt activate la nivel global (bitul ''I'' din ''SREG'' este 1) | ||
- | * Întreruperea este demascată la nivel individual (masca ei este 1) | ||
- | * Întreruperea este activă (flag-ul ei este activ) | ||
- | |||
- | ==== Exerciții ==== | ||
- | |||
- | <note> | ||
- | java -jar avrasm.jar input.txt output.txt | ||
- | </note> | ||
- | |||
- | <note important>În scheletul de laborator veți găsi fișierul de constrângeri configurat astfel: | ||
- | |||
- | * Port B mapat la primele 8 switch-uri din dreapta. | ||
- | * Port A mapat la primele 8 led-uri din dreapta. | ||
- | * Prescaler mapat pe primele 5 switch-uri din stânga, având valoarea selectată afișată în format binar pe ledurile corespunzătoare switch-urilor. | ||
- | * Cele 2 ieșiri ale Timer0 mapate pe LED-urile 8 și 9. | ||
- | </note> | ||
- | |||
- | **Task 01** (2p) Scrieți un program care setează portul A ca ieșire, portul B ca intrare, apoi, într-o buclă, citește valoarea de pe portul B și o scrie pe portul A. Folosiți tool-ul {{:cn2:laboratoare:avrasm.zip | avrasm}} pentru a-l scrie în fișierul ''rom.v''. | ||
- | |||
- | <spoiler task01_skel.asm> | ||
- | <code asm> | ||
- | PINA equ 0x00 | ||
- | DDRA equ 0x01 | ||
- | PORTA equ 0x02 | ||
- | PINB equ 0x04 | ||
- | DDRB equ 0x05 | ||
- | PORTB equ 0x06 | ||
- | OCR0B equ 0x15 | ||
- | OCR0A equ 0x16 | ||
- | TCCR0B equ 0x18 | ||
- | TCCR0A equ 0x19 | ||
- | TIMSK equ 0x26 | ||
- | |||
- | ; TODO 1 | ||
- | |||
- | main: | ||
- | RJMP main | ||
- | </code> | ||
- | </spoiler> | ||
- | \\ | ||
- | |||
- | <hidden> | ||
- | **Task 02** (2p) Scrieți un program care scrie pe portul A următoarea secvență, folosind instrucțiunle SBI si CBI. Vom verifica secvența folosind simularea. | ||
- | |||
- | t0 *------* | ||
- | t1 -*----*- | ||
- | t2 --*--*-- | ||
- | t3 ---**--- | ||
- | t4 ---**--- | ||
- | t5 --*--*-- | ||
- | t6 -*----*- | ||
- | t7 *------* | ||
- | | ||
- | - `-` înseamnă led stins | ||
- | - `*` înseamnă led aprins | ||
- | - (dacă am lega la pinii PAx leduri :-) ) | ||
- | |||
- | |||
- | **Task 03 (3p)** Scrieți și simulați un program în {{:cn2:laboratoare:avrasm.zip | avrasm}} care: | ||
- | * Configurează timer-ul 0 in modul ''fast PWM, TOP == 0xFF'' | ||
- | * HINT: Ce biți controlează modul de operare al timer-ului? Ce valoare trebuie să aibă acei biți? În ce registre se află acei biți? | ||
- | * Setează ceasul timer-ului 0 la ''clkI/O (No prescaling)'' | ||
- | * HINT: Ce biți controlează sursa de ceas a timer-ului? Ce valoare trebuie să aibă acei biți? În ce registru se află acei biți? | ||
- | * Configurează timer-ul 0 să schimbe starea pinului OC0A astfel: ''Clear OC0A on Compare Match, set OC0A at BOTTOM (non-inverting mode)'' | ||
- | * HINT: Ce biți controlează pinul OC0A? Ce valoare trebuie să aibă acei biți? În ce registru se află acei biți? | ||
- | * Setează valoarea lui OCR0A la 63 | ||
- | * Simulați pentru a vedea semnalul PWM | ||
- | </hidden> | ||
- | |||
- | **Task 02 (3p)** Extindeți programul de la punctul 1 astfel încât să configurați Timer0 folosind valoare introdusă folosind portul B pentru ajustarea factorului de umplere al modulării. Verificați comportamentul celor două ieșiri folosind LED-urile 8 și 9. | ||
- | * Configurează timer-ul 0 in modul ''fast PWM, TOP == OCR0A'' | ||
- | * HINT: Ce biți controlează modul de operare al timer-ului? Ce valoare trebuie să aibă acei biți? În ce registre se află acei biți? | ||
- | * Setează ceasul timer-ului 0 la ''clkI/O (No prescaling)'' | ||
- | * HINT: Ce biți controlează sursa de ceas a timer-ului? Ce valoare trebuie să aibă acei biți? În ce registru se află acei biți? | ||
- | * Configurează timer-ul 0 să schimbe starea pinului OC0A astfel: ''Clear OC0A on Compare Match, Set OC0A at BOTTOM (non-inverting mode)'' | ||
- | * HINT: Ce biți controlează pinul OC0A? Ce valoare trebuie să aibă acei biți? În ce registru se află acei biți? | ||
- | * Configurează timer-ul 0 să schimbe starea pinului OC0B astfel: ''Set OC0A on Compare Match, Clear OC0A at BOTTOM (inverting mode)'' | ||
- | * Setează valoarea lui ''OCR0A'' la valoarea citită de pe ''portul B''. | ||
- | |||
- | **Task 04 (3p)** Plecând de la următorul schelet de cod, creați un program care schimbă starea pinului PA0 folosindu-se de o întrerupere, cât timp bucla principală este într-o buclă infinită. Simulați programul. | ||
- | |||
- | <code asm task04_skel.asm> | ||
- | DDRA equ 0x01 | ||
- | PORTA equ 0x02 | ||
- | TCCR0A equ 0x19 | ||
- | TCCR0B equ 0x18 | ||
- | TIMSK equ 0x26 | ||
- | OCR0A equ 0x16 | ||
- | |||
- | rjmp main ; Adresa 0x0000 | ||
- | reti ; Adresa 0x0001 | ||
- | reti ; Adresa 0x0002 | ||
- | reti ; Adresa 0x0003 | ||
- | reti ; Adresa 0x0004 | ||
- | reti ; Adresa 0x0005 | ||
- | reti ; Adresa 0x0006 | ||
- | reti ; Adresa 0x0007 | ||
- | reti ; Adresa 0x0008 | ||
- | rjmp TIM0_COMPA_ISR ; Adresa 0x0009 | ||
- | reti ; Adresa 0x000A | ||
- | reti ; Adresa 0x000B | ||
- | reti ; Adresa 0x000C | ||
- | reti ; Adresa 0x000D | ||
- | reti ; Adresa 0x000E | ||
- | reti ; Adresa 0x000F | ||
- | reti ; Adresa 0x0010 | ||
- | |||
- | TIM0_COMPA_ISR: | ||
- | ; TODO 4: Schimbați (toggle) starea pinului PA0. | ||
- | |||
- | main: | ||
- | ; TODO 4: Configurați pinul PA0 ca și ieșire. | ||
- | |||
- | ; TODO 4: Porniți un timer care să genereze o întrerupere de comparație pe canalul A. Puneți | ||
- | ; valoarea 42 ca valoare de comparație pentru canalul A. | ||
- | |||
- | ; TODO 4: Activați întreruperile global. | ||
- | |||
- | ; Deși programul pare să stea într-o buclă infinită, ar trebui să vedem că totuși starea | ||
- | ; pinului PA0 se schimbă. | ||
- | loop: | ||
- | rjmp loop | ||
- | </code> | ||
- | ==== Resurse ==== | ||
- | |||
- | [0] [[https://gitlab.cs.pub.ro/calculatoare-numerice/cn2-public/-/tree/main/lab09/|Scheletul laboratorului]] | ||
- | |||
- | <hidden> | ||
- | |||
- | |||
- | [0] {{:cn2:laboratoare:09:skel:lab9_skel_v2.zip|Scheletul laboratorului}} | ||
- | </hidden> | ||
- | [1] [[http://www.atmel.com/Images/Atmel-8235-8-bit-AVR-Microcontroller-ATtiny20_Datasheet.pdf | Datasheet ATTiny20]] | ||
- | |||
- | [2] [[http://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf| Setul de Instrucțiuni AVR]] | ||
- | |||
- | [3] [[https://www.xilinx.com/support/documentation/university/XUP%20Boards/XUPNexys3/documentation/Nexys3_rm.pdf|Datasheet Digilent Nexys 3 Spartan6]] | ||
- | |||
- | [4] [[https://gitlab.cs.pub.ro/calculatoare-numerice/cn2-public/-/tree/main/lab09/solutii_avr | Solutii]] |