6. Embedded programming




Group assignment



This week's group assignment was to consult the datasheet of the microcontroller we used in week 4. In my case I used the Xiao RP2040. We compared the performance and workflow of this microcontroller and others. You can consult the group page in the following link.


Microcontroller: Seeed Xiao-Rp2040




The Xiao RP2040 is a compact and powerful microcontroller designed for electronics projects and IoT applications that require a small form factor and efficient processing capabilities. Equipped with a dual-core ARM Cortex M0+ processor that can run at up to 133 MHz, it offers an optimal combination of power efficiency and processing performance.
This microcontroller is highlighted by its on-board memory, with 264KB of SRAM and 2MB of Flash memory, providing ample space for complex program execution and data storage. One of the key features of the Xiao RP2040 is its flexible compatibility; it supports a variety of programming platforms, including Micropython, Arduino and CircuitPython, making it accessible.

Features

  • Powerful MCU: Dual-core ARM Cortex M0+ processor, flexible clock running up to 133 MHz
  • Rich on-chip resources: 264KB of SRAM, and 2MB of on-board Flash memory
  • Flexible compatibility: Support Micropython/Arduino/CircuitPython
  • Easy project operation: Breadboard-friendly & SMD design, no components on the back
  • Small size: As small as a thumb(20x17.5mm) for wearable devices and small projects.
  • Multiple interfaces: 11 digital pins, 4 analog pins, 11 PWM Pins, 1 I2C interface, 1 UART interface, 1 SPI interface, 1 SWD Bonding pad interface.

Specification

Item Value
CPU Dual-core ARM Cortex M0+ processor up to 133MHz
Flash Memory 2MB
SRAM 264KB
Digital I/O Pins 11
Analog I/O Pins 4
PWM Pins 11
I2C interface 1
SPI interface 1
UART interface 1
Power supply and downloading interface Type-C
Power 3.3V/5V DC
Dimensions 20x17.5x3.5mm

Hardware Overview


To know which pins to use when I was programming I had to check the microcontroller documentation. In the documentation I found an image that showed me all the hardware of the microcontroller and this helped me.

How to connect the board to my computer?



The steps to follow to connect the microcontroller to the computer are:

  1. Connect a type C cable to the Xiao.
  2. Long press button "B".
  3. Connect the other side of the cable to the computer.
  4. Finally, it will show a disk driver.

If all goes well, you will get the following on your computer:


Depending on which program we use (Arduino IDE or CircuitPython) we will make some modifications.

For Arduino IDE you have to select File > Preferences, and fill in additional URLs of the Board Manager with the url below:

https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json


Finally, select the option Select board and search the name of the board.


For CircuitPython we will have to download a file to install CircuitPython on the board. At the end we will see the following:


To finish with the configuration, we will install the libraries to use the neopixel included with the Xiao-RP2040.



Arduino IDE



Arduino IDE uses mainly a C/C++ based programming language, with some specific libraries and functions provided by Arduino to simplify the development of projects on Arduino boards. This language is based on the fundamental principles of C/C++ and is tailored to interface with components and peripherals typically used in electronics and robotics projects.

Installing Arduino IDE

To install Arduino IDE it is necessary to go to the official software page for installation. You can consult the page here.

After downloading the software, the next step is to install the program on your computer. The installation process is very simple.


When finished, the following screen will appear:


Code: Lighting sequences



For Arduino, I made a program with different patterns using the leds (including the rgb led). I only made one program because I'm not used to work with C++ syntax. I usually use more Python.

For this program, I used all the LEDs I have on my board, both the Xiao-RP2040 LEDs and the other three LEDs I soldered. The sequences are changing with the button I have on the board. The first sequence is a fast sequence, all the leds turn on quickly. The second sequence is slow. The third sequence increases the speed a little bit. The fourth sequence changes the direction. The fifth sequence turns on all the LEDs together quickly. Finally, it turns off.

