稼働中

Raspberry Pi Pico(d_38)NeoPixel bitstream

NeoPixel bitstream

Raspberry Pi Picoで<class ‘NeoPixel’>を使わずにNeoPixelを駆動したいと思います。
「NeoPixel」や接続例については記事d_37などを参照ください。

bitstream

micro:bitでは記事e_26記事e_27のようにSPI通信のMOSIピンを使って駆動させましたが、Raspberry Pi Picoには「machine.bitstream」のメソッドがあり簡単にNeoPixelを駆動できます。
neopixel.pyにもbitstreamがファンクションとして使えるので、こちらを使って動作確認をしています。
そのためneopixelをインポートして使っています。。
neopixelをインポートしない場合はneopixel.bitstreamの部分をmachine.bitstreamに替えてください。

■bitstream
neopixel.bitstream(pin, encoding, timing, data, /)
で与えます。
timing は (high_time_0, low_time_0, high_time_1, low_time_1)で、nsec単位です。
WS2812 RGB LED(NeoPixel)の場合、
f=800kHz(T=1250nsec)で各々400+850=1250、800+450=1250となり(400, 850, 800, 450)値になります。
tm=(400, 850, 800, 450) #timing

GP16を出力ピンにします。(記事d_37の接続図に合わして)
p0=Pin(16,Pin.OUT)

data
8連LEDの場合、dataは8*3=24bytesなので24bytesとします。
data=bytearray(24)

結局、
neopixel.bitstream(p0, 0 ,tm ,data)
として使うことになります。※下部スクリプトではdataはabufになっています。

動作確認

動作確認のスクリプトは以下のようにしました。以下の順で点灯動作します。
個別点灯確認
pos0 RED
pos2 ORANGE > RED > ORANGE
pos5、6、7 RED、GREEN、BLUE

Colors listで点灯確認
C0 > C1 >c2

シフト確認
pos0-RED 右に3移動(pos3)、2移動(pos5)、2移動(pos7)
pos7-GREEN 左に3移動(pos4)、2移動(pos2)、2移動(pos0)

off、cls確認
C0点灯>off() > 再点灯> cls > データクリア(消灯)

バッファデータ確認
pos0、1、2 R、G、Bを設定
バッファー読み出し shellに表示
off() > 同データ shellに表示
cls() > データクリア shellに表示


pico_btreaml_test_04b.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from machine import Pin
import neopixel
import time

# Color データ RGB-PWM data
RED=(255, 0, 0)
ORANGE=(0xff,0xfA,0)
YELLOW=(255, 150, 0)
GREEN=(0, 255, 0)
CYAN=(0, 255, 255)
BLUE=(0, 0, 255)
PURPLE=(180, 0, 255)
WHITE=(0xff,0xff,0xfd)
ALL=(255,255,255)

# LED 0 ~ 7 の色を設定
C0=[RED,GREEN,RED,GREEN,RED,GREEN,RED,GREEN]        #1
C1=[RED,YELLOW,GREEN,BLUE,RED,YELLOW,GREEN,BLUE]    #2
C2=[RED,ORANGE,YELLOW,GREEN,CYAN,BLUE,PURPLE,WHITE] #3

# send bitstream data 
def d_send(data):
    neopixel.bitstream(p0, 0 ,tm ,data)

# 表示クリア
def d_off():
    buf=bytearray(n*3)
    d_send(buf)

# 表示オン
def d_on():
    global abuf
    d_send(abuf)

# データクリア
def cls():
    global abuf
    abuf=bytearray(n*3)
    d_send(abuf)    
    return abuf

# 個別位置LED表示
# N-1番目のdata bytearray(3)を書き換える
def nLed(num,dat=[0,0,0]):    
    #d=[0x06,0x05,0x04]
    abuf[num*3]=int(dat[1]*rt)     #G
    abuf[num*3+1]=int(dat[0]*rt)   #R
    abuf[num*3+2]=int(dat[2]*rt)   #B
    #print(abuf)

## Color listを表示
def cLed(clist,tms):
## se C list n-LED data
    i=0
    for d in clist:
        nLed(i,d)
        i=i+1
    d_send(abuf)
    time.sleep_ms(tms)

# 右へ移動
def Rsh(n,tms=0):
    global abuf
    for i in range(n):
        sbuf=abuf[-3:]
        sbuf.extend(abuf[0:-3])
        #print(i)
        abuf=sbuf
        if tms !=0:
            d_send(abuf)
            time.sleep_ms(tms)
        else:
            d_send(abuf)
# 左へ移動
def Lsh(n,tms=0):
    global abuf
    for i in range(n):
        sbuf=abuf[3:]
        sbuf.extend(abuf[:3])
        abuf=sbuf
        if tms !=0:
            d_send(abuf)
            time.sleep_ms(tms)
        else:
            d_send(abuf)
