Adsense HTML/JavaScript

Wednesday, March 30, 2022

XIAO BLE Sense (nRF52840)/CircuitPython generate QR Code and display on SSD1306 I2C OLED

adafruit_miniqr is a A non-hardware dependant miniature QR generator library.

Once Adafruit CircuitPython Libraries downloaded (as shown in last post's video), there are two examples miniqr_simpletest.py and miniqr_displaytest.py in extracted examples foler, or can be found here.

cpyX_miniqr_ssd1306.py is modified from miniqr_displaytest.py, to run on Seeed XIAO BLE Sense (nRF52840)/CircuitPython 7.2.3 to generate QR Code and display on SSD1306 I2C OLED.


cpyX_miniqr_ssd1306.py
"""
CircuitPython 7.2.3 exercise run on
Seeed XIAO nRF52840 Sense with nRF52840
- generate QR Code using adafruit_miniqr
- display on SSD1306 I2C OLED

lib needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_miniqr.mpy
"""

import os
import sys
import board
import busio
import displayio
import adafruit_displayio_ssd1306
import adafruit_miniqr

displayio.release_displays()

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

# Create the I2C interface and display object of SSD1306_I2C.
i2c = busio.I2C(board.SCL, board.SDA)

ssd1306_i2c_addr = 60
display_width =128
display_height = 64
display_bus = displayio.I2CDisplay(
    i2c, device_address=ssd1306_i2c_addr)
display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

# remark by Erik:
# base on my testing on 128x64 SSD1306,
# A full white background can improve the recognition
# so I add a background in white
background_bitmap = displayio.Bitmap(display_width,
                                     display_height, 1)
background_palette = displayio.Palette(1)
background_palette[0] = 0xFFFFFF
bg_sprite = displayio.TileGrid(background_bitmap,
                               pixel_shader=background_palette,
                               x=0, y=0)

def bitmap_QR(matrix):

    # monochome (2 color) palette
    BORDER_PIXELS = 2

    # bitmap the size of the screen, monochrome (2 colors)
    bitmap = displayio.Bitmap(
        matrix.width + 2 * BORDER_PIXELS,
        matrix.height + 2 * BORDER_PIXELS, 2
    )
    # raster the QR code
    for y in range(matrix.height):  # each scanline in the height
        for x in range(matrix.width):
            if matrix[x, y]:
                bitmap[x + BORDER_PIXELS, y + BORDER_PIXELS] = 1
            else:
                bitmap[x + BORDER_PIXELS, y + BORDER_PIXELS] = 0
    return bitmap


qr = adafruit_miniqr.QRCode(qr_type=3,
                            error_correct=adafruit_miniqr.L)
qr.add_data(b"http://embedded-things.blogspot.com/")
qr.make()

# generate the 1-pixel-per-bit bitmap
qr_bitmap = bitmap_QR(qr.matrix)
# We'll draw with a classic black/white palette
palette = displayio.Palette(2)
palette[0] = 0xFFFFFF
palette[1] = 0x000000
# we'll scale the QR code as big as the display can handle
scale = min(
    display_width // qr_bitmap.width,
    display_height // qr_bitmap.height
)
# then center it!
pos_x = int(((display_width / scale) - qr_bitmap.width) / 2)
pos_y = int(((display_height / scale) - qr_bitmap.height) / 2)
qr_img = displayio.TileGrid(qr_bitmap,
                            pixel_shader=palette,
                            x=pos_x, y=pos_y)

splash = displayio.Group(scale=scale)
splash.append(bg_sprite)
splash.append(qr_img)
display.show(splash)

# Hang out forever
while True:
    pass

Tuesday, March 29, 2022

Seeed XIAO BLE Sense (nRF52840)/CircuitPython 7.2.3 display on SSD1306 I2C OLED

Updated@2024-01-31

Somethings in displayio changed in CircuitPython 9, check the updated on ESP32-S3:
Waveshare ESP32-S3-Zero/CircuitPython 9.0.0-beta.0 to display on 128x64 SSD1306 I2C OLED



In CircuitPython, to display on SSD1306, there are two approach:
- framebuf  (using adafruit_ssd1306/adafruit_framebuf)
- displayio (using adafruit_displayio_ssd1306)

The video demo Seeed XIAO BLE Sense (nRF52840)/CircuitPython 7.2.3 display on Seeeduino XIAO Expansion board onboard SSD1306 I2C OLED using both framebuf  and displayio.


Exercise code:

cpyX_i2c.py
"""
Seeed XIAO nRF52840 Sense with nRF52840/CircuitPython 7.2.3
- verify I2C SCL/SDA pin
- Scan available I2C devices
"""

import os
import sys
import busio
import board

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

print("SCL: ", board.SCL)
print("SDA: ", board.SDA)
i2c = board.I2C()
print(i2c)
print()

#Scan I2C devices
if(i2c.try_lock()):
    print("i2c.scan(): " + str(i2c.scan()))
    i2c.unlock()
print()

cpyX_ssd1306.py
"""
CircuitPython 7.2.3 exercise run on
Seeed XIAO nRF52840 Sense with nRF52840
- display on SSD1306 I2C OLED
- using adafruit_ssd1306

lib needed:
- adafruit_ssd1306.mpy
- adafruit_framebuf.mpy
- font5x8.bin (from examples folder,
  to current folder in CircuitPython device)
"""

import os
import sys
import board
import busio
import time

import adafruit_ssd1306

# Create the I2C interface and display object of SSD1306_I2C.
i2c = busio.I2C(board.SCL, board.SDA)
display = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(adafruit_ssd1306.__name__, adafruit_ssd1306.__version__)
print("SCL: ", board.SCL)
print("SDA: ", board.SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
    
display.fill(0)
display.show()
time.sleep(1)
display.fill(1)
display.show()
time.sleep(1)

display.fill(0)


strSys = sys.implementation[0] + ' ' + \
         str(sys.implementation[1][0]) +'.'+ \
         str(sys.implementation[1][1]) +'.'+ \
         str(sys.implementation[1][2])

strLib = adafruit_ssd1306.__name__ + '\n' \
         + adafruit_ssd1306.__version__

def drawInfo():
    display.text(strSys, 0, 0, 1)
    display.text(strLib, 0, 10, 1)
    display.text(os.uname()[4], 0, 30, 1)
    display.text("SSD1306", 0, 40, 1)
    strResolution = str(display.rotation) + ' : ' \
                    + str(display.width) + ' x ' \
                    + str(display.height)
    display.text(strResolution, 0, 50, 1)
    
for r in range(0, 4):
    display.fill(0)
    display.rotation = r
    drawInfo()
    display.show()
    time.sleep(5)

display.rotation = 0

#draw rectangle
display.fill(0)
display.rect(0, 0, display.width, display.height, 1)
display.show()
time.sleep(1)
display.fill(0)
display.fill_rect(0, 0, display.width, display.height, 1)
display.show()
time.sleep(1)

#draw circle
display.fill(0)
if display.width > display.height:
    r = (int)(display.height/2)
else:
    r = (int)(display.width/2)
display.circle((int)(display.width/2),
               (int)(display.height/2), r, 1)
display.show()
time.sleep(1)

display.fill(0)
display.show()

# draw pixels
for y in range(0, display.height, 8):
    for x in range(0, display.width, 8):
        display.pixel(x, y, 1)
        display.show()
time.sleep(1)
display.invert(1)
time.sleep(2)
display.invert(0)
time.sleep(1)

cpyX_displayio_ssd1306.py
"""
CircuitPython 7.2.3 exercise run on
Seeed XIAO nRF52840 Sense with nRF52840
- display on SSD1306 I2C OLED
- using adafruit_displayio_ssd1306

lib needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_text folder
"""

import os
import sys
import board
import busio
import time

import displayio
import terminalio
import adafruit_displayio_ssd1306
from adafruit_display_text import label

displayio.release_displays()

# Create the I2C interface and display object of SSD1306_I2C.
i2c = busio.I2C(board.SCL, board.SDA)

ssd1306_i2c_addr = 60
display_width =128
display_height = 64
display_bus = displayio.I2CDisplay(
    i2c, device_address=ssd1306_i2c_addr)
display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(adafruit_displayio_ssd1306.__name__,
      adafruit_displayio_ssd1306.__version__)
print("SCL: ", board.SCL)
print("SDA: ", board.SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
#================================================
# Make the display context
group = displayio.Group()

NUM_OF_COLOR = 2
bitmap = displayio.Bitmap(display_width,
                          display_height,
                          NUM_OF_COLOR)
bitmap_palette = displayio.Palette(NUM_OF_COLOR)
bitmap_palette[0] = 0x000000
bitmap_palette[1] = 0xFFFFFF

tileGrid = displayio.TileGrid(bitmap,
                              pixel_shader=bitmap_palette,
                              x=0, y=0)
group.append(tileGrid)
display.show(group)

time.sleep(1)
bitmap.fill(1)

def range_f(start, stop, step):
    f = start
    while f < stop:
        yield f
        f += step
        
time.sleep(1)
for y in range_f(0, display_height-1, 2):
    for x in range_f(0, display_width-1, 2):
        #print(str(x) + " : " + str(y))
        bitmap[x, y] = 0

time.sleep(1)
#========================================================
# Draw a label
text_group1 = displayio.Group(scale=3, x=0, y=0)
text1 = "Hello"
text_area1 = label.Label(terminalio.FONT,
                         text=text1, color=0xFFFFFF)
text_group1.append(text_area1)
group.append(text_group1)

for xy in range(20):
    time.sleep(0.1)
    text_group1.x=xy
    text_group1.y=xy
#========================================================
#invert palette
time.sleep(1)
bitmap_palette[1] = 0x000000
bitmap_palette[0] = 0xFFFFFF

time.sleep(1)
y = 0
for x in range_f(0, display_width-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)
x = display_width-1
for y in range_f(0, display_height-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)

y = display_height-1
for x in range_f(0, display_width-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)
x = 0
for y in range_f(0, display_height-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)

#invert palette
time.sleep(1)
bitmap_palette[0] = 0x000000
bitmap_palette[1] = 0xFFFFFF
#invert palette
time.sleep(1)
bitmap_palette[1] = 0x000000
bitmap_palette[0] = 0xFFFFFF

time.sleep(1)
bitmap.fill(1)
time.sleep(1)
for xy in range(20):
    time.sleep(0.1)
    text_group1.x=xy+20
    text_group1.y=xy+20
time.sleep(1)
print("- bye -")

cpyX_displayio_ssd1306_ani.py
"""
CircuitPython 7.2.3 exercise run on
Seeed XIAO nRF52840 Sense with nRF52840
- display on SSD1306 I2C OLED
- using adafruit_displayio_ssd1306
- with animation

lib needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_text folder
- adafruit_display_shapes folder
"""

import os
import sys
import board
import busio
import time

import displayio
import terminalio
import adafruit_displayio_ssd1306
from adafruit_display_text import label
from adafruit_display_shapes.roundrect import RoundRect
from adafruit_display_shapes.rect import Rect

displayio.release_displays()

# Create the I2C interface and display object of SSD1306_I2C.
i2c = busio.I2C(board.SCL, board.SDA)

ssd1306_i2c_addr = 60
display_width =128
display_height = 64
display_bus = displayio.I2CDisplay(
    i2c, device_address=ssd1306_i2c_addr)
display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(adafruit_displayio_ssd1306.__name__,
      adafruit_displayio_ssd1306.__version__)
print("SCL: ", board.SCL)
print("SDA: ", board.SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
#================================================
# Make the display context
group = displayio.Group()

NUM_OF_COLOR = 2
bitmap = displayio.Bitmap(display_width,
                          display_height,
                          NUM_OF_COLOR)
bitmap_palette = displayio.Palette(NUM_OF_COLOR)
bitmap_palette[0] = 0x000000
bitmap_palette[1] = 0xFFFFFF

tileGrid = displayio.TileGrid(bitmap,
                              pixel_shader=bitmap_palette,
                              x=0, y=0)
group.append(tileGrid)
display.show(group)

time.sleep(1)
bitmap.fill(1)

def range_f(start, stop, step):
    f = start
    while f < stop:
        yield f
        f += step
 
time.sleep(1)
for y in range_f(0, display_height-1, 2):
    for x in range_f(0, display_width-1, 2):
        #print(str(x) + " : " + str(y))
        bitmap[x, y] = 0

time.sleep(1)

#========================================================
# Draw a label
text_group1 = displayio.Group(scale=3, x=0, y=0)
text1 = "Hello"
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFFFFFF)
text_group1.append(text_area1)
group.append(text_group1)

text_group1.x=20
text_group1.y=20
#========================================================
#invert palette
time.sleep(1)
bitmap_palette[1] = 0x000000
bitmap_palette[0] = 0xFFFFFF

time.sleep(1)
y = 0
for x in range_f(0, display_width-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)
x = display_width-1
for y in range_f(0, display_height-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)

y = display_height-1
for x in range_f(0, display_width-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)
x = 0
for y in range_f(0, display_height-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)

#================================================
#prepare to animate somethin
group_ani = displayio.Group(scale=1)
group_ani.x = 0
group_ani.y = 0
label_ani = label.Label(terminalio.FONT,
                        text="  hello  ",
                        color=0xFFFFFF)
label_ani.anchor_point = (0.0, 0.0)
label_ani.anchored_position = (0, 0)
label_ani_width = label_ani.bounding_box[2]
label_ani_height = label_ani.bounding_box[3]
shape_ani = RoundRect(x=0, y=0,
                       width=label_ani_width,
                       height=label_ani_height,
                       r=6,
                       fill=0x000000,
                       outline=0xFFFFFF, stroke=1)

group_ani.append(shape_ani)
group_ani.append(label_ani)
group.append(group_ani)
#================================================
#prepare to somethin on fixed position
group_fix = displayio.Group(scale=2)
group_fix.x = 70
group_fix.y = 20
label_fix = label.Label(terminalio.FONT,
                        text=":)",
                        color=0xFFFFFF)
label_fix.anchor_point = (0.0, 0.0)
label_fix.anchored_position = (0, 0)
label_fix_width = label_fix.bounding_box[2]
label_fix_height = label_fix.bounding_box[3]
shape_fix = Rect(x=0, y=0,
                 width=label_fix_width,
                 height=label_fix_height,
                 fill=0x000000,
                 outline=0xFFFFFF, stroke=1)

group_fix.append(shape_fix)
group_fix.append(label_fix)
group.append(group_fix)
#=== loop of animation ===
aniXMove = +1
aniYMove = +1
aniXLim = display_width - 1 - label_ani_width
aniYLim = display_height - 1 - label_ani_height

NxAniMs = time.monotonic() + 3

while True:
    time.sleep(0.05)
    
    if time.monotonic() > NxAniMs:
        NxAniMs = time.monotonic() + 1
        
    #Move Temperate group
    x = group_ani.x + aniXMove
    group_ani.x = x
    if aniXMove > 0:
        if x >= aniXLim:
            aniXMove = -1
    else:
        if x <= 0:
            aniXMove = +1
            
    y = group_ani.y + aniYMove
    group_ani.y = y
    if aniYMove > 0:
        if y > aniYLim:
            aniYMove = -1
    else:
        if y <= 0:
            aniYMove = +1
                        
print("- bye -")
next:
XIAO BLE Sense (nRF52840)/CircuitPython generate QR Code and display on SSD1306 I2C OLED


Sunday, March 27, 2022

Install MicroPython on Nucleo F401RE, run on Linux Mint.

To install Install MicroPython on Nucleo F401RE, visit https://micropython.org/download/NUCLEO_F401RE/ to download MicroPython firmware for Nucleo F401RE, in .hex format.

st-flash is used to flash Nucleo F401RE.

To install st-flash, run the command:
$ sudo apt install stlink-tools

To erase existing filesystem:
$ st-flash erase

To flash the .hex file:
$ st-flash --format ihex write firmware.hex



NUCLEO-F401RE

NUCLEO-F401RE is a STM32 Nucleo-64 development board with STM32F401RE MCU.



Development Tools/platforms:

- STM32CubeIDE is an advanced C/C++ development platform with peripheral configuration, code generation, code compilation, and debug features for STM32 microcontrollers and microprocessors.


https://os.mbed.com/ide is a mbed online compiler.


Mbed Studio is a free desktop IDE for Mbed OS application and library development, including all the dependencies and tools you need in a single package so that you can create, compile and debug your Mbed programs on the desktop.


Install MicroPython on Nucleo F401RE, run on Linux Mint.



Saturday, March 26, 2022

CircuitPython 7 on Seeed XIAO BLE Sense

TO install CircuitPython on XIAO BLE Sense, follow the page XIAO BLE with CircuitPython.

cpyX_info.py, get system info.
"""
CircuitPython 7 exercise run on XIAO BLE Sense,
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(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("microcontroller.cpu.frequency:\t\t" + color.RED +
      str(microcontroller.cpu.frequency) + color.END + " Hz")
print("microcontroller.cpu.temperature:\t" + color.RED +
      str(microcontroller.cpu.temperature) + color.END + " C")
print("microcontroller.cpu.voltage:\t\t" + color.RED +
      str(microcontroller.cpu.voltage) + color.END + " V")
print()



cpyX_pins_name.py, list pins name.
"""CircuitPython Essentials Pin Map Script"""
import microcontroller
import board

board_pins = []
for pin in dir(microcontroller.pin):
    if isinstance(getattr(microcontroller.pin, pin), microcontroller.Pin):
        pins = []
        
        pins.append("microcontroller.{}".format(pin))
        pins.append('\t-')
        
        for alias in dir(board):
            if getattr(board, alias) is getattr(microcontroller.pin, pin):
                pins.append("board.{}\t".format(alias))
        if len(pins) > 0:
            board_pins.append(" ".join(pins))
for pins in sorted(board_pins):
    print(pins)


output:

microcontroller.P0_00 	-
microcontroller.P0_01 	-
microcontroller.P0_02 	- board.A0	 board.D0	
microcontroller.P0_03 	- board.A1	 board.D1	
microcontroller.P0_04 	- board.A4	 board.D4	 board.SDA	
microcontroller.P0_05 	- board.A5	 board.D5	 board.SCL	
microcontroller.P0_06 	- board.LED_BLUE	
microcontroller.P0_07 	- board.IMU_SDA	
microcontroller.P0_08 	-
microcontroller.P0_09 	- board.NFC1	
microcontroller.P0_10 	- board.NFC2	
microcontroller.P0_11 	- board.IMU_INT1	
microcontroller.P0_12 	-
microcontroller.P0_13 	-
microcontroller.P0_14 	- board.READ_BATT_ENABLE	
microcontroller.P0_15 	-
microcontroller.P0_16 	- board.PDM_DATA	
microcontroller.P0_17 	- board.CHARGE_STATUS	
microcontroller.P0_18 	-
microcontroller.P0_19 	-
microcontroller.P0_20 	-
microcontroller.P0_21 	-
microcontroller.P0_22 	-
microcontroller.P0_23 	-
microcontroller.P0_24 	-
microcontroller.P0_25 	-
microcontroller.P0_26 	- board.LED	 board.LED_RED	
microcontroller.P0_27 	- board.IMU_SCL	
microcontroller.P0_28 	- board.A2	 board.D2	
microcontroller.P0_29 	- board.A3	 board.D3	
microcontroller.P0_30 	- board.LED_GREEN	
microcontroller.P0_31 	- board.VBATT	
microcontroller.P1_00 	- board.PDM_CLK	
microcontroller.P1_01 	-
microcontroller.P1_02 	-
microcontroller.P1_03 	-
microcontroller.P1_04 	-
microcontroller.P1_05 	-
microcontroller.P1_06 	-
microcontroller.P1_07 	-
microcontroller.P1_08 	- board.IMU_PWR	
microcontroller.P1_09 	-
microcontroller.P1_10 	- board.MIC_PWR	
microcontroller.P1_11 	- board.D6	 board.TX	
microcontroller.P1_12 	- board.D7	 board.RX	
microcontroller.P1_13 	- board.D8	 board.SCK	
microcontroller.P1_14 	- board.D9	 board.MISO	
microcontroller.P1_15 	- board.D10	 board.MOSI






reference:

more exercise:
Seeed XIAO BLE Sense (nRF52840)/CircuitPython 7.2.3 display on SSD1306 I2C OLED
XIAO BLE Sense (nRF52840)/CircuitPython generate QR Code and display on SSD1306 I2C OLED
CircuitPython BLE UART between XIAO BLE Sense and ESP32-C3/S3

Monday, March 21, 2022

Arduino Nano RP2040 Connect/CircuitPython + ov7670 cam (incomplete) display on st7789 Display

It's just my exercise running on Arduino Nano RP2040 Connect/CircuitPython 7.2.3, to work with ov7670 cam module and display on ST7789 SPI display.


For the connection between Nano RP2040 Connect and ov7670/st7789, refer to the code listed below.

In my practice, pre-defined SPI MOSI/SCK are assigned to SDA/SCL for ST7789. I2C SCL/SDA are assigned to SCL/SDA for ov7670.

*ov7670 SCL/SDA are I2C-like control pins, pull-up resistors are needed. 2K ohm resistors are used in my exercise.

For the st7789 part, it's very straightforward - just install libraries and run the exercise code.
Libraries adafruit_st7789 and adafruit_display_text are needed.

For ov7670 part, libraries adafruit_st7789 and adafruit_ov7670 are needed. adafruit_ov7670 is a CircuitPython driver for OV7670 cameras.

The problem is in adafruit_ov7670, data_pins is a list of 8 data pins in sequential order.  But I can't find 8 continuous sequence GPIO on Nano RP2040 Connect. As an exercise, GPIO14~21 are assigned to ov7670 d0~d7, GPIO14 is internal connceted to SCK of the onboard ESP32 (U-blox Nina W102), so it's actually no use. So there are only 7 bits in parallel data bus, and ESP32 SCK is mis-used (you should cannot use ESP32 at the same time). That's why I call it "incomplete".

It seem functionally work, as shown in the video. But I don't know any side-effect. It's just my exercise and not suggested, or follow at your own risk.

To list pins name of all GPIOs (include internal), read last post.


cpyNrp2040_spiST7789_320.py
"""
Example of Arduino Nano RP2040 Connect/CircuitPython 7.2.3
to display on 2.0" IPS 240x320 (RGB) screen
with SPI ST7789 driver.

Connection between Nano RP2040 Connect and
the SPI ST7789 IPS screen.

BLK  - 3V3 (backlight, always on)
CS   - A0
DC   - A1
RES  - A2
SDA  - D11 (=MOSI)
SCL  - D13 (=SCK)
VCC  - 3V3
GND  - GND
"""

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

print("=====================================")
info = sys.implementation[0] + ' ' + \
       os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("board_id:", board.board_id)

print("with number of cpu: " +
      str(len(microcontroller.cpus)))
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.A0
tft_dc = board.A1
tft_res = board.A2
spi_mosi = board.D11
spi_clk = board.D13

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(clock=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()
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(scale=1, x=20, y=40)
text1 = os.uname()[4]
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(scale=1, x=20, y=60)
text2 = sys.implementation[0] + " " + os.uname()[3]
text_area2 = label.Label(terminalio.FONT, text=text2, color=0x00FF00)
text_group2.append(text_area2)  # Subgroup for text scaling

# Draw a label
text_group3 = displayio.Group(scale=2, x=20, y=100)
text3 = adafruit_st7789.__name__
text_area3 = label.Label(terminalio.FONT, text=text3, color=0xFFFFFF)
text_group3.append(text_area3)  # Subgroup for text scaling
# Draw a label
text_group4 = displayio.Group(scale=2, x=20, y=120)
text4 = adafruit_st7789.__version__
text_area4 = label.Label(terminalio.FONT, text=text4, color=0xFFFFFF)
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

cpyNrp2040_ov7670_displayio_pico_st7789.py
"""
Run on Arduino NANO RP2040 Connect/CircuitPython 7.2.3
+ ov7670 cam + st7789 LCD.

Capture images from the camera and display it on LCD.

Modified from ov7670_displayio_pico_st7789_2in.py example

ref:
Adafruit CircuitPython ov7670 Library
https://docs.circuitpython.org/projects/ov7670/
"""

import time
from displayio import (
    Bitmap,
    Group,
    TileGrid,
    FourWire,
    release_displays,
    ColorConverter,
    Colorspace,
)

import board
import microcontroller
import busio
import digitalio
import displayio
import adafruit_st7789
import adafruit_ov7670

"""
Connection between Nano RP2040 Connect and
the SPI ST7789 IPS screen.
==========================================
BLK  - 3V3 (backlight, always on)
CS   - A0
DC   - A1
RES  - A2
SDA  - D11 (MOSI)
SCL  - D13 (SCK)
VCC  - 3V3
GND  - GND
"""

tft_cs = board.A0
tft_dc = board.A1
tft_res = board.A2
spi_mosi = board.D11
spi_clk = board.D13

"""
Connection between Arduino Nano RP2040 Connect and
the ov7670 camera module.
==========================================
              ov7670
             +-----------+
    3V3      |3V3    GND | GND
    A5 (SCL) |SCL    SDA | A4 (SDA)
    TX       |VS     HS  | RX
    D12      |PLK    XLK | D10
    D9       |D7     D6  | D8
    D7       |D5     D4  | D6
    D5       |D3     D2  | D4
    D3       |D1     D0  | XXX
    A3       |RET    PWDN| -
             +-----------+
			 
*ov7670 SCL/SDA are I2C-like control pins, pull-up resistors are needed.
 I use 2K ohm resistor for it.
"""
cam_scl = board.A5
cam_sda = board.A4
cam_vs = board.TX
cam_hs = board.RX
cam_plk = board.D12
cam_xlk = board.D10
cam_ret = board.A3

# cam data pins must be sequential
# I can't find 8 continuous sequence GPIO on Nano RP2040 Connect
# As a exercise, I assign GPIO14~21 to d0~d7,
# GPIO14 is internal connceted to onboard ESP32 SCK,
# so it's actually no use.
cam_d0 = board.SCK1 # GPIO14
cam_d1 = board.D3   # GPIO15
cam_d2 = board.D4   # GPIO16
cam_d3 = board.D5   # GPIO17
cam_d4 = board.D6   # GPIO18
cam_d5 = board.D7   # GPIO19
cam_d6 = board.D8   # GPIO20
cam_d7 = board.D9   # GPIO21

release_displays()

# Set up the display
spi = busio.SPI(clock=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.auto_refresh = False

# Ensure the camera is shut down,
# so that it releases the SDA/SCL lines,
# then create the configuration I2C bus

with digitalio.DigitalInOut(cam_ret) as reset:
    reset.switch_to_output(False)
    time.sleep(0.001)
    bus = busio.I2C(cam_scl, cam_sda)

# Set up the camera
cam = adafruit_ov7670.OV7670(
    bus,
    data_pins=[
        cam_d0,
        cam_d1,
        cam_d2,
        cam_d3,
        cam_d4,
        cam_d5,
        cam_d6,
        cam_d7,
    ],  #Pins must be sequential
    clock=cam_plk,
    vsync=cam_vs,
    href=cam_hs,
    mclk=cam_xlk,
    shutdown=None,
    reset=cam_ret,
)

#cam.test_pattern = adafruit_ov7670.OV7670_TEST_PATTERN_COLOR_BAR

print(adafruit_ov7670.__name__ + " version: "
      + adafruit_ov7670.__version__)
print(adafruit_st7789.__name__ + " version: "
      + adafruit_st7789.__version__)
pid = cam.product_id
ver = cam.product_version
print(f"Detected cam pid={pid:x} ver={ver:x}")

width = display.width
height = display.height

bitmap = None
# Select the biggest size for which we can allocate a bitmap successfully,
# and which is not bigger than the display
for size in range(adafruit_ov7670.OV7670_SIZE_DIV1,
                  adafruit_ov7670.OV7670_SIZE_DIV16 + 1):
    cam.size = size
    if cam.width > width:
        continue
    if cam.height > height:
        continue
    try:
        bitmap = Bitmap(cam.width, cam.height, 65536)
        break
    except MemoryError:
        continue

print(width, height, cam.width, cam.height)
if bitmap is None:
    raise SystemExit("Could not allocate a bitmap")

g = Group(scale=1,
          x=(width - cam.width) // 2,
          y=(height - cam.height) // 2)
tg = TileGrid(
    bitmap, pixel_shader=ColorConverter(
        input_colorspace=Colorspace.RGB565_SWAPPED)
)
g.append(tg)
display.show(g)

#t0 = time.monotonic_ns()
display.auto_refresh = False
while True:
    cam.capture(bitmap)
    bitmap.dirty()
    display.refresh(minimum_frames_per_second=0)
    #t1 = time.monotonic_ns()
    #print("fps", 1e9 / (t1 - t0))
    #t0 = t1


Saturday, March 19, 2022

Nano RP2040 Connect/CircuitPython: list pins name of GPIOs

Many pins on CircuitPython compatible microcontroller boards have multiple names, however, typically, there's only one name labeled on the physical board. This example (modified from CircuitPython on the Arduino Nano RP2040 Connect > CircuitPython Pins and Modules > What Are All the Available Names?) run on Arduino Nano RP2040 Connect/CircuitPython 7.2.3 to list available pin names for all GPIOs.

"""CircuitPython Essentials Pin Map Script"""
import microcontroller
import board

board_pins = []
for pin in dir(microcontroller.pin):
    if isinstance(getattr(microcontroller.pin, pin), microcontroller.Pin):
        pins = []
        
        pins.append("microcontroller.{}".format(pin))
        pins.append('\t-')
        
        for alias in dir(board):
            if getattr(board, alias) is getattr(microcontroller.pin, pin):
                pins.append("board.{}\t".format(alias))
        if len(pins) > 0:
            board_pins.append(" ".join(pins))
for pins in sorted(board_pins):
    print(pins)




Fix "RuntimeError: None data for /?", in CircuitPython on Arduino Nano RP2040 Connect

To install CircuitPython on Arduino Nano RP2040 Connect, it's straightforward to following instruction in Adafruit document  "CircuitPython on the Arduino Nano RP2040 Connect > Install CircuitPython".

After CircuitPython 7.2.3 was installed on Arduino Nano RP2040 Connect, I can run REPL. BUT...I can't access CircuitPython device (named "?"), Problem when handling 'get_dirs_children_info_response' with "RuntimeError: None data for /?"!

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/thonny/workbench.py", line 1711, in event_generate
    handler(event)
  File "/usr/lib/python3/dist-packages/thonny/base_file_browser.py", line 1001, in update_dir_data
    self.render_children_from_cache(msg["node_id"])
  File "/usr/lib/python3/dist-packages/thonny/base_file_browser.py", line 430, in render_children_from_cache
    raise RuntimeError("None data for %s" % path)
RuntimeError: None data for /?



Solution in my case:

I follow "To erase CIRCUITPY" section in CircuitPython on the Arduino Nano RP2040 Connect > Troubleshooting.

Enter in CircuitPython REPL:
>>> import storage
>>> storage.erase_filesystem()

Then, the problem fixed.


Thursday, March 17, 2022

BLE between Nano RP2040 Connect and XIAO BLE Sense, using ArduinoBLE in Arduino Framework.

 Last post a simple ArduinoBLE between Nano RP2040 Connect (Peripheral LED) and XIAO BLE Sense (Central LedControl), this is further exercise in reverse role, with additional feature displaying on OLED.

Seeed XIAO BLE Sense:
XIAOBLE_CallbackLED_OLED.ino,
act as BLE Peripheral, control LED and OLED display base on BLE received data.

Arduino Nano RP2040 Connect:
RP2040Con_LedControl_OLED.ino,
act as BLE Central, read button (the yellow wire) and get user input from Serial, send to Peripheral to control LED and display on OLED.



XIAOBLE_CallbackLED_OLED.ino
/*
  Run on XIAO BLESensor:

  This example creates a BLE peripheral with service that contains a
  characteristic to control an LED and OLED. The callback features of the
  library are used.

  Modified from ArduinoBLE > Peripheral > CallbackLED example

*/

#include <ArduinoBLE.h>
#include <Arduino.h>
#include <U8x8lib.h>
#include <Wire.h>

#define MyLocalName "XIAO BLE"
#define MyStringChar_UUID "22a28815-c6bd-401b-a0f1-d47c42a0bd70"

U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // create service

// create switch characteristic and allow remote device to read and write
BLEByteCharacteristic switchCharacteristic(
              "19B10001-E8F2-537E-4F6C-D104768A1214", 
              BLERead | BLEWrite);
BLEStringCharacteristic myStringCharacteristic(
              MyStringChar_UUID,
              BLERead | BLEWrite, 16);

const int ledPin = LED_BUILTIN; // pin to use for the LED

void setup() {
  u8x8.begin();
  u8x8.setFlipMode(1); //rotary 180

  u8x8.setFont(u8x8_font_chroma48medium8_r);
  u8x8.setCursor(0, 0);
  u8x8.print("XIAO BLE");
  
  Serial.begin(9600);

  //comment to skip Serial port waiting,
  //such that it can sork stand alone without computer.
  //while (!Serial);
  
  pinMode(ledPin, OUTPUT); // use the LED pin as an output

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  // set the local name peripheral advertises
  BLE.setLocalName(MyLocalName);
  // set the UUID for the service this peripheral advertises
  BLE.setAdvertisedService(ledService);

  // add the characteristic to the service
  ledService.addCharacteristic(switchCharacteristic);
  ledService.addCharacteristic(myStringCharacteristic);

  // add service
  BLE.addService(ledService);

  // assign event handlers for connected, disconnected to peripheral
  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  // assign event handlers for characteristic
  switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);
  myStringCharacteristic.setEventHandler(BLEWritten, myStringCharacteristicWritten);
  // set an initial value for the characteristic
  switchCharacteristic.setValue(0);
  myStringCharacteristic.setValue("XIAO BLE");

  // start advertising
  BLE.advertise();

  Serial.println(("Bluetooth device active, waiting for connections..."));
}

void loop() {
  // poll for BLE events
  BLE.poll();
}

void blePeripheralConnectHandler(BLEDevice central) {
  // central connected event handler
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLEDevice central) {
  // central disconnected event handler
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
}

void switchCharacteristicWritten(BLEDevice central, 
                      BLECharacteristic characteristic) {
  // central wrote new value to characteristic, update LED
  Serial.print("Characteristic event, written: ");

  if (switchCharacteristic.value()) {
    Serial.println("LED on");
    digitalWrite(ledPin, !HIGH);
  } else {
    Serial.println("LED off");
    digitalWrite(ledPin, !LOW);
  }
}

void myStringCharacteristicWritten(BLEDevice central, 
                      BLECharacteristic characteristic) {
  // central wrote new value to characteristic, update LED
  Serial.println("mySttringCharacteristic event, written: ");

  Serial.println("myStringCharacteristic received: len=" + 
                  String(myStringCharacteristic.valueLength()));
  String valString = myStringCharacteristic.value();
  Serial.println(valString);

  u8x8.clear();
  u8x8.setCursor(0, 0);
  u8x8.print(valString);

  Serial.println();
}

RP2040Con_LedControl_OLED.ino
/*
  run on Aduino RP2040 NANO Connect

  This example scans for BLE peripherals until one with the advertised service
  "19b10000-e8f2-537e-4f6c-d104768a1214" UUID is found. Once discovered and connected,
  it will remotely control the BLE Peripheral's LED, when the button is pressed or released.

  And also get user input from Serial Monitor, send to BLE Peripheral

  modified from ArduinoBLE > Central > LedControl
*/

#include <ArduinoBLE.h>

// variables for button
const int buttonPin = 2;
int oldButtonState = LOW;

#define MyLocalName "XIAO BLE"
#define MyStringChar_UUID "22a28815-c6bd-401b-a0f1-d47c42a0bd70"

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // configure the button pin as input
  pinMode(buttonPin, INPUT_PULLUP);

  // initialize the BLE hardware
  BLE.begin();

  Serial.println("BLE Central - LED control");

  // start scanning for peripherals
  BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
}

void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();

  if (peripheral) {
    // discovered a peripheral, print out address, local name, and advertised service
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();

    if (peripheral.localName() != MyLocalName) {
      return;
    }

    // stop scanning
    BLE.stopScan();

    controlLed(peripheral);

    // peripheral disconnected, start scanning again
    BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
  }
}

void controlLed(BLEDevice peripheral) {
  // connect to the peripheral
  Serial.println("Connecting ...");

  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    return;
  }

  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }

  // retrieve the LED/OLED characteristic
  BLECharacteristic ledCharacteristic = peripheral.characteristic("19b10001-e8f2-537e-4f6c-d104768a1214");
  BLECharacteristic oledCharacteristic = peripheral.characteristic(MyStringChar_UUID);
  
  /*
  if (!ledCharacteristic) {
    Serial.println("Peripheral does not have LED characteristic!");
    peripheral.disconnect();
    return;
  } else if (!ledCharacteristic.canWrite()) {
    Serial.println("Peripheral does not have a writable LED characteristic!");
    peripheral.disconnect();
    return;
  }
  */

  while (peripheral.connected()) {
    // while the peripheral is connected

    // read the button pin
    int buttonState = !digitalRead(buttonPin);

    if (oldButtonState != buttonState) {
      // button changed
      oldButtonState = buttonState;

      if (buttonState) {
        Serial.println("button pressed");

        // button is pressed, write 0x01 to turn the LED on
        ledCharacteristic.writeValue((byte)0x01);
      } else {
        Serial.println("button released");

        // button is released, write 0x00 to turn the LED off
        ledCharacteristic.writeValue((byte)0x00);
      }
    }

    if (Serial.available() > 0){
      String stringIn = Serial.readString();
      Serial.println(stringIn);
      oledCharacteristic.writeValue(stringIn.c_str());
    }
  }

  Serial.println("Peripheral disconnected");
}


Tuesday, March 15, 2022

ArduinoBLE between Nano RP2040 Connect (Peripheral LED) and XIAO BLE Sense (Central LedControl)

Just examples of ArduinoBLE, on Nano RP2040 Connect and XIAO BLE Sense (Arduino Framework). Both using ArduinoBLE library.


Arduino Nano RP2040 Connect act as Peripher, wait connection from Central, turn ON/OFF on board LED according to received byte from BLE.

Make sure select board "Arduino Nano RP2040 Connect" from "Arduino Mbed OS Nano Boards" (refer to last post Remark on "Arduino Nano RP2040 Connect" of "Arduino Mbed OS Boards" vs "Arduino Mbed OS Nano Boards").

Load with ArduinoBLE > Peripheral > LED example.

XIAO BLE Sense (with Seeeduino XIAO Expansion board) act as Central, connect Peripher, send command base on user button on Expansion board, to control LED on off.

Load with ArduinoBLE > Central > LedControl example.

To  make it work, change in following, marked in RED:

XIAOBLE_LedControl.ino
/*
  LED Control

  This example scans for BLE peripherals until one with the advertised service
  "19b10000-e8f2-537e-4f6c-d104768a1214" UUID is found. Once discovered and connected,
  it will remotely control the BLE Peripheral's LED, when the button is pressed or released.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.
  - Button with pull-up resistor connected to pin 2.

  You can use it with another board that is compatible with this library and the
  Peripherals -> LED example.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

// variables for button
const int buttonPin = 1;
int oldButtonState = LOW;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // configure the button pin as input
  pinMode(buttonPin, INPUT_PULLUP);

  // initialize the BLE hardware
  BLE.begin();

  Serial.println("BLE Central - LED control");

  // start scanning for peripherals
  BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
}

void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();

  if (peripheral) {
    // discovered a peripheral, print out address, local name, and advertised service
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();

    if (peripheral.localName() != "LED") {
      return;
    }

    // stop scanning
    BLE.stopScan();

    controlLed(peripheral);

    // peripheral disconnected, start scanning again
    BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
  }
}

void controlLed(BLEDevice peripheral) {
  // connect to the peripheral
  Serial.println("Connecting ...");

  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    return;
  }

  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }

  // retrieve the LED characteristic
  BLECharacteristic ledCharacteristic = peripheral.characteristic("19b10001-e8f2-537e-4f6c-d104768a1214");

  if (!ledCharacteristic) {
    Serial.println("Peripheral does not have LED characteristic!");
    peripheral.disconnect();
    return;
  } else if (!ledCharacteristic.canWrite()) {
    Serial.println("Peripheral does not have a writable LED characteristic!");
    peripheral.disconnect();
    return;
  }

  while (peripheral.connected()) {
    // while the peripheral is connected

    // read the button pin
    int buttonState = !digitalRead(buttonPin);

    if (oldButtonState != buttonState) {
      // button changed
      oldButtonState = buttonState;

      if (buttonState) {
        Serial.println("button pressed");

        // button is pressed, write 0x01 to turn the LED on
        ledCharacteristic.writeValue((byte)0x01);
      } else {
        Serial.println("button released");

        // button is released, write 0x00 to turn the LED off
        ledCharacteristic.writeValue((byte)0x00);
      }
    }
  }

  Serial.println("Peripheral disconnected");
}



next:
BLE between Nano RP2040 Connect and XIAO BLE Sense, using ArduinoBLE in Arduino Framework.

Remark on "Arduino Nano RP2040 Connect" of "Arduino Mbed OS Boards" vs "Arduino Mbed OS Nano Boards"

It's my case of selecting "Arduino Nano RP2040 Connect" of "Arduino Mbed OS Boards" vs "Arduino Mbed OS Nano Boards".

The case is:
I have both Arduino Nano RP2040 Connect and Seeed XIAO BLE (Sense).

To program in Arduino IDE (1.8.15), follow this post (in my another blogspot) to install Arduino Mbed OS Nano Boards for Arduino Nano RP2040 Connect, and follow former post to install Seeed nRF52 Boards for Seeed XIAO nRF52840 Sense.

After then, there are two selection of "Arduino Nano RP2040 Connect" from "Arduino Mbed OS Boards" and "Arduino Mbed OS Nano Boards".

Case I - "Arduino Nano RP2040 Connect" from "Arduino Mbed OS Boards", actually it come from Seeed nRF52 Boards 2.6.1:


Select board "Arduino Nano RP2040 Connect" from "Arduino Mbed OS Boards"


If you have ArduinoBLE library installed, its examples is located within INCOMPATIBLE.


If you compile any example, even Blink, error will be reported!


Arduino: 1.8.15 (Linux), Board: "Arduino Nano RP2040 Connect"

WARNING: library ArduinoBLE claims to run on samd, megaavr, mbed, apollo3, mbed_nano, mbed_portenta architecture(s) and may be incompatible with your current board which runs on nrf52 architecture(s).
Traceback (most recent call last):
  File "/home/pi/.local/bin/adafruit-nrfutil", line 10, in <module>
    sys.exit(cli())
  File "/usr/lib/python3/dist-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python3/dist-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python3/dist-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python3/dist-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python3/dist-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/home/pi/.local/lib/python3.7/site-packages/nordicsemi/__main__.py", line 239, in genpkg
    package.generate_package(zipfile_path)
  File "/home/pi/.local/lib/python3.7/site-packages/nordicsemi/dfu/package.py", line 189, in generate_package
    Package.normalize_firmware_to_bin(work_directory, firmware[FirmwareKeys.FIRMWARE_FILENAME])
  File "/home/pi/.local/lib/python3.7/site-packages/nordicsemi/dfu/package.py", line 329, in normalize_firmware_to_bin
    temp.tobinfile(new_filepath)
  File "/home/pi/.local/lib/python3.7/site-packages/nordicsemi/dfu/nrfhex.py", line 160, in tobinfile
    start_address = self.minaddr()
  File "/home/pi/.local/lib/python3.7/site-packages/nordicsemi/dfu/nrfhex.py", line 114, in minaddr
    min_address = max(self.get_mbr_end_address(), min_address)
TypeError: '>' not supported between instances of 'NoneType' and 'int'
exit status 1
Error compiling for board Arduino Nano RP2040 Connect.


This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Case II - "Arduino Nano RP2040 Connect" from"Arduino Mbed OS Nano Boards" 2.8.0:


Select board "Arduino Nano RP2040 Connect" from "Arduino Mbed OS Nano Boards"


Now ArduinoBLE example is located under Custom Libraries.


Compile and Upload without error.


Monday, March 14, 2022

XIAO BLE Sense/Expansion board (Arduino Framework) to control SSD1306 I2C OLED

Example run on XIAO BLE Sense/Expansion board (Arduino Framework) to control SSD1306 I2C OLED

Refer to document Seeeduino XIAO Expansion board > OLED Display:
- u8g2 library is suggested
- a example is provided to control the on-Expansion board SSD1306 I2C OLED

To make it work on XIAO BLE Sense/Expansion board (Arduino Framework), change the code as below, using U8X8_SSD1306_128X64_NONAME_HW_I2C instead of U8X8_SSD1306_128X64_NONAME_SW_I2C.

XIAOBLE_OLED.ino

#include <Arduino.h>
#include <U8x8lib.h>
#include <Wire.h>
 
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

void setup(void) {
  u8x8.begin();
  u8x8.setFlipMode(1); //rotary 180
}
 
void loop(void) {
  u8x8.setFont(u8x8_font_chroma48medium8_r);
  u8x8.setCursor(0, 0);
  u8x8.print("Hello World!");
}




Connection of OLED on Seeeduino XIAO Expansion board

According to Seeeduino XIAO Expansion board_v1.0_SCH_200824, OLED SCL and SDA is connected to XIAO D5 and D4.

Sunday, March 13, 2022

Setup Arduino IDE to support Seeed XIAO BLE (Sense), fix 'exec: "adafruit-nrfutil": executable file not found in $PATH'

To add support of Seeed XIAO BLE (Sense) to Arduino IDE:
- File > Preferences
- Add https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json to "Additional Boards Manager URLs"

Tools > Board > Boards Manager...
- Search and install "Seeed nRF52 Boards by Seeed Studio"

Select board:
- Tools > Board > Arduino Mbed OS Boards > "Seeed XIAO nRF52840 Sense"
- Select correct port

Now you can try to program and upload to your XIAO BLE (Sense).

If you run on Linux, including Raspberry Pi OS, you will be reported with error:

exec: "adafruit-nrfutil": executable file not found in $PATH
Error compiling for board Seeed XIAO nRF52840 Sense.

You have to install adafruit-nrfutil manually:

$ pip3 install --user adafruit-nrfutil

Done


ref:
Getting Started with XIAO BLE (Sense)
~ Adafruit Bluefruit nRF52 Feather Learning Guide > Arduino Support Setup

If you have Arduino Nano RP2040 Connect also, check Remark on "Arduino Nano RP2040 Connect" of "Arduino Mbed OS Boards" vs "Arduino Mbed OS Nano Boards".

Friday, March 11, 2022

Install CircuitPython 7.2.0 on ESP32-S3 (ESP32-S3-DevKitC-1), using esptool v3.2 on Linux Mint

CircuitPython 7.2.0 was released. With espressif ESP32-S3 and ESP32-C3 supported (considered alpha and will have bugs and missing functionality).

To flash firmware on esp32s3, esptool v3.2 is needed. This post show the steps to flash CircuitPython 7.2.0 on ESP32-S3-DevKitC-1 N8R8 (with 8MB Flash and 8MB PSRAM) run on Linux Mint (over VirtualBox/Windows 10).



Visit CircuitPython download page, search "S3" and download .BIN for "ESP32-S3-DevKitC-1-N8R8 by Espressif".

Connect USB to the port marked "UART".

To check the ESP chip ID and Flash using commands:
$ esptool.py --chip auto --port /dev/ttyUSB0 chip_id
$ esptool.py --chip auto --port /dev/ttyUSB0 flash_id

Erase flash:
$ esptool.py --port /dev/ttyUSB0 erase_flash

Flash firmware:
$ esptool.py --chip esp32s3 --port <port> write_flash \-z 0x0 <file.BIN>

To program using CircuitPython, re-connect USB to the port marked "USB".

cpyESP32S3_info.py

"""
CircuitPython 7.2.0 exercise run on ESP32-S3,
get system info.
"""
import board
import sys
import os
"""
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()
cpyESP32S3_NEOPIXEL.py, control onboard RGB LED.
import time
import os
import microcontroller
import neopixel
import board

def cycleNeopixel(wait):
    for r in range(255):
        pixel[0] = (r, 0, 0)
        time.sleep(wait)
    for r in range(255, 0, -1):
        pixel[0] = (r, 0, 0)
        time.sleep(wait)
        
    for g in range(255):
        pixel[0] = (0, g, 0)
        time.sleep(wait)
    for g in range(255, 0, -1):
        pixel[0] = (0, g, 0)
        time.sleep(wait)
        
    for b in range(255):
        pixel[0] = (0, 0, b)
        time.sleep(wait)
    for b in range(255, 0, -1):
        pixel[0] = (0, 0, b)
        time.sleep(wait)
        
print("==============================")
print("Hello ESP32-C3/CircuitPython NeoPixel exercise")
#print(os.uname())
for u in os.uname():
    print(u)
print()
print("neopixel version: " + neopixel.__version__)
print()

# Create the NeoPixel object
pixel = neopixel.NeoPixel(board.NEOPIXEL,
                          1,
                          pixel_order=neopixel.GRB)
pixel[0] = (0, 0, 0)
time.sleep(2.0)

cycleNeopixel(0.01)

pixel[0] = (0, 0, 0)
time.sleep(2.0)

print("- bye -\n")

Related:
~ To flash ESP32-S3, esptool v3.2 or above is needed. With esptool upgraded, we can now flash ESP32-S3 on Rspberry Pi.

Next:
CircuitPython BLE UART between XIAO BLE Sense and ESP32-C3/S3


Wednesday, March 9, 2022

Seeed XIAO BLE Sense (nRF52840) + Expansion board

Seeed XIAO BLE Sense (nRF52840) + XIAO Expansion board




ref:
Getting Started with XIAO BLE (Sense)
Seeeduino XIAO Expansion board

Ai-Thinker NodeMCU ESP-C3-32S-Kit and ESP-S3-12K-Kit

Ai-Thinker NodeMCU:
ESP-C3-32S-Kit (internal 4M)
ESP-S3-12K-Kit



Check chip_id and flash_id using esptool:
$ esptool.py --chip auto --port /dev/ttyUSB0 chip_id
$ esptool.py --chip auto --port /dev/ttyUSB0 flash_id
for ESP-C3-32S-Kit:
pi@raspberrypi:~ $ esptool.py --chip auto --port /dev/ttyUSB0 chip_id
esptool.py v3.1
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP32-C3
Chip is unknown ESP32-C3 (revision 3)
Features: Wi-Fi
Crystal is 40MHz
MAC: 34:b4:72:4e:19:f4
Uploading stub...
Running stub...
Stub running...
Warning: ESP32-C3 has no Chip ID. Reading MAC instead.
MAC: 34:b4:72:4e:19:f4
Hard resetting via RTS pin...
pi@raspberrypi:~ $ esptool.py --chip auto --port /dev/ttyUSB0 flash_id
esptool.py v3.1
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP32-C3
Chip is unknown ESP32-C3 (revision 3)
Features: Wi-Fi
Crystal is 40MHz
MAC: 34:b4:72:4e:19:f4
Uploading stub...
Running stub...
Stub running...
Manufacturer: 20
Device: 4016
Detected flash size: 4MB
Hard resetting via RTS pin...



ESP-S3-12K-Kit:
(esptool v3.2 is needed, error reported in esptool v3.1)

Using esptool v3.1 on Raspberry Pi, detected as ESP32-S3(beta3) and reported "A fatal error occurred: Invalid head of packet (0x65)"!
pi@raspberrypi:~ $ esptool.py --chip auto --port /dev/ttyUSB0 chip_id
esptool.py v3.1
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP32-S3(beta3)
Chip is ESP32-S3(beta3)
Features: WiFi, BLE
Crystal is 40MHz
MAC: 00:00:00:00:00:00
Uploading stub...
Running stub...
Stub running...
Warning: ESP32-S3(beta3) has no Chip ID. Reading MAC instead.

A fatal error occurred: Invalid head of packet (0x65)
pi@raspberrypi:~ $ esptool.py --chip auto --port /dev/ttyUSB0 flash_id
esptool.py v3.1
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP32-S3(beta3)
Chip is ESP32-S3(beta3)
Features: WiFi, BLE
Crystal is 40MHz
MAC: 00:00:00:00:00:00
Uploading stub...
Running stub...
Stub running...

A fatal error occurred: Invalid head of packet (0x65)



Using esptool v3.2 on Linux Mint, detected as ESP32-S3 and no error.
eric@eric-VirtualBox:~$ esptool.py --chip auto --port /dev/ttyUSB0 chip_id
esptool.py v3.2
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP32-S3
Chip is ESP32-S3
Features: WiFi, BLE
Crystal is 40MHz
MAC: f4:12:fa:43:65:2c
Uploading stub...
Running stub...
Stub running...
Warning: ESP32-S3 has no Chip ID. Reading MAC instead.
MAC: f4:12:fa:43:65:2c
Hard resetting via RTS pin...
eric@eric-VirtualBox:~$ esptool.py --chip auto --port /dev/ttyUSB0 flash_id
esptool.py v3.2
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP32-S3
Chip is ESP32-S3
Features: WiFi, BLE
Crystal is 40MHz
MAC: f4:12:fa:43:65:2c
Uploading stub...
Running stub...
Stub running...
Manufacturer: c8
Device: 4017
Detected flash size: 8MB
Hard resetting via RTS pin...