Table of Contents

Objectives Timeline Group Assignment Individual Assignment

4. Embedded Programming

Objectives

This week's assignment tasks are listed below:

  1. group assignment:
    • demonstrate and compare the toolchains and development workflows for available embedded architectures
  2. individual assignment:
    • browse through the data sheet 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 connections)
      • extra credit: test it on a development board
      • extra credit: try different languages &/or development environments

Timeline

Img: Week 4 Work Plan

Group Assignment

Comparing Toolchains and Development Workflows of Different Computer Architectures.

We learnt about different toolchains of different microcontrollers from different computer architectures. Along with that we compared our results to Rasberry Pi also, which is a full fledged computer rather than a microcontroller.


Toolchains and Development Workflows of different Microcontrollers and Rasberry Pi

For more information, read our group assignment.

Individual Assignment

Browse through the Data Sheet for your Microcontroller

The official datasheet for the RP2040 has been linked here.

Img: Coverpage of documentation
RP2040 official datasheet from Rasberry Pi

Name of the Chip: RP2040

Name of the chip
Source: Pg 9 of the data sheet

The chip is called RP2040. It is called so because

Speed: 133MHz

The dual cores can run upto 133 MHz. It has two phase-locked loops (PLLs) that provide a fixed 48MHz clock for USB or for Analog Digital Converter (ADC) , and a flexible system clock up to 133MHz for high power applications.

Memory: 264 kB SRAM & no onboard flash memory

The RP2040 has 264 kB of embedded Static Random Access Memory (SRAM; a type of volatile memory) for temporary memory storage and 0B for flash memory (permanent storage; a type of non-volatile memory)

Pins: 36 GPIO Pins, out of which 30 are digital I/O Pins, which also include 4 Pins that can accept both digital and analogue input.

Among the GPIO pins, GPIO 0-25 accept accept digital inputs, whereas GPIO 26-29 can accept both analogue and digital signal input and output digital signals.

Datasheet RP2040 pinout
RP2040 QFN-56 package pinout

Communication protocols supported: UART, I2C, and SPI

Img: DatasheetRP2040Communication
Source: pg 235 in data sheet

Analog to Digital Converter: The RP2040 has an internal ADC.

It has 5 inputs. 4 inputs are available on the pins shared with GPIO (GPIO 26-29), while one input is connected to an internal temperature sensor

Img: Datasheet of RP2040 with ADC
Source: pg 556 in the data sheet

Operating and Logic Voltage: 1.8 to 3.3 V (preferrably 3.3 V)

Along with the previous datasheet, I refered another datasheet from Rasberry Pi called 'Hardware design with RP2040', which states that the RP240 requires 3.3V


Source: pg 7 in Hardware design with RP2040

Source: pg 151 in the official data sheet

Based on this Reddit post a logic voltage of x means that the microcontroller will read a value equal to or close to x as 1 or digital HIGH and any value close to zero Volts as 0 or digital LOW. Hence the logic voltage of the RP2040 is also 3.3V

Maximum Tolerable Current and Voltage: 3.83V and 100 mA

Img: Max Voltage
pg 613 in the official datasheet
Img: Max Current
pg 160 in the official datasheet

Writing a Program for your Microcontroller

Some Definitions

I have listed some definitions for some terms used in programming

  • Function: A block of code that performs a specific task and reused at different parts of the code, eg: sleep in Micropython
  • Class: A 'blueprint' for creating objects, eg: Pin in Micropython
  • Object: A specific implementation of the class, with variables containing data specific to that object
  • Module: A file containing multiple Python functions, classes, and variables. eg: machine
  • Loop: A block of code that keeps being repeated over and over until a certain condition is met. In cases where no condition is added then you get an infinite loop. eg: While True:, void loop()

Program 1: Controlling an LED using a Button using a Rasberry Pi Pico

  • Language: Micropython
  • Microcontroller: RP2040
  • Board: Rasberry Pi Pico
  • Environment: Wokwi (simulation)

