Hi,
I’m trying to write an application using WiFi and Pico 2W with this firmware - GitHub - zenodante/PicoCalc-micropython-driver.
I’m having quite a few problems:
wlan.scan() only works on the second or later attempt.
wlan.connect() works very randomly, sometimes it connects on the nth try.
However, none of the operations using WiFi work:
s.connect((“8.8.8.8”, 53))
addr = socket.getaddrinfo(“google.com”, 80, 0, socket.SOCK_STREAM)
nor the attempt to use request/urequest. They mostly cause the program to hang at this line.
I am considering suggestions from the repo.
Working with WIFI on picoW/2W
The wifi chip connect to the rp2040/2350 via spi1, which shared with LCD. As we autorefresh the lcd on core1, it is necessary to stop the auto refresh function first via the function: pc_terminal.stopRefresh(), after wifi finish its work, use pc_terminal.recoverRefresh() to recover the LCD refreshing.
Using Webmite or Picoware, there were no problems with wifi, so I exclude hardware damage. I’ve been struggling with this for several days without success, but I suspect that the issue is the shared SPI and it would need to be fixed in the firmware itself.
Do you have any similar experiences? Has anyone managed to resolve this?
This is a script I was using to debug this issue, and the last successful stop is the WiFi connection, but sometimes it is not even able to connect (that’s why I am calling connect so many times).
"""
wifidebug2 - Debug WiFi by establishing connection AFTER stopping display
Logs all operations to /sd/wifi_debug2.log
"""
import time
import network
import sys
LOG_FILE = "/sd/wifi_debug2.log"
# WiFi credentials
SSID = "wifiname"
PASSWORD = "wifi pass"
class Logger:
def __init__(self, filepath):
self.filepath = filepath
self.f = None
def open(self):
try:
self.f = open(self.filepath, "w")
return True
except Exception as e:
print("Cannot open log file: {}".format(e))
return False
def log(self, msg):
timestamp = time.ticks_ms()
line = "[{:>8}] {}\n".format(timestamp, msg)
if self.f:
self.f.write(line)
self.f.flush()
def close(self):
if self.f:
self.f.close()
self.f = None
def main(args, shell):
"""Debug WiFi - connect after stopping display"""
print("WiFi Debug 2 - logging to {}".format(LOG_FILE))
print("Will connect to {} after stopping display".format(SSID))
print("Please wait...")
logger = Logger(LOG_FILE)
if not logger.open():
return 1
logger.log("=" * 50)
logger.log("WiFi Debug 2 - Connect After Display Stop")
logger.log("SSID: {}".format(SSID))
logger.log("=" * 50)
logger.log("")
import picocalc
try:
# Step 1: Stop display refresh
logger.log("Step 1: Stopping display refresh...")
picocalc.display.stopRefresh()
logger.log(" OK - display refresh stopped")
# Step 2: Wait 2 seconds
logger.log("")
logger.log("Step 2: Waiting 2 seconds for SPI to stabilize...")
time.sleep(2)
logger.log(" Done waiting")
# Step 3: Deactivate WLAN
logger.log("")
logger.log("Step 3: Deactivating WLAN...")
wlan = network.WLAN(network.STA_IF)
logger.log(" Current state: active={}, connected={}".format(
wlan.active(), wlan.isconnected()))
wlan.active(False)
logger.log(" WLAN deactivated")
# Step 4: Wait 2 seconds
logger.log("")
logger.log("Step 4: Waiting 2 seconds...")
time.sleep(2)
logger.log(" Done waiting")
# Step 5: Activate WLAN
logger.log("")
logger.log("Step 5: Activating WLAN...")
wlan.active(True)
logger.log(" WLAN activated")
time.sleep(5)
logger.log(" active={}, connected={}".format(
wlan.active(), wlan.isconnected()))
# Step 6: Connect to WiFi
logger.log("")
logger.log("Step 6: Connecting to {}...".format(SSID))
wlan.connect(SSID, PASSWORD)
time.sleep(2)
if wlan.isconnected():
logger.log(" Connected OK!")
else:
time.sleep(1)
wlan.connect(SSID, PASSWORD)
time.sleep(2)
if wlan.isconnected():
logger.log(" Connected OK!")
else:
time.sleep(1)
wlan.connect(SSID, PASSWORD)
time.sleep(2)
if wlan.isconnected():
logger.log(" Connected OK!")
else:
time.sleep(1)
wlan.connect(SSID, PASSWORD)
time.sleep(2)
if wlan.isconnected():
logger.log(" Connected OK!")
else:
time.sleep(1)
wlan.connect(SSID, PASSWORD)
time.sleep(2)
# Wait for connection
max_wait = 1
for i in range(max_wait):
status = wlan.status()
connected = wlan.isconnected()
logger.log(" [{}/{}] status={}, connected={}".format(
i+1, max_wait, status, connected))
if connected:
logger.log(" SUCCESS - Connected!")
break
if status == 2: # WRONG_PASSWORD
logger.log(" FAILED - Wrong password")
break
elif status == -1 or status == -2:
logger.log(" FAILED - Connection failed")
break
time.sleep(1)
# Step 7: Check final state
logger.log("")
logger.log("Step 7: Final connection state...")
logger.log(" isconnected(): {}".format(wlan.isconnected()))
logger.log(" status(): {}".format(wlan.status()))
if wlan.isconnected():
ifconfig = wlan.ifconfig()
logger.log(" IP: {}".format(ifconfig[0]))
logger.log(" Gateway: {}".format(ifconfig[2]))
logger.log(" DNS: {}".format(ifconfig[3]))
if not wlan.isconnected():
logger.log("")
logger.log("WiFi connection failed - skipping network tests")
raise Exception("WiFi not connected")
# Step 8: Test gateway connectivity
gateway_ip = wlan.ifconfig()[2]
logger.log("")
logger.log("Step 8: Testing gateway connectivity ({})...".format(gateway_ip))
try:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
s.connect((gateway_ip, 80))
logger.log(" Connected to gateway:80 OK!")
s.close()
except Exception as e:
logger.log(" Gateway:80 failed: {}".format(e))
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
s.connect((gateway_ip, 53))
logger.log(" Connected to gateway:53 OK!")
s.close()
except Exception as e2:
logger.log(" Gateway:53 also failed: {}".format(e2))
# Step 9: Test external IP
logger.log("")
logger.log("Step 9: Testing external IP (8.8.8.8:53)...")
try:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
s.connect(("8.8.8.8", 53))
logger.log(" Connected to 8.8.8.8:53 OK!")
s.close()
except Exception as e:
logger.log(" External IP FAILED: {}".format(e))
# Step 10: Test DNS
logger.log("")
logger.log("Step 10: Testing DNS resolution...")
try:
import socket
addr = socket.getaddrinfo("google.com", 80, 0, socket.SOCK_STREAM)
logger.log(" google.com resolved to: {}".format(addr[0][4]))
except Exception as e:
logger.log(" DNS FAILED: {}".format(e))
# Step 11: Test HTTP
logger.log("")
logger.log("Step 11: Testing HTTP (example.com)...")
try:
import socket
addr = socket.getaddrinfo("example.com", 80)[0][4]
s = socket.socket()
s.settimeout(10)
s.connect(addr)
s.send(b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
response = s.recv(100)
s.close()
logger.log(" HTTP OK - received {} bytes".format(len(response)))
logger.log(" Response: {}".format(response[:50]))
except Exception as e:
logger.log(" HTTP FAILED: {}".format(e))
logger.log("")
logger.log("=" * 50)
logger.log("All tests completed!")
logger.log("=" * 50)
except Exception as e:
logger.log("")
logger.log("FATAL ERROR: {}".format(e))
finally:
# Recover display
logger.log("")
logger.log("Recovering display refresh...")
try:
picocalc.display.recoverRefresh()
logger.log(" OK - display recovered")
except Exception as e:
logger.log(" WARNING: {}".format(e))
logger.log("")
logger.log("=" * 50)
logger.log("WiFi Debug 2 Session Ended")
logger.log("=" * 50)
logger.close()
print("")
print("Debug complete. Check log file:")
print(" cat {}".format(LOG_FILE))
return 0
Well, you’re not waiting for it to connect correctly. It may take more than the 2 seconds you’re waiting for, and the for loop you added only tries once.
You should just use a while loop until it’s connected
That’s not the issue. I have other scripts that do it the right way and they are not working either. Connect is random. Very often ends with `CYW43_LINK_JOIN (1) or CYW43_LINK_NOIP (2)
Thanks for sharing, that looks good to my knowledge. I wonder, are you trying to connect to a 5GHz network? and when you run that script, which error/status are you receiving?
I tried connecting to 3 different networks, each of which is 2.4GHz. Other firmware connects to them without any problem.
I wrote earlier about errors with the connection - that is, status 1 or 2 instead of 3.
As for the errors when using the socket, if the timeout is set, I get TCP/HTTP FAILED: [Errno 110] ETIMEDOUT, and if it isn’t, the script hangs indefinitely at that line.
In Picoware, have you implemented any synchronization between the screen and Wi-Fi? Is the screen running in a separate thread, or is everything single-threaded?
In Picoware, you don’t have to stop and start display refresh, if that’s what your concern is. And the system will auto-connect to your WiFi when the device powers on,
This time last year I got into trouble because my wife complained that the lights in the christmas tree stopped working (Pimoroni Plasma RP2040W). It took me some time to remember that I changed the 2.4Ghz access point to channel 13 (legal in my area) and the country code was set correctly. In the end I found that 1) another channel did work and 2) the Pico could connect on channel 13 when the country code is set to “XX”. A few weeks ago I tried install another Plasma and ran into the same problem, after 30 minutes wasted time I remembered what I did originally.
It looks that MicroPython (CircuitPython) on the Pico may have problems with some country codes and the upper WiFi channels . WebMite on the PicoCalc does not show a problem but it does not ask for a country code either.
I love it when I encounter a problem that I feel I’ve had before and solved, but I can’t remember how. By now, I take notes on many things, just as I now comment on code almost excessively, but even so, I have to remember that I took notes in the first place.
At the moment, the only clue is that the UF2 Loader is causing some issues. I built the latest version of clean (without screen or other libs) MicroPython from the sources with a simple script that connects to WiFi, hits an endpoint, and saves the logs of the whole process on the SD card.
Conclusion:
uf2 loaded via UF2 Loader 2.3 - the script does not connect to WiFi
uf2 loaded directly onto the Pico via USB bootsel - success
I’m surprised because other firmware also loads through the uf2 loader and the Wi-Fi works normally with them.
Has anyone had something similar? Is this a bug in the UF2 Loader itself, or does the new version of MicroPython use some kind of illegal operation? Has anyone noticed similar behavior?
Zerodante’s MicroPython has never worked on uf2loader, either.
It’s probably the one linked from Clockwork’s github though, but they rarely update their code and it’s generally a bad idea to run their suggested software unless you’re just trying out the device for the first time. It’s almost always out of date or potentially broken.
There have been lots of other MicroPython ports, but you’ll have to go digging on github and guess which one might be the most stable, since it seems like everyone has just rolled their own and then abandoned it (except for PicoWare, which is still very actively developed). This search is a good start but may not be comprehensive:
I’ve not messed much with MicroPython myself, outside of PicoWare, but at one point I think this one was the most up to date:
This one also seemed promising, but had issues that are listed:
I’m not sure any of these MicroPython ports work with uf2loader though. PicoWare is known to work with the uf2loader.
As I wrote earlier, this is not related to any specific driver for PicoCalc, but to MicroPython itself. I’m wondering whether something like PicoWare, if it were built on the latest version of MicroPython, would still work via the UF2 loader (unless this is handled in some different way there). I don’t want to rely on any existing system as I am creating my own.