Sunday, May 30, 2021

Raspberry Pi Pico/MicroPython: uasyncio

Raspberry Pi Pico MicroPython exercise of using uasyncio:

"""
MicroPython uasyncio exercise on RP2040
"""
from sys import implementation
from os import uname
import uasyncio as asyncio
from machine import Pin
import utime

led = Pin(25, Pin.OUT)

print(implementation.name)
print(uname()[3])
print(uname()[4])
print()
print(asyncio.__name__)
print(asyncio.__version__)

#Toggle onboard LED every 500ms
async def asyncTask1():
    while True:
        led.toggle()
        await asyncio.sleep_ms(500)

#print time every 1 second
async def asyncTask2():
    while True:
        print(utime.time())
        await asyncio.sleep_ms(1000)
        
loop = asyncio.get_event_loop()
loop.create_task(asyncTask1())
loop.create_task(asyncTask2())
loop.run_forever()

print("- bye -")




~ More exercise on Raspberry Pi Pico

Raspberry Pi Pico: restore factory Flash memory

For any reasons, you want to restore your Raspberry Pi Pico to factory flash memory:
you can visit Raspberry Pi RP2040 Getting Started Guide > About Raspberry Pi Pico tab, scroll down to Resetting Flash memory section to download the flash_nuke.uf2. And flash it on your Pico.



Saturday, May 29, 2021

RPi Pico BOOTSEL button broken! How to enter BOOTLOADER mode using Python code; without BOOTSEL button and un-plug/re-plug USB.


The BOOTSEL button on my Raspberry Pi Pico broken! Here is how to reset Pico and enter BOOTLOADER mode using Python (MicroPython/CircuitPython) code; such that no need touch BOOTSEL button and un-plug/re-plug USB.
 

In case the Raspberry Pi Pico is flashed MicroPython:

import machine
machine.bootloader()

In case of CircuitPython:

import microcontroller
microcontroller.on_next_reset(microcontroller.RunMode.BOOTLOADER)
microcontroller.reset()


Sunday, May 16, 2021

Raspberry Pi Pico/CircuitPython + ESP32/adafruit nina-fw (act as WiFi/BLE Co-Processor)

adafruit nina-fw is a slight variant of the Arduino WiFiNINA core. ESP32 with nina-fw flashed, can be used as WiFi/BLE Co-Processor. This post show how to connected ESP32 to Raspberry Pi Pico, flash ESP32 firmware using Pico, and test WiFi/BLE with Pico/CircuitPython; on Raspberry Pi.

The ESP32 used here is a ESP32-S breadout board, flash with current latest version NINA_W102-1.7.3.bin.

Connection:

	ESP32	RPi Pico
	-----	--------
3.3V	3.3V	3.3V
GND	GND	GND
SCK	IO18	GP10
MISO	IO23	GP12
MOSI	IO14	GP11
CS	IO5	GP13
BUSY	IO33	GP14
RESET	EN	GP16
GPIO0	IO0	GP9
RX	RXD0	GP0 (tx)
TX	TXD0	GP1 (rx)

Install nina-fw on ESP32 using Raspberry Pi Pico:

In my practice , Raspberry Pi Pico act as a bridge to program ESP32. esptool is used to flash ESP32, read Install esptool on Raspberry Pi OS.

Visit https://github.com/adafruit/nina-fw/releases/latest, to download latest nina-fw.bin file, NINA_W102-1.7.3.bin currently.


- Download Pico-RP2040-Passthru.UF2
- Power up Pico in Bootloader mode
- Copy Pico-RP2040-Passthru.UF2 to Pico

- Disconnect and connect Pico again. Pico now act as a passthru bridge.
- Run the command to flash nina-fw to ESP32:

$ esptool.py --port /dev/ttyACM0 --before no_reset --baud 115200 write_flash 0 NINA_W102-1.7.3.bin

where:
- /dev/ttyACM0 is the usb port connect to Pico
- NINA_W102-1.7.3.bin is the downloaded nina-fw file.

Install CircuitPython firmware on Raspberry Pi Pico again

Download libraries:

Visit https://circuitpython.org/libraries to download the appropriate bundle for your version of CircuitPython.

Unzip the file and copy adafruit_airlift, adafruit_ble, adafruit_esp32spi folder and adafruit_requests.mpy to lib folder of Pico's CIRCUITPY driver.


Test CircuitPython code on Raspberry Pi Pico:

cpyPico_ESP32_WiFi.py

import board
import busio
from digitalio import DigitalInOut