Once I learnt the basic syntax with the help of examples from our instructors, I wrote a simple piece of code written in Mycropython using a Rasberry Pico development board (includes RP2040 chip) to control the LED using a button, using an example Blink program

First we import the required modules. Because we only need to import specific objects, ie. 'Pin' class from 'machine' & 'sleep' function from 'time' we only import using the commmand: from x import y

Then we name a variable led where we state that Pin 0 wil be an OUTPUT Pin, meaning an voltage will be sent to it, which will be used to light up the LED.

We also name a second variable named button which is connected to pin 2 on the Rasberry Pi Pico. We set it as an INPUT pin, meaning it will take voltage readings from the push button. Additionally, using the PIN.PULL_UP method, we set pin to a default 'HIGH' state until the button is pressed.

To make neat connections I used a breadboard, added the components to make an electrical circuit. The following image shows how they are connected internally

Source: How to connect a circuit on a breadboard by EMT laboratories

I have previously tinkered with simple circuits in the past so I knew how to connect simple devices like LEDs and switch buttons. Since an LED is a diode, it cannot be connected in any manner. The Anode (A) is the bent end that should be connected to the digital I/O pins and the Cathode (C) should be connected to the ground (GND) pin. Also, a 1K resistor should be connected in series with the LED to stop it from drawing too much current.

Once I have placed all the components, I then connect all the devices using wires. You can see which are the GND pins by hovering on top of the board.

I added a While True:statement to add a loop that goes on infinitely

Make sure to check the file type! When testing the Micropython script will not work in a sketch.ino file. It should be a main.py file

To test the button values, I added a Serial output using the command print(button.value()). But when running, nothing showed up on the console. I tried commenting different parts of the code to see if an LED lights up using the command led.value(1) but it did not work

To comment code, I use the shortcut Ctrl+/

In situations like this, I take a break and come back to the problem with a fresh mind.

And it worked! I realized my error was that I did not connect my resistor to the circuit.Once I changed this, the code started working and the LED starting lighting up

But when I uncommented all the code lines, the code again did not work.

I decided to use the commenting approach again to understand where the problem was, and found out it was a problem with the statement about declaring the variable button

I knew it was a problem with the PIN.PULL_UP command since it was the code was running without it, even though you would then run into issues with sreading the correct button state due to the problem with floating values

I then realized that I used the wrong syntax PIN instead of Pin while writing the command Pin.PULL_UP.

Once I corrected it, the code is now running

Inside the While Trueloop I added an if statement stating that if the button value is 0 (the 'ON' state) using the if button.value()==0. The == operator means to see if 'check if x = y'. If it satisfies that condition, it then goes inside the if code block and switches on the LED using the command led.value()=1.We then add a delay of 1 second using the sleep(1)command. We then repeat the same process for when the button is OFF

But the code did not work again

With the help of my instructor, the error was resolved when the indentation was corrected

The code is now running.

I now added a Serial Output using the print command to state when the LED is on and when it is OFF and commented the print(button.value()) As long as the button is pressed, the LED will remain ON and a message confirming the same will be displayed in the terminal. When the button is not pressed, the LED remains OFF which is also confirmed by another message in the terminal.

The following is the code I wrote. Comments have been added by adding '#' to enhance readability':

  
                                #importing required modules and objects
                                from machine import Pin
                                from utime import sleep
                                
                                #defining variables
                                led = Pin(0, Pin.OUT)
                                button = Pin(2,Pin.IN,Pin.PULL_UP)
    
                                while True:  #creating an infinite loop
                                    
                                    # print(button.value()) #uncomment for debugging 
                                    
                                    #If condition when button is not pressed
                                    if button.value()==0:
                                        led.value(1) #led remains 'ON'
                                        print ("LED is ON")
                                        sleep(1) #sleep for 1 second

                                    #If condition when button is pressed
                                    if button.value()==1: #Button not pressed
                                        led.value(0) #led remains 'OFF'
                                        print ("LED is OFF")
                                        sleep(1) #Add delay for 1
                            

