Showing posts with label CircuitPython. Show all posts
Showing posts with label CircuitPython. Show all posts

Monday, August 8, 2022

SSD1306 SPI OLED on Raspberry Pi Pico/CircuitPython

Raspberry Pi Pico (RP2040) running CircuitPython 7.3.2, to drive 0.96" 128x64 SSD1306 SPI OLED using displayio. Check here.


Tuesday, May 10, 2022

CircuitPython display cursor on displayio, work on Raspberry Pi Pico/ST7789 SPI Display.

CircuitPython exercise run on Raspberry Pi Pico + 240x240 ST7789 SPI RGB Display, to display cursor on displayio.


Libraries needed:
- adafruit_cursorcontrol folder
- adafruit_display_text folder
- adafruit_st7789.mpy


Code:

cpyPico_st7789_240_cursor_mapping.py
cursor position are mapped to variable resistor position.

"""
Example of CircuitPython/RaspberryPi Pico
+ 240x240 ST7789 SPI RGB screen.
display cursor on displayio.

cursor position are mapped to variable resistor position

using adafruit_cursorcontrol.cursorcontrol
https://docs.circuitpython.org/projects/cursorcontrol/en/latest/api.html

Connection between Pico and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
GP11 - CS
GP12 - DC
GP13 - RES
GP15 - SDA
GP14 - SCL
3V3  - VCC
GND  - GND

AnalogIn GP26_A0 connect to variable resistor for Y
AnalogIn GP26_A1 connect to variable resistor for X
"""

import os
import sys
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
import adafruit_st7789
import adafruit_cursorcontrol.cursorcontrol
from analogio import AnalogIn

print("=====================================")
info = sys.implementation[0] + ' ' + \
       os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=====================================")
print(adafruit_st7789.__name__ + " version: " +
      adafruit_st7789.__version__)
print(adafruit_cursorcontrol.cursorcontrol.__name__
      + " version: "
      + adafruit_cursorcontrol.cursorcontrol.__version__)
print()

analog_A0 = AnalogIn(board.GP26_A0)
analog_A1 = AnalogIn(board.GP27_A1)

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.GP11
tft_dc = board.GP12
tft_res = board.GP13
spi_mosi = board.GP15
spi_clk = board.GP14

display_width = 240
display_height = 240

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=display_width, height=display_height,
                    rowstart=80,
                    rotation=180)

