Skip to content

4. Embedded Programming

Individual Assignment

  • Browse through the datasheet for your microcontroller
  • Write a program for a microcontroller, and simulate its operation, to interact (with local input &/or output devices) and communicate (with remote wired or wireless connection)

General

Mr. Dubick recommended that we always simulate our code using TinkerCAD or Wokwi before doing it because that will help eliminate software issues when programming the actual microcontroller. It helps with debugging because if you have it simulated and working properly, then you know that there are likely no errors with the software. It is also important to always test a blink code first to make sure the microcontroller is correctly connected to the computer, which can help eliminate uploading errors later. Arduino has built-in example codes, and one of them is a blink code.

Mr. Dubick also gave us a quick lesson about pull up and pull down resistors.

Pull up → power → 1 Pull down → ground → 0

A pull up resistor is when the resistor is connected to power, and a pull down resistor is when the resistor is connected to ground. When explaining the code with the ESP32 and RP2040, I will provide specific examples of using a pull down resistor.

Mr. Dubick briefly went over scope in programming as well. Scope is the idea that variables can only be accessed from places defined (global variables vs. local variables). In C++, if the variable is defines before voif setup(), then it is always going to be a global variable. In addition, in C++, there must be a semicolon after every line except lines where functions are defined.

XIAO-ESP32-C3

The goal was to create a program in both C++ and Micropython that would use an ESP32-C3 to make an LED light up using a push button as the input.

This was the XIAO-ESP32-C3 I used. I soldered the pin headers on.

Pinout

This is the pinout for a XIAO-ESP32-C3.

  • To access pin D0 in code, you must type in D0.
  • To access pin GPIO2, you only need to type in 2.

Simulating the Program in Wokwi

This was definitely the most difficult part of the week for me because I did not have a lot of prior knowledge with electrical engineering unlike the majority of my classmates. I began by using Wokwi and messing around with the software and the various components. With the help of Cooper Cumbus, I was able to create a working simulation of the ESP32-C3 making an LED blink using a button. During pre-fab, I was able to use the ESP32-C3 to make an LED light up, so the most difficult part of this was incorporating the button. I eventually just looked up an image of which pins of the push button are connected, which I should have done sooner because it made everything SO MUCH EASIER. Once I understood how to wire the button, everything made a lot of sense. This is the diagram of the push button I used from this website:

Cooper helped me with which components to connect because the other thing I was confused about was where to position the resistors. Since we were supposed to be using pull down resistors, I needed to have a 10K resistor connected to the ground pin of the button and ground on the ESP32-C3. Because the resistor was pull down, the LED stayed off until the button was pressed and then as soon as the button was let go of, the LED turned off.

This is the wiring in Wokwi that I made with Cooper’s help but changed to match the pin numbers of my code:

In Wokwi, I still did not fully understand how the circuit worked so to test my understanding, I wanted to try and recreate it on a breadboard, which I struggled in doing. I also wanted to make it on a breadboard in Wokwi because I was going to have to make it on a breadboard in real life with the actual microcontroller, so I figured it would make it easier if I simulated it on a breadboard first. Tyler Russell helped me troubleshoot my Wokwi circuit by pointing out that I did not actually have my pull down resistor as a 10K resistor, which was important because my LED was always staying on.

I also went back just to make an LED light up using the ESP32-C3 in Wokwi to help me better understand the pins, breadboards, and how the ESP32-C3 works. This was my setup:

I also went back to TinkerCAD and set up the circuit in TinkerCAD with the only difference being that I used an Arduino instead of the ESP32-C3. I was able to get this to work without a breadboard, and once I did that, I was easily able to make the necessary changes in Wokwi with the ESP32-C3.

This is the wiring setup I used in TinkerCAD with an Arduino and the code provided to us by Mr. Dubick:

This is the final simulated program in Wokwi:

I also used ChatGPT to help me modify my code to include statements in the Serial Monitor that showed me whether or not the LED was supposed to be on:

Setting Up the Wiring

I ended up getting my RP2040 program to work before the ESP32-C3 program, and since both the ground and power are the same in both pinouts, I only needed to change the input and output pin numbers in the Micropython code. The only change to the wiring I needed to make was switching the RP2040 out for the ESP32-C3. To learn about how I wired the RP2040, scroll down or click here.

Programming the Microcontroller

