Skip to content

Week 14 Adam & David

UART Communication

Wiring - David

First, we connected to RP2040 Pico XIAO microcontrollers together using the RX and TX pins together and sent a messsage (hello) from one pico to the other. Then, the other pico tests using a while loop to see if the message is received. The code in Thonny (MicroPython is displayed below).

We also connected the ground of the XIAO to the ground of the other board.

This is the example wiring for reference:

Wiring

Finding Libraries - David

In order to find the libraries for the code, we used these libraries from GitHub.

Sender Code Modifications - David

It is important to note that there are 2 sets of code in the UART connection that we are testing. The follow is the sender code modifications.

from easy_comms import Easy_comms
from time import sleep

com1 = Easy_comms(uart_id=0, baud_rate=9600)
# com1.start()

count = 0
while True:
    # send a message
    com1.send(f'hello, {count}')

    #check for messages
    # message = com1.read()

    #if message is not None:
     #   print(f"message received: {message.strip('\n')}")
    sleep(1)
    count +=1

After the first couple of connections did not work, I noticed that in the setup, the com1.start() command might be interfering with the communication process. If you look in the library of Easy Comms in the code provided by Adam, you can see that the .start() command prints out “ahoy” and sends the message to the other board.

However, in the while loop, it is sending hello. Therefore, I thought that “ahoy” might be interfering with the hello send loop.

In the while loop, I noticed that the code is asking for the board to check for incoming messages and also sending messages:

 check for messages
    message = com1.read()

    if message is not None:
        print(f"message received: {message.strip('\n')}")

For this reason, I decided to comment this section out, because it was potentially blocking the while loop from continuing and sending “hello”.

Reciever Code Modifications - Adam

I modified the reciever code from the library to the following (with the help of this forum).

from easy_comms import Easy_comms
from time import sleep

com1 = Easy_comms(uart_id=0, baud_rate=9600)
com1.start()

while True:
    message = ""
    message = com1.read()

    if message is not None:
        print(f"message received: {message.strip('\n')}")
    sleep(1)

I also saved this on the pico as easy_comms.py.

from machine import UART, Pin
from time import time_ns

class Easy_comms:

    uart_id = 0
    baud_rate = 9600
    timeout = 1000 # milliseconds

    def __init__(self, uart_id:int, baud_rate:int=None):
        self.uart_id = uart_id
        if baud_rate: self.baud_rate = baud_rate

        # set the baud rate
        self.uart = UART(self.uart_id,self.baud_rate)

        # Initialise the UART serial port
        self.uart.init()

    def send(self, message:str):
        print(f'sending message: {message}')
        message = message + '\n'
        self.uart.write(bytes(message,'utf-8'))

    def start(self):
        message = "ahoy\n"
        print(message)
        self.send(message)

    def read(self)->str:
        start_time = time_ns()
        current_time = start_time
        new_line = False
        message = ""
        while (not new_line) or (current_time <= (start_time + self.timeout)):
            if (self.uart.any() > 0):
                message = message + self.uart.read().decode('utf-8')
                if '\n' in message:
                    new_line = True
                    message = message.strip('\n')
                    # print(f'received message: {message}')
                    return message
            else:
                pass
                #print("No message recieved")
        #else:
        #    return None

Board Design - David

The board design is made with KiCAD, the eeschema schematic design is as follows: Eeschema

The PCB new design is rendered as such:

PCB new

Original Design (Ripped Traces) - David

After I plotted the design in KiCAD and loaded the files into Bantam, I realized that the traces were too thin, they were also at 0.25mm.

Milling took several tries as I failed to do all the steps correctly. The first time, the Othermill machine did not work because the bit did not spin. So, I switched to another machine. When I had everything setup, using the Othermill workflow, I realized that the bit went straight down into the copper board:

Milling error

Fellow student Adam Durrett explained to me that I did not set the height correctly inside the bantam software. Apparently, I forgot to go to BitBraker and lower the bit on to the board, when it does so, it sends out a signal to the software, alerting it has made contact with the board. Then, the software would calculate the height of the stock. This is a basic feature that I forgot to do, and you can see the full workflow here.

Design Corrections - David

When I milled it correctly, I found out that the traces were ripped because of how thin they were. Adam Durrent told me that I could actually change the width of the traces in KiCAD:

Thicker traces

Final Mill - David

After making the changes in KiCAD, this is the render in Bantam:

Bantam render

And, I finally had a good board:

Final board

Final Solder

I soldered female jumper connectors on to the traces due to the fact that I didn’t want to waste unnecessary Xiaos, since we were low on supply:

Plugins

Testing Board - Adam & David

After making sure that the plugins were secure, we plugged in the Xiaos (the ones with the code on them) on milled board:

Plugins plugged in

We plugged in the soldered board and it worked first try!

Wireless (Wi-Fi)

Programming - Adam

I used this website and this website to help me with the programming.

To make sure the hotspot was available I ran this. It turned out that, for some reason, only David’s hotspot worked. We also learned you have to turn on Maximize Compatibility in the hotspot settings for the Pico to be able to connect to the hotspot of Apple iPhones.

wifi_scan.py

import network
import time

# Initialize Wi-Fi in station mode
wlan = network.WLAN(network.STA_IF)
wlan.active(True)

# Scan for available Wi-Fi networks
print("Scanning for Wi-Fi networks...")
networks = wlan.scan()

# Print the SSIDs of the detected networks
print("Available Wi-Fi networks:")
for network in networks:
    ssid = network[0].decode('utf-8')
    print(ssid)

# Deactivate Wi-Fi after scanning
wlan.active(False)

I then made this. The SSID is visible as the network name in the hotspot settings on the iPhone.

secret.py

ssid = **MY HOTSPOT NAME**
password = **MY HOTSPOT PASSWORD**

Then, ChatGPT wrote this code, which failed to connect.

server.py (just trying to connect - written by ChatGPT)

import network
import socket
import time
from secret import ssid, password

wlan = network.WLAN(network.STA_IF)
wlan.active(True)

wlan.connect(ssid, password)

max_wait = 10
while not wlan.isconnected() and max_wait > 0:
    max_wait -= 1
    print('waiting for connection...')
    time.sleep(1)

if not wlan.isconnected():
    print('network connection failed')
    print('Wi-Fi status:', wlan.status())
    print('Wi-Fi config:', wlan.ifconfig())
else:
    print('connected')
    status = wlan.ifconfig()
    print('ip = ' + status[0])

Finally, this code worked!

server.py (from tutorial - worked!)

# Webserver to send RGB data
# Tony Goodhew 5 July 2022
import network
import socket
import time
from machine import Pin, ADC
from secret import ssid,password
import random
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

# Wait for connect or fail
max_wait = 10
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1
    print('waiting for connection...')
    time.sleep(1)

# Handle connection error
if wlan.status() != 3:
    raise RuntimeError('network connection failed')
else:
    print('connected')
    status = wlan.ifconfig()
    print( 'ip = ' + status[0] )

# Open socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

s = socket.socket()
s.bind(addr)
s.listen(1)

print('listening on', addr)

# Listen for connections
while True:
    try:
        cl, addr = s.accept()
        print('client connected from', addr)
        request = cl.recv(1024)
        print(request)
        # Do not unpack request
        # We reply to any request the same way
        # Generate 3 values to send back
        r = random.randint(0,255)
        g = random.randint(0,255)
        b = random.randint(0,255)
        # Join to make a simple string with commas as separators
        rgb = str(r) + "," + str(g) + ","+str(b)

        response = rgb # This is what we send in reply

        cl.send(response)
        print("Sent:" + rgb)
        cl.close()

    except OSError as e:
        cl.close()
        print('connection closed')

But when I ran this on the other pico…

client.py

# Program to read RGB values from a local Pico Web Server
# Tony Goodhew 5th July 2022
# Connect to network
import network
import time
from secret import ssid, password
import socket

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
while not wlan.isconnected() and wlan.status() >= 0:
    print("Waiting to connect:")
    time.sleep(1)

# Should be connected and have an IP address
wlan.status() # 3 == success
wlan.ifconfig()
print(wlan.ifconfig())

while True:
    ai = socket.getaddrinfo("172.20.10.6", 80) # Address of Web Server
    addr = ai[0][-1]

    # Create a socket and make a HTTP request
    s = socket.socket() # Open socket
    s.connect(addr)
    s.send(b"GET Data") # Send request
    ss=str(s.recv(512)) # Store reply
    # Print what we received
    print(ss)
    # Split into RGB components
    l = len(ss)
    ss = ss[2:l-1]     # Strip to essentials  
    p = ss.find(",")   # Find first comma
    r = int(ss[0:p])   # Extract RED value
    ss = ss[p+1:]      # Remove red part
    p = ss.find(",")   # Find comma separator
    g = int(ss[0:p])   # Extract GREEN value
    b = int(ss[p+1:])  # Extract BLUE value
    print(r,g,b)       # Print RGB values
    print()
    # Set RGB LED here
    s.close()          # Close socket
    time.sleep(0.2)    # wait

I got this error.

Waiting to connect:
('0.0.0.0', '255.255.255.0', '192.168.0.1', '8.8.8.8')
Traceback (most recent call last):
  File "<stdin>", line 27, in <module>
OSError: [Errno 113] EHOSTUNREACH

After restarting the pico by unplugging and replugging it in, then also restarting the hotspot, this connection worked and data was transmitted!

For the working video, see Adam’s site here.


Last update: June 7, 2023