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

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