Week 3 · Embedded Programming

This week I worked with the QPAD21 board, based on the ATSAMD21E18. The process started with the kit of parts, and then moved into soldering everything together.

Kit of parts for QPAD21
The kit of parts — everything that went onto the board.
Soldered QPAD21 board
The assembled board after soldering.

The hardest part was definitely the U1 ATSAMD21 chip with its tiny pins. Solder paste helped, but shorts still crept in — seriously annoying. With the patient help of the amazing TAs, I was able to clean things up and finally get the board running.

Once assembled, I tested the board with Arduino IDE. First with the flashing LED code provided in class:

#define PIN_LED 15
void setup() {
  pinMode(PIN_LED, OUTPUT);
}

void loop() {
  digitalWrite(PIN_LED, HIGH);
  delay(500);
  digitalWrite(PIN_LED, LOW);
  delay(500);
}
Flashing LED test on QPAD21
Blinky test — success!

After that, I wanted something more fun. I made a simpler version of the classic Dino game for my board. No ducking, just jumping squares as obstacles. Surprisingly addictive when it’s late at night and you only have two brain cells left.

Simple Dino game running on my QPAD21 board.

The following codes are made up of 9 parts. Each bullet is followed by the relevant code snippet.

The following codes are made up of 9 parts. Each bullet is followed by the relevant code snippet.

  1. Libraries and display.

    #include <Wire.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>
    
    #define SCREEN_WIDTH 128
    #define SCREEN_HEIGHT 64
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
    
  2. Touch input. Set up one capacitive touch pad as a button.

    // TODO: Touch input setup (capacitive pad as button)
    // configure touch sensing pin and read state
    
  3. Game variables. playerY and vy simulate jump/fall; obsX slides obstacles; plus score.

    int playerY = 0;    // player vertical position
    int vy = 0;         // vertical velocity
    int obsX = 128;     // obstacle x position
    int score = 0;
    #define PIN_LED 15  // status LED
    
  4. Reset and Restart. Called at the beginning and whenever player restarts after dying.

    void resetGame() {
      playerY = /* ground */;
      vy = 0;
      obsX = 128;
      score = 0;
    }
    
  5. Physics and input. Gravity makes you fall; touch makes you jump.

    void updatePhysicsAndInput() {
      // if (touchPressed) vy = -JUMP;
      vy += GRAVITY;
      playerY += vy;
      // clamp to ground / ceiling
    }
    
  6. Obstacles movement. Each time player dodges, score +1.

    void updateObstacles() {
      obsX -= SPEED;
      if (obsX < -WIDTH) {
        obsX = 128;
        score++;
      }
    }
    
  7. Collision check. If rectangles overlap, game over.

    bool checkCollision() {
      // AABB overlap between player rect and obstacle rect
      return false;
    }
    
  8. Drawing. Clear screen each frame; draw ground, player, obstacle, score, and Game Over.

    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 15);
    display.println("Chill out,");
    display.setCursor(0, 40);
    display.println("World!");
    display.display();
    
  9. Loop. Keep everything moving ~60 fps.

    void loop() {
      // Blink LED just for fun
      digitalWrite(PIN_LED, !digitalRead(PIN_LED));
      delay(500);
    
      updatePhysicsAndInput();
      updateObstacles();
      if (checkCollision()) {
        // handle game over
      }
      draw();
    }
    

This game is very simple, but it can definatly become pretty addictive, here is my history record ʘ‿ʘ

Flashing LED test on QPAD21
History Record: 93 points