Skip to content

Instantly share code, notes, and snippets.

@matthijskooijman
Last active August 29, 2015 14:17
Show Gist options
  • Save matthijskooijman/94d780bfd75a12298dd4 to your computer and use it in GitHub Desktop.
Save matthijskooijman/94d780bfd75a12298dd4 to your computer and use it in GitHub Desktop.

Praatje Arduino zonder Arduino

  • Wie ben ik? Msc ES UT, FON Wifi firmware, 2,5 jaar bezig met Arduino, 1,5 jaar met Pinoccio.
  • Wat gaan we doen? Introductie over Arduino, wat doet de IDE, hoe kunnen we dat zelf? Samen begin met opdracht, zelfstandig verder. Volgende week nabespreken.
  • Wat is Arduino? Hardware, IDE en API/core.
  • Hardware: Veel soorten, basisidee is simpel: MCU, xtal, power, serial (16u2/ftdi), led, resetknop. Kan op breadboard.
  • Veel software: IDE en core. Veel uitdagingen voor goede software engineers, bijdragen welkom
  • Core == API, veel interessante tradeoffs tussen flexibiliteit en simpelheid. Bijvoorbeeld printing API. Core is gewoon code, zie bijvoorbeeld millis(). boards.txt + variants voor verschillende boards.
  • IDE, voor editen en uploaden. Java source laten zien.
  • Programmeren -> Uploaden -> Draaien
  • Programmeren -> Compilen -> Uploaden -> Draaien
  • IDE met verbose output laten zien
  • Programmeren -> IDE preprocessen -> Compilen -> Linken -> .hex file maken -> Uploaden -> Draaien
  • Compilen met avr-gcc, gewoon C/C++, losse .o files en een .a file
  • Linken met avr-gcc, één .elf file
  • Converteren met avr-objcopy, één .hex file
  • Proberen: lege .cpp file -> linker error main (géén setup/loop). Arduino main laten zien.
  • Proberen: lege main() -> uploaden
  • Proberen: ledje aan met pinMode / digitalWrite -> uploaden
  • Proberen: ledje aan met port registers -> uploaden. Datasheet, variant files, schematic, io.h.
  • Hoe werkt uploaden? ISP via programmer, bootloader via UART / serial.
  • Verder met opdrachten.

