Skip to content

6. Embedded Programming

This week I was tasked with investigating the datasheet for my microcontroller to get to know it better. And to compare it to other microcontroller architectures and document the comparison on our group page.

I also had to write a program for my microcontroller to interact with an external input or output.

UPDATE: The 2025 embedded programming assignemnt was updated to require a simulated program. So I added it at the bottom of this page here: embeded programming simulation

Group work - comparing architectures

Our group work was to compare a few different microcontroller architectures. We documented our work here CDL Fab Lab - embedded programming group page.

The current test board I will be using is the Quentores Xiao RP2040 board that I created in week 4 - Electronics production since this is currently the first (and as of this week) only board I have made myself.

However, for “week 8 Electronics design” and my final project I intend to design and build my board around the ATtiny 412. This is for a few of reasons:

  • The ATtiny412 is a relatively powerful and CHEAP microcontroller, currently US $0.55, and we have allot of them in stock at our lab.

  • The ATtiny412 only has 8 pins, so I think the conplexity of the board design should be easier. And with simpler designs, there’s less chance for errors.

  • Despite it’s fewer pins and cheap cost I think it will be more than capapable of performing all the tasks I would want from it. If not, I can always upgrade to one of the higher Attiny family chips, but most of my knowledge and experience using the 412 should still be transferable.

  • The intension of our lab is to become a hub for entrepreneurs to develop prototypes for products that will hopefully become real world retail products. Most of the product ideas we have heard from past clients have only needed limited digital electronics needs, and price will probably be a major concern in picking thier parts list. For this reason I think the Attiny 412 will be well suited for the majority of them, and if not the 412, then another microcontroller in the Attiny family. To this end I would hope to be become well versed with them, and therefore will be focusing on the 412 for my Electronics design and final project.

  • The SEEED XIAO RP2040 microcontroller board that is used in my current test board is a little pricey (for my use). And we happen to have only 1 more spare in our lab.

Group work - addendum (RP2040 specs)

One of my lab mates, Terrence Carew, already documented the ATtiny412 pretty well on his page.

We initially didn’t document the RP2040 chip in our group page, so I decided to put some of the more relevant details here.

RP2040 datasheet

This is the Pin layout of the SEEED XIAO RP2040 microcontroller board Xiao pin layout

However the SEEED board already has allot of its pins assigned to other parts of the board like: built in LEDs, buttons, and USB interface.

The real (naked) RP2040 chip looks like this: RP2040 Pin layout RP2040 image

RP2040 Key features:

  • Dual ARM Cortex-M0+ @ 133MHz
  • 264kB on-chip SRAM in six independent banks
  • Support for up to 16MB of off-chip Flash memory via dedicated QSPI bus
  • DMA controller
  • Fully-connected AHB crossbar
  • Interpolator and integer divider peripherals
  • On-chip programmable LDO to generate core voltage
  • 2 on-chip PLLs to generate USB and core clocks
  • 30 GPIO pins, 4 of which can be used as analogue inputs
  • Peripherals
  • 2 UARTs
  • 2 SPI controllers
  • 2 I2C controllers
  • 16 PWM channels
  • USB 1.1 controller and PHY, with host and device support
  • 8 PIO state machines

RP2040 overview: RP2040 overview

Individual Assignment

This weeks assignment was to attach our test board to an external input or output device and then write a program to interface with that device.

I chose to use a basic analog potentiometer as an input and then use it to change the output of 2 LEDs on the test board.

I decided to use a potentiometer because I wanted to experiment with an analog input. Digital inputs seemed fairly straight forward and I thought that an analog interaction would be more interesting.

wiring

  • Initially I used a breadboard just to hold the potentiometer in place and more easily attach the wires to it. potentiometer connected

  • However, later on I was told that using a breadboard can often introduce distortion from the signal. So I connected it directly to my board instead.

potentiometer connected -NEW potentiometer connections

  • The Green wire connects the potentiometer to the 5th spot on the female connection header (note: I didn’t have a 6 pos header available, so I used an 8 with the first 2 positions not connected to anything). This is wired to the 5V Vcc pin on my board.

  • The Orange wire connects the potentiometer to the 3rd spot on the header, which is connected to the GND of the SEEED board.

  • The Blue wire connects to the 6th spot on the header, which is wired to pin 28 on the SEEED board. This is set up as our analog input pin in the porgram.

programming

I wrote the program in the Arduino IDE and used it to porgrammed the board.

I didn’t have to go through all the setup procedures for the Arduino IDE software again because I alreay did them in week 4- electronic production using the instructions on the Quentores Xiao RP2040 project page.

program operation