Here is my code:


						#include <Adafruit_NeoPixel.h>
						#define NUM_PIXELS 1 // Number of NeoPixel LEDs
						#define PIN 12 // Pin connected to the NeoPixel
						#define POWER 11 // Pin controlling power to the NeoPixel
						#define BUTTON_PIN D1 // Pin connected to the button
					
						Adafruit_NeoPixel pixels(NUM_PIXELS, PIN, NEO_GRB + NEO_KHZ800);
					
						// Array containing the pins for the non-NeoPixel LEDs
						const int ledPins[] ={25, 26, D6, D7};
						// Ensure this matches the number of elements in ledPins
						const int numLeds = 4;
						int buttonState;
						int lastButtonState = LOW;
						int currentSequence = 0; // Tracks the current sequence to be displayed
					
						void setup(){
								pinMode (POWER, OUTPUT);
								digitalWrite (POWER, HIGH); // Activates power to the NeoPixel
						
								pixels.begin(); // Initializes the NeoPixel LED
					
								for (int i = 0; i < numLeds; i++) {
									pinMode(ledPins[i], OUTPUT); // Sets each LED pin as an output
								}
								pinMode(BUTTON_PIN, INPUT); // Sets the button pin as an input
						}
						
					
						void loop() {
							buttonState = digitalRead(BUTTON_PIN); // Reads the current state of the button
					
							// Detects a button press (rising edge)
							if (buttonState == HIGH && lastButtonState == LOW) {
								delay(50); // Debounce to prevent reading the button press multiple times
								currentSequence = (currentSequence + 1) % 7; // Cycles through 7 sequences
								// Wait for button release to avoid multiple increments
								while(digitalRead(BUTTON_PIN) == HIGH) {
									delay (10);
								}
							}
							
							lastButtonState = buttonState; // Updates the last button state for the next loop iteration
					
							// Executes the current lighting sequence based on the value of currentSequence
							switch (currentSequence) {
								case 1: fastSequence(); break;
								case 2: slowSequence(); break;
								case 3: sequence1(); break;
								case 4: sequence2(); break;
								case 5: simultaneousBlink(); break;
								case 6: zigzag(); break;
								case 7: turnOff(); break;
							}
						}
					
						// Fast Sequence
						void fastSequence() {
							for(int i = 0; i < numLeds; i++) {
								digitalWrite(ledPins[i], HIGH); // Turns on the LED
								delay(100); // Short wait for a quick sequence
								digitalWrite(ledPins[i], LOW); // Turns off the LED
							}
							pixels.setPixelColor(0, pixels.Color(193, 72, 72)); // Sets the NeoPixel to a fast green color
							pixels.show();
							delay(100); // Keeps the color for a short time
							pixels.clear(); // Turns off the NeoPixel
							pixels.show();
						}
					
						// Slow Sequence
						void slowSequence() {
							for(int i = 0; i < numLeds; i++) {
								digitalWrite(ledPins[i], HIGH); // Turns on the LED
								delay(500); // Long wait for a slow sequence
								digitalWrite(ledPins[i], LOW); // Turns off the LED
							}
							pixels.setPixelColor(0, pixels.Color(214, 226, 36)); // Sets the NeoPixel to a slow blue color
							pixels.show();
							delay(500); // Keeps the color for a long time
							pixels.clear(); // Turns off the NeoPixel
							pixels.show();
						}
					
						// Sequence 1
						void sequence1() {
							for(int i = 0; i <= numLeds; i++) {
								if (i < numLeds) {
									digitalWrite(ledPins[i], HIGH); // Turns on each non-NeoPixel LED
								} else {
									pixels.setPixelColor(0, pixels.Color(61, 189, 16)); // Sets NeoPixel LED to green
									pixels.show(); // Updates NeoPixel to display the color
								}
								delay(250); // Waits 250 milliseconds
								if (i < numLeds) {
									digitalWrite(ledPins[i], LOW); // Turns off each non-NeoPixel LED
								} else {
									pixels.clear(); // Clears the NeoPixel LED (turns off)
									pixels.show(); // Updates NeoPixel
								}
							}
						}
								
						// Sequence 2
						void sequence2() {
							for(int i = numLeds; i >= 0; i--) {
								if (i < numLeds) {
									digitalWrite(ledPins[i], HIGH); // Turns on each non-NeoPixel LED in reverse order
								} else {
									pixels.setPixelColor(0, pixels.Color(27, 226, 232)); // Sets NeoPixel LED to blue
									pixels.show(); // Updates NeoPixel to display the color
								}
								delay(250); // Waits 250 milliseconds
								if (i < numLeds) {
									digitalWrite(ledPins[i], LOW); // Turns off each non-NeoPixel LED
								} else {
									pixels.clear(); // Clears the NeoPixel LED (turns off)
									pixels.show(); // Updates NeoPixel
								}
							}
						}

					
						// Simultaneous Blink
						void simultaneousBlink() {
							for (int i = 0; i < 5; i++) {
								for (int pin : ledPins) {
									digitalWrite(pin, HIGH);
								}
								pixels.fill(pixels.Color(27, 86, 232)); // Sets to a yellow color
								pixels.show();
								delay(200);
								for (int pin : ledPins) {
									digitalWrite(pin, LOW);
								}
								pixels.clear();
								pixels.show();
								delay(200);
							}
						}
					
						// Zigzag
						void zigzag() {
							for (int i = 0; i < numLeds; i+=2) {
								digitalWrite(ledPins[i], HIGH);
								if (i+1 < numLeds) digitalWrite(ledPins[i+1], LOW);
							}
							delay(250);
							for (int i = 0; i < numLeds; i+=2) {
								digitalWrite(ledPins[i], LOW);
								if (i+1 < numLeds) digitalWrite(ledPins[i+1], HIGH);
							}
							delay(250);
						}
					
						// Turn Off
						void turnOff() {
							for (int i = 0; i < numLeds; i++) {
								digitalWrite(ledPins[i], LOW);
							}
					
							pixels.clear(); // Sets all NeoPixel LEDs to off (black)
							pixels.show(); // Updates the NeoPixel to display the change
						}
					