Program 3: Find the I2C address of the OLED Display

In Output Devices Week I was able to play with Wokwi a bit more, so I have added my work here as well.

The first step to programming on the OLED is using to find the I2C Address of our device, the SSD1306 OLED in our case. For this I am going to adapt the code from this tutorial to do so. To understand more about each line of code, I use the help of ChatGPT

Now that I have some understanding of what the code means, I will rewrite it for my purposes using ESP32S3 microcontroller in Wokwi simulator.

I was hoping to be able to write this code without looking to promote learning the logic behind it, but I had to refer back to the source with every line.

Now to sort some errors I made while coding. Debugging seems to be the most important part of coding, because while trying to fox your code, you tend to learn the best about what each line of code does and the pros and cons of different code logic. Even if you dont truly understand it while writing it, you tend to understand much more while debugging.

This is a video of the working. As you can see the I2C address of the SSD1306 module is 0x3C, which can be confirmed by Wokwi's reference documentation


    #include <Wire.h>

    #define RGB 38
    #define SDA 8
    #define SCL 9
    
    void setup(){
        Serial.begin(115200);
        // while(!Serial){}
        Serial.println("I2C Scanner scanning...");
        byte count=0;
        pinMode(RGB,OUTPUT);
        digitalWrite(RGB,HIGH);
        Wire.begin();

        for (byte i=1; i<120; i++){
        Wire.beginTransmission(i);
        // Serial.println (Wire.endTransmission());
        if (Wire.endTransmission()==0){
            // Serial.println (Wire.endTransmission());
            Serial.print ("Found Address: ");
            Serial.print(i, DEC);
            Serial.print(" (0x");
            Serial.print(i, HEX);
            Serial.println(")");
            count++;
            delay(1);
        }
        }
        Serial.print("Done. ");
        Serial.print("Found ");
        Serial.print(count, DEC);
        Serial.print(" device(s)");
    }
    
    void loop(){}     
                        

Program 4: Add text to your display

I will be following the code examples seen here for reference and to get familiar with programming the OLED display.

To understand the some parts of the code I used the help of ChatGPT and confirmed with one of the examples from Adafruit_SDD1306 library




        #include <Wire.h>
        #include <Adafruit_GFX.h>
        #include <Adafruit_SSD1306.h>
        
        #define Height 128
        #define Width 64
        
        Adafruit_SSD1306 display(Height,Width,&Wire,-1);
        
        void setup(){
            Serial.begin(115200);
        
            if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)){
            Serial.println ("I2C initialisation failed");
            for(;;);
            }
            delay(200);
            
            display.clearDisplay();
            display.setTextSize(1);
            display.setTextColor(WHITE);
            display.setCursor(0,0);
            display.println("Hello world!");
            display.display(); 
        }
        
        void loop(){ 
        }                            
                        

Program 5: Display a Facial Expression in the OLED Display

To make life a bit easier, I was going to try to use the FluxGarage RoboEyes library, which is based on the Adafruit GFX Library, so it should work with ESP32 as well. However, it won't be possible to simulate on Wokwi, since only paying customers can add custom libraries that are not yet made available for free in the library manager.

So instead I am going to use this tutorial that uses the U8g2 library, which is supported by Wokwi simulator

Following the tutorial I went to Lopaka.app, selected the U8g2 library, and created a new project

This is a youtube video that shows the basic overview of using the Lopaka app

