This is an old revision of the document!


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):

  1. DDRx: Data Direction Register
    • un bit setat pe 0 indică faptul ca va fi folosit pentru 'citire'
    • un bit setat pe 1 indică 'scriere'
  2. PORTx: Data Register: (Stabilesc cum vreau să fie un pin)
    1. 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)
    2. Dacă DDRx e setat ca intrare ('citire')
  3. 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

java -jar avrasm.jar input.txt output.txt

Î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 al 9-lea și al 10-lea LED.

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 avrasm pentru a-l scrie în fișierul rom.v.

task01_skel.asm

task01_skel.asm

PINA        equ 0x00
DDRA        equ 0x01
PORTA       equ 0x02
PINB        equ 0x04
DDRB        equ 0x05
PORTB       equ 0x06
TCCR0A      equ 0x19
TCCR0B      equ 0x18
TIMSK       equ 0x26
OCR0A       equ 0x16
 
; TODO 1


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 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

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.

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

Resurse

cn2/laboratoare/009.1702825495.txt.gz · Last modified: 2023/12/17 17:04 by george_mircea.grosu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0