Skip to content

5. Embedded Programming

This week we are starting off on the embedded programming topics.

Goals

Our group assignment was the compare different architecture of micro controller. It is clear to me that choosing the right micro controller is key given to a successful project. The different features, cost, speed form factor etc. will make your project either easier or harder and so taking the time to define that would work best is worth it

Individual:

  1. Browse through the data sheet for your microcontroller

  2. write program for a microcontroller development board to interact (with local input &/or output) and communicate (remotely)

extra credit: use different languages &/or development environments

extra credit: connect external components to the board

Accomplishments: I have had some experience working with Arduino and 412 in the fab academy prep session we have had and so I revisited the 412 for bare metal programming but focused mainly on the RP2040 and the Arduino.

  1. Reviewed the Data sheet for RP2040 and ESP32-s2
  2. Made a Morse Code "transmitter" using the RP2040 and C
  3. Used Micro python for the first time to make the RP2040 blink a LED
  4. Built a first cut at final project circuitry using the Arduino and C
  5. Tried out ChatGPT for some of the code development - got a basic structure in place but had to do clean up/changes
  6. Reviewed the 412 work we did in Prep week with input (Button Photo resistor) and outputs (LEDs)
  7. Wrote my first bare metal program for the ATTiny 412 to blink an LED

Reading the data sheets RP2040 / ESP32-S2

I reviewed through the data sheetS FOR RP2040 and the ESP32-s2. They are both ery dense and after reading the intro and skimming some of the other areas looking for answers to our group assignment some things start to look more familiar. Especially given the bare metal programming that reviewed in our Lab last week.

R2040 in C

I wanted to start with programming the R2040 to blink using C in the Arduino IDE and MicroPython

I got a set of parts and given the availability in our lab will use the Raspberry Pico for this excersize.

First added the RP2040 to the board manager in the Arudino IDE

Arduino

I used the Blink built in example in Arudino

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

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

I plugged the Pico in, complied and had the onboard led blinking

I wanted to add button and LED and so first off looked for the pinout map

Pinout

Then I connect the LED to the 20th leg. I change to the code to

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

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

But no joy.....a few steps of trouble shooting and another look at the pinout map and i noticed I got confused between the physical leg number and the GPIO number and so quick correction replacing the 20 with 15

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

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

And we are good!!

now for the input I decided to try 2 different things for the first time. Using the serial input and using Chat GPT as the starting point.

I gave chat ChatGPT the following prompt:

ChatGPT try 1

I did not see any of the morse code coming out in the code and so I went back and noticed my typo. I quick correction to the question and we have a better looking code

ChatGPT try 1

Here is the full code from Chat GPT

// Define Morse code patterns for each letter
const int dotDuration = 250; // Duration of a dot in milliseconds
const int dashDuration = 3 * dotDuration; // Duration of a dash (3 times the duration of a dot)
const int interSymbolGap = dotDuration; // Gap between symbols (same duration as a dot)
const int interLetterGap = 3 * dotDuration; // Gap between letters (3 times the duration of a dot)
const int interWordGap = 7 * dotDuration; // Gap between words (7 times the duration of a dot)
const char* morseTable[] = {
  ".-",   // A
  "-...", // B
  "-.-.", // C
  "-..",  // D
  ".",    // E
  "..-.", // F
  "--.",  // G
  "....", // H
  "..",   // I
  ".---", // J
  "-.-",  // K
  ".-..", // L
  "--",   // M
  "-.",   // N
  "---",  // O
  ".--.", // P
  "--.-", // Q
  ".-.",  // R
  "...",  // S
  "-",    // T
  "..-",  // U
  "...-", // V
  ".--",  // W
  "-..-", // X
  "-.--", // Y
  "--.."  // Z
};

int ledPin = 13; // LED pin number
char inputChar; // Character received from the computer
const char* morsePattern; // Morse code pattern for the input character

void setup() {
  Serial.begin(9600); // Initialize serial communication at 9600 bps
  pinMode(ledPin, OUTPUT); // Set LED pin as output
}

