---
# System prepended metadata

title: Lab1

---

---
title: Lab1
---

<div style="height: 1000px; padding-top: 200px">
<center><p style="font-size: 40px; font-weight: 600">Laboppgave 1</p></center>
<center><p style="font-size: 30px">Bli kjent med platformkortet og utviklingsverktøyet</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>
# Laboratorieoppgave 1

## Innholdsliste
[TOC]

## Spesifikasjon av funksjonene til IBS-et.
**Deloppgåvenr:** 6.2
**Dato:** 12.09.2022
**Navn:** Blinkstyring
**Funksjon:** Et lys skal blinke med en fast og passelig periodetid, dvs. slik at blinkingen er godt 
&emsp;&emsp; synlig. Ved å holde inne en bryter, skal lyset være av. Når en slipper brytaren, skal 
&emsp;&emsp; blinkinga fortsette.
**Innganger:** Et signal fra en bryter som er høyt eller lavt ved trykk på bryteren og som har
&emsp;&emsp; motsatt logisk nivå når denne er slept.
**Utganger:** Et signal til lyskilden som styrer denne av eller på.

## Vurdering og valg av maskin- og programvareplattform.
Alle laboppgavene i ELE210 som dreier seg om mikrokontrollerbaserte system, vil ha same maskinvare- og programvareutviklingsplattform, Nucleo-F1013RB og STM32CubeIDE. Programmeringsspråket er C.

## Utvikling av detaljert maskinvarestruktur.
**Deloppgåvenr:** 6.4
**Dato:** 12.09.2022
**Navn:** Kom i gang med utviklingsverktøyet
**Funksjon:** Skal velge ut bryter og lysdiode som skal brukes i laboppgaven
**Framgangsmåte for utføring:** 
1. Bruke brukermanualen for å finne en lysdiode og bryter som kan brukes og programmeres.
2. Finne hvilke pinner disse er koblet til på mikrokontrolleren.
3. Finne hvilke signalnivå som brykes for å slå lysdioden av og på
4. Finne hvilke signalnivå som bryteren har når den er inntrykt eller *slept*.
5. Tegne et blokksjema av maskinvarestrukturen.