I struggled immensely with uploading errors at this point in the process. I kept getting uploading errors for both exit status 1 and exit status 2, so I needed to put my microcontroller into bootloader and reconnect it several times. I also learned that some cords can only be used for charging because when I tried to use a cord I borrowed from a friend to connect the microcontroller to my computer, it would not show up. When I asked Mr. Dubick for help, he tried the cord out on his computer as well, and it would not work, but once we switched the cord, the program uploaded successfully. As mentioned previously, I ended up getting my RP2040 program to work before the ESP32-C3 program, and since both the ground and power are the same in both pinouts, the only change I needed to make in the code was changing the input and output pin numbers.

Uploading error:

C++

First, I ran a simple blink code, but I do not think that the ESP32-C3 has a built-in LED, so I made it blink the LED I needed to use for my program. The purpose of this test was to make sure the microcontroller was successfully connected to my computer, which it was.

Next, I ran the same code that I used for my RP2040.

void setup()
{
  pinMode(D8, INPUT);
  pinMode(D5, OUTPUT);
}

void loop()
{
  // check if pushbutton is pressed.  if it is, the
  // buttonState is HIGH
  if (digitalRead(D8) == HIGH) {
    // turn LED on
    digitalWrite(D5, HIGH);
  } 

  else {
    // turn LED off
    digitalWrite(D5, LOW);
  }
}

This was also successful.

Micropython

I had to change the pin numbers for this code because of the pinout that the ESP32-C3 has. Unlike the RP2040, the ESP32-C3 does not have special pin numbers for Micropython. I also had to change the kind of interpreter under the Tools -> Options -> Interpreter menu to an ESP32.

This is the updated code I used:

from machine import Pin
import time

# Define pins
button = Pin(2, Pin.IN)  # D8 as input
led = Pin(7, Pin.OUT)    # D5 as output

while True:
    if button.value() == 1:  # Button is pressed (HIGH)
        led.value(1)  # Turn LED ON
    else:
        led.value(0)  # Turn LED OFF

    time.sleep(0.01)  # Small delay to debounce

I was also very successful with this.

RP2040

The goal was to create a program in both C++ and Micropython that would use an RP2040 to make an LED light up using a push button as the input.

This was the RP2040 I used. I soldered the pin headers on. To solder the pin headers on, I used a breadboard to hold it in place.

Pinout

This is the pinout for a XIAO RP2040 microcontroller.

  • To access pin D0 in code, you must type in D0.
  • Micropython uses different pin numbers than C++.

Setting Up the Wiring

After creating the simulation for the ESP32-C3 and understanding the how push button works, I was quickly able to get my RP2040 to work. The primary challenge I faced when wiring the RP2040 was that I thought I needed to use a pull up resistor instead of a pull down resistor with the button, but once I consulted with Kathryn Wu and Tyler Russell, I realized that I needed to use a pull down resistor. This was a very quick fix since I just needed to connect the resistor to ground instead of power.

This was my attempt to use a pull up resistor instead of a pull down resistor (incorrect):

This was the updated wiring using a pull down resistor instead (correct):

Programming the Microcontroller

I struggled a bit when tryign to program the RP2040 because the format for the pin numbers was different than the ESP32-C3. I needed to put D in front of the number for the digital pins in C++ and use the specified different pin numbers for Micropython.

C++

This was the initial blink code I started out trying to use on the RP2040 but it did not work because of the pin number not having a D in front of it.

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(5, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(5, HIGH);  // turn the LED on (HIGH is the voltage level)
  delay(500);                      // wait for a second
  digitalWrite(5, LOW);   // turn the LED off by making the voltage LOW
  delay(500);                      // wait for a second
}

It was a simple fix to get the code to work where I used D5 instead of 5. I initally thought I might have soldered the ground pin wrong, but really the code was just wrong. ChatGPT helped me resolve this issue.

void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(D5, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(D5, HIGH);  // turn the LED on (HIGH is the voltage level)
  delay(500);                      // wait for a second
  digitalWrite(D5, LOW);   // turn the LED off by making the voltage LOW
  delay(500);                      // wait for a second
}

This was the final C++ code I used for the RP2040:

void setup()
{
  pinMode(D8, INPUT);
  pinMode(D5, OUTPUT);
}

void loop()
{
  // check if pushbutton is pressed.  if it is, the
  // buttonState is HIGH
  if (digitalRead(D8) == HIGH) {
    // turn LED on
    digitalWrite(D5, HIGH);
  } 

  else {
    // turn LED off
    digitalWrite(D5, LOW);
  }
}

Micropython

I followed this tutorial to download Micropython on my Mac, which was recommended by Kathryn Wu who is also a Mac user.