The program takes in the voltage of the potentiometer as input and uses it to control the blinking of 2 LEDs.

The dial is turned to increase or decrease the voltage coming out of the potentiometer signal(output) terminal.

As the dial is turned counterclockwize it increases the voltage signal value.

Every time the main body of the program loops the board reads the value of the voltage. The input voltage is interpreted as a value between 0 and 1023. Using Serial we send this value back to the Arduino IDE so we can see it change.

This read value is used as the delay between turning the LEDs on and then off, so making them blink faster or slower.

my code

Here’s my code:

/*
  potentiometer - output to LEDs

  Written 1 February 2025
  by James Khan
  for fab academy assignment embedded programming

  https://fabacademy.org/2021/labs/vancouver/students/james-khan/assignments/week06/
*/

// define constants to match the pin layout that you are attaching your potentiometer.
const int potentin = A3;
const int led1 = 26;
const int led3 = 1;

// setup our pins as inputs or outputs
void setup() {
  // initialize analog potentin pin as an input.
  pinMode(potentin, INPUT);

  // setup serial monitor.
  Serial.begin(9600);

  // initialize digital led pins as output.
  pinMode(led1, OUTPUT);
  pinMode(led3, OUTPUT);
}

// the loop function runs over and over again forever
// analog input is from 0 to 1023. 1000 translates to 1 second delay. 
void loop() {
    // read potentiometer value
  int readvalue = analogRead(potentin);

  // send potentiometer reading to the serial monitor
  Serial.println(readvalue);

  // reset LEDs to off
  digitalWrite(led1, LOW);
  digitalWrite(led3, LOW);

  // leave the LEDs off using the readvalue as the delay
  delay((readvalue));

  // turn on the LEDs then leave them on using the readvalue as the delay
  digitalWrite(led1, HIGH);
  digitalWrite(led3, HIGH);
  delay((readvalue));

}

my potentiometer LED blinking code (download)

Running the program (with Serial Monitor in background):

lessons learned

  • There are allot of microprocessors to pick from to use in your project. Each of them have differing strengths and weaknesses.
  • The Arduino IDE can be used for allot of boards, not just Arduino boards.
  • You need to define your input and output ports in your program as such to ensure that they work as intended.

Simulation

I decided to do my code simulation in Wowki.

Because I am a continuing student I am doing allot of my assignments out of order. Due to some mishaps that I couldn’t resolve (discussed in my output assignment page), I switched my board design from using the SEEED XIAO RP2040 microcontroller to one using the ATTINY1614.

Attiny1614

I decided to go ahead and try to write a prgram that I could use as a base for my final project code in Wowki. Wowki had an ATTINY85 microcontroller in the simulator, however this doesn’t have enough data pins for my project. So I decided to just simulate using the Arduino UNO. In the input and output assignments I would make the necessary changes to my code (from the simluated one) to adjust to my boards design.

samples used

My final project uses:

I started building my simulation by looking up sample codes for these components within Wowki itself.

Here are the sample codes I used:

wowki-led-button code:

/*
1. Connect LED anode to digital pin (pin 13) on the Arduino board.
2. Connect LED catode to resiston (200-ohm) and the to the ground (GND) of the Arduino board.
3. Connect one leg of the push button to the digital pin (pin 2).
4. Connect the other leg of the push button to the ground (GND) of the Arduino board.
*/

// Define variables
int buttonPin = 2; // Digital pin where the button is connected.
int ledPin = 13;   // Digital pin where the LED is connected.
bool buttonState = false;

void setup() {
  pinMode(ledPin, OUTPUT);    // LED pin as an output.
  pinMode(buttonPin, INPUT);  // Button pin as an input.
}

void loop() {
  // Read the state of the button
  buttonState = digitalRead(buttonPin);

  // Check if the button is pressed
  if (buttonState == HIGH){
    digitalWrite(ledPin, HIGH);   // Turn LED on.
  } else {
    digitalWrite(ledPin, LOW);    // Turn LED off.
  }
}

wowki-ultrasonic code:

/*
  HC-SR04 Ultrasonic Sensor Example.

  Turn the LED on when an object is within 100cm range.

  Copyright (C) 2021, Uri Shaked
*/

#define ECHO_PIN 2
#define TRIG_PIN 3

void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
}

float readDistanceCM() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  int duration = pulseIn(ECHO_PIN, HIGH);
  return duration * 0.034 / 2;
}

void loop() {
  float distance = readDistanceCM();

  bool isNearby = distance < 100;
  digitalWrite(LED_BUILTIN, isNearby);

  Serial.print("Measured distance: ");
  Serial.println(readDistanceCM());

  delay(100);
}

wowki-oled code:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