void loop() {
  if (Serial.available() > 0) { // Check if data is available on serial port
    inputChar = Serial.read(); // Read the input character
    inputChar = toupper(inputChar); // Convert input character to uppercase
    if (isalpha(inputChar)) { // Check if input is a letter
      morsePattern = morseTable[inputChar - 'A']; // Get the Morse code pattern for the input letter
      for (int i = 0; i < strlen(morsePattern); i++) { // Loop through the Morse code pattern
        if (morsePattern[i] == '.') { // If current symbol is a dot, turn on the LED for the duration of a dot
          digitalWrite(ledPin, HIGH);
          delay(dotDuration);
          digitalWrite(ledPin, LOW);
          delay(interSymbolGap);
        } else if (morsePattern[i] == '-') { // If current symbol is a dash, turn on the LED for the duration of a dash
          digitalWrite(ledPin, HIGH);
          delay(dashDuration);
          digitalWrite(ledPin, LOW);
          delay(interSymbolGap);
        }
      }
      delay(interLetterGap); // Add gap between letters
    } else if (inputChar == ' ') { // If input is a space, add gap between words
      delay(interWordGap);
    }
  }
}

I reviewed the code and it all seemed to make sense . I change the pin from 13 to 15 and gave it a try with both an "SOS" message and a "FAB". It works!!

RP2040 in Micropython

I do not know python so I first took a basic tutorial

I used the following direction to get Micropython loaded here and Thonny installed as an IDE here

No I ran through a basic python tutorial and it was straight forward.

Using the following code:

from machine import Pin, Timer

led = Pin(15, Pin.OUT)
timer = Timer()

def blink(timer):
    led.toggle()

timer.init(freq=2.5, mode=Timer.PERIODIC, callback=blink)

Here it is in action

Arduino and the Vegetable Washing Machine basic set up

To keep this week in sync with my final project I decided to test a set up for the basic VMS functionality replacing the water pump and motor with LED and the sensors with buttons.

Here is the functionality I was aiming for:

Button Label FUnctionality
Button 1 Wash cycle 1. Check Lid / Water sensor -> 2. Turn on Water pump and motor for a set time
Button 2 Dry cycle 1. Check Lid -> 2. Turn on motor for a set time
Button 3 Total cycle 1. Run Wash cycle -> 2. Run Dry cycle
Sensors If either sensor is triggered then stop and turn on error LED

So I turned to ChatGPT and ask for the following:

"As a programmer write the code in Arduino for an RP 2040 to control a dishwasher. When you press button a the wash cycle will start checking the water level sensor making sure there's enough water, checking that the lid is shut, starting to spin the drum inside the washing machine and turning on the water pump for 60 seconds"

They generated a basic set of code.

// Define the pin numbers for the sensors and actuators
const int LED_PIN = 25;
const int BUTTON_PIN = 15;
const int WATER_SENSOR_PIN = 2;
const int LID_SENSOR_PIN = 3;
const int DRUM_PIN = 4;
const int WATER_PUMP_PIN = 5;

void setup() {
    // Initialize the RP 2040
    Serial.begin(9600);
    pinMode(LED_PIN, OUTPUT);
    pinMode(BUTTON_PIN, INPUT_PULLUP);
    pinMode(WATER_SENSOR_PIN, INPUT);
    pinMode(LID_SENSOR_PIN, INPUT);
    pinMode(DRUM_PIN, OUTPUT);
    pinMode(WATER_PUMP_PIN, OUTPUT);
}

void loop() {
    // Wait for the button press
    while (digitalRead(BUTTON_PIN) == HIGH) {
        digitalWrite(LED_PIN, LOW);
        delay(100);
        digitalWrite(LED_PIN, HIGH);
        delay(100);
    }

    // Check the water level and lid status
    if (digitalRead(WATER_SENSOR_PIN) == LOW && digitalRead(LID_SENSOR_PIN) == LOW) {
        // Start the wash cycle
        digitalWrite(DRUM_PIN, HIGH);
        digitalWrite(WATER_PUMP_PIN, HIGH);
        delay(60000);
        digitalWrite(DRUM_PIN, LOW);
        digitalWrite(WATER_PUMP_PIN, LOW);
    } else {
        Serial.println("Not enough water or lid is open.");
    }
}

