Rapport Øving 2 TDT4258 Mikrokontroller Systemdesign Thomas L Falch Torgeir Alstad 19. mars 2010 1
Sammendrag Oppgaven i denne øvingen var å skrive et program for å generere lyd på et utviklingskort [4]. Mer presist skulle programmet fungere slik at man ved å trykke på de ulike knappene på kortet kunne spille av ulike lydeffekter. Vi har i tillegg, utover det som er beskrevet i oppgaveteksten, implementert en løsning hvor man kan bruke to av knappene til å regulere volumet på den avspillte lyden. Vi har løst dette ved å skrive et program som har to avbrudsrutiner. Den ene avbruddsrutinen blir kjørt jevnlig, med avbrudd generert av en klokke. Denne rutinen mater lydgenereringsenheten med verdier. Den andre rutinen reagerer på avbrudd generert av knappene. I denne rutinen brukes informasjon om hvilke knapper som ble trykt ned til å velge hvilken lydeffekt som skal spilles av, eller om volumet skal endres. Programet oppfyller alle kravene i øvingen, og implmenterer også den ekstra funksjonaliteten som ønsket. 2
Innhold 1 Innledning 4 2 Løsningsbeskrivelse 4 2.1 Initialisering............................ 4 2.2 Generering av lyd......................... 6 2.2.1 Generering av en tone.................. 6 2.2.2 Representasjon av lydeffekter.............. 8 2.2.3 Generering av lydeffekt................. 8 2.2.4 Stopping og løkking................... 9 2.3 Kontroll.............................. 9 2.3.1 Avlesing av knapper................... 9 2.3.2 Endring av lydeffekt................... 9 2.3.3 Endring av volum.................... 10 2.4 Samtidighet............................ 10 3 Resultat 11 3.1 Testing.............................. 11 3.1.1 Kjøring.......................... 11 3.1.2 Enhetstesting....................... 11 4 Evaluering 12 5 Konklusjon 12 Referanser 12 3
1 Innledning Vi brukte et STK1000 utviklingskort med en AT32AP7000 mikrokontroller fra Atmel [3] [1]. Dette har en ABDAC, Audio Bitstream Digital to Analog Converter, som kan brukes til å lage lydsignaler som kan sendes til en høytaler. Videre har det åtte trykknapper. Oppgaven, beskrevet i øvingsheftet [4], gikk ut på å skrive et program i C, som skulle kjøre på utviklingskortet uten noe operativsystem, og generere lydeffekter ved hjelp av ABDACen. Mer presist skulle en lydeffekt spilles av hver gang en knapp ble trykket ned. Vi har i tillegg til dette laget en løsning som gjør det mulig å endre volumet på lydeffektene, både mens de spilles av, og også mellom avspilling av lyder. Vi har laget et system som kan ha vilkårlig mange og lange 1 lydeffekter. Vi har laget seks, en for hver ledig knapp. Videre er systemet laget slik at lydeffekter kan spilles av i en uendelig løkke. For å løse denne oppgaven skrev vi et C-program, som hovedsakelig består av to avbruddsrutiner. Den ene blir kjørt jevnlig, basert på avbrudd fra en klokke. Rutinen sjekker om det skal byttes til neste tone i lydeffekten, og mater ABDACen med data, basert på gjeldende lydeffekt og tone i denne. Den andre avbruddsrutinen blir kjørt etter avbrudd fra knappene. I denne brukes informasjon om hvilken knapp som ble trykkt ned til å bytte gjeldende lydeffekt, eller til å endre volumet. 2 Løsningsbeskrivelse Oppgaven er løst med et program skrevet i C. Programet består av to hoveddeler, samt en mindre initialiseringsdel, og en del globale variable. Den ene hoveddelen er avbruddsrutinen for ABDACen, med tilhørende hjelpefunksjoner, denne sørger for å mate ABDACen med data. Den andre er avbruddsrutinen til knappene, med tilhørende hjelpefunksjoner, som kontrollerer hvilken lydeffekt som spilles av. 2.1 Initialisering I begynnelsen av programmet blir maskinvaren initialisert og avbruddene registrert. Avbruddene registreres ved å kalle funksjonen register interrupt(), som blant annet tar funksjonen som utgjør avbruddsrutinen, samt detaljer 1 Åpenbart begrenset av tilgjengelig minne. 4
Figur 1: Skjematisk fremstilling av programmet. Til høyere sees kode, til venstre data. En pil fra en kodebit til en variabel angir at koden skriver til variabelen. En pil fra en variabel til en kodebit angir at koden leser variabelen. Pilene fra lydeffekt og tone til lydeffektene angir at dette er indekser i lydeffektarrayen. 5
om maskinvaren som genererer avbruddet som argumenter. Ved å bruke denne funksjonen ble avbruddsrutinene til ABDACen og knappene registrert. Knappene ble aktivert ved å skrive til PIOBs PER, PUER og IER registere. ABDACen skal kontrolleres av Peripheral A, ikke PIO. Siden ABDA- Cen er koblet til PIO kontrollerens port B, pinne 20 og 21, må denne portens PDR (PIO Disable Register) register for disse pinnene settes til 1, dette gjør at PIOen ikke kontrollerer dem. Videre må portens ASR (Peripheral A Select Register) register settes til 1 for disse pinnene, dette gjør at Peripheral A kontrollerer dem. Klokken som styrer ABDACen blir kontrollert av Power Manageren. Denne startes, og dens frekvens justeres ved å skrive til registeret for dens sjette generelle klokke, siden ABDACen er koblet til denne [4]. Til slutt må ABDACen aktiveres, og avbrudd fra den må aktiveres, også dette gjøres ved å skrive til registere. 2.2 Generering av lyd Lyden som genereres er firkantbølger, som vist i figur 2. Samplene man gir til ABDACen tilsvarer punkter på kurven. Man kan da generere firkantbølger ved i en periode å mate ABDACen med en viss verdi (høye verdier), så mate den med den samme verdien ganget med -1 (lave verdier) en periode osv. Hvor hurtig man bytter mellom å mate ABDACen med høye og lave verdier bestemmer frekvensen (tonen) på lyden. I figur 2 ser man to ulike frekvenser. For å kunne lage lydeffekter må man derfor ha et system som bytter mellom høyt og lavt signal basert på gjeldende tone/frekvens, og et som bytter gjeldende tone/frekvens. 2.2.1 Generering av en tone For å generere en tone må man jevnlig bytte mellom høyt og lavt signal. I vår kode implementerer funksjonen getnextsample() denne funksjonaliteten. Funksjonen blir kallt av avbruddsrutinen til ABDACen, altså hver gang ABDACen skal mates med en ny verdi. Funksjonen bruker en teller, som vist i figur 3. I dette tilfellet er value en verdi som angir den aktuelle tonen, og dosomething() en metode som ganger fortegnet til verdien som ABDACen har blit matet med med -1. På den måten vil ABDACen mates med den høye verdien i en periode, så den lave i en periode, så den høye osv, slik som ønsket. Hvor mange ganger den mates med den ene verdien før det byttes til den andre avhenger av value. Dette vises i figur 4, man får value + 1 høye verdier, så like mange lave osv. I figur 1 representerer firkanten merket 6
Figur 2: Lyden genereres ved å mate ABDACen med samples med jevne mellomrom, hvis man lar disse veklse mellom to verdier får man firkantbølger, som her. Hvor ofte man bytter mellom høye og lave verdier bestemmer frekvensen. I tidsrommene merket f1 og f2 er frekvensene ulike. Figur 3: En generell teller. Hver gang den kjører vil tellervariabelen i bli sjekket mot value. Hvis de er like blir dosomething() kjørt. Hvis ikke blir i inkrementert. 7
Bytt amplitude funksjonen getnextsample(). Den bruker gjeldende sang og tone til og finne verdien for value i telleren, og bytter evt. fortegnet på amplituden. 2.2.2 Representasjon av lydeffekter Som det fremgår av diskusjonen over kan en tone/frekvens representeres med et tall. Sammenhengen mellom dette tallet og den faktiske frekvensen blir f = F 2n+1 der F er frekvensen avbruddsrutinen blir kallt med, og n er det aktuelle tallet. Siden en tone kan representeres med et tall, kan en lydeffekt representeres med en serie med tall i en array, og flere lydeffekter med en todimensjonal array. Dette vises i figur 1. To variabler holder indeksen til gjeldende lydeffekt og tone. Figur 4: Illustrasjon av forholdet mellom telleren i figur 3 og lydbølgen. Her er value 2. Hver gang i når 2 blir dosometing() kjørt, så den verdien får byttet fortegn. For å få et jevnt mønster starter i på -1 2.2.3 Generering av lydeffekt For å generere en lydeffekt må man jevnlig bytte hvilken tone som skal spilles. Siden tonene er lagret i et array vil det i praksis si å inkrementere en 8
variabel som holder indeksen til gjeldende tone. Bytting av tone blir også gjort med en teller, som i figur 3. Her er derimot value en global konstant som angir hvor lenge hver tone skal spilles av. dosometing() er en funksjon som inkrementerer indeksen til den gjeldende tonen. I figur 1 representerer firkanten merket Neste tone koden som bytter tone. Denne skriver variabelen tone, som er indeksen til gjeldende tone i lydeffekterarrayet. 2.2.4 Stopping og løkking Alle lydeffektene avsluttes enten med konstanten END eller LOOP som vist i figur 1, som er implementert med negative verdier. Hver gang indeksen til gjeldende tone inkrementeres, sjekkes det for disse verdiene. Hvis LOOP oppdages settes indeksen til 0, slik at lydeffekten spilles på nytt. Hvis END oppdages blir ikke pekeren inkrementert. Kode i getnextsample() beskrevet i 2.2.1 sørger for at amplituden blir 0 hvis gjeldende tone er END. 2.3 Kontroll Den andre hoveddelen av programmet er avbruddsrutinen til knappene. Denne blir kalt hver gang en av knappene blir trykket opp eller ned. I den styres avspillingen av lydeffektene, basert hvilken knapp som ble trykket ned. Kontrollen foregår ved at knappeavbruddsrutinen skriver til variabler som ABDACens avbruddsrutine leser, figur 1 illustrerer forholdet. 2.3.1 Avlesing av knapper Før knappene blir lest blir det tatt høyde for bouncing, dette gjøres med en løkke som teller ned fra et stort tall. Videre blir verdien i knappenes PIO ports PDSR register lest inn, og omgjort til indeksen til knappen, som vist i figur 5. Hvis ingen knapper er trykkt ned, blir ingenting gjort i avbruddsrutinen. Dette skjer etter avbrudd generert av at knappene slippes. 2.3.2 Endring av lydeffekt Siden lydeffektene er lagret i en todimensjonal array, kan man styre hvilken lydeffekt som skal spilles av ved å endre en variabel som er indeksen til gjeldene lydeffekt. I knappeavbruddsrutinen blir dette gjort hvis en av knappene 0-6 blir trykket ned. Gjeldende lydeffekt blir da satt til samme verdi som indeksen til knappen. Hvis det er færre enn seks lydeffekter, sørger kode i getnextsample(), beskrevet i 2.2.1, for at amplituden settes til 0, hvis en knapp uten lydeffekt velges. Videre settes gjeldende tone til den første 9
Figur 5: Omgjøring til den nedtrykkte kanppens indeks. Registeret er egentlig 32b, men bare de nederste åtte bittene påvirker resultatet. tonen i lydeffekten. Dermed vil man starte lydeffekten på nytt, selv om man ikke bytter lydeffekt. Figur 1 viser hvordan knappeavbrudsrutinen endrer verdien til lydeffekt, som er indeksen til gjeldende lydeffekt, og tone, som er gjeldende tone i lydeffekten. 2.3.3 Endring av volum Volumet styres av absoulttverdien til amplituden. I steden for å lagre amplituden som en verdi, blir absoluttverdien og fortegnet lagret hver for seg. I getnextsample() beskrevet i 2.2.1 blir derfor bare fortegnet ganget med -1, og ABDACen mates med produket av fortegnet og absoluttverdien. For å endre volumet blir absoluttverdien av amplituden økt eller redusert i knappeavbruddsrutinen, hvis man trykker på knapp 7 eller 8. Dette er illustrert i figur 1. 2.4 Samtidighet Siden de to avbruddsrutinene påvirker de samme dataene, og, særlig fordi avbruddsrutinen til ABDACen blir kjørt svært ofte, kan man tenke seg at det vil føre til problemer hvis den ene avbruddsrutinen blir kjørt midt i den andre. Siden begge avbruddene har samme prioritet, og et avbrudd ikke vil avbryte et avbrudd med samme prioritet [2] blir ikke dette noe problem. 10
3 Resultat Programmet løser oppgaven fullt ut, og implementerer den ekstra funksjonaliteten. Oppgaven og den ekstra funksjonaliteten er beskrevet i 1. 3.1 Testing For å sikre at programmet fungerte som ønsket ble det testet. To typer testing ble gjennomført. I den ene ble programmet kjørt, kanppene trykket på og resultatet observert. I den andre ble enhetstesting av alle funksjonene kjørt. 3.1.1 Kjøring Programmet ble testet ved å kjøre det. Resultatet er gjengitt i tabell 2. For alle testene var innholdet i lydeffektarrayet som vist i tabell 1 75 67 59 56 E 89 89 89 89 E 44 50 56 59 L 79 79 79 79 L Tabell 1: Innholdet i lydeffektarrayet under testen. Hver rad er en lydeffekt, hver tall en tone. E og L angir konstantene END og LOOP, som beskrevet i 2.2.4. Som det fremgår av testresultatene virker programet slik det er tenkt. 3.1.2 Enhetstesting Programet ble også testet ved å kjøre enhetstester av alle funksjonene. Dette ble gjort ved å skrive et programm som kallte alle funksjonene i programmet og sammenlignet resultatet, enten hva funksjonen returnerte, eller hvordan den påvirket de globale variablene, med forventede verdier. Siden enhetstestingen ble kjørt på en PC ble de delene av programmet som samhandlet med maskinvaren fjernet. I tilfeller hvor verdier fra maskinvaren var nødvendige, ble disse levert av testkoden. Verdier som i utgangspunktet skulle sendes til maskinvaren ble returnert til testkoden. Kjøringen av testkoden fant ingen feil. Koden, det modifiserte programmet, og utskrift fra kjøringen er vedlagt. 11
Input Resultat - Ingen lyd SW0 Fire stigende toner, etterfulgt av ingen lyd SW1 En langvarig tone, etterfulgt av ingen lyd SW2 Fire dalende toner, i løkke SW3 En vedvarende tone SW4 Ingen lyd SW3, SW4 En vedvarende tone til SW4, deretter ingen lyd SW2, SW1 Fire dalende toner i løkke til SW1, deretter en langvarig tone, så ingen lyd SW2, SW6, SW6, SW6 Fire dalende toner, i løkke, lavere volum for hver SW6 SW2, SW7, SW7, SW7 Fire dalende toner, i løkke, høyere volum for hver SW7 Tabell 2: Testresultater. Input angir hvilke kanpper som ble trykket ned, Resultat beskriver resultatet. 4 Evaluering Vi synes oppgaven var spennende og utfordrende, men ikke uoverkommelig vanskelig. Vi synes øvingsheftet var bra, og ga all den nødvendige informasjonen. 5 Konklusjon Vi lagde et program som spilte av lydeffekter, slik at man ved å trykke på ulike knapper spilte av ulike lydeffekter. I tillegg implementerte vi ekstra funksjonaliet som gjorde det mulig å endre volumet på lydeffektene under avspilling. For å løse oppgaven skrev vi et C-program. Dette bestod av en avbruddsrutine, som jevnlig matet lydavspillingsenheten med nye verdier, og på den måten lagde lyd. Videre ble hvilken lydeffekt som skulle spilles av endret i avbruddsrutinen til knappene, basert på hvilke knapper som var trykket ned. Utover at det var mye nytt materiale å sette seg inn i (programering i C, detaljene rund kontroll av ABDACen osv.) i begynnelsen presenterte denne øvingen ingen store vanskeligheter. 12
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. AVR32101: Configuring the AVR32 Interrupt Controller. http: //www.atmel.com/dyn/resources/prod/documents/doc32010.pdf. Aksessert 18.03.2010. [3] Atmel. AT32AP7000 Datasheet, 2006. http://www.atmel.com/dyn/ resources/prod_documents/doc32003.pdf. Aksessert 18.02.2010. [4] IDI Datamaskingruppa. Øvingshefte i TDT4258 Mikrokontroller systemdesing. NTNU, 2010. 13