# Make the display context
splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(display_width, display_height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xA0A0A0

bg_sprite = displayio.TileGrid(color_bitmap,
                               pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

# Draw a smaller inner rectangle
inner_bitmap = displayio.Bitmap(80, 180, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap,
                                  pixel_shader=inner_palette, x=20, y=20)
splash.append(inner_sprite)

info1 = sys.implementation[0] + ' ' + os.uname()[2]
info2 = 'run on ' + os.uname()[4]

# Draw labels for CircuitPython info
text_group1 = displayio.Group(scale=2, x=5, y=40)
text1 = info1
text_area1 = label.Label(terminalio.FONT, text=text1, color=0x000000)
text_group1.append(text_area1)  # Subgroup for text scaling
#
text_group2 = displayio.Group(scale=1, x=5, y=70)
text2 = info2
text_area2 = label.Label(terminalio.FONT, text=text2, color=0xFFFFFF)
text_group2.append(text_area2)  # Subgroup for text scaling

# Draw labels for adafruit_st7789
text_group3 = displayio.Group(scale=2, x=5, y=120)
text3 = adafruit_st7789.__name__
text_area3 = label.Label(terminalio.FONT, text=text3, color=0x000000)
text_group3.append(text_area3)  # Subgroup for text scaling
#
text_group4 = displayio.Group(scale=2, x=5, y=150)
text4 = adafruit_st7789.__version__
text_area4 = label.Label(terminalio.FONT, text=text4, color=0xFF0000)
text_group4.append(text_area4)  # Subgroup for text scaling

# Draw labels for adafruit_cursorcontrol.cursorcontrol
text_group5 = displayio.Group(scale=1, x=5, y=180)
text5 = adafruit_cursorcontrol.cursorcontrol.__name__
text_area5 = label.Label(terminalio.FONT, text=text5, color=0x000000)
text_group5.append(text_area5)  # Subgroup for text scaling
# 
text_group6 = displayio.Group(scale=2, x=5, y=210)
text6 = adafruit_cursorcontrol.cursorcontrol.__version__
text_area6 = label.Label(terminalio.FONT, text=text6, color=0x000000)
text_group6.append(text_area6)  # Subgroup for text scaling

splash.append(text_group1)
splash.append(text_group2)
splash.append(text_group3)
splash.append(text_group4)
splash.append(text_group5)
splash.append(text_group6)

# initialize the mouse cursor object
# place over all others
mouse_cursor = adafruit_cursorcontrol.cursorcontrol.Cursor(
    display, display_group=splash)

cnv_ratio = 240/65536

while True:
    mouse_cursor.x = (int)(analog_A1.value * cnv_ratio)
    mouse_cursor.y = (int)((64436-analog_A0.value) * cnv_ratio)
    
    time.sleep(0.05)
    
print("~ bye ~")
cpyPico_st7789_240_cursor_delta.py
variable resistor position control the cursor movement.


"""
Example of CircuitPython/RaspberryPi Pico
+ 240x240 ST7789 SPI RGB screen.
display cursor on displayio.

variable resistor position control the cursor movement.

Connection between Pico and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
GP11 - CS
GP12 - DC
GP13 - RES
GP15 - SDA
GP14 - SCL
3V3  - VCC
GND  - GND

AnalogIn GP26_A0 connect to variable resistor for Y
AnalogIn GP26_A1 connect to variable resistor for X
"""

import os
import sys
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
import adafruit_st7789
import adafruit_cursorcontrol.cursorcontrol
from analogio import AnalogIn

print("=====================================")
info = sys.implementation[0] + ' ' + \
       os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=====================================")
print(adafruit_st7789.__name__ + " version: " +
      adafruit_st7789.__version__)
print(adafruit_cursorcontrol.cursorcontrol.__name__
      + " version: "
      + adafruit_cursorcontrol.cursorcontrol.__version__)
print()

analog_A0 = AnalogIn(board.GP26_A0)
analog_A1 = AnalogIn(board.GP27_A1)

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.GP11
tft_dc = board.GP12
tft_res = board.GP13
spi_mosi = board.GP15
spi_clk = board.GP14

display_width = 240
display_height = 240

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=display_width, height=display_height,
                    rowstart=80,
                    rotation=180)

# Make the display context
splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(display_width, display_height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xA0A0A0

bg_sprite = displayio.TileGrid(color_bitmap,
                               pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

# Draw a smaller inner rectangle
inner_bitmap = displayio.Bitmap(50, 180, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap,
                                  pixel_shader=inner_palette, x=50, y=20)
#splash.append(inner_sprite)

info1 = sys.implementation[0] + ' ' + os.uname()[2]
info2 = 'run on ' + os.uname()[4]

# Draw labels for CircuitPython info
text_group1 = displayio.Group(scale=2, x=5, y=40)
text1 = info1
text_area1 = label.Label(terminalio.FONT, text=text1, color=0x000000)
text_group1.append(text_area1)  # Subgroup for text scaling
#
text_group2 = displayio.Group(scale=1, x=5, y=70)
text2 = info2
text_area2 = label.Label(terminalio.FONT, text=text2, color=0xFFFFFF)
text_group2.append(text_area2)  # Subgroup for text scaling

# Draw labels for adafruit_st7789
text_group3 = displayio.Group(scale=2, x=5, y=120)
text3 = adafruit_st7789.__name__
text_area3 = label.Label(terminalio.FONT, text=text3, color=0x000000)
text_group3.append(text_area3)  # Subgroup for text scaling
# 
text_group4 = displayio.Group(scale=2, x=5, y=150)
text4 = adafruit_st7789.__version__
text_area4 = label.Label(terminalio.FONT, text=text4, color=0xFF0000)
text_group4.append(text_area4)  # Subgroup for text scaling

# Draw labels for adafruit_cursorcontrol.cursorcontrol
text_group5 = displayio.Group(scale=1, x=5, y=180)
text5 = adafruit_cursorcontrol.cursorcontrol.__name__
text_area5 = label.Label(terminalio.FONT, text=text5, color=0x000000)
text_group5.append(text_area5)  # Subgroup for text scaling
#
text_group6 = displayio.Group(scale=2, x=5, y=210)
text6 = adafruit_cursorcontrol.cursorcontrol.__version__
text_area6 = label.Label(terminalio.FONT, text=text6, color=0x000000)
text_group6.append(text_area6)  # Subgroup for text scaling

splash.append(text_group1)
splash.append(text_group2)

# initialize the mouse cursor object
# place under inner_sprite, text_group3/4/5/6, and over all other
mouse_cursor = adafruit_cursorcontrol.cursorcontrol.Cursor(
    display, display_group=splash)

splash.append(inner_sprite)
splash.append(text_group3)
splash.append(text_group4)
splash.append(text_group5)
splash.append(text_group6)
"""
# initialize the mouse cursor object
mouse_cursor = adafruit_cursorcontrol.cursorcontrol.Cursor(
    display, display_group=splash)
"""
while True:
    offset_x = 0
    offset_y = 0
    delta_x = analog_A1.value-32768
    delta_y = analog_A0.value-32768
    
    if(delta_x >= 0):
        if delta_x > 30000:
            offset_x = 4
        elif delta_x > 20000:
            offset_x = 2
        elif delta_x > 10000:
            offset_x = 1
    else:
        if delta_x < -30000:
            offset_x = -4
        elif delta_x < -20000:
            offset_x = -2
        elif delta_x < -10000:
            offset_x = -1

    if(delta_y >= 0):
        if delta_y > 30000:
            offset_y = -4
        elif delta_y > 20000:
            offset_y = -2
        elif delta_y > 10000:
            offset_y = -1
    else:
        if delta_y < -30000:
            offset_y = 4
        elif delta_y < -20000:
            offset_y = 2
        elif delta_y < -10000:
            offset_y = 1
    
    mouse_cursor.x = mouse_cursor.x + offset_x
    mouse_cursor.y = mouse_cursor.y + offset_y
    
    time.sleep(0.05)
    
print("~ bye ~")
cpyPico_st7789_240_cursor_delta_bitmap.py
implement custom cursor bitmap.


"""
Example of CircuitPython/RaspberryPi Pico
+ 240x240 ST7789 SPI RGB screen.
display cursor on displayio.

example to apply custom bitmap for cursor

Connection between Pico and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
GP11 - CS
GP12 - DC
GP13 - RES
GP15 - SDA
GP14 - SCL
3V3  - VCC
GND  - GND

AnalogIn GP26_A0 connect to variable resistor for Y
AnalogIn GP26_A1 connect to variable resistor for X
"""

import os
import sys
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
import adafruit_st7789
import adafruit_cursorcontrol.cursorcontrol
from analogio import AnalogIn

print("=====================================")
info = sys.implementation[0] + ' ' + \
       os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=====================================")
print(adafruit_st7789.__name__ + " version: " +
      adafruit_st7789.__version__)
print(adafruit_cursorcontrol.cursorcontrol.__name__
      + " version: "
      + adafruit_cursorcontrol.cursorcontrol.__version__)
print()

analog_A0 = AnalogIn(board.GP26_A0)
analog_A1 = AnalogIn(board.GP27_A1)

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.GP11
tft_dc = board.GP12
tft_res = board.GP13
spi_mosi = board.GP15
spi_clk = board.GP14

display_width = 240
display_height = 240

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=display_width, height=display_height,
                    rowstart=80,
                    rotation=180)

# Make the display context
splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(display_width, display_height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xA0A0A0

bg_sprite = displayio.TileGrid(color_bitmap,
                               pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

# Draw a smaller inner rectangle
inner_bitmap = displayio.Bitmap(50, 180, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap,
                                  pixel_shader=inner_palette, x=50, y=20)
#splash.append(inner_sprite)

info1 = sys.implementation[0] + ' ' + os.uname()[2]
info2 = 'run on ' + os.uname()[4]

# Draw labels for CircuitPython info
text_group1 = displayio.Group(scale=2, x=5, y=40)
text1 = info1
text_area1 = label.Label(terminalio.FONT, text=text1, color=0x000000)
text_group1.append(text_area1)  # Subgroup for text scaling
#
text_group2 = displayio.Group(scale=1, x=5, y=70)
text2 = info2
text_area2 = label.Label(terminalio.FONT, text=text2, color=0xFFFFFF)
text_group2.append(text_area2)  # Subgroup for text scaling

# Draw labels for adafruit_st7789
text_group3 = displayio.Group(scale=2, x=5, y=120)
text3 = adafruit_st7789.__name__
text_area3 = label.Label(terminalio.FONT, text=text3, color=0x000000)
text_group3.append(text_area3)  # Subgroup for text scaling
# 
text_group4 = displayio.Group(scale=2, x=5, y=150)
text4 = adafruit_st7789.__version__
text_area4 = label.Label(terminalio.FONT, text=text4, color=0xFF0000)
text_group4.append(text_area4)  # Subgroup for text scaling

# Draw labels for adafruit_cursorcontrol.cursorcontrol
text_group5 = displayio.Group(scale=1, x=5, y=180)
text5 = adafruit_cursorcontrol.cursorcontrol.__name__
text_area5 = label.Label(terminalio.FONT, text=text5, color=0x000000)
text_group5.append(text_area5)  # Subgroup for text scaling
#
text_group6 = displayio.Group(scale=2, x=5, y=210)
text6 = adafruit_cursorcontrol.cursorcontrol.__version__
text_area6 = label.Label(terminalio.FONT, text=text6, color=0x000000)
text_group6.append(text_area6)  # Subgroup for text scaling

splash.append(text_group1)
splash.append(text_group2)

# initialize the mouse cursor object
# create custom bitmap for cursor
bmp = displayio.Bitmap(20, 20, 3)
for i in range(0, 20):
    bmp[i, (20-1)-i] = 1
    bmp[(20-1)-i, (20-1)-i] = 1
for i in range(0, 20):
    bmp[0, i] = 1
    bmp[i, 0] = 1
    
# initialize the mouse cursor object
# place under inner_sprite, text_group3/4/5/6, and over all other
mouse_cursor = adafruit_cursorcontrol.cursorcontrol.Cursor(
    display, display_group=splash, bmp=bmp)
"""
#use default cursor
mouse_cursor = adafruit_cursorcontrol.cursorcontrol.Cursor(
    display, display_group=splash)
"""
cursor_bitmap = mouse_cursor.cursor_bitmap
print(cursor_bitmap, cursor_bitmap.width, "x", cursor_bitmap.height)

for by in range(0, cursor_bitmap.height):
    s = str(by) + ":\t"
    for bx in range(0, cursor_bitmap.width):
        b = cursor_bitmap[bx, by]
        if b == 0:
            s = s + " " + " "
        else:
            s = s + str(b) + " "
    print(s)

splash.append(inner_sprite)
splash.append(text_group3)
splash.append(text_group4)
splash.append(text_group5)
splash.append(text_group6)
"""
# initialize the mouse cursor object
mouse_cursor = adafruit_cursorcontrol.cursorcontrol.Cursor(
    display, display_group=splash)
"""
while True:
    offset_x = 0
    offset_y = 0
    delta_x = analog_A1.value-32768
    delta_y = analog_A0.value-32768
    
    if(delta_x >= 0):
        if delta_x > 30000:
            offset_x = 4
        elif delta_x > 20000:
            offset_x = 2
        elif delta_x > 10000:
            offset_x = 1
    else:
        if delta_x < -30000:
            offset_x = -4
        elif delta_x < -20000:
            offset_x = -2
        elif delta_x < -10000:
            offset_x = -1

    if(delta_y >= 0):
        if delta_y > 30000:
            offset_y = -4
        elif delta_y > 20000:
            offset_y = -2
        elif delta_y > 10000:
            offset_y = -1
    else:
        if delta_y < -30000:
            offset_y = 4
        elif delta_y < -20000:
            offset_y = 2
        elif delta_y < -10000:
            offset_y = 1
    
    mouse_cursor.x = mouse_cursor.x + offset_x
    mouse_cursor.y = mouse_cursor.y + offset_y
    
    time.sleep(0.05)
    
print("~ bye ~")


Sunday, April 10, 2022

Raspberry Pi Pico/CircuitPython act as IMU USB Mouse, read LSM303 Accelerometer and report as mouse movement.

Base on cpyPico_lsm303_accel_inclinometer.py exercise in last post "Raspberry Pi Pico/CircuitPython, access LSM303(Accelerometer/Magnetometer) and L3GD20(Gyroscope)", added with adafruit_hid.mouse library, it is modified to act as IMU USB Mouse. User hold the 10DOF module, change orientation to move mouse pointer.


cpyPico_lsm303_accel_inclinometer_mouse.py
"""
Raspberry Pi Pico + LSM303
Act as usb_hid,
read Accelerometer and report mouse movement.

ref:
https://docs.circuitpython.org/projects/hid/en/latest/_modules/adafruit_hid/mouse.html
"""
import time
from math import atan2, degrees
import board
import adafruit_lsm303_accel
import busio
import usb_hid
from adafruit_hid.mouse import Mouse

mouse = Mouse(usb_hid.devices)

SDA=board.GP8
SCL=board.GP9
i2c = busio.I2C(SCL,SDA)  # uses board.SCL and board.SDA
sensor = adafruit_lsm303_accel.LSM303_Accel(i2c)

def vector_2_degrees(x, y):
    angle = degrees(atan2(y, x))
    if angle < 0:
        angle += 360
    return angle

def get_inclination(_sensor):
    x, y, z = _sensor.acceleration
    return vector_2_degrees(x, z), vector_2_degrees(y, z)

while True:
    angle_xz, angle_yz = get_inclination(sensor)
    #print("XZ angle = {:6.2f}deg   YZ angle = {:6.2f}deg".format(angle_xz, angle_yz))
    print(angle_xz, angle_yz)
    
    #LEFT/RIGHT
    if angle_xz > 120:
        mouse.move(x=+3)
    elif angle_xz > 105:
        mouse.move(x=+1)
    elif angle_xz < 60:
        mouse.move(x=-3)
    elif angle_xz < 75:
        mouse.move(x=-1)
        
    #UP/DOWN
    if angle_yz > 120:
        mouse.move(y=-3)
    elif angle_yz > 105:
        mouse.move(y=-1)
    elif angle_yz < 60:
        mouse.move(y=+3)
    elif angle_yz < 75:
        mouse.move(y=+1)

    time.sleep(0.02)

related:
XIAO BLE Sense (Arduino framework) IMU USB Mouse

Thursday, April 7, 2022

Raspberry Pi Pico/CircuitPython, access LSM303(Accelerometer/Magnetometer) and L3GD20(Gyroscope)

The 10DOF module used in this exercise integrated with:
- LSM303DLHC Accel/Mag
- L3GD20 Gyroscope
- BMP180 Temp/Baro


Prepare Libraries:
Visit https://circuitpython.org/libraries to download matched CircuitPython Library Bundle. Copy needed libraries to CircuitPython device /lib folder.


for LSM303(Accelerometer/Magnetometer)

cpyPico_lsm303_accel_inclinometer.py, test LSM303 Accelerometer.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

""" Display inclination data five times per second """

import time
from math import atan2, degrees
import board
import adafruit_lsm303_accel
import busio

SDA=board.GP8
SCL=board.GP9
i2c = busio.I2C(SCL,SDA)  # uses board.SCL and board.SDA
sensor = adafruit_lsm303_accel.LSM303_Accel(i2c)

def vector_2_degrees(x, y):
    angle = degrees(atan2(y, x))
    if angle < 0:
        angle += 360
    return angle


def get_inclination(_sensor):
    x, y, z = _sensor.acceleration
    return vector_2_degrees(x, z), vector_2_degrees(y, z)


while True:
    angle_xz, angle_yz = get_inclination(sensor)
    #print("XZ angle = {:6.2f}deg   YZ angle = {:6.2f}deg".format(angle_xz, angle_yz))
    print(angle_xz, angle_yz)
    time.sleep(0.2)


next:
act as IMU USB Mouse, read LSM303 Accelerometer and report as mouse movement.

cpyPico_lsm303dlh_mag_compass.py, test LSM303 Magnetometer.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

""" Display compass heading data five times per second """
import time
from math import atan2, degrees
import board
import adafruit_lsm303dlh_mag
import busio

SDA=board.GP8
SCL=board.GP9
i2c = busio.I2C(SCL, SDA)  # uses board.SCL and board.SDA
sensor = adafruit_lsm303dlh_mag.LSM303DLH_Mag(i2c)


def vector_2_degrees(x, y):
    angle = degrees(atan2(y, x))
    if angle < 0:
        angle += 360
    return angle


def get_heading(_sensor):
    magnet_x, magnet_y, _ = _sensor.magnetic
    return vector_2_degrees(magnet_x, magnet_y)


while True:
    print("heading: {:.2f} degrees".format(get_heading(sensor)))
    time.sleep(0.2)


cpyPico_st7789_240.py, verify connection/function of st7789.
"""
Example of CircuitPython/RaspberryPi Pico
to display on 1.54" IPS 240x240 (RGB) screen
with ST7789 driver via SPI interface.

Connection between Pico and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
GP11 - CS
GP12 - DC
GP13 - RES
GP15 - SDA
GP14 - SCL
3V3  - VCC
GND  - GND
"""

import os
import sys
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
import adafruit_st7789

print("=====================================")
info = sys.implementation[0] + ' ' + \
       os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=====================================")
print(adafruit_st7789.__name__ + " version: " + adafruit_st7789.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.GP11
tft_dc = board.GP12
tft_res = board.GP13
spi_mosi = board.GP15
spi_clk = board.GP14

display_width = 240
display_height = 240

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=display_width, height=display_height,
                    rowstart=80,
                    rotation=180)

# Make the display context
splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(display_width, display_height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFF0000

bg_sprite = displayio.TileGrid(color_bitmap,
                               pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

# Draw a smaller inner rectangle
inner_bitmap = displayio.Bitmap(133, 238, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap,
                                  pixel_shader=inner_palette, x=1, y=1)
splash.append(inner_sprite)

info1 = sys.implementation[0] + ' ' + os.uname()[2]
info2 = 'run on ' + os.uname()[4]

# Draw a label
text_group1 = displayio.Group(scale=2, x=5, y=40)
text1 = info1
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFFFFFF)
text_group1.append(text_area1)  # Subgroup for text scaling

# Draw a label
text_group2 = displayio.Group(scale=1, x=5, y=70)
text2 = info2
text_area2 = label.Label(terminalio.FONT, text=text2, color=0xFFFFFF)
text_group2.append(text_area2)  # Subgroup for text scaling

# Draw a label
text_group3 = displayio.Group(scale=2, x=5, y=100)
text3 = adafruit_st7789.__name__
text_area3 = label.Label(terminalio.FONT, text=text3, color=0xFF0000)
text_group3.append(text_area3)  # Subgroup for text scaling
# Draw a label
text_group4 = displayio.Group(scale=2, x=5, y=130)
text4 = adafruit_st7789.__version__
text_area4 = label.Label(terminalio.FONT, text=text4, color=0x00FF00)
text_group4.append(text_area4)  # Subgroup for text scaling

splash.append(text_group1)
splash.append(text_group2)
splash.append(text_group3)
splash.append(text_group4)

time.sleep(2)
color_palette[0] = 0x00FF00

for c in range(00, 0xFF):
    time.sleep(0.001)
    col = ((0xFF-c)*0x0100) + c
    color_palette[0] = col    
time.sleep(0.001)
color_palette[0] = 0x0000FF

time.sleep(1)
for c in range(00, 0xFF):
    time.sleep(0.001)
    col = 0xFF-c
    color_palette[0] = col    
time.sleep(0.001)
color_palette[0] = 0x000000

time.sleep(1)
for c in range(00, 0xFF):
    time.sleep(0.001)
    col = (c * 0x010000) + (c*0x0100) + 0xFF
    inner_palette[0] = col    
time.sleep(0.001)
inner_palette[0] = 0xFFFFFF

time.sleep(1)
for c in range(0xFF, 0x00, -1):
    time.sleep(0.001)
    col = (c * 0x010000) + (c*0x0100) + c
    inner_palette[0] = col    
time.sleep(0.001)
inner_palette[0] = 0x000000

print("~ bye ~")

cpyPico_st7789_compass.py, read LSM303 Magnetometer, display on ST7789 in compass form.
"""
Example of CircuitPython/RaspberryPi Pico
to display on 1.54" IPS 240x240 (RGB) screen
with ST7789 driver via SPI interface.

Read from lsm303dlh and display on ST7789 in compass form.

Connection between Pico and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
GP11 - CS
GP12 - DC
GP13 - RES
GP15 - SDA
GP14 - SCL
3V3  - VCC
GND  - GND

Connection between Pico and 10DOF
3V3  - VIN
GND  - GND
SCL  - GP9
SDA  - GP8

"""

import os
import sys
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
from adafruit_display_shapes.circle import Circle
from adafruit_display_shapes.line import Line
import adafruit_st7789
from math import sin, cos, radians
from math import atan2, degrees
import adafruit_lsm303dlh_mag
#import gc

print("=====================================")
info = sys.implementation[0] + ' ' + \
       os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=====================================")
print(adafruit_st7789.__name__ + " version: "
      + adafruit_st7789.__version__)
print(adafruit_lsm303dlh_mag.__name__ + " version: "
      + adafruit_lsm303dlh_mag.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

SDA = board.GP8
SCL = board.GP9
i2c_lsm303dlh = busio.I2C(SCL, SDA)

sensor_lsm303dlh = adafruit_lsm303dlh_mag.LSM303DLH_Mag(i2c_lsm303dlh)

def vector_2_degrees(x, y):
    angle = degrees(atan2(y, x))
    if angle < 0:
        angle += 360
    return angle


def get_heading(_sensor):
    magnet_x, magnet_y, _ = _sensor.magnetic
    return vector_2_degrees(magnet_x, magnet_y)

tft_cs = board.GP11
tft_dc = board.GP12
tft_res = board.GP13
spi_mosi = board.GP15
spi_clk = board.GP14

display_width = 240
display_height = 240

spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=display_width, height=display_height,
                    rowstart=80,
                    rotation=180)

# Make the display context
splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(display_width, display_height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000

bg_sprite = displayio.TileGrid(color_bitmap,
                               pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

cir_compass_cx = (int)(display_width/2)
cir_compass_cy = (int)(display_height/2)
cir_compass_r = 100
cir_compass = Circle(cir_compass_cx,
                     cir_compass_cy,
                     cir_compass_r,
                     fill=0x0000FF,
                     outline=0xFF0000)
splash.append(cir_compass)

# Draw a label
labelDir_group = displayio.Group(scale=2, x=5, y=40)
textDir = "0"
labelDir = label.Label(terminalio.FONT, text=textDir, color=0xFFFFFF)
labelDir_group.append(labelDir)
splash.append(labelDir_group)


dir_line_x1 = cir_compass_cx
dir_line_y1 = cir_compass_cy - cir_compass_r
dir_line = Line(cir_compass_cx,
                cir_compass_cy,
                dir_line_x1,
                dir_line_y1,
                0xFFFFFF)
splash.append(dir_line)
#-------------------------------


def drawDir(direction):
    global splach
    global dir_line
    global labelDir
    global display

    labelDir.text = str(direction)
    
    # depends on the alignmenet of your LSM303DLH and display
    dirOffset = -(direction - 180)
    
    x1 = (int)(cir_compass_cx +
               (cir_compass_r * cos(radians(dirOffset))))
    y1 = (int)(cir_compass_cy +
               (cir_compass_r * sin(radians(dirOffset))))

    splash.remove(dir_line)
    dir_line = Line(cir_compass_cx,
                cir_compass_cy,
                x1,
                y1,
                0xFFFFFF)

    splash.append(dir_line)
    #print(gc.mem_free())
    
while True:
    d = get_heading(sensor_lsm303dlh)
    #print(d)
    drawDir(d)
    time.sleep(0.1)
    
print("~ bye ~")

For L3GD20(Gyroscope)

This video show how to run on Raspberry Pi Pico/CircuitPython to read L3GD20(Gyroscope), using modified adafruit_l3gd20 library.

Basically, this exercise modified from CircuiyPython Libraries l3gd20_simpletest.py example, but with two proglem:
- unmatched I2C address, it'seasy to fix by adding parameter of address.
- RuntimeError: bad chip id (d3 != d4 or d7)
  The accepted chip id is hard coded in adafruit_l3gd20 library. To fix it, I download the adafruit_l3gd20.py, edit to add my chip id and save as my custom library in CircuitPython device /lib folder.


cpyPico_I2C_Scan.py, verify I2C devices.
# SPDX-FileCopyrightText: 2017 Limor Fried for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""CircuitPython I2C Device Address Scan"""
# If you run this and it seems to hang, try manually unlocking
# your I2C bus from the REPL with
#  >>> import board
#  >>> board.I2C().unlock()

import time
import board
import busio

SDA = board.GP8
SCL = board.GP9
i2c = busio.I2C(SCL, SDA)

# To use default I2C bus (most boards)
#i2c = board.I2C()

# To create I2C bus on specific pins
# import busio
# i2c = busio.I2C(board.SCL1, board.SDA1)  # QT Py RP2040 STEMMA connector
# i2c = busio.I2C(board.GP1, board.GP0)    # Pi Pico RP2040

while not i2c.try_lock():
    pass

try:
    while True:
        print(
            "I2C addresses found:",
            [hex(device_address) for device_address in i2c.scan()],
        )
        time.sleep(2)

finally:  # unlock the i2c bus when ctrl-c'ing out of the loop
    i2c.unlock()


my_l3gd20.py, modified from adafruit_l3gd20 to add supporting of our chip id, save to CircuitPython device /lib folder.
# SPDX-FileCopyrightText: 2018 Michael McWethy for Adafruit Industries
#
# SPDX-License-Identifier: MIT

# https://github.com/adafruit/Adafruit_CircuitPython_L3GD20

"""
`adafruit_l3gd20`
====================================================

Adafruit 9-DOF Absolute Orientation IMU Fusion Breakout - L3GD20

This is a CircuitPython driver for the Bosch L3GD20 nine degree of freedom
inertial measurement unit module with sensor fusion.

* Author(s): Michael McWethy

Implementation Notes
--------------------

**Hardware:**

* Adafruit `L3GD20H Triple-Axis Gyro Breakout Board <https://www.adafruit.com/product/1032>`_

**Software and Dependencies:**

* Adafruit CircuitPython firmware for the supported boards:
  https://circuitpython.org/downloads


* Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
"""

# imports
from math import radians
from struct import unpack

from micropython import const
from adafruit_register.i2c_struct import Struct

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_L3GD20.git"

L3DS20_RANGE_250DPS = const(0)
L3DS20_RANGE_500DPS = const(1)
L3DS20_RANGE_2000DPS = const(2)

L3DS20_RATE_100HZ = const(0x00)
L3DS20_RATE_200HZ = const(0x40)
L3DS20_RATE_400HZ = const(0x80)
L3DS20_RATE_800HZ = const(0xC0)

_L3GD20_REGISTER_CTRL_REG1 = const(0x20)
_L3GD20_REGISTER_CTRL_REG4 = const(0x23)

# _L3GD20_REGISTER_OUT_X_L = const(0x28)
_L3GD20_REGISTER_OUT_X_L_X80 = const(0xA8)
_L3GD20_REGISTER_OUT_X_L_X40 = const(0x68)

_ID_REGISTER = const(0x0F)

_MY_L3GD20_CHIP_ID = const(0xD3)
_L3GD20_CHIP_ID = const(0xD4)
_L3GD20H_CHIP_ID = const(0xD7)

_L3GD20_SENSITIVITY_250DPS = 0.00875  ## Roughly 22/256 for fixed point match
_L3GD20_SENSITIVITY_500DPS = 0.0175  ## Roughly 45/256
_L3GD20_SENSITIVITY_2000DPS = 0.070  ## Roughly 18/256


# pylint: disable=no-member
class L3GD20:
    """
    Driver for the L3GD20 3-axis Gyroscope sensor.

    :param int rng: a range value one of:

                    * :const:`L3DS20_RANGE_250DPS`
                    * :const:`L3DS20_RANGE_500DPS`
                    * :const:`L3DS20_RANGE_2000DPS`

                    Defaults to :const:`L3DS20_RANGE_250DPS`

    :param int rate: a rate value one of

                    * :const:`L3DS20_RATE_100HZ`
                    * :const:`L3DS20_RATE_200HZ`
                    * :const:`L3DS20_RATE_400HZ`
                    * :const:`L3DS20_RATE_800HZ`

                    Defaults to :const:`L3DS20_RATE_100HZ`
    """

    def __init__(self, rng=L3DS20_RANGE_250DPS, rate=L3DS20_RATE_100HZ):
        chip_id = self.read_register(_ID_REGISTER)
        if chip_id not in (_MY_L3GD20_CHIP_ID, _L3GD20_CHIP_ID, _L3GD20H_CHIP_ID):
            raise RuntimeError(
                "bad chip id (%x != %x, %x or %x)"
                % (chip_id, _MY_L3GD20_CHIP_ID, _L3GD20_CHIP_ID, _L3GD20H_CHIP_ID)
            )

        if rng not in (L3DS20_RANGE_250DPS, L3DS20_RANGE_500DPS, L3DS20_RANGE_2000DPS):
            raise ValueError(
                "Range value must be one of L3DS20_RANGE_250DPS, "
                "L3DS20_RANGE_500DPS, or L3DS20_RANGE_2000DPS"
            )

        # Set CTRL_REG1 (0x20)
        # ====================================================================
        # BIT  Symbol    Description                                   Default
        # ---  ------    --------------------------------------------- -------
        # 7-6  DR1#0     Output data rate
        # 5-4  BW1#0     Bandwidth selection
        #     3  PD        0 = Power-down mode, 1 = normal#sleep mode
        #     2  ZEN       Z-axis enable (0 = disabled, 1 = enabled)
        #     1  YEN       Y-axis enable (0 = disabled, 1 = enabled)
        #     0  XEN       X-axis enable (0 = disabled, 1 = enabled)

        # Switch to normal mode and enable all three channels
        self.write_register(_L3GD20_REGISTER_CTRL_REG1, rate | 0x0F)

        # Set CTRL_REG2 (0x21)
        # ====================================================================
        # BIT  Symbol    Description                                   Default
        # ---  ------    --------------------------------------------- -------
        # 5-4  HPM1#0    High-pass filter mode selection
        # 3-0  HPCF3..0  High-pass filter cutoff frequency selection

        # Nothing to do ... keep default values
        # ------------------------------------------------------------------

        #  Set CTRL_REG3 (0x22)
        # ====================================================================
        # BIT  Symbol    Description                                   Default
        # ---  ------    --------------------------------------------- -------
        #     7  I1_Int1   Interrupt enable on INT1 (0=disable,1=enable)
        #     6  I1_Boot   Boot status on INT1 (0=disable,1=enable)
        #     5  H-Lactive Interrupt active config on INT1 (0=high,1=low)
        #     4  PP_OD     Push-Pull#Open-Drain (0=PP, 1=OD)
        #     3  I2_DRDY   Data ready on DRDY#INT2 (0=disable,1=enable)
        #     2  I2_WTM    FIFO wtrmrk int on DRDY#INT2 (0=dsbl,1=enbl)
        #     1  I2_ORun   FIFO overrun int on DRDY#INT2 (0=dsbl,1=enbl)
        #     0  I2_Empty  FIFI empty int on DRDY#INT2 (0=dsbl,1=enbl)

        #  Nothing to do ... keep default values
        #  -----------------------------------------------------------------

        #  Set CTRL_REG4 (0x23)
        # ====================================================================
        # BIT  Symbol    Description                                   Default
        # ---  ------    --------------------------------------------- -------
        #     7  BDU       Block Data Update (0=continuous, 1=LSB#MSB)
        #     6  BLE       Big#Little-Endian (0=Data LSB, 1=Data MSB)
        # 5-4  FS1#0     Full scale selection
        #                                 00 = 250 dps
        #                                 01 = 500 dps
        #                                 10 = 2000 dps
        #                                 11 = 2000 dps
        #     0  SIM       SPI Mode (0=4-wire, 1=3-wire)

        # Adjust resolution if requested

        if rng == L3DS20_RANGE_250DPS:
            self.scale = _L3GD20_SENSITIVITY_250DPS
            self.write_register(_L3GD20_REGISTER_CTRL_REG4, 0x00)

        if rng == L3DS20_RANGE_500DPS:
            self.scale = _L3GD20_SENSITIVITY_500DPS
            self.write_register(_L3GD20_REGISTER_CTRL_REG4, 0x10)

        if rng == L3DS20_RANGE_2000DPS:
            self.scale = _L3GD20_SENSITIVITY_2000DPS
            self.write_register(_L3GD20_REGISTER_CTRL_REG4, 0x20)

        # ------------------------------------------------------------------

        # Set CTRL_REG5 (0x24)
        # ====================================================================
        # BIT  Symbol    Description                                   Default
        # ---  ------    --------------------------------------------- -------
        #     7  BOOT      Reboot memory content (0=normal, 1=reboot)
        #     6  FIFO_EN   FIFO enable (0=FIFO disable, 1=enable)
        #     4  HPen      High-pass filter enable (0=disable,1=enable)
        # 3-2  INT1_SEL  INT1 Selection config
        # 1-0  OUT_SEL   Out selection config

        # Nothing to do ... keep default values
        # ------------------------------------------------------------------

    @property
    def gyro(self):
        """
        x, y, z angular momentum tuple floats, rescaled appropriately for
        range selected in rad/s
        """
        raw = self.gyro_raw
        return tuple(radians(self.scale * v) for v in raw)


class L3GD20_I2C(L3GD20):
    """
    Driver for L3GD20 Gyroscope using I2C communications

    :param ~busio.I2C i2c: The I2C bus the device is connected to
    :param int rng: range value. Defaults to :const:`0x68`
    :param int rate: rate value. Defaults to :const:`L3DS20_RATE_100HZ`


    **Quickstart: Importing and using the device**

        Here is an example of using the :class:`L3GD20_I2C` class.
        First you will need to import the libraries to use the sensor

        .. code-block:: python

            import board
            import adafruit_l3gd20

        Once this is done you can define your `board.I2C` object and define your sensor object

        .. code-block:: python

            i2c = board.I2C()  # uses board.SCL and board.SDA
            sensor = adafruit_l3gd20.L3GD20_I2C(i2c)

        Now you have access to the :attr:`gyro` attribute

        .. code-block:: python

            gyro_data = sensor.gyro


    """

    gyro_raw = Struct(_L3GD20_REGISTER_OUT_X_L_X80, "<hhh")
    """Gives the raw gyro readings, in units of rad/s."""

    def __init__(
        self, i2c, rng=L3DS20_RANGE_250DPS, address=0x6B, rate=L3DS20_RATE_100HZ
    ):
        from adafruit_bus_device import (  # pylint: disable=import-outside-toplevel
            i2c_device,
        )

        self.i2c_device = i2c_device.I2CDevice(i2c, address)
        self.buffer = bytearray(2)
        super().__init__(rng, rate)

    def write_register(self, register, value):
        """
        Update a register with a byte value

        :param int register: which device register to write
        :param value: a byte to write
        """
        self.buffer[0] = register
        self.buffer[1] = value
        with self.i2c_device as i2c:
            i2c.write(self.buffer)

    def read_register(self, register):
        """
        Returns a byte value from a register

        :param register: the register to read a byte
        """
        self.buffer[0] = register
        with self.i2c_device as i2c:
            i2c.write_then_readinto(self.buffer, self.buffer, out_end=1, in_start=1)
        return self.buffer[1]


class L3GD20_SPI(L3GD20):
    """
    Driver for L3GD20 Gyroscope using SPI communications

    :param ~busio.SPI spi_busio: The SPI bus the device is connected to
    :param ~digitalio.DigitalInOut cs: digital in/out to use as chip select signal
    :param int rng: range value. Defaults to :const:`L3DS20_RANGE_250DPS`.
    :param baudrate: SPI baud rate. Defaults to :const:`100000`
    :param int rate: rate value. Defaults to :const:`L3DS20_RATE_100HZ`

    **Quickstart: Importing and using the device**

        Here is an example of using the :class:`L3GD20_SPI` class.
        First you will need to import the libraries to use the sensor

        .. code-block:: python

            import board
            import adafruit_l3gd20

        Once this is done you can define your `board.SPI` object and define your sensor object

        .. code-block:: python

            spi = board.SPI()
            sensor = adafruit_l3gd20.L3GD20_SPI(spi)

        Now you have access to the :attr:`gyro` attribute

        .. code-block:: python

            gyro_data = sensor.gyro


    """

    def __init__(
        self,
        spi_busio,
        cs,
        rng=L3DS20_RANGE_250DPS,
        baudrate=100000,
        rate=L3DS20_RATE_100HZ,
    ):  # pylint: disable=too-many-arguments
        from adafruit_bus_device import (  # pylint: disable=import-outside-toplevel
            spi_device,
        )

        self._spi = spi_device.SPIDevice(spi_busio, cs, baudrate=baudrate)
        self._spi_bytearray1 = bytearray(1)
        self._spi_bytearray6 = bytearray(6)
        super().__init__(rng, rate)

    def write_register(self, register, value):
        """
        Low level register writing over SPI, writes one 8-bit value

        :param int register: which device register to write
        :param value: a byte to write
        """
        register &= 0x7F  # Write, bit 7 low.
        with self._spi as spi:
            spi.write(bytes([register, value & 0xFF]))

    def read_register(self, register):
        """
        Low level register reading over SPI, returns a list of values

        :param register: the register to read a byte
        """
        register = (register | 0x80) & 0xFF  # Read single, bit 7 high.
        with self._spi as spi:
            self._spi_bytearray1[0] = register
            spi.write(self._spi_bytearray1)
            spi.readinto(self._spi_bytearray1)
            # Uncomment to dump bytearray:
            # print("$%02X => %s" % (register, [hex(i) for i in self._spi_bytearray1]))
            return self._spi_bytearray1[0]

    def read_bytes(self, register, buffer):
        """
        Low level register stream reading over SPI, returns a list of values

        :param register: the register to read bytes
        :param bytearray buffer: buffer to fill with data from stream
        """
        register = (register | 0x80) & 0xFF  # Read single, bit 7 high.
        with self._spi as spi:
            self._spi_bytearray1[0] = register
            spi.write(self._spi_bytearray1)
            spi.readinto(buffer)

    @property
    def gyro_raw(self):
        """Gives the dynamic rate raw gyro readings, in units rad/s."""
        buffer = self._spi_bytearray6
        self.read_bytes(_L3GD20_REGISTER_OUT_X_L_X40, buffer)
        return tuple(radians(x) for x in unpack("<hhh", buffer))

cpyPico_l3gd20_simpletest.py, exercise to read L3GD20 using our library.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

import time
import board
import my_l3gd20
import busio

SDA = board.GP8
SCL = board.GP9
# Hardware I2C setup:
I2C = busio.I2C(SCL, SDA)  # uses board.SCL and board.SDA
# Initializes L3GD20 object using default range, 250dps
SENSOR = my_l3gd20.L3GD20_I2C(I2C, address=0x69)
# Initialize L3GD20 object using a custom range and output data rate (ODR).
# SENSOR = adafruit_l3gd20.L3GD20_I2C(
#    I2C, rng=adafruit_l3gd20.L3DS20_RANGE_500DPS, rate=adafruit_l3gd20.L3DS20_RATE_200HZ
# )

# Possible values for rng are:
# adafruit_l3gd20.L3DS20_Range_250DPS, 250 degrees per second. Default range
# adafruit_l3gd20.L3DS20_Range_500DPS, 500 degrees per second
# adafruit_l3gd20.L3DS20_Range_2000DPS, 2000 degrees per second

# Possible values for rate are:
# adafruit_l3gd20.L3DS20_RATE_100HZ, 100Hz data rate. Default data rate
# adafruit_l3gd20.L3DS20_RATE_200HZ, 200Hz data rate
# adafruit_l3gd20.L3DS20_RATE_400HZ, 400Hz data rate
# adafruit_l3gd20.L3DS20_RATE_800HZ, 800Hz data rate

# Hardware SPI setup:
# import digitalio
# CS = digitalio.DigitalInOut(board.D5)
# SPIB = board.SPI()
# SENSOR = adafruit_l3gd20.L3GD20_SPI(SPIB, CS)
# SENSOR = adafruit_l3gd20.L3GD20_I2C(
#    SPIB,
#    CS,
#    rng=adafruit_l3gd20.L3DS20_RANGE_500DPS,
#    rate=adafruit_l3gd20.L3DS20_RATE_200HZ,
# )

while True:
    #print("Angular Velocity (rad/s): {}".format(SENSOR.gyro))
    print(SENSOR.gyro[0], SENSOR.gyro[1], SENSOR.gyro[2])
    #print()
    time.sleep(1)














Saturday, October 16, 2021

CircuitPython 7.0.0 run on Raspberry Pi Pico RP2040

 CircuitPython 7.0.0 run on Raspberry Pi Pico RP2040:

"""
CircuitPython 7 exercise run on Raspberry Pi Pico PR2040,
get system info.
"""
import board
import sys
import os
import microcontroller
# ref:
# The entire table of ANSI color codes working in C:
# https://gist.github.com/RabaDabaDoba/145049536f815903c79944599c6f952a
class color:
   RED = '\033[1;31;48m'
   BLUE = '\033[1;34;48m'
   BLACK = '\033[1;30;48m'
   END = '\033[1;37;0m'

print(board.board_id)
print(sys.implementation[0] + ' ' +
      str(sys.implementation[1][0]) +'.'+
      str(sys.implementation[1][1]) +'.'+
      str(sys.implementation[1][2]))
print("=====================================")
info = color.RED + \
       sys.implementation[0] + ' ' + \
       os.uname()[3] + color.END + '\n' + \
       'run on ' + color.BLUE + os.uname()[4] + color.END
print(info)
print("=====================================")
print("with number of cpu: " + color.RED +
      str(len(microcontroller.cpus)) + color.RED)

print()

To install CircuitPython firmware on Raspberry Pi, read the HERE.


Wednesday, August 18, 2021

ov7670/ov2640 + ST7789 (IPS Display) on Raspberry Pi Pico/CircuitPython 7.0.0 alpha 6

This post show how to connect OV7670/OV2640 0.3-Megapixel Camera Module to Raspberry Pi Pico (in CircuitPython 7.0.0 alpha 6), display on ST7789 SPI IPS screen; running example ov2640_jpeg_sd_pico_st7789_2in.py.

ov7670:


It's library named adafruit_ov7670.mpy and example named ov7670_displayio_pico_st7789_2in.py in CircuitPython Bundle Libraries. I tried to run it on Pico with current stable CircuitPython 6.3.0. But fail with error of:

ImportError: cannot import name Colorspace


Then I tried on CircuitPython 7.0.0 alpha 6.

The connection between Pico and ov7670 camera module and st7789 SPI IPS display follow the ov7670_displayio_pico_st7789_2in.py example. But I have to add reset pin for display.


Connection:
Connection between Pico and ov7670 cam module
=============================================
	+-----------+
3V3	|3V3	DGND|	GND
GP9	|SCL	SDA |	GP8
GP7	|VS	HS  |	GP21
GP11	|PLK	XLK |	GP20
GP19	|D7	D6  |	GP18
GP17	|D5	D4  |	GP16
GP15	|D3	D2  |	GP14
GP13	|D1	D0  |	GP12
GP10	|RET	PWDN|
	+-----------+
		
*SCL/SDA are I2C control pin, pull-up resistors are needed.
 I use 2K ohm resistor for it.
		
Connection between Pico and ST7789 SPI IPS
==========================================
3V3		BLK
GP1		CS
GP0		DC
GP4		RES
GP3		SDA
GP2		SCL
3V3		VCC
GND		GND

Makesure Raspberry Pi Pico is installed with CircuitPython 7.0.0 alpha 6, download the matched bundle libraries 7.x. Copy adafruit_st7789.mpy and adafruit_ov7670.mpy from lib folder to Pico CIRCUITPY lib folder. Modify ov7670_displayio_pico_st7789_2in.py from examples folder to add reset pin to GP4, as shown in above screenshot.

remark:
In my test, once the program ran and stopped, to re-run it, have to disconnect and reconnect USB to Pico.



ov2640:


My ov2640 module have same pin assignment in ov7670, aligned to top with D0/D1 opened.

Connection:
Connection between Pico and ov2640 cam module
=============================================
	+-----------+
3V3	|3V3	GND |	GND
GP9	|SIOC	SIOD|	GP8
GP7	|VSYNC	HREF|	GP21
GP11	|PCLK	XCLK|	GP20
GP19	|D9	D8  |	GP18
GP17	|D7	D6  |	GP16
GP15	|D5	D4  |	GP14
GP13	|D3	D2  |	GP12
GP10	|RESET	PWDN|
	|D1	D0  |
	+-----------+
		
Library:
Copy adafruit_ov2640.mpy and adafruit_st7789.mpy from CircuitPython bundle 7.x lib to CIRCUITPY lib folder.

Example:

Locate and edit ov2640_displayio_pico_st7789_2in.py from CircuitPython bundle 7.x examples, as shown in this video:


Wednesday, August 11, 2021

ST7789 SPI (2" 240x320/1.54" 240x240) IPS RGB Display, on Raspberry Pi Pico/CircuitPython

Test 2" 240x320 and 1.54" 240x240 ST7789 SPI IPS RGB Display, on Raspberry Pi Pico/CircuitPython.


Connection:

3V3  - BLK
GP11 - CS
GP12 - DC
GP13 - RES
GP15 - SDA
GP14 - SCL
3V3  - VCC
GND  - GND

Prepare Libraries:

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

Unzip the file, copy adafruit_st7789.mpy, adafruit_display_text and adafruit_display_shapes folder to the lib folder on your CIRCUITPY drive.


Examples code for 2" 240x320 ST7789 SPI IPS RGB Display :

cpyPico_spiST7789_320.py
"""
Example of CircuitPython/RaspberryPi Pico
to display on 2.0" IPS 240x320 (RGB) screen
with ST7789 driver via SPI interface.

Connection between Pico and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
GP11 - CS
GP12 - DC
GP13 - RES
GP15 - SDA
GP14 - SCL
3V3  - VCC
GND  - GND
"""

import os
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
#from adafruit_st7789 import ST7789
import adafruit_st7789

print("==============================")
print(os.uname())
print("Hello Raspberry Pi Pico/CircuitPython ST7789 SPI IPS Display")
print(adafruit_st7789.__name__ + " version: " + adafruit_st7789.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.GP11
tft_dc = board.GP12
tft_res = board.GP13
spi_mosi = board.GP15
spi_clk = board.GP14

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=240, height=320)

# Make the display context
splash = displayio.Group(max_size=10)
display.show(splash)

color_bitmap = displayio.Bitmap(135, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x00FF00

bg_sprite = displayio.TileGrid(color_bitmap,
                               pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

# Draw a smaller inner rectangle
inner_bitmap = displayio.Bitmap(133, 238, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap,
                                  pixel_shader=inner_palette, x=1, y=1)
splash.append(inner_sprite)

# Draw a label
text_group1 = displayio.Group(max_size=10, scale=2, x=20, y=40)
text1 = "RPi Pico"
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFF0000)
text_group1.append(text_area1)  # Subgroup for text scaling
# Draw a label
text_group2 = displayio.Group(max_size=10, scale=1, x=20, y=60)
text2 = "CircuitPython"
text_area2 = label.Label(terminalio.FONT, text=text2, color=0xFFFFFF)
text_group2.append(text_area2)  # Subgroup for text scaling

# Draw a label
text_group3 = displayio.Group(max_size=10, scale=1, x=20, y=100)
text3 = adafruit_st7789.__name__
text_area3 = label.Label(terminalio.FONT, text=text3, color=0x0000000)
text_group3.append(text_area3)  # Subgroup for text scaling
# Draw a label
text_group4 = displayio.Group(max_size=10, scale=2, x=20, y=120)
text4 = adafruit_st7789.__version__
text_area4 = label.Label(terminalio.FONT, text=text4, color=0x000000)
text_group4.append(text_area4)  # Subgroup for text scaling

splash.append(text_group1)
splash.append(text_group2)
splash.append(text_group3)
splash.append(text_group4)

time.sleep(3.0)

rot = 0
while True:
    time.sleep(5.0)
    rot = rot + 90
    if (rot>=360):
        rot =0
    display.rotation = rot

cpyPico_spiST7789_bitmap_320.py
"""
Example of CircuitPython/Raspberry Pi Pico
to display on 2.0" IPS 240x320 (RGB) screen
with ST7789 driver via SPI interface.

Connection between Pico and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
GP11 - CS
GP12 - DC
GP13 - RES
GP15 - SDA
GP14 - SCL
3V3  - VCC
GND  - GND
"""

import os
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
import adafruit_st7789

print("==============================")
print(os.uname())
print("Hello Raspberry Pi Pico/CircuitPython ST7789 SPI IPS Display")
print(adafruit_st7789.__name__ + " version: " + adafruit_st7789.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.GP11
tft_dc = board.GP12
tft_res = board.GP13
spi_mosi = board.GP15
spi_clk = board.GP14

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=240, height=320)
display.rotation = 270

group = displayio.Group(max_size=10)
display.show(group)

bitmap_width = 320
bitmap_height = 240
bitmap = displayio.Bitmap(bitmap_width, bitmap_height, bitmap_height)

palette = displayio.Palette(bitmap_height)
for p in range(bitmap_height):
    palette[p] = (0x010000*p) + (0x0100*p) + p

for y in range(bitmap_height):
    for x in range(bitmap_width):
        bitmap[x,y] = y
        
tileGrid = displayio.TileGrid(bitmap, pixel_shader=palette, x=0, y=0)
group.append(tileGrid)

time.sleep(3.0)

while True:
    for p in range(bitmap_height):
        palette[p] = p
    time.sleep(3.0)

    for p in range(bitmap_height):
        palette[p] = 0x0100 * p
    time.sleep(3.0)

    for p in range(bitmap_height):
        palette[p] = 0x010000 * p
    time.sleep(3.0)

cpyPico_spiST7789_shape_320.py
"""
Example of CircuitPython/Raspberry Pi Pico
to display on 2.0" IPS 240x320 (RGB) screen
with ST7789 driver via SPI interface.

modify example from:
https://circuitpython.readthedocs.io/projects/display-shapes/en/latest/index.html

Connection between Pico and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
GP11 - CS
GP12 - DC
GP13 - RES
GP15 - SDA
GP14 - SCL
3V3  - VCC
GND  - GND
"""

import os
import board
import time
import terminalio
import displayio
import busio
import adafruit_st7789
from adafruit_display_shapes.rect import Rect
from adafruit_display_shapes.circle import Circle
from adafruit_display_shapes.roundrect import RoundRect
from adafruit_display_shapes.triangle import Triangle

print("==============================")
print(os.uname())
print("Hello Raspberry Pi Pico/CircuitPython ST7789 SPI IPS Display")
print(adafruit_st7789.__name__ + " version: " + adafruit_st7789.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.GP11
tft_dc = board.GP12
tft_res = board.GP13
spi_mosi = board.GP15
spi_clk = board.GP14

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=240, height=320)
display.rotation = 270

splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

triangle = Triangle(170, 50, 120, 140, 210, 160, fill=0x00FF00, outline=0xFF00FF)
splash.append(triangle)

rect = Rect(80, 20, 41, 41, fill=0x0)
splash.append(rect)

circle = Circle(100, 100, 20, fill=0x00FF00, outline=0xFF00FF)
splash.append(circle)

rect2 = Rect(50, 100, 61, 81, outline=0x0, stroke=3)
splash.append(rect2)

roundrect = RoundRect(10, 10, 61, 81, 10, fill=0x0, outline=0xFF00FF, stroke=6)
splash.append(roundrect)

while True:
    pass

Examples code for 1.54" 240x240 ST7789 SPI IPS RGB Display :


cpyPico_spiST7789_240.py
"""
Example of CircuitPython/RaspberryPi Pico
to display on 2.0" IPS 240x320 (RGB) screen
with ST7789 driver via SPI interface.

Connection between Pico and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
GP11 - CS
GP12 - DC
GP13 - RES
GP15 - SDA
GP14 - SCL
3V3  - VCC
GND  - GND
"""

import os
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
#from adafruit_st7789 import ST7789
import adafruit_st7789

print("==============================")
print(os.uname())
print("Hello Raspberry Pi Pico/CircuitPython ST7789 SPI IPS Display")
print(adafruit_st7789.__name__ + " version: " + adafruit_st7789.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.GP11
tft_dc = board.GP12
tft_res = board.GP13
spi_mosi = board.GP15
spi_clk = board.GP14

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=240, height=240, rowstart=80)

# Make the display context
splash = displayio.Group(max_size=10)
display.show(splash)

color_bitmap = displayio.Bitmap(135, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x00FF00

bg_sprite = displayio.TileGrid(color_bitmap,
                               pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

# Draw a smaller inner rectangle
inner_bitmap = displayio.Bitmap(133, 238, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap,
                                  pixel_shader=inner_palette, x=1, y=1)
splash.append(inner_sprite)

# Draw a label
text_group1 = displayio.Group(max_size=10, scale=2, x=20, y=40)
text1 = "RPi Pico"
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFF0000)
text_group1.append(text_area1)  # Subgroup for text scaling
# Draw a label
text_group2 = displayio.Group(max_size=10, scale=1, x=20, y=60)
text2 = "CircuitPython"
text_area2 = label.Label(terminalio.FONT, text=text2, color=0xFFFFFF)
text_group2.append(text_area2)  # Subgroup for text scaling

# Draw a label
text_group3 = displayio.Group(max_size=10, scale=1, x=20, y=100)
text3 = adafruit_st7789.__name__
text_area3 = label.Label(terminalio.FONT, text=text3, color=0x0000000)
text_group3.append(text_area3)  # Subgroup for text scaling
# Draw a label
text_group4 = displayio.Group(max_size=10, scale=2, x=20, y=120)
text4 = adafruit_st7789.__version__
text_area4 = label.Label(terminalio.FONT, text=text4, color=0x000000)
text_group4.append(text_area4)  # Subgroup for text scaling

splash.append(text_group1)
splash.append(text_group2)
splash.append(text_group3)
splash.append(text_group4)

time.sleep(3.0)

rot = 0
while True:
    time.sleep(5.0)
    rot = rot + 90
    if (rot>=360):
        rot =0
    display.rotation = rot

cpyPico_spiST7789_bitmap_240.py
"""
Example of CircuitPython/Raspberry Pi Pico
to display on 2.0" IPS 240x320 (RGB) screen
with ST7789 driver via SPI interface.

Connection between Pico and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
GP11 - CS
GP12 - DC
GP13 - RES
GP15 - SDA
GP14 - SCL
3V3  - VCC
GND  - GND
"""

import os
import board
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
import adafruit_st7789

print("==============================")
print(os.uname())
print("Hello Raspberry Pi Pico/CircuitPython ST7789 SPI IPS Display")
print(adafruit_st7789.__name__ + " version: " + adafruit_st7789.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.GP11
tft_dc = board.GP12
tft_res = board.GP13
spi_mosi = board.GP15
spi_clk = board.GP14

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=240, height=240, rowstart=80)
display.rotation = 270

group = displayio.Group(max_size=10)
display.show(group)

bitmap_width = 240
bitmap_height = 240
bitmap = displayio.Bitmap(bitmap_width, bitmap_height, bitmap_height)

palette = displayio.Palette(bitmap_height)
for p in range(bitmap_height):
    palette[p] = (0x010000*p) + (0x0100*p) + p

for y in range(bitmap_height):
    for x in range(bitmap_width):
        bitmap[x,y] = y
        
tileGrid = displayio.TileGrid(bitmap, pixel_shader=palette, x=0, y=0)
group.append(tileGrid)

time.sleep(3.0)

while True:
    for p in range(bitmap_height):
        palette[p] = p
    time.sleep(3.0)

    for p in range(bitmap_height):
        palette[p] = 0x0100 * p
    time.sleep(3.0)

    for p in range(bitmap_height):
        palette[p] = 0x010000 * p
    time.sleep(3.0)

cpyPico_spiST7789_shape_240.py
"""
Example of CircuitPython/Raspberry Pi Pico
to display on 2.0" IPS 240x320 (RGB) screen
with ST7789 driver via SPI interface.

modify example from:
https://circuitpython.readthedocs.io/projects/display-shapes/en/latest/index.html

Connection between Pico and
the IPS screen, with ST7789 SPI interface.
3V3  - BLK (backlight, always on)
GP11 - CS
GP12 - DC
GP13 - RES
GP15 - SDA
GP14 - SCL
3V3  - VCC
GND  - GND
"""

import os
import board
import time
import terminalio
import displayio
import busio
import adafruit_st7789
from adafruit_display_shapes.rect import Rect
from adafruit_display_shapes.circle import Circle
from adafruit_display_shapes.roundrect import RoundRect
from adafruit_display_shapes.triangle import Triangle

print("==============================")
print(os.uname())
print("Hello Raspberry Pi Pico/CircuitPython ST7789 SPI IPS Display")
print(adafruit_st7789.__name__ + " version: " + adafruit_st7789.__version__)
print()

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.GP11
tft_dc = board.GP12
tft_res = board.GP13
spi_mosi = board.GP15
spi_clk = board.GP14

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=240, height=240, rowstart=80)
display.rotation = 270

splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(240, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

triangle = Triangle(170, 50, 120, 140, 210, 160, fill=0x00FF00, outline=0xFF00FF)
splash.append(triangle)

rect = Rect(80, 20, 41, 41, fill=0x0)
splash.append(rect)

circle = Circle(100, 100, 20, fill=0x00FF00, outline=0xFF00FF)
splash.append(circle)

rect2 = Rect(50, 100, 61, 81, outline=0x0, stroke=3)
splash.append(rect2)

roundrect = RoundRect(10, 10, 61, 81, 10, fill=0x0, outline=0xFF00FF, stroke=6)
splash.append(roundrect)

while True:
    pass


Related:

Next:

Tuesday, July 6, 2021

CircuitPython/Raspberry Pi Pico Exercise: get sys info

cpyPico_info.py run on Raspberry Pi Pico/CircuitPython to get system info.

import sys
import os
import microcontroller

print("\nCircuitPython/Raspberry Pi Pico Exercise: get sys info\n")

print('read sys.implementation :-')
print("sys.implementation.name:\t", sys.implementation.name)
print("sys.implementation.version:\t", sys.implementation.version)
print()

# Check if it's 32/64 bits
# ref:
# https://circuitpython.readthedocs.io/en/latest/docs/library/sys.html#sys.maxsize
bits = 0
v = sys.maxsize
while v:
    bits += 1
    v >>= 1
if bits > 32:
    print("It's 64-bit (or more) platform")
else:
    print("It's 32-bit (or less) platform")
    
print('\n======')
print('os.uname() :-')
u = os.uname()
print("type: ", type(u))
print(dir(u))
print(u)

print("sysname:\t", u.sysname)
print("nodename:\t", u.nodename)
print("release:\t", u.release)
print("version:\t", u.version)
print("machine:\t", u.machine)
    
print('\n======')

print()
print('microcontroller.cpus :-')
numOfCpu = len(microcontroller.cpus)
print('Number of CPU: ', numOfCpu)
for i in range(numOfCpu):
    print('CPU[', i, ']:')
    print('\tfrequency:\t', microcontroller.cpus[i].frequency)
    print('\ttemperature:\t', microcontroller.cpus[i].temperature)
    print('\tvoltage:\t', microcontroller.cpus[i].voltage)

print('\n======')





~ more exercises for RPi Pico/CircuitPython

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