ESP32-WROOM-32Dでマイコン内蔵RGB LED WS2813Bを駆動するためにこのプログラムを作りました。ハードウェアタイマ割込みハンドラとして記述していますので、メインの処理を(ほとんど)邪魔することなくLEDをドライブできます。作者はSDカードからwavデータを読み出し再生するプログラムに本LEDドライバを組み込んで動作確認しました。
開発環境はVisual Studio Code + PlatformIOです。
RGB_LEDで定義している定数値がGPIOピン番号(任意)です。
CPUクロックについては、board_build.f_cpu = 240000000L に最適化してありますのでCPUクロック80MHzなどの場合は、LED_WAITの定義値を小さくしてみてください。
main.cpp
# define RGB_LED (27)
const unsigned int ledMask[24] = {
0b000000000000000000000001,
0b000000000000000000000010,
0b000000000000000000000100,
0b000000000000000000001000,
0b000000000000000000010000,
0b000000000000000000100000,
0b000000000000000001000000,
0b000000000000000010000000,
0b000000000000000100000000,
0b000000000000001000000000,
0b000000000000010000000000,
0b000000000000100000000000,
0b000000000001000000000000,
0b000000000010000000000000,
0b000000000100000000000000,
0b000000001000000000000000,
0b000000010000000000000000,
0b000000100000000000000000,
0b000001000000000000000000,
0b000010000000000000000000,
0b000100000000000000000000,
0b001000000000000000000000,
0b010000000000000000000000,
0b100000000000000000000000,
};
// cnt == 1 : 0.08us @ 240MHz
void ledWait(unsigned int cnt) {
volatile int timeWaster;
for(int i = 0; i < cnt; i++) {
timeWaster += i;
}
}
# define LED_WAIT (5)
// data sender for WS2813B
void IRAM_ATTR send24bits(unsigned int dat) {
// reset
//digitalWrite(RGB_LED, 0); ledWait(500);
for(int i = sizeof(ledMask) / sizeof(unsigned int) - 1; i >= 0; i--) {
if((dat & ledMask[i])) {
// send '1'
digitalWrite(RGB_LED, 1); ledWait(LED_WAIT << 2); // 'H' about 0.8us
digitalWrite(RGB_LED, 0); ledWait(LED_WAIT); // 'L' about 0.4us
} else {
// send '0'
digitalWrite(RGB_LED, 1); ledWait(LED_WAIT);
digitalWrite(RGB_LED, 0); ledWait(LED_WAIT << 2);
}
}
}
使用例を以下に示します。
main.cpp
hw_timer_t *timerLed = NULL;
const unsigned int ledPattern[] = {
0b000000000000000011111111,
0b000000001111111100000000,
0b111111110000000000000000,
};
void IRAM_ATTR ledOut() {
static int idx = 0;
send24bits(ledPattern[idx]);
++idx %= 3;
}
void setup(void) {
pinMode(RGB_LED, OUTPUT);
timerLed = timerBegin(2, 16, true);
timerAttachInterrupt(timerLed, ledOut, true);
timerAlarmWrite(timerLed, 300000, true);
timerAlarmEnable(timerLed);
}
void loop() {
}