LuckFox Pico ProでUbuntuを使ってみる

Adafruit Blinkaライブラリ

python-peripheryは素晴らしいライブラリですが、基本的なデバイスのアクセスしかサポートしていないので、いろいろ作り込む必要 が有ります。
こちらにPython GPIOライブラリのAdafruit-Blinkaが公開されています。
このAdafruit-BlinkaライブラリをベースにしたAdafruit CircuitPythonライブラリと言うライブラリが有ります。
こ ちらにライブラリの一覧が公開されています。
2024年時点で利用可能なライブラリは 273 個もあります。
これらのリポジトリを見ると全てのリポジトリのrequirements.txtにAdafruit-Blinkaが登録されています。
つまりこれらのライブラリは全てAdafruit-Blinkaをベースに構築されています。
Adafruit-Blinkaが対応しているボードでは、これらのライブラリを利用することができます。

残念ながらこのライブラリは、LuckFoxシリーズに対応していませんでした。
このライブラリへの対応を追加するだけで 273 個のライブラリが使えるようになるのは魅力です。
そこで、Adafruit-BlinkaのサポートボードにLucxFox Pico Maxを追加し、リポジトリに反映しました。

Adafruit-Blinkaは8.44.0以降、必須パッケージにsysv_ipcが追加されました。
なぜか、LockFoxではsysv_ipcをインストールすることができません。
以下のエラーとなります。
$ sudo apt install python3-pip python3-setuptools

$ python3 -m pip -V
pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)

$ python3 -m pip install -U pip

$ python3 -m pip -V
pip 25.0.1 from /home/pico/.local/lib/python3.10/site-packages/pip (python 3.10)

$ python3 -m pip install sysv_ipc
Defaulting to user installation because normal site-packages is not writeable
Collecting sysv_ipc
  Using cached sysv_ipc-1.1.0.tar.gz (99 kB)
  Preparing metadata (setup.py) ... done
Building wheels for collected packages: sysv_ipc
  Building wheel for sysv_ipc (setup.py) ... error
  error: subprocess-exited-with-error

  × python setup.py bdist_wheel did not run successfully.
  x exit code: 1
  mq> [17 lines of output]
      running bdist_wheel
      running build
      running build_ext
      building 'sysv_ipc' extension
      creating build
      creating build/temp.linux-armv7l-3.10
      arm-linux-gnueabihf-gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.10 -c common.c -o build/temp.linux-armv7l-3.10/common.o
      arm-linux-gnueabihf-gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.10 -c memory.c -o build/temp.linux-armv7l-3.10/memory.o
      arm-linux-gnueabihf-gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.10 -c mq.c -o build/temp.linux-armv7l-3.10/mq.o
      arm-linux-gnueabihf-gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.10 -c semaphore.c -o build/temp.linux-armv7l-3.10/semaphore.o
      arm-linux-gnueabihf-gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.10 -c sysv_ipc_module.c -o build/temp.linux-armv7l-3.10/sysv_ipc_module.o
      creating build/lib.linux-armv7l-3.10
      arm-linux-gnueabihf-gcc -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -g -fwrapv -O2 -Wl,-Bsymbolic-functions -g -fwrapv -O2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.linux-armv7l-3.10/common.o build/temp.linux-armv7l-3.10/memory.o build/temp.linux-armv7l-3.10/mq.o build/temp.linux-armv7l-3.10/semaphore.o build/temp.linux-armv7l-3.10/sysv_ipc_module.o -o build/lib.linux-armv7l-3.10/sysv_ipc.cpython-310-arm-linux-gnueabihf.so
      /usr/bin/ld: cannot find -lgcc: No such file or directory
      /usr/bin/ld: cannot find -lgcc: No such file or directory
      collect2: error: ld returned 1 exit status
      error: command '/usr/bin/arm-linux-gnueabihf-gcc' failed with exit code 1
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for sysv_ipc
  Running setup.py clean for sysv_ipc
Failed to build sysv_ipc
ERROR: Failed to build installable wheels for some pyproject.toml based projects (sysv_ipc)