I then decided to add dry and total cycles

"Now add a dry cycle that if we press a different button will spin slowly and then fast the drum for 120 seconds"

// Define the pin numbers for the sensors and actuators
const int LED_PIN = 25;
const int WASH_BUTTON_PIN = 15;
const int DRY_BUTTON_PIN = 14;
const int WATER_SENSOR_PIN = 2;
const int LID_SENSOR_PIN = 3;
const int DRUM_PIN = 4;
const int WATER_PUMP_PIN = 5;

void setup() {
    // Initialize the RP 2040
    Serial.begin(9600);
    pinMode(LED_PIN, OUTPUT);
    pinMode(WASH_BUTTON_PIN, INPUT_PULLUP);
    pinMode(DRY_BUTTON_PIN, INPUT_PULLUP);
    pinMode(WATER_SENSOR_PIN, INPUT);
    pinMode(LID_SENSOR_PIN, INPUT);
    pinMode(DRUM_PIN, OUTPUT);
    pinMode(WATER_PUMP_PIN, OUTPUT);
}

void loop() {
    // Wait for the wash button press
    if (digitalRead(WASH_BUTTON_PIN) == LOW) {
        // Check the water level and lid status
        if (digitalRead(WATER_SENSOR_PIN) == LOW && digitalRead(LID_SENSOR_PIN) == LOW) {
            // Start the wash cycle
            digitalWrite(DRUM_PIN, HIGH);
            digitalWrite(WATER_PUMP_PIN, HIGH);
            delay(60000);
            digitalWrite(DRUM_PIN, LOW);
            digitalWrite(WATER_PUMP_PIN, LOW);
        } else {
            Serial.println("Not enough water or lid is open.");
        }
    }

    // Wait for the dry button press
    if (digitalRead(DRY_BUTTON_PIN) == LOW) {
        // Start the slow spin
        digitalWrite(DRUM_PIN, HIGH);
        delay(10000);

        // Start the fast spin
        digitalWrite(DRUM_PIN, LOW);
        delay(1000);
        digitalWrite(DRUM_PIN, HIGH);
        delay(10000);
        digitalWrite(DRUM_PIN, LOW);
    }
}

and finally added a total

"Now add a full cycle button that will run the wash and then the dry cycle"

Here ChatGPT kept stopping in the middle and I had to prompt it to finish

// Define the pin numbers for the sensors and actuators
const int LED_PIN = 25;
const int WASH_BUTTON_PIN = 15;
const int DRY_BUTTON_PIN = 14;
const int FULL_BUTTON_PIN = 13;
const int WATER_SENSOR_PIN = 2;
const int LID_SENSOR_PIN = 3;
const int DRUM_PIN = 4;
const int WATER_PUMP_PIN = 5;

void setup() {
    // Initialize the RP 2040
    Serial.begin(9600);
    pinMode(LED_PIN, OUTPUT);
    pinMode(WASH_BUTTON_PIN, INPUT_PULLUP);
    pinMode(DRY_BUTTON_PIN, INPUT_PULLUP);
    pinMode(FULL_BUTTON_PIN, INPUT_PULLUP);
    pinMode(WATER_SENSOR_PIN, INPUT);
    pinMode(LID_SENSOR_PIN, INPUT);
    pinMode(DRUM_PIN, OUTPUT);
    pinMode(WATER_PUMP_PIN, OUTPUT);
}

