Skocz do zawartości

[C] [STM32F4] Sterowanie "adresowalnymi" diodami z chipem WS2812B sygnałem z SPI


akurczyk

Pomocna odpowiedź

Witam,

Próbuję wysterować z STM32F4 (Kamami KA-NUCLEO-F411CE) pasek "adresowalnych" diod LED z chipami WS2812B.

Diody te wymagają wysyłania szeregowo po 24 bity informacji (RGB TrueColor) dla każdej diody bez przerwy oraz przerwy min. 50 us po wysłaniu informacji o kolorach dla wszystkich diod, aby diody zmieniły kolory. Jedynka kodowana jest jako dłuższy okres stanu wysokiego za którym następuje krótki okres stanu niskiego, a zero jako krótki okres stanu wysokiego i dłuższy stanu niskiego. Czas trwania pojedynczego bitu to 1.25 us, więc jest to dość szybkie. Dokładniej jest to opisane tutaj: https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf

Ustawianie odpowiednich stanów na pinach i odczekiwanie (np. while(delay--)) mogło by nie być zbyt optymalne. Widziałem w Internecie podobne rozwiązania wykorzystujące UART do generowania "waveforma" z bitów zapisanych w tablicy poprzez DMA. Z pewnym trikiem jest to możliwe na XMedze - link.

Ja chciałbym wykonać to przy pomocy SPI. Wyliczyłem że aby pojedynczy bajt nadawany przez SPI (traktowany jako pojedynczy bit sygnału dla diod - "waveform" jedynki albo zera) trwał 1.25 us, potrzebuję ustawić taktowanie procesora na 51.2 MHz i podzielić tą częstotliwość przez 8 (w ustawieniach SPI). Wynika to stąd że pojedynczy bit SPI kodujący 1/8 bit dla diod musi trwać przez 1.25/8 us = 0.15625 us, a to daje częstotliwość 6.4 MHz. Następnie tworzę odpowiedni bufor wartości odpowiadających bitom sygnału dla diod i transmituję go przez SPI.

Mój kod z wyciętymi niepotrzebnymi fragmentami:

http://pastebin.com/fg0sdCuC

Wrzuciłem go też jako załącznik.

Sama funkcja generująca bufor do transmisji przez SPI:

int main(void)
{
   HAL_Init();
   SystemClock_Config();
   MX_GPIO_Init();
   MX_SPI1_Init();

   while (1) {
       uint8_t zeroes = 0;
       uint8_t zero = 0b11100000;
       uint8_t one = 0b11111000;

       uint8_t buffer[744];

       for (int i = 0; i < 24; i++)
           buffer[i] = zeroes;

       uint8_t color = 0;
       for (int i = 24; i < 744; i += 24) {
           for (int j = 0; j < 24; j++)
               buffer[i+j] = zero;

           if (color == 0) {
               buffer[i] = one;
               color++;
           } else if (color == 1) {
               buffer[i + 8] = one;
               color++;
           } else if (color == 2) {
               buffer[i + 16] = one;
               color = 0;
           }
       }

       HAL_SPI_Transmit(&hspi1, &buffer, 744, 1000);
       HAL_Delay(10000);
   }
}

Problem w tym że mój kod czasem działa, a czasem nie. Na początku bardziej działał - wyświetlał naprzemiennie kolory GRB, ale czasem traciły one na jasności (w kolejnych cyklach odświeżania co 10 sec) i ponownie stawały się jasne. Obecnie bardziej nie działa - cały pasek jest biały, czasem widać że na ten biały kolor składają się naprzemiennie bardziej zielone, czerwone i niebieskie piksele (kolejne diody).

Co może być przyczyną takiego zachowania? Czy między ramkami SPI następuje jakaś przerwa? Czy do ramek jest coś doklejane jak w UART? Niestety nie mam oscyloskopu ani nawet analizatora stanów logicznych. To ostatnie planuję kupić.

Nie chciał bym przerabiać gotowych rozwiązać, ponieważ dopiero uczę się STM32 z HAL-em. Nie korzystałem jeszcze z DMA itp.

ws2812b.c

Link do komentarza
Share on other sites

I jak poradziles sobie z problemem?

Użyłem SPI. Problem był banalny - użyłem inne taśmy i zaczęło działać. Ta pierwsza była zepsuta. Przy okazji kupiłem analizator stanów logicznych, żeby zobaczyć co tam się dzieje i STM nadawał wszystko prawidłowo.

Tutaj kod i projekt do CubeMX: https://github.com/akurczyk/STM32-Training/tree/master/8-WS2812B

Można by to ulepszyć, stosując I2S zamiast SPI - powinno się tym sterować bardzo podobnie, jednak I2S ma swoje własne wyjście z pętli PLL, więc można niezależnie ustawić dla rdzenia taktowanie nawet 100 MHz i osobno 6.4 MHz dla transmisji po I2S.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.