Неопиксельный пример кода сбой при использовании большего количества пикселей - PullRequest
2 голосов
/ 17 апреля 2020

Контекст

Я перезапускаю личный проект, в котором участвовали ESP8266 и WS2812B (Neopixels).

Стоит отметить, что в данный момент у меня нет подключенных неопикселей; Я просто пытаюсь понять, как быстро я могу обновлять пиксели.

Я использую очень простой пример кода, взятый из репозитория Adafruit Neopixel GitHub. Я немного изменил его, чтобы сделать его более точным для моего варианта использования и удалить комментарии (для публикации здесь).

Подробности

Пример кода:

#include <Adafruit_NeoPixel.h>

#define PIN 13        
#define NUMPIXELS 300 
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

void setup()
{
  Serial.begin(115200);
  delay(1000);  
  pixels.begin();
}

void loop()
{
  Serial.println("Start");
  for (int i = 0; i < NUMPIXELS; i++)
  {
    Serial.println(i);
    pixels.setPixelColor(i, pixels.Color(0, 150, 0));
    pixels.show();
  }
  Serial.println("End");
}

Это вызовет sh, прежде чем вызывается "End". Значение l oop достигает ~ 227:

...
227

Soft WDT reset

ctx: cont 
sp: 3ffffd80 end: 3fffffd0 offset: 01b0

>>>stack>>>
3fffff30:  feefef00 feefeffe feefeffe 0000012c  
3fffff40:  3ffee798 00000003 3ffee798 40202a7c  
3fffff50:  3ffee798 3ffee768 3ffee798 40202bc5  
3fffff60:  3ffe894c 000000e3 3ffee798 40202cd7  
3fffff70:  3ffe8940 3ffee810 3ffee798 40202be0  
3fffff80:  3ffee798 3ffee768 0000012b 3ffee768  
3fffff90:  402014f2 3ffee768 000000e4 40202777  
3fffffa0:  feefeffe 00000000 3ffee7b4 3ffee7bc  
3fffffb0:  3fffdad0 00000000 3ffee7b4 40202ed4  
3fffffc0:  feefeffe feefeffe 3ffe85d8 40100739  
<<<stack<<<

 ets Jan  8 2013,rst cause:2, boot mode:(1,6)

Устранение неполадок

Этот код не обработает sh, если я уменьшу количество пикселей до 200 или добавлю задержку (1 ) в течение 1 oop.

В качестве альтернативы - удаление for l oop и установка светодиодов простым нажатием l oop (), похоже, работает.

#include <Adafruit_NeoPixel.h>

#define PIN 13        
#define NUMPIXELS 300 
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int i = 0;

void setup()
{
  Serial.begin(115200);
  delay(1000);  
  pixels.begin();
}

void loop()
{
    Serial.println(i);
    pixels.setPixelColor(i, pixels.Color(0, 150, 0)); 
    pixels.show();

  if (i == 299) {
    i = 0;
  } else {
    i = i + 1;
  }
}

Итак - проблема, похоже, в конечном итоге зависит при вызове show () определенное количество раз (227+) в пределах a для l oop внутри функции l oop ().

Question

Многие примеры включают в себя show в течение 1 oop. Я подозреваю, что перенос шоу за пределы l oop - это адекватный обходной путь; Я сделал это в своем первоначальном проекте, казалось бы, без проблем.

Но мне все еще интересно, ПОЧЕМУ это происходит. Тот факт, что во многих примерах show () включен в for для l oop, заставляет меня думать, что это должно работать.

Кто-нибудь знает, почему установка ~ 300 светодиодов в приведенном выше коде может привести к сбою sh, а 200 - нет?

Ответы [ 2 ]

2 голосов
/ 17 апреля 2020

Выход с платы указывает на проблему:

Soft WDT reset

Программный сторожевой таймер запускает и сбрасывает плату. См. https://arduino-esp8266.readthedocs.io/en/latest/faq/a02-my-esp-crashes.html#watchdog.

Встраиваемые системы обычно имеют аппаратный и / или программный сторожевой таймер. Сторожевой таймер сбросит систему, если она не будет обслуживаться в течение предварительно определенного периода времени. Это предотвращает зависание системы, если программное обеспечение блокируется или перегружается.

Для рассматриваемого кода loop():

void loop()
{
  Serial.println("Start");
  for (int i = 0; i < NUMPIXELS; i++)
  {
    Serial.println(i);
    pixels.setPixelColor(i, pixels.Color(0, 150, 0));
    pixels.show();
  }
  Serial.println("End");
}

Реализация pixels.show() использует занятый l oop для реализации сроков записи на светодиод. См. https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp#L205:

  // Data latch = 300+ microsecond pause in the output stream. Rather than
  // put a delay at the end of the function, the ending time is noted and
  // the function will simply hold off (if needed) on issuing the
  // subsequent round of data until the latch time has elapsed. This
  // allows the mainline code to start generating the next frame of data
  // rather than stalling for the latch.
  while(!canShow());

227 итераций l oop достаточно для занятого l oop, чтобы сторожевой таймер включился.

Вызов * на 1024 * меньше или delay() (который вызывает yield() для внутреннего использования) позволяет обслужить сторожевой таймер.

Самое простое решение - вызвать pixels.show() один раз в конце loop().

Так что вам нужно помнить, чтобы погладить щенка / собаку - иначе он кусается.

0 голосов
/ 17 апреля 2020

Это дикое предположение, но эти полоски работают последовательно: первый светодиод берет первые 24 бита, отбрасывает их, а остальные передает следующий светодиод и так далее. Это означает, что отправляемое вами сообщение увеличивается с увеличением количества светодиодов, на которые вы в настоящее время обращаетесь.

Этим светодиодам I C также необходимо некоторое время для сброса, прежде чем следующее сообщение Возможно, существует конфликт данных, поскольку полоса не может догнать увеличивающуюся длину сигнала на полной скорости вашего ESP.

Ваш второй пример содержит несколько тестов, которые могут замедлить передачу, достаточную для Избегайте конфликта.

Итак, вам может понадобиться добавить небольшую задержку в ваш первый пример, из документации чего-то небольшого, например, 50 микросекунд. Для этого вы можете использовать delayMicrosecond().

...