void loop() {
    // Wait for the wash button press
    if (digitalRead(WASH_BUTTON_PIN) == LOW) {
        // Check the water level and lid status
        if (digitalRead(WATER_SENSOR_PIN) == LOW && digitalRead(LID_SENSOR_PIN) == LOW) {
            // Start the wash cycle
            digitalWrite(DRUM_PIN, HIGH);
            digitalWrite(WATER_PUMP_PIN, HIGH);
            delay(60000);
            digitalWrite(DRUM_PIN, LOW);
            digitalWrite(WATER_PUMP_PIN, LOW);
        } else {
            Serial.println("Not enough water or lid is open.");
        }
    }

    // Wait for the dry button press
    if (digitalRead(DRY_BUTTON_PIN) == LOW) {
        // Start the slow spin
        digitalWrite(DRUM_PIN, HIGH);
        delay(10000);

        // Start the fast spin
        digitalWrite(DRUM_PIN, LOW);
        delay(1000);
        digitalWrite(DRUM_PIN, HIGH);
        delay(10000);
        digitalWrite(DRUM_PIN, LOW);
    }

    // Wait for the full cycle button press
    if (digitalRead(FULL_BUTTON_PIN) == LOW) {
        // Perform the wash cycle
        if (digitalRead(WATER_SENSOR_PIN) == LOW && digitalRead(LID_SENSOR_PIN) == LOW) {
            // Start the wash cycle
            digitalWrite(DRUM_PIN, HIGH);
            digitalWrite(WATER_PUMP_PIN, HIGH);
            delay(60000);
            digitalWrite(DRUM_PIN, LOW);
            digitalWrite(WATER_PUMP_PIN, LOW);
        } else {
            Serial.println("Not enough water or lid is open.");
            return;
        }

        // Perform the dry cycle
        // Start the slow spin
        digitalWrite(DRUM_PIN, HIGH);
        delay(10000);

        // Start the fast spin
        digitalWrite(DRUM_PIN, LOW);
        delay(1000);
        digitalWrite(DRUM_PIN, HIGH);
        delay(10000);
        digitalWrite(DRUM_PIN, LOW);
    }
}

Reviewing the code there were a number of things I wanted to change:

  1. Pin numbers - I decided to use the Arduino and so change the pin numbers

  2. Button functionality - I wanted to trigger the cycle when button is pressed and there for input would be HIGH. For some reason ChatGPT used INPUT_PULLUP when would do the opposite so I adjusted that

  3. No sensor checks for Dry cycle or total - added those + changed the trigger from low to high

  4. Decided to have LED flashing rather then "fast/low spin" and reduce the time for the sake of our test

  5. Add a error led to the sensor trigger

Here is my updated code:

// Define the pin numbers for the sensors and actuators
const int LED_PIN = 7;
const int WASH_BUTTON_PIN = 11;
const int DRY_BUTTON_PIN = 10;
const int FULL_BUTTON_PIN = 9;
const int WATER_SENSOR_PIN = 2;
const int LID_SENSOR_PIN = 3;
const int DRUM_PIN = 4;
const int WATER_PUMP_PIN = 5;

void setup() {
    Serial.begin(9600);
    pinMode(LED_PIN, OUTPUT);
    pinMode(WASH_BUTTON_PIN, INPUT);
    pinMode(DRY_BUTTON_PIN, INPUT);
    pinMode(FULL_BUTTON_PIN, INPUT);
    pinMode(WATER_SENSOR_PIN, INPUT);
    pinMode(LID_SENSOR_PIN, INPUT);
    pinMode(DRUM_PIN, OUTPUT);
    pinMode(WATER_PUMP_PIN, OUTPUT);
}

