This shows you the differences between two versions of the page.
|
cn2:laboratoare:07 [2019/11/17 15:34] mihaela.lungoci [4. Exerciții] |
— (current) | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ===== Laboratorul 07 - GPIO 2: Intrări ===== | ||
| - | ==== Obiective ==== | ||
| - | În acest laborator vom îmbunătăți implementarea noastră a modulului de GPIO adăugând posibilitatea pinilor de a funcționa și ca intrări. | ||
| - | |||
| - | {{page>cn2:laboratoare:07:obiective&nofooter}} | ||
| - | |||
| - | ==== 1. Registrele de control al perifericelor și al porturilor I/O ==== | ||
| - | |||
| - | |||
| - | În laboratorul trecut am învățat că dacă un pin are funcția de GPIO, atunci vom putea să îi controlăm direcția și valoarea în mod programatic prin scrieri și citiri în/din anumite registre. | ||
| - | |||
| - | Registrele care controlează comportamentul unui port sunt: | ||
| - | |||
| - | * DDRx: Port x Data Direction Register (ie: DDRA și DDRB) | ||
| - | * PORTx: Port x Data Register (ie: PORTA si PORTB) | ||
| - | * PINx: Port x Data Input Register (ie: PINA și PINB) | ||
| - | |||
| - | Aceste registre sunt toate pe 8 biți iar fiecare bit controlează comportamentul unui pin al portului respectiv. Ca și în laboratorul trecut, ne vom limita la portul A al microcontroller-ului. | ||
| - | |||
| - | == PORTA (recapitulare) == | ||
| - | |||
| - | În laboratorul trecut am învățat ce efect avea schimbarea unui bit din registrul PORTA: | ||
| - | |||
| - | * PORTAn: dacă bitul n este 0 atunci pinul respectiv va lua valoarea LOW, iar dacă bitul este 1 atunci pinul va lua valoarea HIGH. | ||
| - | |||
| - | == DDRA == | ||
| - | |||
| - | Registrul DDRA controleaza direcția pinilor din portul A astfel: | ||
| - | |||
| - | * DDRAn: dacă bitul n este 1 atunci pinul va funcționa ca și ieșire (microcontroller-ul va putea impune o tensiune electrică pe acel pin), iar dacă bitul este 0 atunci pinul respectiv va funcționa ca și intrare (microcontroller-ul nu va impune nicio tensiune pe linie) | ||
| - | |||
| - | == PINA == | ||
| - | |||
| - | Din registrul PINA putem citi valoarea tensiunii de pe pinii portului A astfel: | ||
| - | |||
| - | * PINAn: dacă bitul n este 0 atunci pinul respectiv are valoarea LOW, iar dacă bitul este 1 atunci pinul are valoare HIGH | ||
| - | |||
| - | ==== 2. Instrucțiunile SBI și CBI ==== | ||
| - | |||
| - | Până acum am învațat că dacă schimbăm un bit din DDRA sau PORTA putem să influențăm comportamentul unui pin. Însă instrucțiunile ''in'' și ''out'' nu pot scrie decât valori pe 8 biți. Spre exemplu, dacă dorim să schimbăm doar bitul 5 din DDRA în 1 atunci pașii pe care trebuie sa îi urmăm sunt: | ||
| - | |||
| - | <code asm> | ||
| - | ldi R17, 0b00100000 ; încărcăm în R17 o mască ce are 1 pe bitul 5 | ||
| - | in R16, DDRA ; încărcăm în R16 valoarea din DDRA | ||
| - | or R16, R17 ; în urma operației sau între R16 și R17 în R16 bitul 5 va fi pus pe 1 | ||
| - | out DDRA, R16 ; stocăm valoarea din R16 înapoi în DDRA | ||
| - | </code> | ||
| - | |||
| - | <note tip> | ||
| - | Pentru a pune bitul 5 din DDRA pe 1 a trebuit să folosim o mască de biți ce are 1 **pe poziția** 5. | ||
| - | </note> | ||
| - | |||
| - | Fiindcă acțiunea de a schimba un bit în 1 (set) sau în 0 (clear) este una întâlnită des în programele ce rulează pe arhitectura AVR aceasta include două instrucțiuni ce permit schimbarea unui bit dintr-un registru ce se află în primele 32 de adrese din I/O Space în 0 sau în 1: ''cbi'' (Clear Bit in Register) și ''sbi'' (Set Bit in Register). Ele primesc ca și argumente adresa registrului (în intervalul [0:31]) și numărul bitului (în intervalul [0:7]). Dacă rescriem codul folosind aceste înstrucțiuni el devine: | ||
| - | |||
| - | <code asm> | ||
| - | sbi DDRA, 5 | ||
| - | </code> | ||
| - | |||
| - | <note tip> | ||
| - | Instrucțiunile ''cbi'' și ''sbi'' primesc ca și argument **numărul** bitului pe care dorim să-l schimbăm, nu o mască de biți. | ||
| - | </note> | ||
| - | |||
| - | {{page>cn2:laboratoare:07:continut&nofooter}} | ||
| - | |||
| - | ==== 3. TL;DR ==== | ||
| - | Pentru a modifica valoarea unui registru I/O putem sa folosim: | ||
| - | * instructiunea OUT cu masca de biti: | ||
| - | <code asm> | ||
| - | LDI R16, 7 | ||
| - | OUT 0x01, R16 ; DDRA = 00001111 | ||
| - | </code> | ||
| - | * instructiunile SBI si CBI pentru a modifica un singur bit | ||
| - | <code asm> | ||
| - | LDI R16 0 | ||
| - | OUT 0x01, R16 ; DDRA = 00000000 | ||
| - | SBI 0x01, 5 ; DDRA = 00100000 | ||
| - | SBI 0x01, 4 ; DDRA = 00110000 | ||
| - | CBI 0x01, 5 ; DDRA = 00010000 | ||
| - | </code> | ||
| - | |||
| - | {{page>cn2:laboratoare:07:tldr&nofooter}} | ||
| - | |||
| - | ==== 4. Exerciții ==== | ||
| - | |||
| - | **Task 01** (4p) Extindeți modulul gpio astfel încât să suporte și intrări și ieșiri. Urmăriți comentariile marcate cu ''TODO 1'' din ''gpio.v'' și ''cpu.v''. | ||
| - | |||
| - | **Task 02** (2p) Decodificați instrucțiunile ''sbi'' și ''cbi'' și completați logica necesară execuției lor. Urmăriți comentariile marcate cu ''TODO 2'' din ''signal_generation_unit.v'', ''decode_unit.v'' și ''control_unit.v''. | ||
| - | |||
| - | **Task 03** (1p) 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. | ||
| - | |||
| - | **Task 04** (1p) Urcați programul de la punctul precedent pe placa de dezvoltare. Portul A va fi mapat pe cele 8 led-uri astfel: PA0 - LED0, ..., PA7 - LED7. Portul B va fi mapat pe cele 8 switch-uri astfel: PB0 - SW0, ..., PB7 - SW7. | ||
| - | |||
| - | **Task 05** (2p) Scrieți un program care să aprindă led-urile în următoarea secvență folosind instructiunle SBI si CBI. Încărcați-l pe placa de dezvoltare: | ||
| - | |||
| - | t0 *------* | ||
| - | t1 -*----*- | ||
| - | t2 --*--*-- | ||
| - | t3 ---**--- | ||
| - | t4 ---**--- | ||
| - | t5 --*--*-- | ||
| - | t6 -*----*- | ||
| - | t7 *------* | ||
| - | |||
| - | **Task 06** (Bonus 2p) Modificați programul de la punctul 5 astfel încât viteza de derulare a secvenței să fie controlată prin intermediul portului B. Încărcați-l pe placa de dezvoltare. | ||
| - | |||
| - | |||
| - | {{page>cn2:laboratoare:07:exercitii&nofooter}} | ||
| - | |||
| - | ==== 5. Resurse ==== | ||
| - | * {{ | Scheletul laboratorului}} | ||
| - | <hidden> | ||
| - | * {{ | Soluția laboratorului}} | ||
| - | </hidden> | ||
| - | * [[http://www.atmel.com/Images/Atmel-8235-8-bit-AVR-Microcontroller-ATtiny20_Datasheet.pdf | Datasheet ATTiny20]] | ||
| - | * [[http://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf| Setul de Instrucțiuni AVR]] | ||
| - | * [[https://www.xilinx.com/support/documentation/university/XUP%20Boards/XUPNexys3/documentation/Nexys3_rm.pdf| Datasheet Digilent Nexys]] | ||
| - | * {{:cn2:laboratoare:avrasm.zip | avrasm}} - tool java pentru a genera cod mașină AVR. | ||
| - | |||
| - | {{page>cn2:laboratoare:07:resurse&nofooter}} | ||