Raspberry Pi 3 で WS281X



# 環境

- Raspberry Pi 3
- Raspberry Pi 3
- Raspberry Pi OS Lite
- Release date: February 21st 2023
- System: 32-bit
- WS2812 および WS2815
- Python 3.9.2

写真では分かりづらいけど、接続は RaspberryPi の GPIO10 に WS2812 の DIN を接続。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/16068e74-ab4d-99dd-308f-2f4cd5a0d993.png)


NeoPixel は正確なパルスを出さないといけないので、ハードウェア的な仕組みで動かす。
PWM ,PCM や SPI などがあるけれども、GPIO10 に割り当てられている SPI 機能を使ってドライブする。


# adafruit-circuitpython-neopixel

まずは Python で動かしてみる。

こちらの内容に沿って動かしてみる。
https://learn.adafruit.com/adafruit-neopixel-uberguide/python-circuitpython




```
$ sudo pip3 install rpi_ws281x adafruit-circuitpython-neopixel
$ sudo python3 -m pip install --force-reinstall adafruit-blinka
```

pythonを起動してインタラクティブに動かしてみる

```
$ sudo python3
```

```
>>> import board
>>> import neopixel
>>> pixels = neopixel.NeoPixel(board.D10,10)
>>> pixels[0] = (255,0,0)
Cannot open /dev/spidev0.0. spi_bcm2835 module not loaded?
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.9/dist-packages/adafruit_pixelbuf.py", line 313, in __setitem__
    self.show()
  File "/usr/local/lib/python3.9/dist-packages/adafruit_pixelbuf.py", line 205, in show
    return self._transmit(self._post_brightness_buffer)
  File "/usr/local/lib/python3.9/dist-packages/neopixel.py", line 180, in _transmit
    neopixel_write(self.pin, buffer)
  File "/usr/local/lib/python3.9/dist-packages/neopixel_write.py", line 41, in neopixel_write
    return _neopixel.neopixel_write(gpio, buf)
  File "/usr/local/lib/python3.9/dist-packages/adafruit_blinka/microcontroller/bcm283x/neopixel.py", line 82, in neopixel_write
    raise RuntimeError(
RuntimeError: ws2811_init failed with code -13 (Unable to initialize SPI)
>>> exit()
```

エラーが出た。接続に SPI 機能を使っているので、SPI 機能を有効にする必要がある。

```

$ sudo raspi-config
```
で設定してから、再起動
```

$ sudo reboot
```

```
$ sudo python3
Python 3.9.2 (default, Mar 12 2021, 04:06:34) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import board
>>> import neopixel
>>> pixels = neopixel.NeoPixel(board.D10,10)
>>> pixels[0]=(255,0,0)
>>> pixels[0]=(255,0,255)
>>> pixels[0]=(10,0,0)
>>> pixels[1]=(10,0,0)
>>> pixels[1]=(0,0,0)
>>> exit()
```

ソフトウェア的にエラーは出なくなったが、発光がコントロールできていない。いくつかが白色で光り続けている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/bffeb52e-985c-aa2e-ff7d-6e29270312de.png)

原因は SPI バスのクロック設定らしい。

後述の、/boot/config.txt への設定を行って、以下のプログラムを動かすと正常に動作した。

```
import board
import neopixel
pixels = neopixel.NeoPixel(board.D10, 10)
pixels[0] = (5, 0, 0)
pixels[2] = (20, 0, 0)
pixels[4] = (50, 0, 0)
pixels[6] = (100, 0, 0)
pixels[8] = (200, 0, 0)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/d6ee3387-327e-4ba2-28b3-6721912a62a4.png)


## WS2815

接続を WS2815に変えて、同様に動かすと緑に発色した。

信号が GRB タイプのストリップらしい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/815ed957-d1ed-9709-5bf0-5b4abba030ab.png)



# jgarff/rpi_ws281x

`https://github.com/jgarff/rpi_ws281x`

クロスチェックのために、 C プログラムを使ってみる。

```
$ git clone https://github.com/jgarff/rpi_ws281x.git
$ cd rpi_ws281x/
$ ls
clk.h           DEBIAN  dma.h   LICENSE   mailbox.c  main.c  pcm.h             pwm.c  README.md  rpihw.h     SConstruct  version.h.in  ws2811.c
CMakeLists.txt  dma.c   gpio.h  linux.py  mailbox.h  pcm.c   pkg-config.pc.in  pwm.h  rpihw.c    SConscript  version     version.py    ws2811.h
```

ビルド方法はいくつかあるらしいが、cmake を使ってみた。


```

$ sudo apt install cmake
$ mkdir build
$ cd build 
$ cmake -D BUILD_SHARED=OFF -D BUILD_TEST=ON ..
$ cmake --build .
```
インストールしてみる。
```
$ sudo make install
[ 77%] Built target ws2811
[100%] Built target test
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/lib/libws2811.a
-- Installing: /usr/local/include/ws2811/ws2811.h
-- Installing: /usr/local/include/ws2811/rpihw.h
-- Installing: /usr/local/include/ws2811/pwm.h
-- Installing: /usr/local/include/ws2811/clk.h
-- Installing: /usr/local/include/ws2811/dma.h
-- Installing: /usr/local/include/ws2811/gpio.h
-- Installing: /usr/local/include/ws2811/mailbox.h
-- Installing: /usr/local/include/ws2811/pcm.h
-- Installing: /usr/local/lib/pkgconfig/libws2811.pc
```
```
$ ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  install_manifest.txt  libws2811.a  libws2811.pc  Makefile  test  version.h
$ ./test
Can't open /dev/mem: Permission denied
ws2811_init failed: mmap() failed
```
test プログラムは 標準で GPIO8 を使うようなので、GPIO10 を使う方法を調べてみる。
```
$ ./test --help
./test version 1.1.0
Usage: ./test 
-h (--help)    - this information
-s (--strip)   - strip type - rgb, grb, gbr, rgbw
-x (--width)   - matrix width (default 8)
-y (--height)  - matrix height (default 8)
-d (--dma)     - dma channel to use (default 10)
-g (--gpio)    - GPIO to use
                 If omitted, default is 18 (PWM0)
-i (--invert)  - invert pin output (pulse LOW)
-c (--clear)   - clear matrix on exit.
-v (--version) - version information
```

こんな感じかな?
```
$ sudo ./test -g10
```

先の python でのテストと同じく、白色で光り続けている。

レポジトリの README を見ると、

> On an RPi 3 you have to change the GPU core frequency to 250 MHz, otherwise the SPI clock has the wrong frequency.

とあるので、

`/boot/config.txt`

を編集して、最後に以下を追加する

```
core_freq=250
```
再起動してから、試してみる

```

$ sudo ./test -g10
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/f2f2644e-3a60-1d6d-61c1-d6d2da109d65.png)

うまく動きました。