---
# System prepended metadata

title: Lab2

---

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