PSoC WS2812B driver Component

Neo Pixel LED WS2812 を駆動するためのUDBを使ったPSoCコンポーネントの使い方について.
(PSoC4で動作を確認していますが,3や5でも動くと思います.)

View the Project on GitHub betaEncoder/PSoC_WS2812Bdriver

コンポーネントをダウンロード

PSoC Creator で使用するコンポーネントをダウンロードには ここからWS2812Driver.cycpmpをダウンロード して下さい.


コンポーネントをインポートする

PSoC Creator の左側にある Workspace Explorer の Component タブを開きます.


Workspace Explorer 上で右クリックし, Import Component... を開きます.
Import from archive を選択し,ダウンロードしたファイルを読み込みます.


すると,PSoC Creator の右側にある Component Catalog の Default タブの中にインポートしたコンポーネントがあるので,デザインにドラッグ&ドロップできるようになっています.


クロックの設定

WS2812へ入力するパルスは決まった時間幅を持つ必要があるので,WS2812 driver に供給するクロックも決まった周波数である必要があります.
このコンポーネントでは20MHzをCLKに入れる必要があるので,HFCLKはその倍の40MHz以上としなければなりません.
この理由からPSoC4ではこのような設定になります.
(外部クロックが利用できるならEXTCLKを利用するのがベターです)


デザイン

たとえば,こんな感じに接続するとよいでしょう.


WS2812BdriverのFIFO_EMPTYピンは内部のFIFOが空になるとHになります.この立ち上がりエッジを利用して割り込みをかけることで,連続したデータを流すことができます.
FIFO_EMPTYがHのとき,FIFOへはWS2812driver_write2fifo()を使って最大で9バイトを流しこむことができます.
また,BUSYピンはパルスの出力処理中にHになります.FIFOが空になっても新しいデータが書き込まれない場合に処理が完了し,L出力になります.
BUSYピン出力を使って周期が50usのカウンタを回すことで,50usのリセットパルスの出力に役立ちます.
今回はカウンタへ入力するクロックを5MHzとしたので,カウンタの設定はこんな感じが良いでしょう.
Period=249で50usになります.


ワンショット動作にしたいのでAdvanceタブはこんな感じに.


さらに,このモジュールの出力信号で割り込みを発生させるためには,ISRの Interrupt Type をRISING_EDGEにしておきます.

割り込み毎にFIFOへデータを流し込む事で別の処理の合間に処理できます.
もちろん,FIFO_EMPTYをポーリングして流しこむこともできますが,最後のパルス出力が終わる前に書き込まないと途切れて表示が更新されてしまう可能性があります.割り込み時も直ちにFIFOへデータを流し込む必要があります.


割込み優先度について

FIFO_EMPTYシグナルによる割込みは,発生したら直ちに実行しなければなりません.
最後の1バイトの送信にかかる時間は9.6usです.この間に割込みへのオーバーヘッドを含めて次の1バイトを書き込まなければなりません.さもなくば,送信が途切れてしまい,途中でLEDが更新されてしまうでしょう.
そのため,FIFO_EMPTYをハンドルする割込み優先度は他の割込みよりも高い優先度(例えば"0")で駆動されるべきです.
FIFO_EMTPTY割込みは84.6us毎に発生します.かなりの高負荷とはなりますが,asmでタイミングを取るよりはずっと良いでしょう.

コーディングのtips

WS2812へ送り込むバイト列は,GRBの順で送り込みます.
そこで,構造体を利用してドライバを叩くことでコードがすっきりします.

typedef struct _RGB_tag{
	unsigned char g;
	unsigned char r;
	unsigned char b;
} rgb_tag;

void hoge(){
	rgb_tag rgb[] = { {hoge1, hoge2, hoge3} , {foo1, foo2, foo3}, {bar1, bar2, bar3} };
	WS2812driver_1_write2fifo((unsigned char*)rgb, 9);
}