W porządku, oto pinout:
P16: DOUT (do DIN na pasku)
P22: 24v Power Enable (kontroluje pin +24v do paska LED)
P24: Przycisk (niski po naciśnięciu, wysoki, gdy nie jest naciśnięty)
Wypróbowałem sterownik SM16703 i wygląda na to, że z jakiegoś powodu występuje przesunięcie bitowe, które powoduje, że kanały nie są prawidłowo ustawione. Ale z tego, co wiem, kolejność kanałów jest następująca:
Kanał 1: Czerwony
Kanał 2: Zielony
Kanał 3: Niebieski
Kanał 4: Ciepła biel 1
Kanał 5: Ciepła biel 2 (ta sama dioda LED co kanał 4, ale tylko dodatkowa jasność)
Kanał 6: Chłodna biel 1
Kanał 7: Chłodna biel 2 (Ta sama dioda LED co kanał 6, ale tylko dodatkowa jasność)
Wygląda więc na to, że kanały RGB mogą działać w zakresie 0-255, ale kanały bieli mogą efektywnie działać w zakresie 0-510.
Sterownik SM16703 zdecydowanie wydaje się błędny, nawet biorąc pod uwagę, że jest przeznaczony tylko dla 3 kanałów zamiast 7. Wydaje się, że nie czyści bufora podczas inicjalizacji, więc wszystko zaczyna się od losowych wartości, chyba że zainicjujesz je wszystkie jawnie. Wydaje się również, że nie zapobiega ustawianiu wartości LED, które są większe niż inicjalizacja, co prowadzi do uszkodzenia pamięci, co powoduje, że urządzenie przechodzi w zły stan. Wydaje się również, że występuje dziwny problem z przesunięciem bitów, w którym kanały nie są do końca zgodne bit po bicie, więc ustawienie jednego kanału na 255 wydaje się powodować ustawienie niektórych z tych bitów na poprzednim kanale. Nie jestem pewien, dlaczego tak się dzieje.
Ale przynajmniej mogę kontrolować światła!
Dla ogólnego sterownika myślę, że chciałbyś mieć następujące opcje konfiguracji:
1. Liczba kanałów.
2. Mapowanie kanałów. (RGB, BGR, WWRGBCC, itp.)
3. Może informacje o taktowaniu, aby mógł być również kompatybilny z neopikselami?
UPDATE: Jeszcze tego nie testowałem, ale myślę, że rodzaj zmian, które chcielibyśmy wprowadzić w sterowniku, wygląda mniej więcej tak:
diff --git a/src/driver/drv_sm16703P.c b/src/driver/drv_sm16703P.c
index e0e011ce..0593dbd6 100644
--- a/src/driver/drv_sm16703P.c
+++ b/src/driver/drv_sm16703P.c
@@ -22,12 +22,16 @@
#include "drv_spidma.h"
+#define SM16703P_MAX_CHANNELS (8)
+
static uint8_t data_translate[4] = {0b10001000, 0b10001110, 0b11101000, 0b11101110};
-UINT8 *send_buf;
-struct spi_message *spi_msg;
+UINT8 *send_buf = NULL;
+struct spi_message *spi_msg = NULL;
BOOLEAN initialized = false;
uint32_t pixel_count = 0;
+uint8_t channel_count = 3;
+uint8_t channel_map[SM16703P_MAX_CHANNELS];
static uint8_t translate_2bit(uint8_t input) {
//ADDLOG_INFO(LOG_FEATURE_CMD, "Translate 0x%02x to 0x%02x", (input & 0b00000011), data_translate[(input & 0b00000011)]);
@@ -58,7 +62,7 @@ static void SM16703P_setMultiplePixel(uint32_t pixel, UINT8 *data) {
// Iterate over pixel
uint8_t *dst = spi_msg->send_buf + 2;
- for (uint32_t i = 0; i < pixel * 3; i++) {
+ for (uint32_t i = 0; i < pixel * channel_count; i++) {
uint8_t input = *data++;
*dst++ = translate_2bit((input >> 6));
*dst++ = translate_2bit((input >> 4));
@@ -66,14 +70,21 @@ static void SM16703P_setMultiplePixel(uint32_t pixel, UINT8 *data) {
*dst++ = translate_2bit(input);
}
}
-void SM16703P_setPixel(int pixel, int r, int g, int b) {
- translate_byte(r, spi_msg->send_buf + (2 + 0 + (pixel * 3 * 4)));
- translate_byte(g, spi_msg->send_buf + (2 + 4 + (pixel * 3 * 4)));
- translate_byte(b, spi_msg->send_buf + (2 + 8 + (pixel * 3 * 4)));
+void SM16703P_setPixel(int pixel, int r, int g, int b, int w, int c) {
+ translate_byte(r, spi_msg->send_buf + (2 + channel_map[0]*4 + (pixel * channel_count * 4)));
+ translate_byte(g, spi_msg->send_buf + (2 + channel_map[1]*4 + (pixel * channel_count * 4)));
+ translate_byte(b, spi_msg->send_buf + (2 + channel_map[2]*4 + (pixel * channel_count * 4)));
+
+ if (channel_count >= 4) {
+ translate_byte(w, spi_msg->send_buf + (2 + channel_map[3]*4 + (pixel * channel_count * 4)));
+ }
+ if (channel_count >= 5) {
+ translate_byte(c, spi_msg->send_buf + (2 + channel_map[4]*4 + (pixel * channel_count * 4)));
+ }
}
commandResult_t SM16703P_CMD_setPixel(const void *context, const char *cmd, const char *args, int flags) {
- int pixel, i, r, g, b;
+ int pixel, i, r, g, b, w, c;
Tokenizer_TokenizeString(args, 0);
if (Tokenizer_GetArgsCount() != 4) {
@@ -86,32 +97,43 @@ commandResult_t SM16703P_CMD_setPixel(const void *context, const char *cmd, cons
g = Tokenizer_GetArgIntegerRange(2, 0, 255);
b = Tokenizer_GetArgIntegerRange(3, 0, 255);
- ADDLOG_INFO(LOG_FEATURE_CMD, "Set Pixel %i to R %i G %i B %i", pixel, r, g, b);
+ if (channel_count >= 4) {
+ w = Tokenizer_GetArgIntegerRange(4, 0, 255);
+ }
+
+ if (channel_count >= 5) {
+ c = Tokenizer_GetArgIntegerRange(5, 0, 255);
+ }
+
+ if (channel_count send_buf[2 + 1 + (pixel * 3 * 4)],
- spi_msg->send_buf[2 + 2 + (pixel * 3 * 4)],
- spi_msg->send_buf[2 + 3 + (pixel * 3 * 4)],
- spi_msg->send_buf[2 + 4 + (pixel * 3 * 4)],
- spi_msg->send_buf[2 + 5 + (pixel * 3 * 4)],
- spi_msg->send_buf[2 + 6 + (pixel * 3 * 4)],
- spi_msg->send_buf[2 + 7 + (pixel * 3 * 4)],
- spi_msg->send_buf[2 + 8 + (pixel * 3 * 4)],
- spi_msg->send_buf[2 + 9 + (pixel * 3 * 4)],
- spi_msg->send_buf[2 + 10 + (pixel * 3 * 4)],
- spi_msg->send_buf[2 + 11 + (pixel * 3 * 4)]);
+ else if (pixel < pixel_count) {
+ SM16703P_setPixel(pixel, r, g, b, w, c);
+
+ for (i = 0; i < channel_count; i++) {
+ ADDLOG_INFO(LOG_FEATURE_CMD, "Raw Data CH%i 0x%02x 0x%02x 0x%02x 0x%02x",
+ i,
+ spi_msg->send_buf[2 + 0 + i*4 + (pixel * channel_count * 4)],
+ spi_msg->send_buf[2 + 1 + i*4 + (pixel * channel_count * 4)],
+ spi_msg->send_buf[2 + 2 + i*4 + (pixel * channel_count * 4)],
+ spi_msg->send_buf[2 + 3 + i*4 + (pixel * channel_count * 4)]);
+ }
+ } else {
+ ADDLOG_INFO(LOG_FEATURE_CMD, "Bad pixel index %i", pixel);
+ return CMD_RES_BAD_ARGUMENT;
}
-
return CMD_RES_OK;
}
@@ -120,30 +142,64 @@ static void SM16703P_Send(byte *data, int dataSize) {
}
commandResult_t SM16703P_Start(const void *context, const char *cmd, const char *args, int flags) {
-
+ int i;
Tokenizer_TokenizeString(args, 0);
if (Tokenizer_GetArgsCount() == 0) {
- ADDLOG_INFO(LOG_FEATURE_CMD, "Not Enough Arguments for init SM16703P: Amount of LEDs missing");
+ ADDLOG_INFO(LOG_FEATURE_CMD, "Not Enough Arguments for init SM16703P: Pixel count is missing");
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
}
pixel_count = Tokenizer_GetArgIntegerRange(0, 0, 255);
+ if (Tokenizer_GetArgsCount() >= 2) {
+ channel_count = Tokenizer_GetArgIntegerRange(1, 0, SM16703P_MAX_CHANNELS);
+ } else {
+ channel_count = 3;
+ }
+
+ if (Tokenizer_GetArgsCount() >= 3) {
+ for (i = 0; i < channel_count; i++) {
+ channel_map[i] = Tokenizer_GetArgIntegerRange(2+i, 0, 8);
+ if (channel_map[i] >= channel_count) {
+ ADDLOG_INFO(LOG_FEATURE_CMD, "Bad channel index %i for channel %i", channel_map[i], i);
+ return CMD_RES_BAD_ARGUMENT;
+ }
+ }
+ } else {
+ for (i = 0; i < channel_count; i++) {
+ channel_map[i] = i;
+ }
+ }
+
ADDLOG_INFO(LOG_FEATURE_CMD, "Register driver with %i LEDs", pixel_count);
+ // Free the old buffer if one was allocated.
+ if (initialized) {
+ os_free(send_buf);
+ }
+
// Prepare buffer
- uint32_t buffer_size = 2 + (pixel_count * 3 * 4); //Add two bytes for "Reset"
+ uint32_t buffer_size = 2 + (pixel_count * channel_count * 4); //Add two bytes for "Reset"
send_buf = (UINT8 *)os_malloc(sizeof(UINT8) * (buffer_size)); //18LEDs x RGB x 4Bytes
- int i;
send_buf[0] = 0;
send_buf[1] = 0;
+ // Turn on all channels on all pixels at maximum brightness.
+ // TODO: Is this REALLY what we want to do? Shouldn't we be
+ // be setting the initial value to be encoded zero bits
+ // instead of encoded 1 bits? Consider changing to
+ // 0b10001000 after discussion.
for (i = 2; i < buffer_size; i++) {
send_buf[i] = 0b11101110;
}
+ // Free the old buffer if one was allocated.
+ if (initialized) {
+ os_free(spi_msg);
+ }
+
spi_msg = os_malloc(sizeof(struct spi_message));
spi_msg->send_buf = send_buf;
spi_msg->send_len = buffer_size;
Pozwoliłoby to na inicjalizację z niestandardową liczbą kanałów, takich jak ten (7 kanałów, RGBWxCx)
SM16703P_Init 10 7 0 1 2 3 5
Ale jeśli nie określisz liczby kanałów, przyjmie "3 0 1 2" (3 kanały, kolejność RGB).
Ponownie, nie testowałem powyższego kodu (nie jestem nawet pewien, czy jeszcze się kompiluje), ale to powinien być dobry początek.
Dodano po 11 [godzinach] 22 [minutach]: Argh.... Wygląda na to, że coś jest bardzo dziwnego ze sterownikiem SPI. Ciągle dostaję bardzo dziwne przesunięcie / zapętlenie na wyjściu SPI, takie rzeczy jak kanały są wyłączone o dwa lub więcej, ale nadal faktycznie owijają się w taki sposób, że jeśli wypełnisz wszystkie piksele, wszystkie piksele nadal będą oświetlone. Przesunięcie wydaje się zmieniać w zależności od rozmiaru bufora.
Mój mózg boli zbyt mocno, aby kontynuować pracę nad tym dziś wieczorem.
AKTUALIZACJA:
Tak, wyjście SPI nie pasuje do danych w buforze:
Możesz zobaczyć tę lukę w środku: To jest impuls "reset" (rozszerzony do 7 bajtów w moim kodzie), który powinien być na początku transmisji. Innymi słowy, cała transmisja powinna być wyświetlana jako duży blok, a nie dwa bloki. Z jakiegoś powodu impuls "reset" znajduje się w środku!
Jeśli zmniejszę całkowitą liczbę świateł do 2 (po 7 kanałów każdy), mogę niezawodnie uzyskać impuls resetowania na początku. Jestem naprawdę zdezorientowany, dlaczego wyjście SPI nie jest zgodne z kolejnością w pamięci. Jakieś pomysły?