---
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
   synlig. Ved å holde inne en bryter, skal lyset være av. Når en slipper brytaren, skal
   blinkinga fortsette.
**Innganger:** Et signal fra en bryter som er høyt eller lavt ved trykk på bryteren og som har
   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
  - LD2:
   - Koblet til perifermodulen GPIO_A
   - For å påvirke det logiske nivået må vi skrive til Output Data Register (ODR)
   - Nivåverdien for PA5 settes i registerbit 5
  - B1:
   - Koblet til perifermodulen GPIO_C
   - For å lese det logiske nivået må vi til Input Data Register (IDR)
   - Nivåverdien for PC13 settes i registerbit 13.
3. Brukermanualen side 21 viser at PA5 er koblet til D13 via SB42 og videre SB21.
  - På baksiden av kortet ser vi at både SB21 og SB42 har en *motstand*
  - 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
  - På baksiden av kortet ser vi at både SB17 også har en *motstand*
  a) Hvis bryteren er på (inntrykt) vil det logiske nivået være 1.
  b) Hvis bryteren er av (slept) vil det logiske nivået være 0.
5. 
* Periodetiden for klokkesignalet til $\mu$P er $t_{clk\ \mu P} = \frac{1}{f_{clk\ \mu P}} = \frac{1}{72*10^6} = 13.9ns$
* 
**Analyse og konklusjon:** Velger altså bryter B1 som er en del av GPIO_C og kan lese det logiske
   nivået via IDR og lysdiode LD2 som er en del av GPIO_A og som kan settes til å lyse eller
   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:**
  - Verifikasjon av diodepinnen:
   - Denne er satt til `GPIO_Output`.
   - Hvis denne funksjonen setter data i ODR får lysdioden så burde den være riktig.
  - Sjekk av programmene som er genererte:
   - 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 */
}
```
   - Fordi det er ingenting i while-loopen så vil det ikke skje noen ting med
   lysdioden.
**Analyse og konklusjon:** Fik kommet i gang med utviklingsverktøyet og ting ble
  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
  ø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
  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 */
```
  - Når vi bygger og kjører programkoden blinker bare lysdioden, og om vi endrer
  verdiene kan vi få den til å blinke raskere eller tregere.
  - `GPIOA->ODR = GPIOA->ODR ^ LD2_Pin`
   - Ø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 |
   - 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;
}
}
```
  - Hvis bryteren **ikke** er trykket inn vil vi invertere signalet som `LD2_Pin` har. Hvis
  bryteren er trykket inn vil `else` inntreffe og vi setter `LD2_Pin` til å være det
  inverterte til *på*
```c
uint32_t les_brytar(void) {
return ( GPIOC->IDR & 0x2000 ); // *(uint32_t *) 0x40011000 = *(uint32_t *) 0x40011000 & 0x2000;
}
```
  - Bryteren B1 er en del av GPIO_C og vi ønsker å lese verdien til bryteren
  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 |
   - Slipper altså bare igjenom signalet på bit 13 som da får addressen
   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
   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
  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
  koden optimaliseres med **-O3**.
**Framgangsmåte for utføring:** Bruke konsollvinduet til å se etter forskjeller før og
  etter at koden er bygget på optimalisert måte.
**Resultat:**

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

   - Etter optimaliseringa kan vi se at koden tar mye mindre plass. 1544 på
   heksadesimal form og 5444 på desimal form. Vi kan se at etter
   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
  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:**
  - *main.h*
```c
/* USER CODE BEGIN Private defines */
#define ODR_A *(uint32_t *) 0x4001080C
/* USER CODE END Private defines */
```
  - *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 */
```
   - 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.