記事のミス等のお問い合わせはTwitterにてお願いします。制御方法カテゴリ:工作の基礎マイコン今回はマイコンを使ってマイコン内蔵のLEDであるWS2812Bを制御します。WS2812Bの特徴はマイコンなどから信号を与えることで各LEDを個別で制御できかつ安価である(AliExpressで1つ当たり10円を切る価格)で売られているという所です。数珠接続で個別制御できるため安価なLEDテープを大進化させたLEDともいえると思います。最強そうに見えるこのLED実はマイコンから制御するのが一筋縄にはできないという問題があります。(本来は専用のコントローラを使います)今回はこのWS2812B搭載のLEDテープをAVRマイコンとSTM32マイコンで制御する方法を考えていきます。制御信号の形まずはWS2812Bのデータシートを見てみます。http://www.world-semi.com/DownLoadFile/108こちらが製造元の新しいバージョンとみられるデータシートhttps://cdn-shop.adafruit.com/datasheets/WS2812B.pdfそしてこちらがadafruitとか秋月に掲載されているデータシートです。ややこしいことに、信号生成に関わる箇所のパラメータがこの2者で違うことを覚えておいてください。データシートを見ていくとUARTでもSPIでもI2Cでも無い、専用のデータ形式であることがわかります。具体的な信号の形(1bit)は下図のような感じです。このbitが以下のように連続して送られることで1つのLEDの制御信号になります。各bitを緑、赤、青の順に連続的に並べたのみでスタートビットやストップビットといったものは無いのが特徴と言えます。複数のLEDの制御はこの24bitのデータを連続的に並べることで行います。LEDの接続と信号の順番を図で表すと以下のようになります。Amazonとかの販売ページにはアドレス指定可能とか書かれていますが、実際にはアドレスを指定して制御するわけではなく、手前のLEDから順番にデータを送る形式となっています。280us)続くリセット信号を送らないといけないことです。逆に言い換えるとリセットされない時間であればLOWが続いても大丈夫ということです。実はこの仕様のおかげでAVRマイコンでも制御することができます。続いてどうやってこの信号を作り出すかを考えていきます。制御信号の形上UARTとかI2CとかSPIをそのまま使うことはもちろんできません。信号速度的にArduinoのdigitalWriteとかは使えないのはもちろん、レジスタを叩いてもdelayとか割り込みでの処理も困難です。アセンブラを使えばクロック単位で処理できるので信号生成できますが、難しいし処理も重い、でもクロック単位レベルの高速な信号生成が必要。調べてみるとSPIの複数bitを使って信号生成してる例があったので、今回はSPIを使ってAVRとSTM32で信号生成をしてみることにします。SPI通信の仕様を軽く説明します。SPI通信はUARTと違って4つのピンを使って制御します。スレーブセレクト(SS(ーー))です。通信を行うときはSSーーピンをLOWにして、SCKピンにクロックを掛けてクロックと同期した信号を送信します。タイミングチャートを下に示してみます。ここで、ややこしいことが起きてしまいます。それはMOSI(マスター送信ピン)がアイドル時に状態が不定になるということです。その他SCKピンのアイドル時のLOW,HIGHの差や先行端、後行端を採るかの差はマイコン間などでSPI通信を行うときは合わさないといけませんが、今回のLED制御には本質的には関わりません。今回WS2812Bを制御するにあたって使うピンはMOSIピンのみです。他のピンは使いません。送信するデータの工夫でWS2812Bの制御信号を作り出します。今回はSPIのデータの4bitをWS2812Bの1bitとして使います。送り出すパケット形状より下図のようにHIGHになるbitの数を調整することで0のパケットと1のパケットを作り出します。1パケットの場合0b1110(0xE)になります。SPIのアイドル時の状態が不定であるためです。ここで、今回使用するマイコンのデータシートを見てみます。:https://avr.jp/user/DS/PDF/mega328P.pdfSTM32マイコン(STM32F446):https://www.st.com/content/ccc/resource/technical/document/reference_manual/4d/ed/bc/89/b5/70/40/dc/DM00135183.pdf/files/DM00135183.pdf/jcr:content/translations/en.DM00135183.pdfまずはAVRマイコンで制御信号を作り出す方法を考えるため、データシートのSPIのタイミングチャートが書かれている121ページを見てみます。一応こちらにも引用しておきます。このデータシートを見るとAVRマイコンではMOSIのアイドル時の状態はHIGHになってるように見えます。確認のために実際にオシロスコープで出力波形を確認してみたいと思います。(ロジックアナライザー持ってないのでオシロを使います。)送ってるデータは0xEE(0x11101110)です。信号が始まる前と後はHIGHになってることがわかります。これより、データシート通りアイドル時がHIGHになっていることがわかりました。WS2812Bはアイドル時がLOWです。そのため、そのままではWS2812Bは動かせません。そこで、AVRマイコンでWS2812Bを制御する場合信号を反転(つまりNOTをかける)してアイドル時がLOWの信号を作りだします。信号を反転させるので送るbitも反転します。最終的に出力した波形はこんな感じです。これによりAVRマイコンでWS2812Bを制御する信号が生成できました。これら図では少々わかりにくいですが、AVRの性能上8bit単位で信号に間隔が空いてしまい(LOWが長く続いてる)ます。WS2812Bの仕様上50usまでは許容されているので問題ありません。続いてSTM32マイコン(STM32F446)で制御信号を作り出すために、データシートのSPIのタイミングチャートが書かれている856ページを見てみます。こちらにも引用します。このタイミングチャートを見るとMOSIのアイドル時の状態がHIGHもLOWも両方書かれていてどちらかがわかりません。データシート上は不定というわけです。タイミングチャートのMISO(スレーブ側は出力になる)を見ると後行端採取(CPHA=1)の時はLSBが少し伸びるとみられる表記が見られるので、この条件で実験してみました。結果は下図のようにLSBの状態が次のデータの先頭まで続いていました。」「1パケットで0b1110」となっておりLSBが必ず0となります。LSBのステートがアイドル時のステートとなるためアイドル時も必ず0となります。そのため、STM32マイコンで制御する場合はAVRと異なり信号の反転は不要です。STM32マイコンではDMAが使えることもあり、8bitの間での信号の伸びが無く連続した信号が生成できています。(DMAを使わない場合でも伸びはほぼ見られませんでした)最後にSPIの通信速度の設定です。通信速度(クロック)はマイコンのクロックに依存します。WS2812Bの場合1パケット(4bit)の長さが大体900nsから1400ns程度となっており、これから逆算するとSPIの通信速度は4.44Mbpsから2.86Mbps程度となります。正常に作動しています。ペリフェラルクロック42MHzのSTM32マイコンの場合はペリフェラルクロックの1/16(分周1/16)で2.625MHz(2.625bps)と新版のデータシート範囲から少々ずれがありますが正常に動作しています。(ただし、個体により動かない可能性はあるので注意必要だと思います)最後にWS2812BをAVRマイコンとSTM32マイコンで使う場合のまとめです。AVR(ATmega328P)アイドル時がHIGHのため信号にロジックICなどでNOTを掛ける必要がある。赤緑青の順にフル点灯させる場合以下のような配列のデータをDMAで流します。0x88,};2つのマイコンで比較すると多くのLEDを正確に制御する場合はDMAが使えるSTM32マイコンを使う方が良く、少ないLEDを簡単に制御する程度であればAVRマイコンでもできるといったところだと思います。必要な用途に応じて使い分けると良いでしょう。