from adafruit_esp32spi import adafruit_esp32spi
import adafruit_requests as requests

print("Raspberry Pi RP2040 - ESP32SPI hardware test")

esp32_cs = DigitalInOut(board.GP13)
esp32_ready = DigitalInOut(board.GP14)
esp32_reset = DigitalInOut(board.GP16)

spi = busio.SPI(board.GP10, board.GP11, board.GP12)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)

if esp.status == adafruit_esp32spi.WL_IDLE_STATUS:
    print("ESP32 found and in idle mode")
print("Firmware vers.", esp.firmware_version)
print("MAC addr:", [hex(i) for i in esp.MAC_address])

for ap in esp.scan_networks():
    print("\t%s\t\tRSSI: %d" % (str(ap['ssid'], 'utf-8'), ap['rssi']))

print("Done!")

ref:
Quickstart IoT - Raspberry Pi Pico RP2040 with WiFi

cpyPico_ESP32_BLE.py

import board
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService
from adafruit_airlift.esp32 import ESP32

esp32 = ESP32(
    reset=board.GP16,
    gpio0=board.GP9,
    busy=board.GP14,
    chip_select=board.GP13,
    tx=board.GP0,     #connect to ESP32 RX
    rx=board.GP1,     #connect to ESP32 TX
)


adapter = esp32.start_bluetooth()

ble = BLERadio(adapter)
uart = UARTService()
advertisement = ProvideServicesAdvertisement(uart)

while True:
    ble.start_advertising(advertisement)
    print("waiting to connect")
    while not ble.connected:
        pass
    print("connected: trying to read input")
    while ble.connected:
        # Returns b'' if nothing was read.
        one_byte = uart.read(1)
        if one_byte:
            print(one_byte)
            uart.write(one_byte)

ref:
Quickstart - Raspberry Pi RP2040 with BLE and CircuitPython

Tested with:
~ ESP32 running arduino-esp32 framework BLE UART Client


Wednesday, May 12, 2021

Raspberry Pi Pico/CircuitPython + ESP32/adafruit nina-fw (as WiFi Co-Processor)

Updated:
It's another post using Raspberry Pi Pico as pass through bridge to program ESP32 with nina-fw.

This post show how ESP32 flashed with adafruit nina-fw, act as WiFi Co-Processor work with Raspberry  Pi Pico with CircuitPython.

adafruit nina-fw is a slight variant of the Arduino WiFiNINA core. The ESP32 used here is a ESP32-S breadout board, flash with current latest version NINA_W102-1.7.3.bin.

Raspberry Pi Pico is flashed CircuitPython 6.2.0, with adafruit_esp32spi and adafruit_requests libraries installed.

Install nina-fw on ESP32

In my practice, esptool is used to flash ESP32, on Raspberry Pi. Read Install esptool on Raspberry Pi OS.

Download adafruit nina-fw:

Visit https://github.com/adafruit/nina-fw/releases/latest, to download latest nina-fw.bin file, NINA_W102-1.7.3.bin currently.

Flash ESP32 using esptool:

Depends on your ESP32 board, connect and force it into bootloader mode, may be:
- Press and hold GPIO0 to GND
- Reset ESP32
- Release GPIO0

Run the command:

$ esptool.py --port /dev/ttyUSB0 --before no_reset --baud 115200 write_flash 0 NINA_W102-1.7.3.bin

where:
- /dev/ttyUSB0 is the usb port connect to ESP32
- NINA_W102-1.7.3.bin is the downloaded nina-fw file.

Connect ESP32 to Raspberry Pi Pico

		ESP32		RPi Pico
3.3V		3.3V		3.3V
GND		GND		GND
SCK		IO18		GP10
MISO		IO23		GP12
MOSI		IO14		GP11
CS		IO5		GP13
BUSY		IO33		GP14
RESET		EN		GP15
GPIO0		IO0
RXD		RXD0		
TX		TXD0

Download libraries:

Visit https://circuitpython.org/libraries to download the appropriate bundle for your version of CircuitPython.


Unzip the file and copy adafruit_esp32spi folder and adafruit_requests.mpy to lib folder of Pico's CIRCUITPY driver.


Test CircuitPython code on Raspberry Pi Pico

Copy from https://learn.adafruit.com/quickstart-rp2040-pico-with-wifi-and-circuitpython/circuitpython-wifi.


import board
import busio
from digitalio import DigitalInOut

from adafruit_esp32spi import adafruit_esp32spi
import adafruit_requests as requests

