Adsense HTML/JavaScript

Showing posts with label Arduino Nano RP2040 Connect. Show all posts
Showing posts with label Arduino Nano RP2040 Connect. Show all posts

Friday, July 22, 2022

Display on I2C SSD1327 grayscale OLED with Arduino Nano RP2040 Connect/CircuitPython

Exercise to display on I2C SSD1327 grayscale OLED with Arduino Nano RP2040 Connect/CircuitPython 7.3.2.


CircuitPython Libraries is needed, visit https://circuitpython.org/libraries to download.

The default I2C pins assigned for Arduino Nano RP2040 Connect/CircuitPython are:
SDA - A4
SCL - A5

The I2C address of my no-brand SSD1327 OLED is 0x3C.



cpyNrp2040_i2c_test.py, I2C test code to I2C pins and address.
import board

i2c = board.I2C()

print("SDA :", board.SDA)
print("SCL :", board.SCL)

while not i2c.try_lock():
    pass

print([hex(x) for x in i2c.scan()])
i2c.unlock()


cpyNrp2040_ssd1327_ani.py
"""
Arduino Nano RP2040 Connect/CircuitPython
128x128 I2C ssd1327 OLED support grayscale
- with something animation.

CircuitPython lib need,
have to be copied to CircutPytho device's /lib:
- adafruit_ssd1327.mpy
- adafruit_display_text folder
- adafruit_display_shapes folder
"""

import time
import board
import displayio
import adafruit_ssd1327
import terminalio
from adafruit_display_text import label
from adafruit_display_shapes.roundrect import RoundRect
from adafruit_display_shapes.rect import Rect

import sys, os

displayio.release_displays()

# print system info
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 = sys.implementation[0] + ' ' + \
       os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=====================================")
print(adafruit_ssd1327.__name__,
      adafruit_ssd1327.__version__)

# Use for I2C
i2c = board.I2C()
#display_bus = displayio.I2CDisplay(i2c, device_address=0x3D)
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)

display_width = display_height = 128

time.sleep(1)
display = adafruit_ssd1327.SSD1327(display_bus,
                                   width=display_width,
                                   height=display_height)

print()
print(display)
print(display.width,"x", display.height)
print()

g = displayio.Group()
color_count = 128
pattern = displayio.Bitmap(display_width,
                           display_height,
                           color_count)
palette = displayio.Palette(color_count)
t = displayio.TileGrid(pattern, pixel_shader=palette)

pattern.fill(color_count-1)

#init palette
for i in range(color_count):
    component = i * 255 // (color_count - 1)
    #print(component)
    palette[i] = component << 16 | component << 8 | component
    
    """
    print(i, ' - ' ,
          component,":",
          hex(component << 16),
          hex(component << 8),
          hex(component))
    """

g.append(t)

display.show(g)

time.sleep(1)

for i in range(color_count):
    for z in range(i+1):
        pattern[z, 0] = i
        pattern[z, i] = i
        pattern[0, z] = i
        pattern[i, z] = i
    #for y in range(i+1):
    #    pattern[0, y] = i
    #    pattern[i, y] = i

    #time.sleep(0.2)

time.sleep(1)

#================================================
#reverse palette
for i in range(color_count):
    component = i * 255 // (color_count - 1)
    palette[color_count-1-i] = (
        component << 16 | component << 8 | component)
    
time.sleep(3)

#re-reverse palette
for i in range(color_count):
    component = i * 255 // (color_count - 1)
    palette[i] = (
        component << 16 | component << 8 | component)
    
time.sleep(1)
#================================================
#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)
g.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)
g.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 ~")



cpyNrp2040_ssd1327_ani2.py
"""
Arduino Nano RP2040 Connect/CircuitPython
128x128 I2C ssd1327 OLED support grayscale
- Change background bitmap by changing palette

CircuitPython lib need,
have to be copied to CircutPytho device's /lib:
- adafruit_ssd1327.mpy
- adafruit_display_text folder
- adafruit_display_shapes folder
"""

import time
import board
import displayio
import adafruit_ssd1327
import terminalio
from adafruit_display_text import label
from adafruit_display_shapes.circle import Circle

import sys, os

displayio.release_displays()

# print system info
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 = sys.implementation[0] + ' ' + \
       os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=====================================")
print(adafruit_ssd1327.__name__,
      adafruit_ssd1327.__version__)

# Use for I2C
i2c = board.I2C()
#display_bus = displayio.I2CDisplay(i2c, device_address=0x3D)
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)

display_width = display_height = 128

time.sleep(1)
display = adafruit_ssd1327.SSD1327(display_bus,
                                   width=display_width,
                                   height=display_height)

print()
print(display)
print(display.width,"x", display.height)
print()

g = displayio.Group()

# I define the OLED in 16 grayscale,
# hardcode defined in a list (instead of by calculating),
# such that you can manual set according to your need.
grayscale = [0x00, 0x10, 0x20, 0x30,
             0x40, 0x50, 0x60, 0x70,
             0x80, 0x90, 0xA0, 0xB0,
             0xC0, 0xD0, 0xE0, 0xF0]
grayscale_count = len(grayscale)
#print([hex(g) for g in grayscale])
#print(grayscale_count)

#back ground have on color only
bg_color_count = 1
bg_bitmap = displayio.Bitmap(display_width,
                           display_height,
                           bg_color_count)
bg_palette = displayio.Palette(bg_color_count)
t = displayio.TileGrid(bg_bitmap,
                       pixel_shader=bg_palette)

bg_bitmap.fill(0)

print()
print("default bg_palette without init")
print([hex(p) for p in bg_palette])
print()

#================================================
#prepare to display grayscale
group_gray = displayio.Group(scale=1)
group_gray.x = 0
group_gray.y = 0
label_gray = label.Label(terminalio.FONT,
                        text="    ",
                        color=0xB0B0B0)
label_gray.anchor_point = (0.0, 0.0)
label_gray.anchored_position = (10, 10)
label_gray_width = label_gray.bounding_box[2]
label_gray_height = label_gray.bounding_box[3]

shape_gray = Circle(x0=0,
                    y0=0,
                    r=80,
                    fill=0xFFFFFF,
                    outline=0x000000,
                    stroke=3)

group_gray.append(shape_gray)
group_gray.append(label_gray)

#====================================

g.append(t)
g.append(group_gray)

display.show(g)

for gs in grayscale:
    
    bg_palette[0] = (gs << 16
                     | gs << 8
                     | gs)
    
    # you can try to remove any elements
    # to check the effect.
    #bg_palette[0] = (0
    #                 | gs << 8
    #                 | 0)
    
    #print([hex(p) for p in bg_palette])
    label_gray.text = str(hex(bg_palette[0]))
    time.sleep(0.5)

time.sleep(1)

#================================================
            
print("~ bye ~")



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.