Rapport Øving 1 TDT4258 Mikrokontroller Systemdesign Thomas L Falch Torgeir Alstad 21. februar 2010 1
Sammendrag Oppgaven i denne øvingen var å skrive et assemblyprogramm for å få knappene til å styre lysdiodene på et utviklingskort [3]. Mer presist skulle to knapper brukes til å styre hvilken av diodene som skulle lyse. Ved å trykke på den ene eller andre knappen skal lyset flytte seg til høyre eller venstre. Vi har i tillegg, utover det som er beskrevet i oppgaveteksten, implementert en løsning som gjør det mulig å få samme resultat ved en kontinuerlig nedpressing av knappene, som ved mange gjentatte trykk. Vi har løst dette ved å skrive et program som reagerer på avbrudd generert av knappene, og som, når disse intreffer, oppdaterer informasjon om hvilke knapper som er trykkt ned. I programmets hovedløkke brukes denne informasjonen til å styre hvilke dioder som skal lyse. Programmet oppfyller alle kravene i øvingen, og implementerer også den ekstra funkjsonaliteten som ønsket. 2
Innhold 1 Innledning 4 2 Løsningsbeskrivelse 4 2.1 Initialisering............................ 4 2.1.1 I/O-enheter........................ 4 2.1.2 Avbrudd......................... 5 2.2 Hovedløkke............................ 5 2.3 Avbruddsrutine.......................... 7 3 Resultat 9 3.1 Testing.............................. 9 3.1.1 GDB............................ 9 3.1.2 Kjøring.......................... 9 4 Evaluering 11 5 Konklusjon 11 Referanser 11 3
1 Innledning Vi brukte et STK1000 utvikligskort med en AT32AP7000 mikrokontroller fra Atmel [2] [1]. STK1000 har åtte lysdioder plassert i en rekke, og åtte trykknapper plassert under disse. Oppgaven, beskrevet i øvingsheftet [3], gikk ut på å bruke to av knappene til å styre lysdiodene. Ved start skulle en diode være tent. Ved å trykke på den ene eller andre knappen skulle den tente dioden slukke, og dioden til høyere eller venstre for denne bli tent. Hvis den tente dioden var den lengst til venstere, skulle ikke det å trykke på knappen for å flytte lyset til venstere ha noen effekt. Tilsvarende hvis den tente dioden var den lengst til høyere. Vi har i tillegg til dette laget en løsning som gjør det mulig å få samme effekt som ved gjentatte knappetrykk når man holder knappen vedvarende nede. Altså: hvis man holder en av knappene nede vedvarende, vil lyset flytte segbortover,påsammemåtesomommanhaddetrykketmangegangerraskt etterhverandre. For å løse denne oppgaven skrev vi et assemblyprogram. Vi brukte avbrudd for å håndtere input fra knappene. Når knappene blir trykket ned eller opp blir et avbrudd generert. Dette sørger for at en rutine blir kjørt, som oppdaterer informasjon om hvilke knapper som er trykt ned. Denne informasjonen blir brukt i programmets hovedløkke for å styre hvilke dioder som skal tennes. 2 Løsningsbeskrivelse Oppgaven er løst med et program skrevet i assembly. Programet består av tre hoveddeler. I den første delen foregår ulik initialisering, særlig av I/O-enhetene og avbrudskontrolleren. Den andre delen er programmets hovedløkke. Her brukes informasjon samlet inn i avbruddsrutinen for å avgjøre hvilke knapper som er nede, dette brukes for å oppdatere hvilke lysdioder som skal tennes. Den siste delen er avbrudsrutinen. Her sjekkes det om knappene er trykket opp eller ned, slik at denne informasjonen kan overføres til hovedløkken. 2.1 Initialisering 2.1.1 I/O-enheter AT32AP7000 har en I/O-kontroller, kalt PIO [2] [3]. Denne har flere porter, som hver kan kobles til ulike enheter, både inn- og utenheter. Hver port 4
har 32 I/O-linjer. For å kunne kommunisere med disse enhetene må PIO kontrolleren først initialiseres. Kommunikasjon med PIO foregår ved å skrive dennes registere. Disse er lageravbildet, så man skriver og leser i praksis til og fra bestemte adresser i minnet. I dette tilfellet var lysdiodene koblet til PIOens port C, mens knappene var koblet til PIOens port B [3]. For å initialisere lysdiodene ble først den aktuelle PIO portens PER(PIO Enable Register) satt til 1 for de aktuelle linjene, for å la PIOen styre dem. Vidrere ble OER (Output Enable Register) satt til 1 for de aktuelle linjene, for å bruke porten som en outputport. For knappene ble PER og PUER (Pull-Up Enable Register) satt til 1, det siste for å kunne lese knappestatus. 2.1.2 Avbrudd For å kunne reagere på input fra knappene må disse settes opp slik at de kan gi avbrudd. Dette ble gjort ved å sette de relevante bittene i knappenes PIO-ports IER (Interrupt Enable Register) til 1, for å aktivere avbrudd fra knappene. Videre ble prosessoren og avbruddskontrolleren satt opp slik de kan finne den riktige avbrudsrutinen for avbrudd fra knappene. Prosessoren regner ut adressen til denne ved å legge sammen sit EVBA(Exception Vector Base Addres) register og en delvis adresse den får fra avbrudskontrolleren. EVBA ble satt til 0, og adressen til rutinen ble lagt inn i avbruddskontrollerens register for avbrudd fra knappene. Til slutt ble avbrudd aktivert globalt. 2.2 Hovedløkke Figur 1 viser programflyten i programets hovedløkke. Hvike lysdioder som skal lyse eller ikke blir styrt av innholdet i et register. Hver av de åtte nederste bitene representerer en diode, og er satt til 1 hvis dioden skal lyse. Ved å shifte dette registeret til høyere eller venstere kan man endre hvilken diode som skal lyse. Man må i tillegg sjekke at den dioden som lyser ikke er den lengst til høyere eller venstere før man shifter. Hvorvidt de to aktuelle knappene (SW0 og SW2) er trykket ned eller ikke lagres i to registere, et for hver knapp. Når knappene er nede er registerene satt til 1, når de er oppe er de satt til 0. Registerene blir satt i avbruddsrutinen, når kanappestatusen endres. Hvis ingen avbrudd genereres vil det samme skje i hver iterasjon, enten vil den samme dioden forbli tent, eller lyset vil bevege seg mot høyere eller venstere til det når kanten, hvor det vil stoppe. 5
Slår av alle dioder SW0 Oppe SW2 Nede Nede På høyere ende På venstre ende Oppe Nei Nei Ja Shift til venstre Ja Shift til høyere Slår på dioder Vent Figur 1: Flytdiagram for hovedløkken. SW2 og SW0 er venstere og høyere knapp, respektivt. I hovedløkken blir ikke disse sjekket direkte, man sjekker registere som holder deres status. Siden SW0 blir sjekket først, vil det å trykke ned begge kanppene få samme effekt som å bare trykke ned SW0, uavhengig av hvilken knapp som ble trykket ned først. 6
For å hindre at lyset beveger seg for raskt når en knapp holdes nede er det lagt inn en ventepause i hovedløkken. Denne er impementert som en løkke som teller ned et stort tall, som vist i figur 2. reg = STORT_TALL reg = reg - 1 FALSE reg == 0 TRUE Ferdig Figur 2: Flytdiagram som viser venting. 2.3 Avbruddsrutine Avbruddsrutinen blir kallt hver gang knappene endrer status, dvs både når de går opp og ned. Dermed er det lett å til en hver tid å ha oversikt over hvilke knapper som er nedtrykt. Vi har et register for de to knappene vi er interessert i. Hver gang knappene endrer status, med andre ord hver gang avbrudsrutinene blir kallt, oppdateres verdiene i registerene, avhengig av hvilke kanpper som er nedtrykt. I et større program vil det være naturlig å lagre disse verdiene i minnet, ikke i registere, særlig hvis man skal ha overskit over mange knapper. I dette enkle programmet valgte vi i steden å dedikere to registere til oppgaven. Dette gjør det svært enkelt å kommunisere mellom hovedløkken og avbruddsrutinen. Figur 3 viser flytdiagrammet for avbruddsrutinen. Det første som ble gjort var å lagre alle registerene i bruk på stakken. Dette gjør det mulig å bruke registerene til andre ting i avbruddsrutinen, uten at verdiene går tapt. I vår løsning har vi bare lagret de registerene som er i bruk på stakken. Naturlig nokk er ikke registrene som holder statusen til kanppene lagret (jf. diskusjonen over). Etter dette ble det kompenseret for bouncing. Dette er et fenomen som skyldes at knappenes kontakter spretter opp og ned noen ganger etter 7
Pusher på stakk Debouncing Leser statusregister og nedtrykkte knapper Sjekker nedtrykte knapper SW2 nede SW0 nede Set reg for venstere Set reg for høyere Ellers Popper fra stakk Returnerer Figur 3: Flytdiagram for avbruddsrutinen. SW2 og SW0 er venstere og høyere knapp, respektivt 8
nedslag, og derfor kan gi forvirrende signaler [3]. Ved å vente en kort stund, ved hjelp av samme teknikk som i hovedløkken, ble dette problemet ungåt. Videre ble kanppenes PIO ports ISR (Interrupt Status Register) register lest. Dette gir enheten beskjed om at avbruddet er håndtert. Videre ble PDSR(Pin Data Status Register) lest, som inneholder informasjon om hvilke knapper som er nedtrykt. Denne informasjonen ble så brukt til å sette verdien i registerene som holder informasjon om knappenes status. Deretter ble verdien til registerene hentet fra stakken, og til slutt returnerer man. 3 Resultat Programet som ble skrevet løser oppgaven, og lar brukeren kontrollere knappene som beskrevet i 1. I tillegg ble det implementeret ekstra funksjonalitet, (også beskrevet i 1) som også virket som planlagt. 3.1 Testing For å sikre at programmet fungerte som ønsket ble det testet. To typer testing ble gjennomført. I den ene ble GDB brukt. I den andre programmet kjørt, og knappene trykket på. 3.1.1 GDB Avlusingsverktøyet GDB [3] ble brukt til å sjekke at programmet oppførte seg slik vi hadde tenkt. Det ble satt to breakpoints inne i hovedløkken, et helt i begynnelsen, og et før ventingen. I tilleg ble det satt et breakpoint inne i avbruddsrutinen. Testingen og resultatene er i korte trekk gjengitt i tabell 1. Som vi ser gir knappene avbrudd både når de går opp og ned, og dette fører til at avbruddsrutinen blir kjørt. Videre ser vi at kontinuerlig nedpressing fører til at indeksen på den tente dioden øker, uten nye abvrudd. Etter at knappen er sluppet opp, forblir den samme dioden tent. En utskrift fra kjøringen, som detaljert viser oppførselen er vedlagt. 3.1.2 Kjøring Programmet ble også testet ved å kjøre det. Resultatet er gjengitt i tabell 2. 9
Test 1 Test 2 Br1, LED:0 Br1, LED:0 SW2 ned SW2 ned Br2 Br2 Br1 Br1 Br3 Br3 Br1, LED:1 Br1, LED:1 SW2 opp Br3 Br2 Br1, LED:2 Br1 Br3 Br1, LED:1 Tabell 1: Testresultater. Hver kolonne er en test, og leses nedover. Br1 og Br3 er breakpointene i hovedløkka (Br1 linje 85, Br2 linje 61), Br2 i avbruddsrutinen. Mellom hver celle ble GDB kommandoen cont kjørt. Knappene ble holdt nede helt fra SWx ned til SWx opp. Starttilstand Input Effekt LED:0 SW0 kort LED:0 LED:0 SW2 kort LED:1 LED:0 SW3 kort LED:0 LED:0 SW2 lang LED: 0 1 2 3 4 LED:7 SW0 kort LED:6 LED:7 SW5 kort LED:7 LED:7 SW0 lang LED:7 6 5 4 3 Tabell 2: Testresultater. Tabellen viser hvilke dioder som lyste ved start, hvilke knapper som ble trykt ned, og resultatet. Notasjonen x y angir at diode x lyste en kort stund, før den ble slukket, og diode y tent. Betegnelsene kort og lang er kvalitative 10
Som det fremgår av testresultatene virker programet slik det er tenkt. 4 Evaluering Vi synes oppgaven var spennende og utfordrende, men ikke uoverkommelig vanskelig. Vi synes øvingsheftet og det utleverte rammeverket fungerte bra, menmednoenunntak.brukenavlddpc,ogikkeminstgrunnentilbrukenav denne burde vært nevnt i øvingsheftet. Videre burde det ikke vært utlevert noen makefile. Å bli tvunget til å lage denne selv ville vært mer lærerikt. 5 Konklusjon Vi lagde et program som lot brukeren kontrolere lysdiodene på utviklingskortet, slik at to av knappene kunne brukes til å styre hvilken lysdiode som skulle lyse. Vi implementerte også ekstra funksjonalitet slik at det å holde en knapp lenge inne tilsvarte mange gjentatte knappetrykk. Vi implementerte løsningen med et assemblyprogram. I dette blir hvilke knapper som til en hver tid er nedtykt oppdatert i en rutine som kalles når knappene genererer avbrudd. I programets hovedløkke brukes denne informasjonen til å avgjøre hvilke dioder som skal tennes. Utover at det var mye nytt materiale å sette seg inn i (assemblykodesyntaks, detaljene rundt I/O-håndtering) i begynnelsen presenterte denne øvingen ingen store vanskeligheter. Referanser [1] Atmel. Atmel corporation - avr solutions - tools card. http:// www.atmel.com/dyn/products/tools_card_mcu.asp?tool_id=3918. Aksessert 18.02.2010. [2] Atmel. AT32AP7000 Datasheet, 2006. http://www.atmel.com/dyn/ resources/prod_documents/doc32003.pdf. Aksessert 18.02.2010. [3] IDI Datamaskingruppa. Øvingshefte i TDT4258 Mikrokontroller systemdesing. NTNU, 2010. 11