print("Raspberry Pi RP2040 - ESP32SPI hardware test")

esp32_cs = DigitalInOut(board.GP13)
esp32_ready = DigitalInOut(board.GP14)
esp32_reset = DigitalInOut(board.GP15)

spi = busio.SPI(board.GP10, board.GP11, board.GP12)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)

if esp.status == adafruit_esp32spi.WL_IDLE_STATUS:
    print("ESP32 found and in idle mode")
print("Firmware vers.", esp.firmware_version)
print("MAC addr:", [hex(i) for i in esp.MAC_address])

for ap in esp.scan_networks():
    print("\t%s\t\tRSSI: %d" % (str(ap['ssid'], 'utf-8'), ap['rssi']))

print("Done!")


reference:
adafruit learn: Quickstart IoT - Raspberry Pi Pico RP2040 with WiFi
~ adafruit_esp32spi doc
adafruit_requests doc



Thursday, May 6, 2021

Raspberry Pi Pico/MicroPython, read and set CPU Frequency (overclock)

On Raspberry Pi Pico/MicroPython, machine.freq() can be used to read/set CPU frequency, in hertz.

Tested on Raspberry Pi Pico flashed with MicroPython v1.15 on 2021-05-06.




Change CPU Frequency and monitor Temperature, at runtime, with graphical display on ili9341 SPI display.


With 320x240 ILI9341 SPI Display, using jeffmer/micropython-ili9341 library, and modified from former exercise read internal temperature sensor, it's a exercise to change CPU Frequency and monitor Temperature, at runtime.

Tested on Raspberry Pi Pico with MicroPython v1.15 on 2021-04-18.


mpyPico_ClockVsTemp_ili9341_20210509a.py
"""
Exercise on Raspberry Pi Pico/MicroPython
with 320x240 ILI9341 SPI Display

Pico plot internal temperature graphically
vs CPU Clock
"""
from ili934xnew import ILI9341, color565
from machine import Pin, SPI, Timer
from micropython import const
import os
import glcdfont
import tt24
import tt32
#import freesans20fixed
import utime

sensor_temp = machine.ADC(4) #internal temperature sensor
conversion_factor = 3.3/(65535)

SCR_WIDTH = const(320)
SCR_HEIGHT = const(240)
SCR_ROT = const(0)
#SCR_ROT = const(2)

dispW = 240
dispH = 320
marginX = const(20)
marginY = const(10)
TempFrame_W = dispW-(2*marginX)
TempFrame_H = 100
TempFrame_X0 = marginX
TempFrame_Y0 = marginY
TempFrame_Y1 = marginY+TempFrame_H

TempPanel_X0 = TempFrame_X0
TempPanel_Y0 = TempFrame_Y1 + 10
TempPanel_W = TempFrame_W
TempPanel_H = 32

sampleSize = TempFrame_W      #200
tempValueLim = TempFrame_H  #100

FreqFrame_W = dispW-(2*marginX)
FreqFrame_H = 100
FreqFrame_X0 = marginX
FreqFrame_Y0 = marginY + 150

FreqFrame_Y1 = marginY+FreqFrame_H + 150

FreqPanel_X0 = FreqFrame_X0
FreqPanel_Y0 = FreqFrame_Y1 + 10

led = Pin(25, Pin.OUT)

#set default CPU freq
machine.freq(125000000)
FreqChangeInterval = 15  #change freq in 15 sec interval
freqSet = [50000000, 250000000, 40000000, 260000000]
freqCnt = FreqChangeInterval
freqIdx = 0

print("MicroPython:")
print(os.uname()[3])
print(os.uname()[4])
print()

TFT_CLK_PIN = const(6)
TFT_MOSI_PIN = const(7)
TFT_MISO_PIN = const(4)

TFT_CS_PIN = const(13)
TFT_RST_PIN = const(14)
TFT_DC_PIN = const(15)

spi = SPI(
    0,
    baudrate=40000000,
    miso=Pin(TFT_MISO_PIN),
    mosi=Pin(TFT_MOSI_PIN),
    sck=Pin(TFT_CLK_PIN))
print(spi)

display = ILI9341(
    spi,
    cs=Pin(TFT_CS_PIN),
    dc=Pin(TFT_DC_PIN),
    rst=Pin(TFT_RST_PIN),
    w=SCR_WIDTH,
    h=SCR_HEIGHT,
    r=SCR_ROT)

def drawHLine(x, y, w, color):
    for i in range(w):
        display.pixel(x+i,y,color)
        