1.Download Thonny

2.Tools -> Options -> Interpreter

3.Change settings to this:

I struggled with this because I think my RP2040 was still connected to the Arduino since I did not close ot=ut that app initially. I also needed to put my RP2040 into bootloader mode by holding down the button next to B on the microcontroller while unplugged from the computer and keep holding the button down until around two seconds after plugging the microcontroller cord into the computer. ChatGPT helped me with this. I struggled to get the target volume to appear.

This was the sample countdown code I used that was on the tutorial I followed:

from machine import Pin, Timer

led = Pin(25, Pin.OUT)
Counter = 0
Fun_Num = 0

def fun(tim):
    global Counter
    Counter = Counter + 1
    print(Counter)
    led.value(Counter%2)

tim = Timer(-1)
tim.init(period=1000, mode=Timer.PERIODIC, callback=fun)

This countdown worked very successfully, and the built-in LED on the RP2040 blinked successfully, so I was surprised when I tried the button code and it did not work. ChatGPT recommended I try to use the code below to see if the button was the issue or if it was something else. It initially did not work because there are different pins for Micropython, so I needed to change that, and then I believe it worked.

from machine import Pin
import time

button = Pin(2, Pin.IN)

while True:
    print("Button state:", button.value())  # Print button status
    time.sleep(0.5)

This was the output:

This was the final Micropython code I used:

from machine import Pin
import time

button = Pin(2, Pin.IN)  # D8 as input
led = Pin(7, Pin.OUT)    # D5 as output

while True:
    if button.value() == 1:  # Button is pressed (HIGH)
        led.value(1)  # Turn LED ON
    else:
        led.value(0)  # Turn LED OFF

    time.sleep(0.01)  # Small delay to debounce

ATTiny412

This is my ATTiny412 chip soldered using surface-mount soldering:

Setting Up Software

1.Open Arduino 1.8.19

2.Go to this link and download by pressing the three dots on the right side and selecting “download”

3.File → Settings and then paste http://drazzy.com/package_drazzy.com_index.json in the box after “Additional Board Manager URLS:” and press OK

4.Tools → Board → Board Manager… and then search “Mega Tiny Core”

5.Open the jtag2updi Arduino file from Downloads

6.Upload to Arduino Uno board using a COM port that is not COM1

7.Once uploaded successfully, open Arduino 1.8.19, select ATTiny412 as the board, and select jtag2updi as the programmer

8.Set up wiring, enter code in Arduino 1.8.19, and upload

One LED

Wiring

This is the pinout for the ATTiny412:

The yellow wires are connected to power, and the black, gray, and brown are connected to ground.

Code

This is the code to make 1 LED light up using pin 1 on the Arduino:

void setup() {
  pinMode(1, OUTPUT);
}

void loop() {
  digitalWrite(1, HIGH);  
  delay(1000);            
  digitalWrite(1, LOW);    
  delay(1000);
}

Challenges

The first time I tried to make one LED light up, my circuit would not work because one of the legs on my 412 chip was not fully soldered onto the board, so I went back and fixed the soldering. The second time, I placed the LED backwards in the breadboard, and since LEDs have polarity, that caused my circuit to not work. Once I flipped it around so the longer leg of the LED is connected to the resistor, the LED lit up and started blinking.

Two LEDs

Wiring

Code

This is the code to make the two LEDs blink in an alternating pattern:

void setup() {
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
}

void loop() {
  digitalWrite(1, HIGH);   
  delay(1000);              
  digitalWrite(1, LOW);    

  digitalWrite(2, HIGH);   
  delay(1000);              
  digitalWrite(2, LOW);    

}

LEDs blinking in sync:

Three LEDs

Wiring

Code

This is the code to make 3 LEDs light up like a traffic light:

void setup() {
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
}

void loop() {
  digitalWrite(0, HIGH);   
  delay(1000);              
  digitalWrite(0, LOW);    

  digitalWrite(1, HIGH);   
  delay(1000);              
  digitalWrite(1, LOW);    

  digitalWrite(2, HIGH);   
  delay(1000);              
  digitalWrite(2, LOW);    

}

Group Assignment

For our group assignment, we needed to demonstrate and compare the toolchains and development workflows for available embedded architectures. You can read more about the entire group project here. This week I worked with Kathryn Wu and Tyler Russell.