sysv_ipcをインストールできない原因を調べたら、デフォルトでインストールされているgcc-11が不完全なことが原因でした。
sysv_ipcはpipでインストールすると、arm-linux-gnueabihf-gccを使ってビルドします。
arm-linux-gnueabihf-gccは以下の様にgcc-11にシンボリックリンクされています。
arm-linux-gnueabihf-gcc(=gcc-11)でソースをビルドするとエラーとなります。
$ arm-linux-gnueabihf-gcc a.c
/usr/bin/ld: cannot find -lgcc: No such file or directory
/usr/bin/ld: cannot find -lgcc: No such file or directory
collect2: error: ld returned 1 exit status

$ which arm-linux-gnueabihf-gcc
/usr/bin/arm-linux-gnueabihf-gcc

$ ls -la /usr/bin/arm-linux-gnueabihf-gcc
lrwxrwxrwx 1 root root 6 Aug  5  2021 /usr/bin/arm-linux-gnueabihf-gcc -> gcc-11

$ arm-linux-gnueabihf-gcc --version
cc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

そこで、arm-linux-gnueabihf-gccのリンク先をgcc-12に変更します。
これで、arm-linux-gnueabihf-gcc(=gcc-12)を使ったビルドが正しく動くようになり、Adafruit- Blinkaをインストールすることができます。
$ ls -l /usr/bin/arm-linux-gnueabihf-gcc
lrwxrwxrwx 1 root root 6 Aug  5  2021 /usr/bin/arm-linux-gnueabihf-gcc -> gcc-11

$ sudo unlink /usr/bin/arm-linux-gnueabihf-gcc

$ sudo ln -s gcc-12 /usr/bin/arm-linux-gnueabihf-gcc

$ ls -l /usr/bin/arm-linux-gnueabihf-gcc
lrwxrwxrwx 1 root root 6 Apr 16 14:32 /usr/bin/arm-linux-gnueabihf-gcc -> gcc-12

