--- title: Lab2 --- <div style="height: 1000px; padding-top: 200px"> <center><p style="font-size: 40px; font-weight: 600">Laboratorieøving 2</p></center> <center><p style="font-size: 30px">Litt om samenhengen mellom høynivå- og lavnivåinstruksjoner.</p></center> <center><p style="font-size: 20px">Gruppe: SA</p></center> <center><p style="font-size: 20px">Erik Martin (250660)</p></center> <center><p style="font-size: 20px">Tormod Kvam (250612)</p></center> </div> # Laboratorieøving 2 ## Innholdsliste [TOC] ## Realisering av en enkel blinkeløkke **Deloppgåvenr:** 5.2 **Dato:** 26.09.2022 **Navn:** Gjenskape blinkstyrings programmet uten bryter **Funksjon:** LD2 skal blinke, men skal ikke kontrolleres av bryteren. Koden skal altså refaktoriseres &emsp;&emsp;og bygges. **Framgangsmåte for utføring:** 1. lage et nytt prosjekt i en ny mappe. 2. Endre programmfilen *main.c* slik som det er vist i laboppgaven. 3. Sjekke at optimaliserings innstillingen er satt til **-O0** og at LD2 blinker etter bygging og opplasating. 4. Kommentere ut for-løkka. 5. Sette optimaliseringen til **-Ofast** og bygge og laste ned på nytt. **Resultat:** * Variablen: * **k** er en *global/statisk* variabel. * Blir lagret i flash segmentet i minnet. * **i** er en *lokal* variabel. * Blir lagret i stack segmentet i minnet. * Forslag til assemblyinstruksjone for *while-løkka* * ```assembly movw r0, #0x5678 ;siste 16bit fra addressen til variablen k movt r0, #0x1234 ;første 16bit fra addressen til variablen k movw r1, #0x080C ;siste 16bit fra addressen til GPIOA_ODR movt r1, #0x4001 ;første 16bit fra addressen til GPIOA_ODR ldr r2, [r0, #0] ;laster inn verdien til k i r2 L1: ;while starter eor r2, r2, #0x20 ;XOR verdien til k med 0x20 str r1, [r2, #0] ;lagrer resultatet i GPIOA_ODR b L1 ;brancher til starten av while, uten vilkår ``` **Analyse og konklusjon:** Lager et nytt prosjekt og setter opp et forslag til en assemblyinstruksjon for while-løkka <br /> **Deloppgåvenr:** 5.3 **Dato:** 26.09.2022 **Navn:** Kom i gang med utviklingsverktøyet **Funksjon:** LD2 skal blinke, men skal ikke kontrolleres av bryteren. Koden skal altså refaktoriseres &emsp;&emsp;og bygges. **Framgangsmåte for utføring:** 1. Lager et **break-point** i koden på linjen med `k = k ^ 0x20;` 2. Starter debugging programmet 3. Åpner *memory browser* for å sjekke baseaddressen til SRAM 4. Kjører et par ganger gjennom koden i *debug-mode* **Resultat:** * Hva skjer når du kjører programmet i *debug-mode*? * Programmet stopper da opp og venter på *user input*. Ved a trykke **Resume (F8)** så kjører den 1 gang gjennom while-loopen. * Etter å ha bladd igjennom minneaddressen ved started av *SRAM* `0x20000000` fant vi at * 0x20000000 - 0x20000003 inneholder variabel *k* altså `0x12345678` * ``` | 0x12 | <-- 0x20000003 | 0x34 | <-- 0x20000002 | 0x56 | <-- 0x20000001 | 0x78 | <-- 0x20000000 ``` * Er ARM Cortex M3 *big endian* eller *little endian*? * Basert på det vi ser over i minneallokeringen av variabel *k* så vil ARM Cortex M3 være *little endian* fordi `0x78` som er LSB i `0x12345678` er lagret i `0x20000000` mens `0x12` som er MSB i `0x12345678` er lagret i `0x20000003` * Addresseen til variablen *k* er: * I dette eksempelet er den lik baseaddressen til SRAM altså `0x20000000`. * Hvilken av instruksjonene får lysdioden til å lyse? * `str r3, [r2, #12]` er instruksjonen som slår på/av lysdioden. * ```assembly 08000274: ldr r2, [pc, #16] ; 08000276: ldr r3, [r3, #0] ; laster inn variablen k i GPIOA_ODR 08000278: eor.w r3, r3, #32 ; xor variablen k med 0x20 0800027c: str r3, [r2, #12] ; lagrer variablen som ble xor med 0x20 tilbake i k. 0800027e: b.n 0x8000278 <main+200> ; kaller whileloopen igjen unconditionally. ``` * Etter kjøring av programmet mens vi observerer register verdiene: * Ser at `r3` variablen endrer seg for hver *loop* den skifter frem og tilbake mellom `0x12345678` og `0x12345658` altså *switches* bit 5 hver gang. * LSB på binær form for den siste byten i r3 er * 01011000 - 58 * 01111000 - 78 * Hvor mange instruksjoner er det nå i while-løkka? * ```assembly 08000160: ldr r3, [pc, #20] ; (0x8000178 <main+44>) 08000162: ldr r3, [r3, #0] 08000164: eor.w r3, r3, #32 08000168: ldr r2, [pc, #12] ; (0x8000178 <main+44>) 0800016a: str r3, [r2, #0] 0800016c: ldr r2, [pc, #12] ; (0x800017c <main+48>) 0800016e: ldr r3, [pc, #8] ; (0x8000178 <main+44>) 08000170: ldr r3, [r3, #0] 08000172: str r3, [r2, #12] 08000174: b.n 0x8000160 <main+20> ``` * Det er 10 instrukjoner, i motsetning til de 5 som var når vi hadde *fast* optimalisering. **Analyse og konklusjon:** Ser på forskjellige måter å *debugge* koden på. Kan bruke *debug-mode* til å se på innholdet i minnet til $\mu$P og kan se assemblyinstruksjonene til den ferdigbyggede koden. ## Tidsanalyse av Blinkeprogram **Deloppgåvenr:** 5.4.1 **Dato:** 30.09.2022 **Navn:** Litt om klokkene i mikrokontrolleren **Funksjon:** Skal endre klokkesignalet prosessoren opererer på fra **64MHz** til **72MHz** ved hjelp av STM32CubeIDE GUI **Framgangsmåte for utføring:** 1. Åpne *Blinkanalyse.ioc* i STM32CubeIDE 2. Finne **PLL Mu(ltiple)x(ar)** og bytte fra HSI til HSE som inngang. 3. Endre PLL-modul multiplikatoren fra *X16* til *X9*. 4. Lagre fila, sjekke at **-Ofast** optimaliseringen er aktivert og bygge programmet. **Resultat:** Fikk gjordt de spesifiserte endringene for klokkesignalet og bygget koden. <br /> **Deloppgåvenr:** 5.4.2 **Dato:** 30.09.2022 **Navn:** Utrekning av teoretisk utføringstid for blinkeløkka **Funksjon:** **Framgangsmåte for utføring:** Bruke informasjon fra deloppgave 5.3.1 til å svare på etterfølgende spørsmål. **Resultat:** * ARM Cortex-M3 har et 3-stegsrør (eller pipeline). Disse tre stegene er: hent, dekod og utfør. Altså prosessoren kan hente en ny instruksjon samtidig som den dekoder den forrige instruksjonen og utfører den før det. * Teoretisk set kan prosessoren gjøre en hoppinstruksjon ila. 2 klokkesyklar hvis den bruker ting som *branch prediction* og *speculative fetch*. * Det vi da ta 6 klokkesykler for å utføre en *loop* av while-løkken. * $\mu$p bruker ca. 13.9ns å utføre en klokke sykel. Så for å utføre 6 sykler tar det $13.9ns*6 = 83.4ns$ **Analyse og konklusjon:** Regner ut den teoretiske utføringstiden for blinkinstruksjonen til å være 6 klokkesykler som tar ca. 83.4ns å utføre. **Deloppgåvenr:** 5.4.3 **Dato:** 02.10.22 **Navn:** Måling av utføringstid med oscilloskop **Funksjon:** **Framgangsmåte for utføring:** 1. Finne frem skopet og sette utstyret opp som vist i *figur 6*. 2. Gå gjennom instillingsprosessen på skopet for å få vist riktig omløpstid som oppgitt i oppgavefremstillingen. 3. Endre optimalisering og kode 4. Gjør step. 2 på nytt og svare på relaterte spørsmål. **Resultat:** ![](https://i.imgur.com/zigIXMU.png) * Ved å se på $\Delta$x, kan vi se at periodetida er på 166.000 nanosekunder. * En gjennomgang av while-løkka vil da være halvparten av periodetiden, $\frac{1}{2}*166.000 = 83.000$ nanosekund * $\frac{83.000}{13.9} \approx 6$, som er det svaret vi kom fram til i oppgave 5.4.2. * Det vil være 2 klokkesykler på hver operasjon. Altså: $2*13.9ns = 27.8ns$ per instruksjon * ```c k = k ^ 0x20; ``` > Tar 2 klokke sykler (1 sykel for den aritmetiske operasjonen og 1 sykel for lagring av verdien i *k*) * ```c GPIOA->ODR = k; ``` > Tar 2 klokke sykler (1 sykel for hentingen av verdien i *k* og 1 sykel for å lagre den i *GPIOA_ODR*) * Det er plass til $\frac{1*10^6}{13.9} \approx 72 000$ gjennomsnittlige C-instruksjoner innen ett millisekund. * Etter å ha byttet optimalisering til 0, ble omløpstida 1000 nanosekunder. * Det tilsvarer $\frac{500}{13.9} \approx 36$ sykler. * Vi kan se at fast kutter 30 ekstra "unødvendige" instruksjoner som blir kjørt. * ```assembly 0800027c: ldr r1, [pc, #20] ; (0x8000294 <main+220>) 0800027e: ldr r3, [r3, #0] 08000280: ldr r2, [pc, #24] ; (0x800029c <main+228>) 08000282: eor.w r3, r3, #32 08000286: str r3, [r1, #12] 08000288: ldr r0, [r2, #8] 0800028a: b.n 0x8000282 <main+202> ``` * $\frac{\frac{1}{2}*306.000ns}{13.9ns} = \frac{153.000}{13.9ns} \approx 11$ sykler. Det tar da 5 ekstra sykler for den ekstra instruksjonen. **Analyse og konklusjon:** Bruker skopet til å se forskjell i signaltid med forkjellige typer optimalisering. **-Ofast** bruker 6 klokkesykler som er ca. 83ns mens **-O0** (default) bruker 36 klokkesykler som er ca. 500ns.