LoginSignup
2
0

More than 1 year has passed since last update.

NucleoF103でNeoPixel制御

Last updated at Posted at 2022-01-22

はじめに

前回の投稿から6年ほど経過した。
https://qiita.com/gkmaro634/items/7b2ce4f72615c96f41d3

その間STM32の開発環境も様変わりしているようで、時代に追いつくために今風の開発環境で何か試そうと思い立った。
前回の記事で取り上げたCubeMXがIDEとして取り込まれたCubeIDEというものがSTMicroからリリースされていたようで、今回こちらを使うこととする。インストール方法はネット上にたくさん情報があり、それらを参考にした。

単なるLチカでは物足りないので色々物色していたところテープLEDなるものが目に止まり、こちらの制御にトライすることにした。一筋縄では行かなかったのでその経緯を記事に残すこととした。

今回使用したもの

NeoPixelの制御

NeoPixelは素のSPIやI2Cでは制御できない独特な制御仕様となっている。
SPIを使ってNeoPixelへのHigh/Lowの制御信号を複数bitで表現する方法が紹介されており、今回はSPIでの制御を採用した。
https://www.newinnovations.nl/post/controlling-ws2812-and-ws2812b-using-only-stm32-spi/
https://blog.handen.net/archives/19087339.html

PWMを使って制御する方法もあるようだが、まだ試せていない。
https://qiita.com/kanehara/items/0e7776c225f83a6b4152

ピンアサイン、クロックの設定

今回用いるNeoPixelは電源(5V)、GND, 信号線をマイコンと接続すれば良い。
信号線はPB15(SPI2_MOSI)に接続することとした。

NeoPixelへのHigh/Lowの信号は1.25usの期間でのDuty比で決定される。
データシートに記載のしきい値に対して実際は多少のマージンを持っているようである。
https://qiita.com/mml/items/770bcf8b0f82a6ec9ad1

ひとまずSPI2へのクロックは8MHzとなるようCubeIDEで設定することとした。
NeoPixelへの制御は
5 / 8MHz = 0.625us
3 / 8MHz = 0.375us
であるので
High: 0b11111000
Low: 0b11100000
とHigh/Lowの制御信号を8bitで表現すればよさそうである。

image.png

プログラムの例

メイン関数から呼び出すメソッドを抜粋して記載する。

main.c
#define NEOPIXEL_0      0b11000000
#define NEOPIXEL_1      0b11111100
#define NEOPIXEL_RESET  0b00000000
#define NEOPIXEL_COUNT  30
#define NEOPIXEL_SIGNAL_CLOCK_COUNT 8

typedef struct {
    uint8_t r;
    uint8_t g;
    uint8_t b;
} RGB;

RGB g_neoPixels[NEOPIXEL_COUNT];

void UpdateNeoPixelBuffer(uint32_t pixelIndex, RGB newValue){
    if (pixelIndex >= NEOPIXEL_COUNT){
        return;
    }

    g_neoPixels[pixelIndex].r = newValue.r;
    g_neoPixels[pixelIndex].g = newValue.g;
    g_neoPixels[pixelIndex].b = newValue.b;
}

void TurnOffNeoPixelBuffer(uint32_t pixelIndex){
    if (pixelIndex >= NEOPIXEL_COUNT){
        return;
    }

    g_neoPixels[pixelIndex].r = 0;
    g_neoPixels[pixelIndex].g = 0;
    g_neoPixels[pixelIndex].b = 0;
}

void ResetNeoPixel(){
    uint8_t txValue = NEOPIXEL_RESET;
    uint32_t i = 0;

    // SPI Clock: 8MHz
    // Send Low >50us
    // 8 * 50 / 1e-6 = 400
    for (i = 0; i < 512; i++){
        HAL_SPI_Transmit(&hspi2, &txValue, 1, 100);
    }
}

void UpdateNeoPixel(){
    uint32_t i, j = 0;
    uint8_t txValue;

    ResetNeoPixel();

    for (i=0; i < NEOPIXEL_COUNT; i++){
        for (j=0; j<NEOPIXEL_SIGNAL_CLOCK_COUNT; j++){
            txValue = g_neoPixels[i].g & 0x80 >> j ? NEOPIXEL_1 : NEOPIXEL_0;
            HAL_SPI_Transmit(&hspi2, &txValue, 1, 100);
        }

        for (j=0; j<NEOPIXEL_SIGNAL_CLOCK_COUNT; j++){
            txValue = g_neoPixels[i].r & 0x80 >> j ? NEOPIXEL_1 : NEOPIXEL_0;
            HAL_SPI_Transmit(&hspi2, &txValue, 1, 100);
        }

        for (j=0; j<NEOPIXEL_SIGNAL_CLOCK_COUNT; j++){
            txValue = g_neoPixels[i].b & 0x80 >> j ? NEOPIXEL_1 : NEOPIXEL_0;
            HAL_SPI_Transmit(&hspi2, &txValue, 1, 100);
        }
    }
}
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0