Result:





CircuitPython



To program in Python install MU editor in the following link.

After downloading it, we select CircuitPython at the end of the installation, as shown in the image:


Code: 4-bit counter



Python is a language I use more frequently as opposed to C++. So I know more of its syntax and I don't find it difficult to program in this language. The code I made is a 4-bit counter. To make it I used the three leds I soldered and the rgb led. As first value I take the neopixel (or rgb) led. Then I used the other three leds. Each time I press the button, the leds light up and go from 0 to 15. The following image is a support to test the code on the board.


Here is my code:


						import board
						import digitalio
						import time
						import neopixel
					
						# Pin configuration
						BUTTON_PIN = board.D1  
						LEDS_PINS = [board.D7, board.D6, board.D0]  
						NUM_PIXELS = 1
						PIXEL_PIN = board.NEOPIXEL  
					
						# Button initialization
						button = digitalio.DigitalInOut(BUTTON_PIN)
						button.direction = digitalio.Direction.INPUT
						button.pull = digitalio.Pull.DOWN
					
						# Regular LEDs initialization
						leds = [digitalio.DigitalInOut(pin for pin in LEDS_PINS]
						for led in leds:
							led.direction = digitalio.Direction.OUTPUT
					
						# NeoPixel initialization
						pixels = neopixel.NeoPixel(PIXEL_PIN, NUM_PIXELS, brightness=0.5)
					
						# Counter and button state initialization
						counter = 0
						button_state = False
					
						def decimal_to_binary(n, size):
							binary_list = []
							while n > 0:
								remainder = n % 2
								binary_list.append(remainder)
								n //= 2
							while len(binary_list) < size:
								binary_list.append(0=
							binary_list.reverse()  # Reverse the list to have it in the correct order
							return binary_list
					
						def Combinations(n):
							combinations = []
							for i in range(2 ** n):
								list = decimal_to_binary(i, n)
								combinations.append(list)
							return combinations
					
						def update_leds(combination):
							# Update regular LEDs based on the first three bits
							for i, led in enumerate(leds):
								led.value = combination[i]
							# Update the NeoPixel based on the fourth bit
							if combination[3]:
								pixels.fill((255, 0, 0))  # Turned on, red
							else:
								pixels.fill((0, 0, 0))  # Turned on, red

						# Get all combinations for 4 bits (3 regular LEDs + 1 NeoPixel)
						combinations = Combinations(4)/span>
					
						while True:
							# Detect button press 
							if button.value and not button_state:
								button_state = True
								update_leds(combinations[counter])
								counter = (counter + 1) % len(combinations)  # Increment the counter and loop it within the range
							elif not button.value and button_state:
								button_state = False  # Reset the button state when released
							time.sleep(0.01)
					

Result:




Code: Lighting sequences



The following code does the same as the code I did in Arduino IDE. I did it to make a comparison between both languages using the same code.


						import board
						import digitalio
						import time
						import neopixel
					
						# Pin configuration
						NUM_PIXELS = 1
						PIXEL_PIN = board.NEOPIXEL  
						BUTTON_PIN = board.D1  
						led_pins = [board.D0, board.D6, board.D7]  
						numLeds = len(led_pins)
					
						# Setup
						pixels = neopixel.NeoPixel(PIXEL_PIN, NUM_PIXELS, brightness=0.5, auto_write=True)
						button = digitalio.DigitalInOut(BUTTON_PIN)
						button.direction = digitalio.Direction.INPUT
						button.pull = digitalio.Pull.DOWN  
						leds = [digitalio.DigitalInOut(pin) for pin in led_pins]
						for led in leds:
							led.direction = digitalio.Direction.OUTPUT
					
						current_sequence = 0
						last_button_state = button.value
					
						# Fast sequence
						def fast_sequence():
							button_was_pressed = False
							while not button_was_pressed:
								for led in leds:
									led.value = True
									time.sleep(0.1)
									led.value = False
									# Check if button state changed
									if button.value != last_button_state:
										button_was_pressed = True
										break
									
									# Light up NeoPixel with red color, then turn off
									pixels.fill((193, 72, 72))
									pixels.show()
									time.sleep(0.1)
									pixels.fill((0, 0, 0))
									pixels.show()
									if button.value != last_button_state:
										break
							
						# Slow sequence
						def slow_sequence():
							for led in leds:
								led.value = True
								time.sleep(0.5)
								led.value = False
								
							# Light up NeoPixel with yellow color, then turn off
							pixels.fill((214, 226, 36))
							pixels.show()
							time.sleep(0.5)
							pixels.fill((0, 0, 0))
							pixels.show()
					
						# Sequence 1
						def sequence1():
							for i in range(numLeds + 1):
								if i < numLeds:
									leds[i].value = True
								else:
									# Light up NeoPixel with green color
									pixels.fill((61, 189, 16))  # Green
									pixels.show()
								time.sleep(0.25)
								if i < numLeds:
									leds[i].value = False
								else:
									pixels.fill((0, 0, 0))
									pixels.show()
					
						# Sequence 2
						def sequence2():
							for i in range(numLeds, -1, -1):
								if i < numLeds:
									leds[i].value = True
								else:
									# Light up NeoPixel with blue color
									pixels.fill((27, 226, 232))  # Blue
									pixels.show()
								time.sleep(0.25)
								if i < numLeds:
									leds[i].value = False
								else:
									pixels.fill((0, 0, 0))
									pixels.show()
					
						# Simultaneous blink
						def simultaneous_blink():
							for _ in range(5):
								for led in leds:
									led.value = True
								pixels.fill((27, 86, 232))  # Yellow
								pixels.show()
								time.sleep(0.2)
								for led in leds:
									led.value = False
								pixels.fill((0, 0, 0))
								pixels.show()
								time.sleep(0.2)
					
						# Turn off
						def turn_off():
							for led in leds:
								led.value = False
							pixels.fill((0, 0, 0))
							pixels.show()
					
						while True:
							button_state = button.value
							# Check for button press and update sequence
							if button_state != last_button_state and button_state:
								current_sequence += 1
								if current_sequence > 6:
									current_sequence = 0
								time.sleep(0.1)
							last_button_state = button_state
					
							# Execute the sequence based on current_sequence value
							if current_sequence == 0:
								fast_sequence()
							elif current_sequence == 1:
								slow_sequence()
							elif current_sequence == 2:
								sequence1()
							elif current_sequence == 3:
								sequence2()
							elif current_sequence == 4:
								simultaneous_blink()
							elif current_sequence == 5:
								turn_off()
					
							time.sleep(0.01)
					

At the end, I wrote down the advantages and disadvantages of each language:

Advantages of Arduino IDE

  • Wide compatibility: Arduino IDE is compatible with a wide range of Arduino boards.
  • Performance: By programming in C/C++, Arduino IDE can offer superior performance in terms of speed and resource efficiency.
  • Low-level control: It provides more fine-grained control over the hardware, which is useful for projects that need hardware-level optimizations.

Disadvantages or Arduino IDE

  • Learning curve: It can be more difficult to learn compared to Python.
  • Slower development: Writing and debugging in C/C++ can take longer than in higher-level languages such as Python.

Advantages of CircuitPython

  • Easy to learn: Python is known for its clear and simple syntax, making CircuitPython an excellent choice for beginners.
  • Rapid development: Python makes it easy to write code more quickly, which speeds up the development of prototypes and projects.
  • Interactivity: CircuitPython supports real-time code editing, allowing developers to modify and test their code directly on the device without the need for recompilations.
  • Libraries: You have access to a growing library of modules and software that can simplify development.

Disadvantages or CircuitPython

  • Performance: CircuitPython can be slower than C/C++ because it is an interpreted language.
  • Resource usage: It may require more system resources, such as memory, which can be a problem on resource-constrained devices.

The conclusion I reached was the following: For someone not so familiar with programming your best option is to use Python for programming because of its ease of use. However, if you need performance and control for a more complex project Arduino IDE might be more suitable.