v2cpse notities

https://canvas.hu.nl/courses/416

Je hebt nodig: Arduino Due, kabeltjes, een weerstand, een luidspreker, een OLED display.

Clone in je workspace:

git clone https://github.com/wovo/v2cpse1-assignments
git clone https://github.com/wovo/v2cpse1-rtos

Zie je een onzorgvuldigheid? Email mij op fdannenberg@live.nl

Readers

Huiswerkopgaven    2018-2019-V2CPSE1-assigments.docx
Reader C++              2018-2019-V2CPSE1-reader-c++.docx
Reader Assembler    2018-2019-V2CPSE1-reader-cortex-m0-assembly.docx

Voorbeeld code

Verschillende constructors
Filestream gebruiken
Verschillende manieren van compileren
Constexpr templated array
Masking

Opdracht 1 Note player

Jouw oplossing heeft minimaal drie files: Makefile, main.cpp, preprocessor.cpp. De preprocessor compiled op x86, jouw laptop. Hier kun je dus gewoon gcc voor gebruiken. De main.cpp is een runtime product van preprocessor, en compiled voor M0 cortex.

Waar ik op let bij nakijken: consistente benamingen, niet de w1-library aanpassen, juiste configuratie van je makefile.

Opdracht 1.1 UML

Inspecteer de files in w1-library. Wat je vind oa:

note_player__gpio implements note_player
note_player met virtual method play()
note
melody

email .png naar: frits.dannenberg@hu.nl

Opdracht 1.2 Opbouwen

Vergeet de weerstand niet!

Opdracht 1.3 Noten printen

Hou de originele directory zodat je altijd je hardware kunt testen. Bouw je eigen class. Je kunt ‘gewoon’ numerieke waardes afdrukken ipv namen. Druk dus de toonhoogte en lengte af voor iedere toon.

Opdracht 1.5 Makefile

Zorg dat je met een enkel makecommand de gehele pipeline van native compile, native run, due compile, due run uitvoert.

Opdracht 2 Assembly

Explaining uart_print_char.asm

   .cpu cortex-m0        // Use cortex-m0 instructions
   .text                 // text is read-only 
   .align 1              // rightmost N=1 bits of the program counter are now zero
   .global print_asciz   // makes the function available to others

print_asciz:
    push { r5, lr }
    // push the content of r5 and link register

    mov r5, r0
    // r5 obtains the value of r0 (r0 is the function argument)

loop:
    ldrb r0, [ r5 ]
    // load into r0 the char value pointed to by r5. 
    // This is dereferencing the pointer.

    add r0, r0, #0 
    // add zero to the char value in r0 
    // simply an empty operation to enable the following line

    beq done 
    // check if the char value is null -- null terminated strings 
    // if so, end the program

     bl uart_put_char 
    // branch link to stdout function

    add r5, r5, #1
    // increment the pointer to the char array

    b loop 
    // branch back to start of loop

done: 
    pop { r5, pc } 
    // push from the stack onto r5 and pc
    // the program will simply return to whatever was pushed from lr

 

Opdracht 3 NEC decoder

Jouw oplossing heeft verschillende klassen: msg_decoder, msg_listener, msg_logger, pause_detector, pause_listener.

Gebruik de volgende constructie om rtos::task te subclassen:

// Deze code roept de superconstructor aan in de list initializer.
// 6 is hier de prioriteit van de task. 
// "oled_clock" is de naam van de task.

class oled_clock : public rtos::task<> {

oled_clock(): 
    rtos::task<>(6, "oled_clock")
    {};

}

Kijk in de reader hoe je een rtos::task object moet aanroepen. Bekijk ook de source code van rtos::channel<>, dit is een fifo queue. Op die manier hoef je die niet zelf te implementeren.

Opdracht 4 Constexpr

Waarschijnlijk ga je drie keer het keyword constexpr gebruiken, meer kan ook.

Eenmaal om aan te geven dat een constructor gebruikt kan worden tijdens compilatie, eenmaal om aan te geven dat een bepaalde geometrische functie gebruikt kan worden tijdens compilatie. Ook gebruik je het keyword om aan te geven dat een object instantie daadwerkelijk tijdens compilatie geïnitialiseerd wordt.

Gebruikt jouw arm compiler c++14 en niet c++17? Dan moet je constexpr functies en constructors in-line gebruiken. De definitie komt dan direct na de declaratie in de header file.

Let er op dat static class members geïnitialiseerd moeten worden buiten de class definitie. Je krijgt dan:

class my_class{
    static int my_var;
}

int my_class::my_var = 7;

Je kunt natuurlijk ook direct doen:

namespace geometric_values{
    static int my_var = 7;
}

Voor het maken van het klokje zelf: Let er op dat de handen van de klok verschillende lengtes hebben. Het best kun je hwlib::now_us() direct aanroepen in het begin de  while(true) of for(;;) loop. Het proces laten slapen met wait() en daarna handmatig de tijd verhogen is niet de beste oplossing.

Opdracht 5 Lempel-Ziv

In applicatie.asm kun je de gecomprimeerde string op deze manier inladen:

mymessage:
.ascii "Wilhelmus van Nassouwe \n"
.ascii " Ben ick@F5Duytsch@A3Bloedt,@O3D@O3Vaderland [..] ngi@O3\n"
.ascii " B@U3ick vry onverveert.@I3D@O3Conin@M4an Hispangi@F3\n"

.. etc

Let op dat je line breaks correct toepast, anders krijg je met een correcte decompressor alsnog de verkeerde output.

Je kunt deze opdracht opsplitsen in kleinere stappen, dat is vaak makkelijker. Je programma testen gaat vaak het makkelijkste met een (zeer) korte tekst.

  • Wat je kunt proberen is een speciaal karakter printen, bijvoorbeeld een ‘*’, in plaats van het karakter uit het buffer te lezen.
  • Zorg er vervolgens voor de alle geprinte characters in een buffer opgeslagen worden.
  • Wat je vervolgens kunt doen, is op het einde van je programma het buffer printen. Als dat lukt, en het buffer bevat te tekens die je daar verwacht, dan kan je de laatste stap nemen en de decompressor daadwerkelijk uit het buffer laten lezen.

Om een buffer aan te maken, zou je de volgende assembly kunnen gebruiken:

    .bss
mybuffer:
    .skip 40

In de text sectie kun je dan op de gebruikelijke manier het address van de variabele inladen:

ldr r0, =mybuffer