void loop() {
    // Wait for the wash button press
    if (digitalRead(WASH_BUTTON_PIN) == HIGH) {
        // Check the water level and lid status
        if (digitalRead(WATER_SENSOR_PIN) == LOW && digitalRead(LID_SENSOR_PIN) == LOW) {
            // Start the wash cycle
            digitalWrite(DRUM_PIN, HIGH);
            digitalWrite(WATER_PUMP_PIN, HIGH);
            delay(600);
            digitalWrite(DRUM_PIN, LOW);
            digitalWrite(WATER_PUMP_PIN, LOW);
              delay(400);
              digitalWrite(WATER_PUMP_PIN, HIGH);
           delay(400);
            digitalWrite(WATER_PUMP_PIN, LOW);
        } else {
            Serial.println("Not enough water or lid is open.");
                        digitalWrite(LED_PIN, HIGH);

        }
    }

    // Wait for the dry button press
    if (digitalRead(DRY_BUTTON_PIN) == HIGH) {
        // Start the slow spin
                if (digitalRead(LID_SENSOR_PIN) == LOW) {

        digitalWrite(DRUM_PIN, HIGH);
        delay(600);

        // Start the fast spin
        digitalWrite(DRUM_PIN, LOW);
        delay(300);
        digitalWrite(DRUM_PIN, HIGH);
        delay(300);
        digitalWrite(DRUM_PIN, LOW);
                }     else {
            Serial.println("lid is open.");
                        digitalWrite(LED_PIN, HIGH);

        }
    }

    // Wait for the full cycle button press
    if (digitalRead(FULL_BUTTON_PIN) == HIGH) {
        // Perform the wash cycle
        if (digitalRead(WATER_SENSOR_PIN) == LOW && digitalRead(LID_SENSOR_PIN) == LOW) {
            // Start the wash cycle
            digitalWrite(DRUM_PIN, HIGH);
            digitalWrite(WATER_PUMP_PIN, HIGH);
            delay(600);
            digitalWrite(DRUM_PIN, LOW);
            digitalWrite(WATER_PUMP_PIN, LOW);
                delay(400);
            digitalWrite(WATER_PUMP_PIN, HIGH);
           delay(400);
            digitalWrite(WATER_PUMP_PIN, LOW);
        } else {
            Serial.println("Not enough water or lid is open.");
             digitalWrite(LED_PIN, HIGH);
            return;
        }

        // Perform the dry cycle
        // Start the slow spin
        if (digitalRead(LID_SENSOR_PIN) == LOW) {
        digitalWrite(DRUM_PIN, HIGH);
        delay(200);

        // Start the fast spin
        digitalWrite(DRUM_PIN, HIGH);
        delay(200);
        digitalWrite(DRUM_PIN, LOW);
        delay(200);
        digitalWrite(DRUM_PIN, HIGH);
        delay(100);
        digitalWrite(DRUM_PIN, LOW);

       } else {
            Serial.println("Not enough water or lid is open.");
             digitalWrite(LED_PIN, HIGH);
            return;
        }

    }}

Here is the basic circuit I am planning

Circuit

I followed this diagram (except for the different colored wires) and it went pretty smoothly

Here is the one I built in action:

412 Blinking and Button and Photo resistor

We covered this in the Fab Academy prep 412 documentation

412 Bare metal blinking

I start off by getting my Arudino Uno loaded with JTAG based on the same process I documented in Fab Prep week

Once I have that set up, I reviewed the lecture we had in class and watch a number of tutorials about bare metal programing

I looked up the pinout map for the ATTiny412

412 Map

Now it was time to start the coding

Based on the map and the ATTiny I wanted to take the Blink code and start replacing some of the code turning PIN2 to out put and then turning it one and off

Here is the starting code:

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

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

To start off I replaced

pinMode(2, OUTPUT); with DDRB = 1; based on many of the example I have seen however it seemed the DDRB was not recognized....a LOT of googleing later I found out that for 412 the code is differnt then for the Ardunio and I need to use PORT.DIR;

So I set up PORT.DIR = 1; and....no blinking.

Reviewing the lecture and discuss with a class mate I was reminded that this is index 0 so PA1 is actualy the second slot and so I need to set it to 2 to turn on, not 1.

PORT.DIR = 2;

worked!

Now to replace digitalWrite(1, HIGH);

For the 412 I needed to us PORTA.OUT = 2; which again was differnt then the other examples and so here is the final code I used:

void setup() {
  // initialize digital pin LED_BUILTIN as an output.
 PORTA.DIR = 1;
}

// the loop function runs over and over again forever
void loop() {
  PORTA.OUT = 2;   // turn the LED on (HIGH is the voltage level)
  delay(200);                       // wait for a second
  PORTA.OUT = 0;   // turn the LED on (HIGH is the voltage level)
  delay(200);                       // wait for a second
}

Here are the files from this week work

Morse Code

Micro Python Blink

412 Bare metal Blink

Vegetable Washing Machine V1.0 Code


Last update: May 19, 2023