Skip to content

Programming the Quentorres DevBoard

Okay, so for this task, I’m going to program the quentorres board that I’ve made on Week 4: Electronics Production and Week 8: Electronics Design.

Development Environment

In order to write our program, we definitely require the utilization of a code editor/compiler software, like Arduino IDE or PlatformIO. However, actually there are 2 feasible approaches to programming our quentorres board:

  • (1) composing the program within an IDE software that’s connected to the board for testing and debugging, or
  • (2) composing the program in a simulator software, so that we can simulate the performance beforehand, and then and then transferring it to the IDE software for uploading to the board

🛡️ Since I’m a noob here, and I’m still learning how to program, I think it’s better for me to take the least risky approach, which is (2) to craft my program within a simulator software to review its performance beforehand. This way, I can prevent ‘clumsy/careless’ mistake to my board, and ensure the program runs correctly initially, adding an extra layer for testing and debugging process. So that I know if I upload the code to my board and it’s not working, it’s probably because of the hardware components, not the program.

Simulating in Wokwi

The simulation software that I’m going to use here is Wokwi, because it has various development board options to choose form. However, there’s no Xiao RP2040 available in Wokwi. Since the Quentorres board uses the RP2040 MCU, which shares a similar architecture with the Raspberry Pi Pico, I’m going to mimic the Quentorres board with this MCU, based on the diagrams below.

Alt text Alt text

Because for now I’m going to program interactions between an LED and a button, I only need to select one LED (D1) and the button switch, and determine the components related to them. In this process, we need to refer to the Xiao RP2040 pinout diagram (on the right) to identify which pins we can connect each of these components to. This is to ensure that we don’t connect the components to the wrong pins. What we need to pay attention to is the GPIO pins for LED and Button, Ground (GND) pin, and Power Pin. Aside from that, also notice where the serial pins are.

So, basically, here are the key components and pins that I should connect to:

  • LED (D1) ** – R1 – R4 –> GND** pin
  • LED –> GPIO pin 26
  • Button –> 3.3V pin
  • Button – R4 –> GPIO pin 27

Next step is to arrange the wiring connection and components based on the connection information above. Which in the end looks like this:

wiring-reconstruction-pico

Debugging: Blinking not working & unnotified error >> Reserved Pins for UART

At first, before setlling into the wiring connection above, I connected the LED to the pin no. 0 and button to pin no. 1. There’s no really special reason why I chose 0 and 1… only because access-wise, they’re closer to where I placed my LED and button in the Wokwi.

my inital wiring reconstruction looks like this: w6-1-7-initial-wiring

However, when I tried to simulate with basic blinking test, it didn’t work. Then, I tried to run the example code given by Seeed Studio here. The led was successfully on, but the switch didn’t work the way it should be…

What’s interesting from this trouble, is that the compiler didn’t give any error message after compilation. So, we know it’s most-likely not a code problem, but more likely and environment/setup problem.

After various troubleshooting moves, (with the help of my colleague, Eka, obviously) from changing the code syntax, doing SerialPrint to check if the code’s actually running, to trying different pins, we finally found that Pin 0 and 1 are a reserved pins, thus can’t be used for general input/output.

However, this is kinda confusing because I did beforehand crosschecking the pinout diagram of Xiao RP2040 with Pi Pico. And from what I understood, pin no. 1 and 2 are digital pins that can be used both for GPIO and UART communication.

Alt text

Alt text

Well, maybe pin 0 and 1 can be used for GPIO but needs to tweak the codes(?) Idk.. Anyway, my take from this case is.. for general input output devices, if possible, better avoid using the pins that also have other special functions. And, always try different scenario possibilities when debugging.

Writing the Program

Here, I’m going to demonstrate the general process of C programming. One thing to note is that the process of programming is not necessarily linear, so you don’t have to strictly follow this sequence when coding. However, since the computer will run your code from top to bottom, it’s important to organize your code by following this structure:

  1. Library (optional)
  2. Variables
  3. Custom function (optional)
  4. Setup function
  5. Loop function

1. Variables

First of all, we need to write/set ‘variables’ to represent (in my understanding: introduce to the computer) the pins connected to our LED (pin 26) and button (pin 27). For this purpose, I use the #define command:

#define ledPin 26  // define the number of the LED pin
#define buttonPin 27  // define the number of the pushbutton pin

💡 #define vs const int

Here, you can use either the #define or const int command which both serves a similar purpose for declaring constant variables. The main difference between the two is that #define is processed by the compiler before the actual compilation begins, which means it doesn’t occupy memory. In contrast, const int creates a named constant that occupies memory like any other variable, and its value cannot be changed once initialized. However, const int offers type-safety, meaning the compiler software can catch type-related errors during compilation, while #define does not provide such safety.

2. Setup

Now that the we have defined the variables, next, we need to setup the tasks for these variable components. By using the pinMode(,) command, we can assign the LED pin as Output and the button pin as Input:

void setup() {
  pinMode(ledPin, OUTPUT); // set the LED pin as an output
  pinMode(buttonPin, INPUT); // set the pushbutton pin as an input

3. Loop

Once we’ve finished setting our variables, we can now write the ‘main logic’ of the program. The simplest test we can conduct to see if our simulation board is working is by blinking an LED. Here, I will use the digitalWrite(,) command, by also accounting for the time duration (delay()) when the LED is turning on and off:

void loop() {
  // Blink LED
  digitalWrite(ledPin, HIGH); // turn LED on
  delay(500); // for this long (duration)
  digitalWrite(ledPin, LOW); // turn LED off
  delay(500); // for this long (duration)
}

you can always change the value inside the delay( ) command

Test: Blinking an LED

Putting it all together, here’s the resulting code to blink an LED

#define ledPin 26  // define the number of the LED pin

void setup() {
  pinMode(ledPin, OUTPUT); // set the LED pin as an output
}

void loop() {
  // Blink LED
  digitalWrite(ledPin, HIGH); // turn LED on
  delay(500); // for this long (duration)
  digitalWrite(ledPin, LOW); // for this long (duration)
  delay(500); // for this long (duration)
}

Simulation

Click run the simulation to see if our program works

Result

If all is well in the simulation, we can go ahead to upload the code to our board through Arduino IDE.

Testing with another LED and changed delay value to 100:

Programming I/O Interaction

By following the workflow above and you can also refer to my coding cheatsheet here, we can proceed with programming the interaction that we’d like to see happen.

Controlling ON/OFF LED with the push button

Here, I’m trying to control an LED based on the state of a pushbutton. When the pushbutton is unclicked, the LED remains off. When the pushbutton is clicked, the LED turns on.

#define ledPin 26  // define the number of the LED pin
#define buttonPin 27  // define the number of the pushbutton pin
boolean buttonState = 0; // initial pushbutton status (unclicked) = LOW = 0 = false

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

void loop() {
  // read the state of the pushbutton value
  buttonState = digitalRead(buttonPin);

  // if the pushbutton is unclicked = LOW
  if (buttonState == LOW) {
    // LED is off
    digitalWrite(ledPin, LOW);
  // otherwise
  } else {
      // turn LED on
      digitalWrite(ledPin,HIGH);
      }
}

Simulation

Result

Programming Communication

UART Serial Programs

UART (Universal Asynchronous Receiver/Transmitter) is the serial communication protocols that uses two lines for communication - one for transmitting data (TX pin) and one for receiving data (RX pin). UART communication is asynchronous, meaning there is no separate clock signal shared between devices. Instead, devices must agree on the same baud rate (data transfer rate) for proper communication. The overall workflow of a UART serial communication:

  1. Initialization:

    • #Serial.begin(rate) : Initializes serial communication with the specified baud rate (data transmission speed).
  2. Sending Data:

    • Serial.print(data): Prints data (numbers, text, variables) to the serial port as human-readable ASCII characters
    • Serial.println(data): Similar to Serial.print(), but adds a newline character at the end.
    • Serial.write(data): Writes raw binary data to the serial port, useful for sending non-textual data.
  3. Receiving Data:

    • Serial.available(): Checks by returning the number of bytes available for reading in the serial buffer.
    • Serial.read(): Reads incoming serial data one byte at a time.
  4. Pausing Serial Output (optional):

    • Serial.setTimeout(time): Sets a timeout for serial data transmission.

Interactive Data Input with Blinking Feedback

Here, I’m trying to prompt the user to enter their name through the serial monitor. When the user inputs their name and sends it through the serial monitor, the program reads the input, prints it back to the serial monitor, and blinks an LED briefly to indicate data processing.

For this part, I took inspiration from Neil’s lecture code and also from this youtube tutorial.

void setup() {
  Serial.begin(115200);
  Serial.setTimeout(10);
  Serial.println("What is your name?");
}
void loop() {

  //check if there's an incoming data/message, if yes
  if (Serial.available() > 0 ) {
      // turn LED on
      digitalWrite(ledPin,HIGH);
      // read the incoming data/message as text, store as 'userName'
      String userName = Serial.readString();
      // print prompt for users to input userName
      Serial.print("your name is: ");
      // print userName data
      Serial.println(userName);
      delay(10);
      // turn LED off
      digitalWrite(ledPin, LOW);
      }

Result | Putting it all together

Combined Codes

#define ledPin 26  // define the number of the LED pin
#define buttonPin 27  // define the number of the pushbutton pin
boolean buttonState = 0; // initial pushbutton status (unclicked) = LOW = 0 = false

void setup() {
  pinMode(ledPin, OUTPUT); // initialize the LED pin as an output
  pinMode(buttonPin, INPUT); // initialize the pushbutton pin as an input
  Serial.begin(115200);
  Serial.setTimeout(10);
  Serial.println("What is your name?");
}

void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  //check if there's an incoming data/message
  if (Serial.available() > 0 ) {
      //if yes, turn LED on
      digitalWrite(ledPin,HIGH);
      // to read the input data/message
      String userName = Serial.readString();
      // input data to be sent
      Serial.print("your name is: ");
      // print data
      Serial.println(userName);
      delay(10);
      digitalWrite(ledPin, LOW);
      }
  // if the pushbutton is unclicked = LOW
  if (buttonState == LOW) {
    // turn LED off:
    digitalWrite(ledPin, LOW);
  } else {
      // turn LED on
      digitalWrite(ledPin,HIGH);
      }
}

Simulation

Uploaded Codes