Opdracht Arduino zonder Arduino

  1. Schrijf een programma dat de ingebouwde LED op de Arduino aanzet. Verder hoeft het niets te doen.

  2. Schrijf een programma dat de ingebouwde LED laat knipperen, met een periode van 5 seconden. Gebruik hiervoor de _delay_ms functie uit util/sleep.h.

  3. Voeg code toe om de UART (seriele poort) aan te spreken. Zorg dat er, steeds wanneer de LED van status wisselt, "ON" of "OFF" naar de seriele poort geschreven wordt. Gebruik 115200 baud. Het kan zijn dat hierdoor de periode van de LED iets meer dan 5 seconden wordt, dat is niet erg.

    Om te zorgen dat je je kunt concentreren op het aansturen van de hardware, en je je niet druk hoeft te maken over het formatten van strings en getallen, kunen we de printf functie naar onze hand zetten. Hiervoor moeten we zorgen dat we de stdout globale variabele een zinnig waarde geven:

     int write(char b, FILE *f) {
       // Schrijf hier 1 byte naar de UART
       return 0;
     }
    
     void main() {
       // Maak een nieuw FILE object, registreer de write() functie
       // hierboven onder dat object en zorg dat stdout er naar
       // verwijst.
       static FILE io;
       fdev_setup_stream(&io, write, NULL, _FDEV_SETUP_WRITE);
       stdout = &io;
    
       // Nu werkt printf zoals verwacht:
       printf("%d\r\n", 123);
    
       // Hier meer code
     }
    

    Deze code kun je later ook handig gebruiken om debug printjes toe te voegen, mochten er dingen niet meteen werken.

  4. Voeg een knop aan de arduino toe (of, bij gebrek aan een knop, twee jumper wires die je tegen elkaar kunt houden om een druk op de knop te simuleren). Voeg een tweede LED toe (vergeet de weerstand niet).

    Zorg dat als je op de knop drukt, de tweede LED aangaat en aanblijft zolang je de knop ingedrukt houdt.

    Als je het knipperen op de voordehandliggende manier hebt geïmplementeerd, dus met _delay_ms(2500), zul je zien dat de knop niet direct reageert, het kan wel een paar seconden duren. Snap je waarom?

  5. Los de vertraging op door een timer te gebruiken. De AVR hardware heeft een aantal (bijna identieke) timers beschikbaar. Voor deze toepassing is timer1 het handigst. Dit is een 16-bit timer, waardoor deze tot maximaal een paar seconden kan tellen voordat hij overflowed.

    Gebruik nu nog geen interrupts, maar controleer voortdurend de waarde van de timer (polling) en zodra er 2,5 seconde verstreken is, inverteer je de LED en reset je de timer.

  6. Gebruik nu een timer overflow interrupt om de led te inverteren, zodat je niet steeds hoeft te pollen. Je zult hiervoor het maximum van de timer (de waarde waarbij hij overflowed) moeten aanpassen (dmv OCR1A en CTC mode) zodat de overflow steeds precies op het goede moment gebeurt.

  7. Vaak zal je programma ook nog andere dingen moet doen en niet voortdurend kunnen pollen. Om dit te simuleren laten we de Arduino grote priemgetallen berekenen. Gebruik hiervoor de volgende code:

     // Is het gegeven getal een priemgetal? Opzettelijk suboptimale
     // implementatie
     bool isPrime(uint32_t n) {
             for (uint32_t i = 2; i < n; i++) {
                     if (n % i == 0)
                             return false;
             }
             return true;
     }
    
     void main() {
             uint32_t n = 100000;
             while(true) {
                     if (isPrime(n))
                             Serial.println(n);
                     n++;
    
                     // Plaats hier je andere code
             }
     }
    

    Het is niet toegestaan de isPrime() functie aan te passen, de andere code wel.

    Je zult nu zien dat de knop weer traag wordt met reageren, omdat main loop soms lang bezig is met een iteratie en er dus lang niet gepolled kan worden (we zeggen dan dat de isPrime() functie "blocking" is).

    Bij opdracht 5. heb je een zelfde soort probleem opgelost door het knipperen van de led "non-blocking" te maken (door een timer te gebruiken in plaats van de blocking _delay_ms() functie). Omdat het niet altijd lukt om code non-blocking te maken, zul je dit nu aan de andere kant moeten oplossen.

    Implementeer de afhandeling van de knop met een "External Interrupt", die afgaat zodra de status van de knop verandert. De knop zou nu weer supersnel moeten reageren. Let op dat external interrupts maar op een beperkt aantal pinnen beschikbaar is, en let op dat de argumenten aan attachInterrupt binnen Arduino niet altijd logisch zijn. Kijk dus vooral goed naar het schematic en de datasheet.

  8. Herimplementeer de write() functie zonder gebruik te maken van de hardware UART. Je zult dus handmatig de TX pin moeten aansturen met de goede timing ("bitbangen", of "software serial").

    • Standaard is de TX lijn hoog, wanneer er niets verzonden wordt.
    • Elke byte begint met een 1 startbit, die is laag
    • Vervolgens volgen er 8 databits, de MSB eerst. Een 0 is hoog, een 1 is laag.
    • Tot slot volgt er 1 stopbit, die is weer hoog.

    De bitrate bepaalt hoe lang 1 bit duurt. Het is handig om niet te snel te beginnen, bijvoorbeeld op 9600bps (1/9600 = 104μs per bit).

    Je kunt het beste een tweede timer (bijvoorbeeld timer2) gebruiken, zodat je led-knipper-timer gewoon kan blijven werken. Aangezien de write() functie toch al blocking was, kun je timer2 gewoon pollen om de goede timing te bereiken.

    Wanneer je de hardware UART niet initialiseert, blijven de bijbehorende pinnen (0/1, RX/TX) gewoon bruikbaar als normale I/O pinnen die je via de port registers kunt aansturen. Je kunt je write() functie dus naar pin 1 (TX) laten schrijven, dan kun je het resultaat normaal via USB uitlezen.

    Je kunt deze techniek dus ook gebruiken om meer dan 1 seriele poort te gebruiken, op elke willekeurige pin.

    Als het niet direct werkt, kan het handig zijn om een logic analyzer te gebruiken om te zien wat er precies op de TX pin gebeurt (en eventueel kun je op andere pinnen nog debug signalen geven en uitlezen met de logic analyzer). Als je nog een tweede Arduino hebt, kun je daar een eenvoudige logic analyzer van maken:

    https://github.com/gillham/logic_analyzer

    Als je het werkend hebt, kijk dan eens hoe snel je kunt gaan. Kan 115.200bps? 1.000.000 bps? Nog sneller? Kun je beredeneren en berekenen wat de maximale snelheid zou zijn?

    Als je het leuk vind, probeer je write functie dan eens over te zetten naar binnen de Arduino omgeving, met behulp van digitalWrite. Hoe snel kun je nu gaan?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment