Reputation: 33
I'm trying to achieve 2-way communication over USB (COM port) between Raspberry Pi Pico and Windows PC (Python). I'm unable to send from my PC to Raspberry Pi Pico nor the way back. Doesn't affect the LEDs on breadboard, nor messages get printed in terminal.
Code for PC:
import serial
import time
# open a serial connection
s = serial.Serial("COM7", 115200)
print(s)
# blink the led
while True:
s.write(b"on\n")
time.sleep(1)
s.readline().strip()
s.write(b"off\n")
time.sleep(1)
s.readline().strip()
Code on Raspberry Pi Pico:
import time
from machine import Pin
import sys
led = Pin(0, machine.Pin.OUT)
led2 = Pin(2, machine.Pin.OUT)
led2.value(0)
led.value(0)
def led_on():
led.value(1)
def led_off():
led.value(0)
while True:
# read a command from the host
v = sys.stdin.readline().strip()
# perform the requested action
if v.lower() == "on":
led_on()
print("Turned on!")
elif v.lower() == "off":
led_off()
print("Turned off!")
What's the smartest way to debug code on the Raspberry Pi Pico? After acquiring the serial connection, standard print debug? Is there any way to use the sequence debugger in Thonny IDE?
I've tried methods from both serial and stdlib libraries without result. For PC I'm using PyCharm, for Raspberry Pi Pico Thonny. After flashing Raspberry Pi Pico I'm disconnecting the serial and run the script in PyCharm with different interpreter.
Upvotes: 2
Views: 18258
Reputation: 403
Easiest Solution
Serial communication is purely bi-directional. There cannot be more than 2 devices on a given serial port. In Thonny (and micropython) this is dedicated to loading code. You cannot directly write to the serial port from your computer when a program is running. When a program isn't running on the pico, however, you have access to REPL. You can read a little more about it here. This allows you to call functions directly on the pico. So you could write a program such as this:
from machine import pin
led = Pin(0, machine.Pin.OUT)
led2 = Pin(2, machine.Pin.OUT)
led2.value(0)
led.value(0)
def led_on():
led.value(1)
def led_off():
led.value(0)
and call it from REPL by sending
>>> led_on()
This is far and away the easiest solution and also gives you access to any function within microPython which may be useful for debugging as you can just print whatever value you want.
More Robust Solution
Code above isn't wrong. It just will not work with Thonny since Thonny has taken over the serial port. If you upload your code as a .u2f file or use a separate debugger (such as a pi or a second pico as a picoprobe) using one of the UART peripherals then you could use the USB port as a serial connection. There is a thread over on the raspberry pi forms where functional 2-way serial code is shown. Similarly, this tutorial walks you through doing it in a background-thread.
Upvotes: 0
Reputation: 1
you can use Pico's dual core , create a thread to listen the COM. Look this page to give you a solution( https://forums.raspberrypi.com//viewtopic.php?t=302889 ). Upload a main.py to Pico and release the COM serial (usually COM3 , you can also use PC python to query). Connect Pico MicroUSB , main.py in Pico will run . Then you can use PC python to operate COM to send data.
''' main.py in Pico
#coming from https://forums.raspberrypi.com//viewtopic.php?t=302889
from sys import stdin, exit
from _thread import start_new_thread
from utime import sleep
#
# global variables to share between both threads/processors
#
bufferSize = 1024 # size of circular buffer to allocate
buffer = [' '] * bufferSize # circular incoming USB serial data buffer (pre fill)
bufferEcho = True # USB serial port echo incoming characters (True/False)
bufferNextIn, bufferNextOut = 0,0 # pointers to next in/out character in circualr buffer
terminateThread = False # tell 'bufferSTDIN' function to terminate (True/False)
#
# bufferSTDIN() function to execute in parallel on second Pico RD2040 thread/processor
#
def bufferSTDIN():
global buffer, bufferSize, bufferEcho, bufferNextIn, terminateThread
while True: # endless loop
if terminateThread: # if requested by main thread ...
break # ... exit loop
buffer[bufferNextIn] = stdin.read(1) # wait for/store next byte from USB serial
if bufferEcho: # if echo is True ...
print(buffer[bufferNextIn], end='') # ... output byte to USB serial
bufferNextIn += 1 # bump pointer
if bufferNextIn == bufferSize: # ... and wrap, if necessary
bufferNextIn = 0
#
# instantiate second 'background' thread on RD2040 dual processor to monitor and buffer
# incoming data from 'stdin' over USB serial port using ‘bufferSTDIN‘ function (above)
#
bufferSTDINthread = start_new_thread(bufferSTDIN, ())
#
# function to check if a byte is available in the buffer and if so, return it
#
def getByteBuffer():
global buffer, bufferSize, bufferNextOut, bufferNextIn
if bufferNextOut == bufferNextIn: # if no unclaimed byte in buffer ...
return '' # ... return a null string
n = bufferNextOut # save current pointer
bufferNextOut += 1 # bump pointer
if bufferNextOut == bufferSize: # ... wrap, if necessary
bufferNextOut = 0
return (buffer[n]) # return byte from buffer
#
# function to check if a line is available in the buffer and if so return it
# otherwise return a null string
#
# NOTE 1: a line is one or more bytes with the last byte being LF (\x0a)
# 2: a line containing only a single LF byte will also return a null string
#
def getLineBuffer():
global buffer, bufferSize, bufferNextOut, bufferNextIn
if bufferNextOut == bufferNextIn: # if no unclaimed byte in buffer ...
return '' # ... RETURN a null string
n = bufferNextOut # search for a LF in unclaimed bytes
while n != bufferNextIn:
if buffer[n] == '\x0a': # if a LF found ...
break # ... exit loop ('n' pointing to LF)
n += 1 # bump pointer
if n == bufferSize: # ... wrap, if necessary
n = 0
if (n == bufferNextIn): # if no LF found ...
return '' # ... RETURN a null string
line = '' # LF found in unclaimed bytes at pointer 'n'
n += 1 # bump pointer past LF
if n == bufferSize: # ... wrap, if necessary
n = 0
while bufferNextOut != n: # BUILD line to RETURN until LF pointer 'n' hit
if buffer[bufferNextOut] == '\x0d': # if byte is CR
bufferNextOut += 1 # bump pointer
if bufferNextOut == bufferSize: # ... wrap, if necessary
bufferNextOut = 0
continue # ignore (strip) any CR (\x0d) bytes
if buffer[bufferNextOut] == '\x0a': # if current byte is LF ...
bufferNextOut += 1 # bump pointer
if bufferNextOut == bufferSize: # ... wrap, if necessary
bufferNextOut = 0
break # and exit loop, ignoring (i.e. strip) LF byte
line = line + buffer[bufferNextOut] # add byte to line
bufferNextOut += 1 # bump pointer
if bufferNextOut == bufferSize: # wrap, if necessary
bufferNextOut = 0
return line # RETURN unclaimed line of input
#
# main program begins here ...
#
# set 'inputOption' to either one byte ‘BYTE’ OR one line ‘LINE’ at a time. Remember, ‘bufferEcho’
# determines if the background buffering function ‘bufferSTDIN’ should automatically echo each
# byte it receives from the USB serial port or not (useful when operating in line mode when the
# host computer is running a serial terminal program)
#
# start this MicroPython code running (exit Thonny with code still running) and then start a
# serial terminal program (e.g. putty, minicom or screen) on the host computer and connect
# to the Raspberry Pi Pico ...
#
# ... start typing text and hit return.
#
# NOTE: use Ctrl-C, Ctrl-C, Ctrl-D then Ctrl-B on in the host computer terminal program
# to terminate the MicroPython code running on the Pico
#
try:
inputOption = 'LINE' # get input from buffer one BYTE or LINE at a time
while True:
if inputOption == 'BYTE': # NON-BLOCKING input one byte at a time
buffCh = getByteBuffer() # get a byte if it is available?
if buffCh: # if there is...
print (buffCh, end='') # ...print it out to the USB serial port
elif inputOption == 'LINE': # NON-BLOCKING input one line at a time (ending LF)
buffLine = getLineBuffer() # get a line if it is available?
if buffLine: # if there is...
print (buffLine) # ...print it out to the USB serial port
sleep(0.1)
except KeyboardInterrupt: # trap Ctrl-C input
terminateThread = True # signal second 'background' thread to terminate
exit()
'''
Upvotes: -1