**Resultat:** Ved utførelse av fremgangsmåte:
1. Finner via brukermanualen at **LD2** og bryter **B1** er programmerbare så disse blir valgt.
2. GPIO pinner for bryter og lysdiode
&emsp; - LD2: 
&emsp;&emsp; - Koblet til perifermodulen GPIO_A
&emsp;&emsp; - For å påvirke det logiske nivået må vi skrive til Output Data Register (ODR)
&emsp;&emsp; - Nivåverdien for PA5 settes i registerbit 5
&emsp; - B1: 
&emsp;&emsp; - Koblet til perifermodulen GPIO_C
&emsp;&emsp; - For å lese det logiske nivået må vi til Input Data Register (IDR)
&emsp;&emsp; - Nivåverdien for PC13 settes i registerbit 13.
3. Brukermanualen side 21 viser at PA5 er koblet til D13 via SB42 og videre SB21.
&emsp; - På baksiden av kortet ser vi at både SB21 og SB42 har en *motstand*
&emsp; - Det logiske nivået for pinnen for at den skal gi lys må være 1.
4. Brukermanualen side 19 viser at PC13 er koblet til B1 via SB17
&emsp; - På baksiden av kortet ser vi at både SB17 også har en *motstand*
&emsp; a) Hvis bryteren er på (inntrykt) vil det logiske nivået være 1.
&emsp; b) Hvis bryteren er av (slept) vil det logiske nivået være 0.
5. ![](https://i.imgur.com/YiHiNi8.png)
* Periodetiden for klokkesignalet til $\mu$P er $t_{clk\ \mu P} = \frac{1}{f_{clk\ \mu P}} = \frac{1}{72*10^6} = 13.9ns$
* ![](https://i.imgur.com/9G0LtAR.png)



**Analyse og konklusjon:** Velger altså bryter B1 som er en del av GPIO_C og kan lese det logiske 
&emsp;&emsp; nivået via IDR og lysdiode LD2 som er en del av GPIO_A og som kan settes til å lyse eller
&emsp;&emsp; ikke via å sette eller nullstille ODR

## Utvikling av detaljert programvarestruktur.

**Deloppgåvenr:** 6.5.1
**Dato:** 12.09.2022
**Navn:** Kom i gang med utviklingsverktøyet
**Funksjon:** Skal sette opp og initialisere utviklingsverktøyet som spesifisert.
**Framgangsmåte for utføring:** Følge oppsette som er oppgitt i oppgaven
**Resultat:**
&emsp; - Verifikasjon av diodepinnen: 
&emsp;&emsp; - Denne er satt til `GPIO_Output`. 
&emsp;&emsp; - Hvis denne funksjonen setter data i ODR får lysdioden så burde den være riktig.
&emsp; - Sjekk av programmene som er genererte:
&emsp;&emsp; - main() metoden: 
```c
    int main(void)
    {
      /* USER CODE BEGIN 1 */

      /* USER CODE END 1 */

      /* MCU Configuration--------------------------------------------------------*/

      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();

      /* USER CODE BEGIN Init */

      /* USER CODE END Init */

      /* Configure the system clock */
      SystemClock_Config();

      /* USER CODE BEGIN SysInit */

      /* USER CODE END SysInit */

      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_USART2_UART_Init();
      /* USER CODE BEGIN 2 */

      /* USER CODE END 2 */

      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
      }
      /* USER CODE END 3 */
    }
```
&emsp;&emsp; - Fordi det er ingenting i while-loopen så  vil det ikke skje noen ting med 
&emsp;&emsp;&emsp;lysdioden.
**Analyse og konklusjon:** Fik kommet i gang med utviklingsverktøyet og ting ble 
&emsp;&emsp;generert riktig.

<br />

**Deloppgåvenr:** 6.5.2
**Dato:** 12.09.2022
**Navn:** Tegning av programstruktur for det genererte programmet
**Funksjon:** Skal tegne en mer detaljert utgave av flytskjemaet.
**Framgangsmåte for utføring:** Tegne flytskjema med detaljerte versjoner av de 
&emsp;&emsp;ønskede funksjonene
**Resultat:** 
```mermaid

graph TD;

    subgraph "les_brytar()"
        les_brytar(["Les_brytar()"]) --> GPIO_C_ODR([Les nivået til GPIO_C_ODR_Pin_13])
        GPIO_C_ODR --> Returner([Return GPIO_C_ODR_Pin_13])
    end

    subgraph "snu_ld2_nivaa()"
        snu([Snu_ld2_nivaa]) --> lesbrytar[les_brytar]
        lesbrytar --> if{"Bryter er inntrykkt"}
        if --> |Ja| nullstill([nullstill LD2 nivå])
        nullstill --> returner([Return])
        if --> |Nei| toggle([Toggle LD2 nivå])
        toggle --> returner
    end
    
	subgraph "main()"
    	main(["hovedprogram main()"]) --> init[Initialisering av RCC og GPIO]
        init --> while{i != 0?}
        while --> |Ja| snuld2nivaa[snu_LD2_nivaa]
        snuld2nivaa --> while
        
    end
    
    subgraph "SysTick()"
    	interrupt(["Avbruddsmetode: SysTick_Handler()"]) --> HAL["Inkrementer tikkeren for systemet HAL_IncTick()"]
        HAL --> return([Return])
        avbrud>Abvrudd fra SysTick timeren] --> interrupt
    end

```
**Analyse og konklusjon:** Fikk satt opp en antatt fungerende programflyt 

## Utvikling av programkode og testing av denne.

**Deloppgåvenr:** 6.6.1
**Dato:** 12.09.2022
**Navn:** Først ein test av kode for blinking
**Funksjon:** Skal legge inn oppgitt kode i *main()*
**Framgangsmåte for utføring:** Legge inn oppgitt kode fra lab oppgave utskrift i riktig 
&emsp;&emsp;programfil.
**Resultat:** 
```c
uint32_t i;
  while (1)
  {
    /* USER CODE END WHILE */
	  GPIOA->ODR = GPIOA->ODR ^ 0x0020;
	  for(i=0;i<0x100000;i++);
    /* USER CODE BEGIN 3 */
  
```
&emsp; - Når vi bygger og kjører programkoden blinker bare lysdioden, og om vi endrer 
&emsp;&emsp;verdiene kan vi få den til å blinke raskere eller tregere.
&emsp; - `GPIOA->ODR = GPIOA->ODR ^ LD2_Pin` 
&emsp;&emsp; - Ønsker bare å endre på PA5 (bit 5).
| Bit nr.  | 15   | 14   | 13   | 12   | 11   | 10   | 9    | 8    | 7    | 6    | 5    | 4    | 3    | 2    | 1    | 0    |
| -------- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
| XOR       | 0    | 0    | 0    | 0    | 0    | 0    | 0   | 0    | 0    | 0    | 1    | 0    | 0    | 0    | 0    | 0    |
| Gir      | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  | 1/0  | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  |

&emsp;&emsp; - Snur altså bare på bit 5 som da får addressen 0000|0000|0010|0000 = 0x0020.

**Analyse og konklusjon:** Fikk vist at XOR operasjonen bare endrer på bit 5 i GPIO_A_ODR.

<br />

**Deloppgåvenr:** 6.6.2
**Dato:** 12.09.2022
**Navn:** Metodeutvikling
**Funksjon:** Lag metodane void snu_LD2_nivaa(void) og uint32_t les_brytar(void) 
**Framgangsmåte for utføring:** Bruke flytdiagram fra oppgave 6.5.2 til å lage funksjonene 
**Resultat:** 
```c
void snu_LD2_nivaa(void) {
	if (les_brytar()) {
		GPIOA->ODR = GPIOA->ODR ^ 0x0020; // *(uint32_t *) 0x4001080C = *(uint32_t *) 0x4001080C ^ 0x0020;
	} else {
		GPIOA->ODR = GPIOA->ODR & ~0x0020; // *(uint32_t *) 0x4001080C = *(uint32_t *) 0x4001080C & ~0x0020;
	}
}
```
&emsp; - Hvis bryteren **ikke** er trykket inn vil vi invertere signalet som `LD2_Pin` har. Hvis 
&emsp;&emsp;bryteren er trykket inn vil `else` inntreffe og vi setter `LD2_Pin` til å være det 
&emsp;&emsp;inverterte til *på*

```c
uint32_t les_brytar(void) {
	return ( GPIOC->IDR & 0x2000 );  // *(uint32_t *) 0x40011000 = *(uint32_t *) 0x40011000 & 0x2000;
}
```
&emsp; - Bryteren B1 er en del av GPIO_C og vi ønsker å lese verdien til bryteren 
&emsp;&emsp;så bruker vi inngangsregisteret (IDR).
| Bit nr.  | 15   | 14   | 13   | 12   | 11   | 10   | 9    | 8    | 7    | 6    | 5    | 4    | 3    | 2    | 1    | 0    |
| -------- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
| AND       | 0    | 0    | 1    | 0    | 0    | 0    | 0   | 0    | 0    | 0    | 0    | 0    | 0    | 0    | 0    | 0    |
| Gir      | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  | 0/0  | 0/1  | 0/1  | 0/1  | 0/1  | 0/1  |

&emsp;&emsp; - Slipper altså bare igjenom signalet på bit 13 som da får addressen 
&emsp;&emsp;&emsp;0010|0000|0000|0000 = 0x2000.
**Analyse og konklusjon:** Fikk vist at AND operasjonen bare slipper igjenom signalet fra på bit 13 i GPIO_C_IDR.

<br />

**Deloppgåvenr:** 6.6.3
**Dato:** 12.09.2022
**Navn:** Utvikling av ny kode for hovudprogrammet
**Funksjon:** Legg inn informasjonen på rett plass i main.c
**Framgangsmåte for utføring:** Følge eksempelet i laboppgave fila.
**Resultat:** 
```c
/* USER CODE BEGIN PFP */
uint32_t les_brytar(void);
void snu_LD2_nivaa(void);
/* USER CODE END PFP */

...
    
int main(void)
{
    ...

  /* USER CODE BEGIN WHILE */
  uint32_t i;
  while (1)
  {
    /* USER CODE END WHILE */
	  snu_LD2_nivaa();
	  for(i=0;i<0x100000;i++);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

...

/* USER CODE BEGIN 4 */
uint32_t les_brytar(void) {
	return ( GPIOC->IDR & 0x2000 );  // *(uint32_t *) 0x40011000 = *(uint32_t *) 0x40011000 & 0x2000;
}

void snu_LD2_nivaa(void) {
	if (les_brytar()) {
		GPIOA->ODR = GPIOA->ODR ^ 0x0020; // *(uint32_t *) 0x4001080C = *(uint32_t *) 0x4001080C ^ 0x0020;
	} else {
		GPIOA->ODR = GPIOA->ODR & ~0x0020; // *(uint32_t *) 0x4001080C = *(uint32_t *) 0x4001080C & ~0x0020;
	}
}

/* USER CODE END 4 */
```
**Analyse og konklusjon:** Fikk satt inn koden på riktig plass og definert den som den 
&emsp;&emsp; skulle defineres.

<br />

**Deloppgåvenr:** 6.6.4
**Dato:** 12.09.2022
**Navn:** Test av blinkstyringssystemet
**Funksjon:** Bygg og køyr koden.
**Framgangsmåte for utføring:** Bruke STM32CubeIDE til å bygge og kjøre koden.
**Resultat:** Koden virket som forventet. Den stopper å blinke når vi holder inne 
&emsp;&emsp;knappen og blinker når knapper er *slept*
**Analyse og konklusjon:** Fikk bygget og kjørt koden.

## Undersøkingar på kva optimalisering gjer med programkoden din

**Deloppgåvenr:** 6.7.1
**Dato:** 12.09.2022
**Navn:** Optimalisering av blinkstyringssystemet
**Funksjon:** Studer opplysningene i konsollen etter bygging og se etter endringer når 
&emsp;&emsp;koden optimaliseres med **-O3**.
**Framgangsmåte for utføring:** Bruke konsollvinduet til å se etter forskjeller før og 
&emsp;&emsp;etter at koden er bygget på optimalisert måte.
**Resultat:** 
![Bygg uten optimalisering](https://i.imgur.com/S7zbDL1.png)

&emsp;&emsp; - Her kan vi se størrelsen på programkoden er på 5628 bytes. 
&emsp;&emsp; - De initialiserte statiske variablene tar opp 20 bytes.
&emsp;&emsp; - Det blir satt av 1636 bytes stakk og ikke-initialiserte statiske variabler.
&emsp;&emsp; - Det blir totalt 1c74 bytes på hexadesimal form(7284 på desimalform).

![Bygg med optimalisering](https://i.imgur.com/RFynPcA.png)
&emsp;&emsp; - Etter optimaliseringa kan vi se at koden tar mye mindre plass. 1544 på 
&emsp;&emsp;&emsp;heksadesimal form og 5444 på desimal form. Vi kan se at etter 
&emsp;&emsp;&emsp;optimaliseringa tar programmet ca 25% mindre plass.
**Analyse og konklusjon:** Fikk Optimalisert koden og kjørt den.

## Fysisk adressering
**Deloppgåvenr:** 6.8.1
**Dato:** 19.09.2022
**Navn:** Fysisk adressering
**Funksjon:** Realisere blinking basert på bitvis eksklusiv ELLER-operasjon og direkte fysisk 
&emsp;&emsp;adressering av lysdioden.
**Framgangsmåte for utføring:** Følgende:
1. Finn den fysiske adressen til GPIO_A_ODR.
2. Lag en definisjon av utgangsregisteret som kobler dette mot den fysiske adressen.
3. Bruk en XELLER-operasjon i C for å invertere den aktuelle bit-en, mens de andre bit-ene i ODR ikke endres. 
4. Kommenter vekk den CMSIS-baserte blinkeinstruksjonen du har frå før i koden og legg inn den nye instruksjonen din i blinkemetoden Blinkstyring().
5. Test koden.

**Resultat:** 
&emsp; - *main.h*
```c
/* USER CODE BEGIN Private defines */
#define ODR_A *(uint32_t *) 0x4001080C
/* USER CODE END Private defines */
```
&emsp; - *main.c*
```c
/* USER CODE BEGIN PFP */
uint32_t les_brytar(void);
void snu_LD2_nivaa(void);
/* USER CODE END PFP */

...
    
int main(void)
{
    ...

  /* USER CODE BEGIN WHILE */
  uint32_t i;
  while (1)
  {
    /* USER CODE END WHILE */
	  snu_LD2_nivaa();
	  for(i=0;i<0x100000;i++);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

...

/* USER CODE BEGIN 4 */
uint32_t les_brytar(void) {
	return ( GPIOC->IDR & 0x2000 );  // *(uint32_t *) 0x40011000 = *(uint32_t *) 0x40011000 & 0x2000;
}

void snu_LD2_nivaa(void) {
	//if (les_brytar()) {
		// GPIOA->ODR = GPIOA->ODR ^ 0x0020; // *(uint32_t *) 0x4001080C = *(uint32_t *) 0x4001080C ^ 0x0020;
	//} else {
		//GPIOA->ODR = GPIOA->ODR & ~0x0020; // *(uint32_t *) 0x4001080C = *(uint32_t *) 0x4001080C & ~0x0020;
	//}
	if (les_brytar()) {
		ODR_A = ODR_A ^ 0x0020;
	} else {
		ODR_A = ODR_A & ~0x0020;
	}
}

/* USER CODE END 4 */
```
&emsp;&emsp; - Koden kjører likt som før. Kan ikke se noen forskjell
**Analyse og konklusjon:** Fikk bygget og kjørt koden med den nye definisjonen.