$ arm-linux-gnueabihf-gcc --version
arm-linux-gnueabihf-gcc (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ python3 -m pip install Adafruit-Blinka

$ pip list
Package                                  Version
---------------------------------------- -------
Adafruit-Blinka                          8.56.0
adafruit-circuitpython-busdevice         5.2.11
adafruit-circuitpython-connectionmanager 3.1.3
adafruit-circuitpython-requests          4.1.10
adafruit-circuitpython-typing            1.11.2
Adafruit-PlatformDetect                  3.77.0
Adafruit-PureIO                          1.1.11
binho-host-adapter                       0.1.6
dbus-python                              1.2.18
distro                                   1.7.0
netifaces                                0.11.0
pip                                      25.0.1
pyftdi                                   0.56.0
PyGObject                                3.42.1
pyserial                                 3.5
python-periphery                         2.4.1
pyusb                                    1.3.1
PyYAML                                   5.4.1
setuptools                               59.6.0
ssh-import-id                            5.11
sysv-ipc                                 1.1.0
toml                                     0.10.2
typing_extensions                        4.13.2
wheel                                    0.37.1

これでAdafruit-Blinkaが動くようになります。
以下のコードできちんとLuckFox Pico Maxを認識します。
$ cat detect.py
from adafruit_platformdetect import Detector
detector = Detector()
print("Chip id: ", detector.chip.id)
print("Board id: ", detector.board.id)

$ python3 detect.py
Chip id:  RV1106
Board id:  LUCKFOX_PICO_MAX

以下のコードでこのボードに定義されているポートの情報を表示します。
$ cat pins.py
import board
print(vars(board))

$ sudo -E python3 pins.py
Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
All Rights Reserved., 'credits':     Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
    for supporting Python development.  See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.}, '__version__': '8.56.0', '__repo__': 'https://github.com/adafruit/Adafruit_Blinka.git', '__blinka__': True, 'sys': <module 'sys' (built-in)>, 'ap_board': <module 'adafruit_platformdetect.constants.boards' from '/home/pico/.local/lib/python3.10/site-packages/adafruit_platformdetect/constants/boards.py'>, 'board_id': 'LUCKFOX_PICO_MAX', 'detector': <adafruit_platformdetect.Detector object at 0xa6c0bca0>, 'pin': <module 'adafruit_blinka.microcontroller.rockchip.rv1106.pin' from '/home/pico/.local/lib/python3.10/site-packages/adafruit_blinka/microcontroller/rockchip/rv1106/pin.py'>, 'G42': (1, 10), 'G43': (1, 11), 'G55': (1, 23), 'G54': (1, 22), 'G53': (1, 21), 'G52': (1, 20), 'G58': (1, 26), 'G59': (1, 27), 'G73': (2, 9), 'G48': (1, 16), 'G49': (1, 17), 'G50': (1, 18), 'G51': (1, 19), 'G72': (2, 8), 'G56': (1, 24), 'G57': (1, 25), 'G68': (2, 4), 'G69': (2, 5), 'G64': (2, 0), 'G65': (2, 1), 'G66': (2, 2), 'G67': (2, 3), 'G70': (2, 6), 'G71': (2, 7), 'UART3_TX': (1, 24), 'UART3_RX': (1, 25), 'UART4_TX': (1, 21), 'UART4_RX': (1, 20), 'TX': (1, 24), 'RX': (1, 25), 'TXD': (1, 24), 'RXD': (1, 25), 'I2C3_SCL': (1, 27), 'I2C3_SDA': (1, 26), 'SCL': (1, 27), 'SDA': (1, 26), 'SPI0_MISO': (1, 19), 'SPI0_MOSI': (1, 18), 'SPI0_SCLK': (1, 17), 'SPI0_CS0': (1, 16), 'SPI0_CS1': (1, 26), 'MISO': (1, 19), 'MOSI': (1, 18), 'SCLK': (1, 17), 'PWM5': (2, 8), 'PWM6': (2, 9), 'PWM10': (1, 22), 'PWM11': (1, 23), 'ADC_IN0': 0, 'ADC_IN1': 1, 'I2C': <function I2C at 0xa6c19268>, 'SPI': <function SPI at 0xa6c22e38>}



pipの実行時に以下の証明書エラーになる事が有ります
$ python3 -m pip install -U pip
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: pip in ./.local/lib/python3.10/site-packages (24.0)
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate is not yet valid (_ssl.c:1007)'))': /simple/pip/
WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate is not yet valid (_ssl.c:1007)'))': /simple/pip/
WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate is not yet valid (_ssl.c:1007)'))': /simple/pip/
WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate is not yet valid (_ssl.c:1007)'))': /simple/pip/
WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate is not yet valid (_ssl.c:1007)'))': /simple/pip/
Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host='pypi.org', port=443): Max retries exceeded with url: /simple/pip/ (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate is not yet valid (_ssl.c:1007)'))) - skipping

その場合の解決策がこちらに 有ります。
Linuxの場合は$HOME/.config/pip/pip.confを作って、そこに以下を記載すれば解決します。
$ cat $HOME/.config/pip/pip.conf
[global]
trusted-host = pypi.python.org
               pypi.org
               files.pythonhosted.org



手始めにこ ちらのライブラリをインストールしてBMP280から温度を読み出してみました。
このライブラリはI2C/SPI両方に対応しています。
これがI2Cインタフェースを使う場合のスクリプト(bmp280-i2c.py)です。
#!/usr/bin/python
#-*- encoding: utf-8 -*-
import time
import board
# import digitalio # For use with SPI
import adafruit_bmp280

# Create sensor object, communicating over the board's default I2C bus
i2c = board.I2C()   # uses board.SCL and board.SDA
bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c, 0x76)

# OR Create sensor object, communicating over the board's default SPI bus
# spi = board.SPI()
# bmp_cs = digitalio.DigitalInOut(board.D10)
# bmp280 = adafruit_bmp280.Adafruit_BMP280_SPI(spi, bmp_cs)

