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