I worked on the RP2040 and read through this datasheet to learn more about this microcontroller. I used ChatGPT to help summarize and answer my questions based off the datasheet because the datasheet is 636 pages long, which would be a lot to read and process on my own. You can find a link to a pdf of all the ChatGPT conversations I had during week 4 in the AI Help section of this page.

Overview

Feature Description
Processor Dual ARM Cortex-M0+ cores, up to 133MHz
Memory 264kB SRAM in six banks, supports up to 16MB of external flash via QSPI
GPIO 30 multifunction GPIO pins, 4 of which support ADC
Peripherals 2x UART, 2x SPI, 2x I2C, 16x PWM channels, USB 1.1, 8 PIO state machines
Clock System 2 PLLs for system and USB clocks, flexible clocking architecture
Power Management Internal LDO regulator, multiple low-power modes
Debugging Serial Wire Debug (SWD) interface, hardware breakpoints, watchpoints
ADC 4-channel, 12-bit, 500ksps ADC with internal temperature sensor
Bus Fabric Fully connected AHB crossbar for high-speed data transfer
Manufacturing Process 40nm process technology for low power consumption
Ease of Use Supports C, C++, and MicroPython, making it beginner-friendly
Built-in Libraries Includes SDK with hardware abstraction layers for easy peripheral access
Recommended Use Suitable for embedded systems, IoT, robotics, signal processing, and real-time applications
Notable Features Programmable I/O (PIO) for custom peripheral support, deterministic cycle timing, DMA support

Toolchain Comparison

I was confused about what toolchain the RP2040 uses, and Kathryn Wu told me that the RP2040 uses the GNU toolchain, which I double-checked with ChatGPT, and she was correct. This is a table that ChatGPT helped me come up with, only using information from the RP2040 datasheet.

Feature GNU Toolchain Arduino Toolchain
Compilation Uses GCC (arm-none-eabi-gcc) for compiling C/C++ code. Uses a simplified build system with pre-configured toolchains.
SDK Support Fully supports the RP2040 C/C++ SDK, enabling low-level control. Uses Arduino Core for RP2040, which abstracts hardware details.
Optimization Provides manual control over optimization flags for performance tuning. Optimized for ease of use, but with less fine-grained control over optimizations.
Debugging Supports GDB and SWD (Serial Wire Debug) for in-depth debugging. Limited debugging features, mainly serial print debugging.
Build System Uses CMake for configuration and building projects. Uses a simplified, built-in build system managed by the Arduino IDE.
Library Access Direct access to hardware abstraction layers (HAL) and low-level registers. Provides Arduino libraries and APIs for easy peripheral access.
Ease of Use Requires manual setup but offers full control over the hardware. Beginner-friendly, with drag-and-drop UF2 programming.

Development Workflows

To compare their development workflows, I used the knowledge I gained through my experience programming both, which is documented below as well as ChatGPT’s summary of the 636 page datasheet. I also used ChatGPT to help format the table.

Workflow Section Arduino (C/C++) MicroPython (Python)
Project Setup Arduino IDE Use Micropython through Thonny
Performance Compiled to machine code, significantly faster execution. Interpreted language, slower execution due to runtime interpretation.
Memory Usage More memory-efficient; optimized for RP2040’s 264kB SRAM. Uses more RAM due to interpreter overhead.
GPIO & Hardware Control Direct control with low-level optimization. Easier for beginners but with higher latency.
Interrupt Handling Fast, real-time capable interrupt handling. Possible but with added latency from Python runtime.
Boot & Startup Time Faster boot and execution as compiled code runs immediately. Longer due to interpreter initialization.
SDK & Library Support Full access to the RP2040 C/C++ SDK with extensive libraries. MicroPython has a built-in firmware with library support but limited low-level access.
Real-Time Capabilities Supports real-time applications and precise control. Not ideal for precise timing tasks.
Concurrency Can fully utilize RP2040’s dual-core processing. Supports lightweight threading but lacks true parallel execution.
Flash Storage Usage Smaller compiled binaries allow more efficient flash usage. Larger due to the MicroPython runtime.

From the information I gained by programming the RP2040 in both C++ and Micropython and the information ChatGPT provided from the datasheet, I would say both function fairly similarly and can program the RP2040 successfully, but C++ is able to work faster and better utilizes the abilities of the RP2040.

PDF Compressor

Video Compressor

Another Video Compressor

Micropython Downloading Tutorial

AI Help

Here are all my ChatGPT searches from Week 4: PDF

Files

Here are the codes I used in Week 4: Compressed Micropython files


Last update: February 19, 2025