# change this to match the location's pressure (hPa) at sea level
bmp280.sea_level_pressure = 1013.25

while True:
    print("\nTemperature: %0.1f C" % bmp280.temperature)
    print("Pressure: %0.1f hPa" % bmp280.pressure)
    print("Altitude = %0.2f meters" % bmp280.altitude)
    time.sleep(2)

LuckFox Pico Pro/MaxのI2CはGPIO58(SDA)/GPIO59(SCL)です。
$ sudo -E python3 bmp280-i2c.py

Temperature: 27.3 C
Pressure: 1013.9 hPa
Altitude = -5.68 meters

Temperature: 27.3 C
Pressure: 1014.0 hPa
Altitude = -5.88 meters

Temperature: 27.3 C
Pressure: 1013.9 hPa
Altitude = -5.72 meters



これがSPIインタフェースを使う場合のスクリプト(bmp280-spi.py)です。
#!/usr/bin/python
#-*- encoding: utf-8 -*-
import time
import board
import digitalio # For use with SPI
import adafruit_bmp280

# Create sensor object, communicating over the board's default I2C bus
#i2c = board.I2C()       # uses board.SCL and board.SDA
#bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c, 0x76)

# OR Create sensor object, communicating over the board's default SPI bus
spi = board.SPI()
#bmp_cs = digitalio.DigitalInOut(board.G73)
bmp_cs = digitalio.DigitalInOut(board.G72)
bmp280 = adafruit_bmp280.Adafruit_BMP280_SPI(spi, bmp_cs)

# change this to match the location's pressure (hPa) at sea level
bmp280.sea_level_pressure = 1013.25

while True:
        print("\nTemperature: %0.1f C" % bmp280.temperature)
        print("Pressure: %0.1f hPa" % bmp280.pressure)
        print("Altitude = %0.2f meters" % bmp280.altitude)
        time.sleep(2)

LuckFox Pico Pro/MaxのSPIはGPIO49(SCLK)/GPIO50(MOSI)/GPIO51(MISO)です。
CSにはGPIO72を使いました。
$ sudo -E python3 bmp280-spi.py

Temperature: 27.3 C
Pressure: 1015.7 hPa
Altitude = -20.31 meters

Temperature: 27.3 C
Pressure: 1015.7 hPa
Altitude = -20.46 meters

Temperature: 27.3 C
Pressure: 1015.7 hPa
Altitude = -20.53 meters



Adafruit_CircuitPython_SSD1306のこ ちらのサンプルを動かしてみました。
このサンプルを実行するためには、こ ちらのフレームバッファライブラリのサンプルに含まれるフォントファイルが必要になります。
インストールは以下の手順です。
$ python3 -m pip install adafruit-circuitpython-ssd1306

$ git clone https://github.com/adafruit/Adafruit_CircuitPython_SSD1306
$ git clone https://github.com/adafruit/Adafruit_CircuitPython_framebuf
$ cp $HOME/Adafruit_CircuitPython_framebuf/examples/font5x8.bin $HOME/Adafruit_CircuitPython_SSD1306/examples/

$ cd $HOME/Adafruit_CircuitPython_SSD1306/examples/

$ vi ssd1306_framebuftest.py

#reset_pin = DigitalInOut(board.D5)
#display = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c, addr=0x3C, reset=reset_pin)
display = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c, addr=0x3C)

$ sudo -E python3 ./ssd1306_framebuftest.py

手元のモジュールにはRESETピンが無いので、RESETピンの指定は無効にしました。




LuckFox Pico Miniでも動きます。






こ ちらにSPIインタフェースのW5500を利用するライブラリが公開されています。
issuesを検索したらW5200でも使えるみたいです。
こ ちらのサンプルを少し変更してLuckFoxで試してみました。
変更したのは以下の部分で、WIZNET5Kのインスタンス生成時にcs、reset、macを追加しています。
cs_pin = digitalio.DigitalInOut(board.G72)
reset_pin = digitalio.DigitalInOut(board.G73)
spi_bus = busio.SPI(board.SCLK, MOSI=board.MOSI, MISO=board.MISO)