# バッファーデータを返す
def r_data(buf):
    c_list=[]
    num=len(buf)
    for i in range(int(num/3)):
        pos=[]
        #ORDER -- (1, 0, 2, 3) G R B W
        pos.append(buf[i*3+1])#R
        pos.append(buf[i*3+0])#G
        pos.append(buf[i*3+2])#B
        c_list.append(pos)
    return c_list

## example
# Control output pin
p0=Pin(16,Pin.OUT)

# machine.bitstream(pin, encoding, timing, data, /)
# timing (high_time_0, low_time_0, high_time_1, low_time_1)
tm=(400, 850, 800, 450)

# 8連LED NeoPixel
n=8                      # 8LED  LED Pos 0 ~ 7 (n-1)
abuf=bytearray(n*3)      # 8LEDx3(RGB-PWM data)

# 明るさ減 PWM値の調整
rt=0.05

## 個別LED点灯確認
# led pos0 RED
nLed(0,RED)
d_send(abuf)
time.sleep(1)

# led pos2 ORANGE>RED>ORANGE
nLed(2,ORANGE)
#d_send(abuf)
d_send(abuf)
time.sleep(1)
nLed(2,RED)
d_send(abuf)
time.sleep(1)
nLed(2,ORANGE)
d_send(abuf)
time.sleep(1)

# led pos5,6,7 RED,GREEN,BLUE
nLed(5,RED)
nLed(6,GREEN)
nLed(7,BLUE)
d_send(abuf)
time.sleep(3)
d_off()

## Colors listで点灯確認
wt=1500 #msec
cLed(C0,wt)
d_off();time.sleep_ms(500)

cLed(C1,wt)
d_off();time.sleep_ms(500)

cLed(C2,wt)
d_off();time.sleep_ms(500)

##シフト動作確認
# Rsh(n,tms=0) test
cls()
nLed(0,RED)
d_send(abuf)
time.sleep(1)

Rsh(3,500)         # 右に3シフト500ms間隔
#time.sleep(1)
Rsh(2)             # 右に2
time.sleep_ms(500)
Rsh(2)             # 右に2
time.sleep_ms(500)
d_off()

# Lsh(n,tms=0) test
cls()
nLed(7,GREEN)
d_send(abuf)
time.sleep(1)

Lsh(3,500)        # 左に3シフト500ms間隔
#time.sleep(1)
Lsh(2)            # 左に2
time.sleep_ms(500)
Lsh(2)            # 左に
time.sleep_ms(500)

## off() cls() test
nLed(3,BLUE)
nLed(4,BLUE)
d_send(abuf)
time.sleep(1)
d_off()
time.sleep(1)
d_send(abuf)   # LED ON (Undo Data)
time.sleep(1)

cls()
time.sleep(1)
d_send(abuf)   # Not ON (Reset Data)
time.sleep(1)

## バッファー値の確認
nLed(0,RED)
nLed(1,GREEN)
nLed(2,BLUE)
d_send(abuf)
time.sleep(1)
print(r_data(abuf))  #current data
d_off()
print(r_data(abuf))  #same data
cls()
print(r_data(abuf))  #all '0'deta (Reset)

関数 部分説明

以下に部分的な説明を記載します。
■nLed(num,dat=[0,0,0])
個別のLEDに明るさ調整したpwmデータを送ります
num:NeoPixel LED連番号です。
dat:[r,g,b]の色データです。この値に明るさ比を掛けてPWM値にしています。
■cLed(Cdat,tms=0)
Cdat:NeoPixel LEDの個数分の色リスト、各値に明るさ比を掛けてPWM値にしています。
tms:待機時間です。単位はmsecです。0なら実質データ送信だけです。
■Rshf(n=1,tms=0)
右側(上)にシフトします。
n:シフト数
tms:シフト間隔の時間です。単位はmsecです。0なら実質データ送信だけです。
■Lshf(n=1,tms=0)
左側(下)にシフトします。
n:シフト数
tms:シフト間隔の時間です。単位はmsecです。0なら実質データ送信だけです。
■cls()
PWMデータをクリアします。
■d_off()
元のデータは残してLEDをoffします。
■d_on()
バッファデータを送りLEDをonします。
■r_data(buf)
bufデータを返します。[[r,g,b], [r,g,b],…[r,g,b]]のリストを返します。

実行結果

結果は以下の動画ようになりました。

動画 bitstream_01.mp4

バッファー値の確認はThonnyのShellに表示されます。


>>> %Run -c $EDITOR_CONTENT
[[12, 0, 0], [0, 12, 0], [0, 0, 12], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[12, 0, 0], [0, 12, 0], [0, 0, 12], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]# off() 前と同じ
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] # cls() クリアされる
>>>

まとめ

Raspberry Pi PicoのbitstreamでNeoPixel シリアルLEDの動作確認ができました。