Whenever I face errors, I use ChatGPT to understand what the error message actually means and what I have to do to solve it






                            #include <U8g2lib.h>
                            #include <Wire.h>
                            
                            // #define SCL_PIN 6
                            // #define SDA_PIN 5
                            // U8G2_SSD1306_128X64_NONAME_F_HW_I2C(rotation, [reset [, clock, data]]) [full framebuffer, size = 1024 bytes]
                            
                            U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /*SCL_PIN, SDA_PIN,*/ U8X8_PIN_NONE);
                            
                            void setup(){
                                Serial.begin(9600);
                                if (!u8g2.begin()){
                                Serial.println("Display not initialized");
                                for(;;);
                                }
                                delay(1000);
                                Serial.println("Display initialized");
                            }
                            
                            void eye_open(){
                                u8g2.clearBuffer();
                                u8g2.setFontMode(1);
                                u8g2.setBitmapMode(1);
                                u8g2.drawFilledEllipse(36, 23, 12, 18);
                                u8g2.drawFilledEllipse(89, 23, 12, 18);
                                u8g2.drawFilledEllipse(61, 53, 12, 4);
                                u8g2.sendBuffer();
                            }
                            
                            void loop(){
                                eye_open();
                            }
                        

Program 6: Controlling an LED via Serial Monitor

I used the board I made during Electronics Production Week to control an LED via Serial Monitor

Serial Monitor is a software application usually found in Integrated Development Environemnts to read and write data with microcontrollers using a serial connection.

                            #define LED D3
                            char user;

                            void setup() {
                            pinMode(LED,OUTPUT);
                            Serial.begin(9600);
                            }

                            void loop() {
                            user = Serial.read();

                            if (user == '1') {
                                digitalWrite(LED, HIGH);
                                Serial.println("ON");
                            } 
                            
                            else if (user == '0') {
                                digitalWrite(LED, LOW);
                                Serial.println("OFF");
                            }
                            }
                        

Testing on a development board

I tested some of my previous code in a development board called Seeed Xiao RP2040

Try different languages &/or development environments

I used ATtiny 1614 and Arduino IDE and UPDI tool chain to make an LED blink.

This is the code I used for the same:

                            #define LED 10 #defining pin in a variable

                            void setup(){
                            pinMode(LED,OUTPUT); #setting up LED as an output pin
                            }

                            void loop(){ 
                            digitalWrite(LED,HIGH); #LED turns ON
                            delay(1000); #delay of 1 second
                            digitalWrite(LED,LOW); #LED turns OFF
                            delay(1000);
                            }
                        

More information can be found in the group assignment.

Using the STM32 microcontroller

This time I wanted to do something more relevant to my final project. Since I was already familiar programming in C++ with the Arduino IDE and based on a suggestion by my instructor Sibin, I chose to simulate a program in the NUCLEO-C031C6

Based on the databrief of the STM32 Nucleo-64 development board & the datasheet of the STM32C031C6 microcontroller.

  • Language: Embedded C++
  • Board: NUCLEO-C031C6
  • Microcontroller: STM32C031C6T6
    • Core: ARM Cortex M0+
    • Speed: 48 MHz
    • Flash:32 KB
    • SRAM: 12 KB
    • Operating voltage: 2-3.6V
    • Pins: 48 pins
    • Communication interfaces: I2C (PB6/PB7), USART (PA9/PA10), SPI
    • Development support: SWD (SWCLK-PA13(Pin 35), SWDIO-PA14(Pin 36), Power-VSS/VDD(Pin 6/7), GND-VREF(Pin 5))
    • ADC: 12 bit internal ADC
  • Development toolchains: Arduino IDE with SWD programming tool (ST-LINK/V2)

When I was facing some difficulty finding all required information, my instructor told me to use STM32CUbeMX software, which is a graphical tool normally used to configure STM32 microntrollers and microprocessors.

Pins for SWD debugging

I used it here to find other information that I was not able to get easily from the datasheet, for eg: the pins for SWD debugging.

Conclusion

This week I learnt the following:

  • learnt about computer architectures and their differences
  • learnt about different toolchains for different microchips and programming languages
  • learnt to program in Micropython and Arduino C++ in an RP2040 microchip & an ATTiny1614

Mistakes, Solutions & Tips

Tips: To find out which PORT is being connected to your board, you can use the Device Manager > COM and Ports