/*
* Connections
* SSD1306 OLED | Arduino Uno
* ---------------------------
*     VCC      |    +5V       (Vcc/power/+ve)
*     GND      |    GND       (Ground/-ve/0v)
*     SCL      |    A5        (Serial Clock Line)
*     SDA      |    A4        (Serial Data Line)
*/

const int SCREEN_WIDTH = 128; // OLED display width, in pixels
const int SCREEN_HEIGHT = 64; // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  Serial.begin(9600);

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    while(true);
  }
}

void loop() {
  display.clearDisplay();

  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  // Display static text
  display.println("Hello, World!");
  display.display();
}

My simulated code

Setup

  • To build my simulated code, I first had to add all the components together.
  • I started with the LED sample as a base and added the oled display and ultrasonic sensor as components to the simulator.
  • I wired all the components the same as they were in the individual samples,
  • EXCEPT the OLED display and the button were both initially wired to PORT 2, so I switched the button input port to port 4 (and made sure to change the defined “buttonPin” to 4)
  • I then added all the libraries and definitions from the other samples in the code.
  • then I added the “Adafruit GFX Library” and “Adafruit SSD1306” to the library manager.
  • Then I added the setup code for the other samples.
  • I copied the READDISTANCE function from the ultrasonic code into my code.
  • the ultrasonic and oled samples have different “serial.begin()” rates. I had to use the slower OLED speed for the OLED to work.

Making code

  • The real part of the code that would make it mine was the section within “void loop ()”
  • My program would wait till the button was pressed to begin, then constantly read the value of the ultrasonic sensor and output that value to oled screen.
  • It will also light the LED if the distance was less than 200, and output the distance the the seiral monitor.

Here’s the link to my completed simulation

wowki-oled

My code:

/*
James Khan Fab Academy simulation. Embedded programming week.
https://fabacademy.org/2021/labs/vancouver/students/james-khan/assignments/week06/

started by using these Wowki samples:
https://wokwi.com/projects/375237011181407233
https://wokwi.com/projects/290056311044833800
https://wokwi.com/projects/365718993906978817
*/

#include <Wire.h>             // for OLED
#include <Adafruit_GFX.h>     // for OLED
#include <Adafruit_SSD1306.h> // for OLED

const int SCREEN_WIDTH = 128; // OLED display width, in pixels
const int SCREEN_HEIGHT = 64; // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // for OLED


// Define variables button and LED
int buttonPin = 4; // Digital pin where the button is connected.
int ledPin = 13;   // Digital pin where the LED is connected.
bool buttonState = false;

// DEfine variables Ultrasonic
#define ECHO_PIN 2
#define TRIG_PIN 3

void setup() {
  pinMode(ledPin, OUTPUT);    // LED pin as an output.
  pinMode(buttonPin, INPUT);  // Button pin as an input.

    // for OLED

  Serial.begin(9600);

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    while(true);
  }

    // for ultrasonic
  // Serial.begin(115200);    this was the ultrasonic samples code that conflicted
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);

}


float readDistanceCM() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  int duration = pulseIn(ECHO_PIN, HIGH);
  return duration * 0.034 / 2;
}

void loop() {
      // read state of button only if buttonstate is LOW
  if (buttonState == LOW){
    buttonState = digitalRead(buttonPin);
  }

  if (buttonState == HIGH){ // once buttonState is HIGH then run rest of code

  float distance = readDistanceCM();    // ultrasonic read 
  if (distance < 200){                  // LED on or off?
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }

  Serial.print("Measured distance: ");  // serial output static 
  Serial.println(readDistanceCM());     // serial output distance
  delay(100);

  display.clearDisplay();               // oled clear
  display.setTextSize(1);               // oled setup
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  display.println("Distance:");         // static display
  display.println(readDistanceCM());    // display distance
  display.display();
  delay(100);

  }

}

Lessons Learned

  • Wowki is a great tool for designing and testing code on a simulated board.

  • It also comes in really handy:

    • to test a component you might not have on hand yet.
    • to test your code that isn’t working on a real world board to see if your problem is hardware related.
    • it also has a pretty good library of sample codes and submitted projects that you can use to help troubleshooting and/or inspiration.
  • However it has a few shortcomings to note:

    • There currently aren’t a wide selection of microcontroller models to choose from. Although this will probably continue to improve with time.
    • If you make changes in your code often and try to recompile, you may get stuck waiting a long time to compile your code. It may even come up with an error and you have to retry compiling.
    • output on simulated OLED screen can be display incorrectly if you are zoomed out too far in the silulator window. If you are worried that your output doesn’t match what you think it should be, try zooming in on the OLED screen.

Last update: April 15, 2025