# Initialize ethernet interface with DHCP
#eth = WIZNET5K(spi_bus, cs)
eth = WIZNET5K(spi_bus, cs=cs_pin, reset=reset_pin, mac='DE:AD:BE:EF:FE:ED')

このライブラリはHelperライブラリとしてこ ちらのライブラリを利用します。
このライブラリの中のcp_version = sys.implementation[1]がエラーになります。
LuckFoxではsys.implementationはlistではなくnamespaceとなっています。
sys.implementation=namespace(name='cpython', cache_tag='cpython-310', version=sys.version_info(major=3, minor=10, micro=12, releaselevel='final', serial=0), hexversion=50990320, _multiarch='arm-linux-gnueabihf')

そこで、この部分をコメントアウトしました。
この変更については、現在Adafruitに問合せしています。→修正されました。
$ vi $HOME/.local/lib/python3.10/site-packages/adafruit_connection_manager.py


            # Note: At this time, SSL/TLS connections are not supported by older
            # versions of the Wiznet5k library or on boards withouut the ssl module
            # see https://docs.circuitpython.org/en/latest/shared-bindings/support_matrix.html
            ssl_context = None

            """
            cp_version = sys.implementation[1]
            if pool.SOCK_STREAM == 1 and cp_version >= WIZNET5K_SSL_SUPPORT_VERSION:
                try:
                    import ssl  # pylint: disable=import-outside-toplevel

                    ssl_context = ssl.create_default_context()
                except ImportError:
                    # if SSL not on board, default to fake_ssl_context
                    pass

            """

こちらこちらの サイトの情報が正しくferchできました。
$ sudo -E python3 wiznet5k_simpletest.py
Wiznet5k WebClient Test
Chip Version: w5500
MAC Address: ['0xde', '0xad', '0xbe', '0xef', '0xfe', '0xed']
My IP address is: 192.168.10.145
IP lookup adafruit.com: 104.20.39.240
Fetching text from http://wifitest.adafruit.com/testwifi/index.html
----------------------------------------
This is a test of Adafruit WiFi!
If you can read this, its working :)
----------------------------------------

Fetching json from http://api.coindesk.com/v1/bpi/currentprice/USD.json
----------------------------------------
{'time': {'updated': 'Jun 8, 2024 22:23:59 UTC', 'updatedISO': '2024-06-08T22:23:59+00:00', 'updateduk': 'Jun 8, 2024 at 23:23 BST'}, 'disclaimer': 'This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org', 'bpi': {'USD': {'code': 'USD', 'rate': '69,435.326', 'description': 'United States Dollar', 'rate_float': 69435.3264}}}
----------------------------------------
Done!

W5500を追加すれば、PicoやPico MiniなどのEthernetの無いモデルでEthernetが使えるようになりますが、W5500は$4ぐらいの追加コストが必要になります。
Ethernetの無いモデル + W5500は、送料を考慮するとPico Plusよりも高価になります。
こ ちらにPico MiniにEthernetを追加する記事が公開されています。
OSはBuildrootです。大変興味深い記事です。

以下は2024年6月時点のこちらの オフィシャルサイトでの価格です。
オフィシャルサイトで購入すると、一個口あたり$5.00の送料が掛かります。
送料は一個口あたりの送料で、同時に複数個購入しても$5.00です。
1個だけ購入する場合は、AliExpressのセーラーの方が安い場合が有ります。
AliExpressのセーラーでPico Plusが送料込みで$11.38でした。
Model SoC Memory NAND FLASH Network Price Shipping
Pico RV1103 64MB

$6.99 $5.00
Pico Mini-A RV1103 64MB

$6.99 $5.00
Pico Mini-B RV1103 64MB 128MB
$8.99 $5.00
Pico Plus RV1103 64MB 128MB Ethernet $9.99 $5.00
Pico Pro RV1106 128MB 256MB Ethernet $12.99 $5.00
Pico Max RV1106 256MB 256MB Ethernet $14.99 $5.00