def drawVLine(x, y, h, color):
    for i in range(h):
        display.pixel(x,y+i,color)
        
def drawVLineUp(x, y, h, color):
    for i in range(h):
        display.pixel(x,y-i,color)
      
frameBGcolor = color565(150, 150, 150)
TempPanel = color565(0, 0, 0)

def drawFrame(x, y, w, h):
    display.fill_rectangle(x, y, w, h, frameBGcolor)

    l1x = x-1
    l2x = x+w
    l1y = y-1
    l2y = y+h+1
    lcolor = color565(250, 250, 250)
    
    for i in range(w+2):
        display.pixel(l1x+i,l1y,lcolor)
        display.pixel(l1x+i,l2y,lcolor)
 
    for i in range(h+2):
        display.pixel(l1x,l1y+i,lcolor)
        display.pixel(l2x,l1y+i,lcolor)
      
display.erase()

display.set_font(tt24)
display.set_pos(0, 0)
display.set_color(color565(250, 250, 0), color565(0, 0, 0))
display.print("Pico plot internal temperature vs CPU Clock")
display.print("")
display.set_color(color565(250, 250, 250), color565(0, 0, 0))
display.print("MicroPython:")
display.print(os.uname()[3])
display.print("")
display.print(os.uname()[4])
utime.sleep(3)

timReached = False
tim = Timer()
def TimerTick(timer):
    global led
    led.toggle()
    global timReached
    timReached = True
    
tim.init(freq=1, mode=Timer.PERIODIC, callback=TimerTick)
    
display.set_font(tt32)
#display.set_font(freesans20fixed)

display.set_color(color565(250, 250, 0), color565(0, 0,0))
display.erase()

drawFrame(TempFrame_X0, TempFrame_Y0, TempFrame_W, TempFrame_H)
drawFrame(FreqFrame_X0, FreqFrame_Y0, FreqFrame_W, FreqFrame_H)

utime.sleep(1)

#sampleTemp=[0]*sampleSize
sampleIndex=0
tempString = "0"
while True:
    if timReached:
        
        timReached = False
        
        reading = sensor_temp.read_u16()*conversion_factor
        tempValue = 27-(reading-0.706)/0.001721
        
        print(tempValue)
        
        tempString=str(tempValue)
        if tempValue >= tempValueLim:
            display.set_color(color565(250, 0, 0), color565(0, 0, 0))
        else:
            display.set_color(color565(0, 0, 250), color565(0, 0, 0))
        display.set_pos(TempPanel_X0, TempPanel_Y0)
        display.print(tempString)
        
        if sampleIndex == 0:
            #clear frame
            display.fill_rectangle(TempFrame_X0,
                                   TempFrame_Y0,
                                   TempFrame_W,
                                   TempFrame_H,
                                   frameBGcolor)
            
            display.fill_rectangle(FreqFrame_X0,
                                   FreqFrame_Y0,
                                   FreqFrame_W,
                                   FreqFrame_H,
                                   frameBGcolor)
        
        #plot temperature
        if tempValue >= tempValueLim:
            drawVLineUp(TempFrame_X0+sampleIndex,
                        TempFrame_Y1,
                        tempValueLim,
                        color565(250, 0, 0))
        else:
            drawVLineUp(TempFrame_X0+sampleIndex,
                        TempFrame_Y1,
                        tempValue,
                        color565(0, 0, 250))
            
        #plot CPU freq
        freqValue = machine.freq()
        print(freqValue)
        
        freqBar = freqValue/3000000  #freqBar in range 0~100
        drawVLineUp(FreqFrame_X0+sampleIndex,
                    FreqFrame_Y1,
                    freqBar,
                    color565(250, 250, 0))
        
        freqString=str(freqValue/1000000) + " (MHz)"
        display.set_color(color565(0, 0, 250), color565(0, 0, 0))
        display.set_pos(FreqPanel_X0, FreqPanel_Y0)
        display.print(freqString)
        
        sampleIndex = sampleIndex+1
        if(sampleIndex>=sampleSize):
            sampleIndex = 0
            
        
        
        #check if frequency changeinterval reached
        freqCnt = freqCnt-1
        if freqCnt == 0:
            freqCnt = FreqChangeInterval
            newFreq = freqSet[freqIdx]
            print(newFreq)
            machine.freq(newFreq)
            freqIdx = freqIdx + 1
            if freqIdx == len(freqSet):
                freqIdx = 0;
print("- bye-")