• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Нужна помощь Нестабильность ШИМ - вспышки яркости LED

Wake_me

New member
Управляю RGB светодиодной лентой через полевики с помощью ШИМ. Хотел добиться плавных медленных изменений цвета, для чего сперва использовал стороннюю библиотеку, где обнаружил баг - в определенные моменты смены светов (а именно в моменты смены направления цвета) происходит очень короткий, но заметный (особенно находясь в помещении, освещенной 10 метрами ленты) импульс в виде мгновенного небольшого изменения яркости текущего цвета.

Сначала грешил на библиотеку, но потом смоделировал проблему из стандартного простого скетча Fading. Код прилагаю.
Одно из основных условий - пониженная частота ШИМа, заданная через analogWriteFreq(150);
Чем ниже частота - тем заметнее такие периодические баги.
На частоте 1000 такие короткие вспышки сложно заметить, но если специально следить, то можно заметить, что они тоже иногда происходят.

Что самое интересное, мигание недерминированно.
Все зависит от комбинации цветов. Абсолютные значения яркости значения не имеют. Главное - их относительное изменение
Вот пример скетча, в котором вспышка у меня проявляется на каждый проход:

Код:
#define REDPIN 4
#define GREENPIN 5
#define BLUEPIN 14

void writeRgb(int r, int g, int b){
    analogWrite(REDPIN, r);
    analogWrite(GREENPIN, g);
    analogWrite(BLUEPIN, b);
    Serial.print("R: ");  Serial.print(r);
    Serial.print(", G: "); Serial.print(g);
    Serial.print(", B: "); Serial.println(b);
   delay(1000);
}

void setup() {
  Serial.begin(115200);
  Serial.println("");
  analogWriteFreq(150);
  pinMode(REDPIN,OUTPUT);
  pinMode(GREENPIN,OUTPUT);
  pinMode(BLUEPIN,OUTPUT);
}

void loop() {
    static int count = 1;
    Serial.print("---PASS №");Serial.println(count);
    writeRgb(30, 997, 30);
    writeRgb(31, 998, 31);
    writeRgb(32, 999, 32);
    writeRgb(33, 1000, 33);
    Serial.println("BLINK!");
    writeRgb(34, 999, 33);
    writeRgb(35, 998, 33);
    writeRgb(36, 997, 33);
    count++;
}

И ВНИМАНИЕ...
В следующем коде таких вспышек нет. Хотя что принципиально изменилось то:
P.S. Код оформляю как цитату специально, чтобы сработало выделение жирным.

void loop() {
static int count = 1;
Serial.print("---PASS №");Serial.println(count);
writeRgb(30, 997, 30);
writeRgb(31, 998, 31);
writeRgb(32, 999, 32);
writeRgb(33, 1000, 33);
Serial.println("BLINK!");
writeRgb(34, 999, 34);
writeRgb(35, 998, 35);
writeRgb(36, 997, 36);
count++;
}
Еще один пример, когда мелкое изменение нивелирует проявление бага:

void loop() {
static int count = 1;
Serial.print("---PASS №");Serial.println(count);
writeRgb(30, 997, 30);
writeRgb(31, 998, 31);
writeRgb(32, 999, 32);
writeRgb(33, 1000, 33);
Serial.println("BLINK!");
writeRgb(33, 999, 33);
writeRgb(33, 998, 33);
writeRgb(33, 997, 33);
count++;
}
Пример, подстроенный по аналогии с первым скетчем и где вспышки есть. Но значения уже совсем другие. Хотя тут теперь редко, но случаются моменты, когда на очередном проходе вспышка не случается.


void loop() {
static int count = 1;
Serial.print("---PASS №");Serial.println(count);
writeRgb(780, 10, 10);
writeRgb(781, 11, 11);
writeRgb(782, 12, 12);
writeRgb(783, 13, 13);
Serial.println("BLINK!");
writeRgb(782, 13, 14);
writeRgb(781, 13, 15);
writeRgb(780, 13, 16);
count++;
}
А вот так уже вспышек нет, несмотря на, казалось бы, резкий скачок:
void loop() {
static int count = 1;
Serial.print("---PASS №");Serial.println(count);
writeRgb(780, 1, 1);
writeRgb(781, 1, 1);
writeRgb(782, 1, 1);
writeRgb(783, 1, 1);
Serial.println("BLINK!");
writeRgb(782, 3, 3);
writeRgb(781, 3, 3);
writeRgb(780, 3, 3);
count++;
}
В общем, я никак не могу собрать в кучу все эти признаки, чтобы сделать какой-то вывод...
Такое чувство, что какой-то баг во внутренней реализации ШИМа при определенных взаимодействиях нескольких одновременных ШИМ на разных пинах.
 
Последнее редактирование:

pvvx

Активный участник сообщества
А в чем проблема синхронного вывода ШИМ каналов?
В ESP же софтовый ШИМ - процом по прерываниям. И его работа прерывается некоторыми процедурами WiFi, а не "муар". Даже если прерывания по NMI.
При активности некоторых режимов sleep для station, вообще отключаются все таймеры на периоды между beacon, как и сам CPU, для "экономии энергии"...
Если выключите этот режим - будет лучше, но будет больше жрать.
И всё равно, через непонятные временные периоды в ESP происходит какой-то процесс в WiFi драйвере, что отключается и прием-передача на время до 1 сек...
Для стабилизации вывода ШИМ можно посоветовать только отключать WiFi на время требуемой стабильности.
У других (RTL871x) аппаратный контроллер - там всё синхронно.
Возможно, что в ESP-32S это тоже исправлено или сделали(ют) нормально...
 
Последнее редактирование:

Wake_me

New member
А в чем проблема синхронного вывода ШИМ каналов?
В ESP же софтовый ШИМ - процом по прерываниям. И его работа прерывается некоторыми процедурами WiFi, а не "муар". Даже если прерывания по NMI.
При активности некоторых режимов sleep для station, вообще отключаются все таймеры на периоды между beacon, как и сам CPU, для "экономии энергии"...
Если выключите этот режим - будет лучше, но будет больше жрать.
И всё равно, через непонятные временные периоды в ESP происходит какой-то процесс в WiFi драйвере, что отключается и прием-передача на время до 1 сек...
Для стабилизации вывода ШИМ можно посоветовать только отключать WiFi на время требуемой стабильности.
У других (RTL871x) аппаратный контроллер - там всё синхронно.
Возможно, что в ESP-32S это тоже исправлено или сделали(ют) нормально...
Я не говорю, что в моем случае причина та же. Он писал, что дело в том, что пины с ШИМ висят на разных таймерах.
У меня же, если бы эти мерцания были бы связаны с wifi фоновым сетевым функционалом (или любым другим), то они не были бы так четко привязаны к моменту смены направления изменения цвета и вывод сообщения "Blink!" не совпадал бы с мерцанием и не исчезали бы одновременно с изменением алгоритма смены цветов.
Я проверил. Добавление [inline]WiFi.mode( WIFI_OFF );[/inline] картину не меняет: такие же мерация.
 

pvvx

Активный участник сообщества
Я проверил. Добавление [inline]WiFi.mode( WIFI_OFF );[/inline] картину не меняет: такие же мерация.
Значит что-то другое.
Тут надо определиться - в вашем SDK используется софт ШИМ по NMI или просто по прерыванию таймера. Существуют разные версии SDK.
Если просто по прерыванию, без задействования NMI, то любой процесс вызвавший хотя-бы memalloc будет отключать на время прерывания - в его коде стоит запрет прерываний пока память не распределиться. Ну и т.д. А к функциям memalloc очень часто обращается C++. Получите мигание.
Народ на ESP использует внешнюю микросхему ШИМ.
К примеру такой 16 Канала 12 bit PWM Сервоприводом Driver I2C интерфейс PCA9685 для arduino или Raspberry pi щит модуль servo щит купить на AliExpress
 
Последнее редактирование:

Wake_me

New member
Да, похоже, что придется заказывать. Спасибо.

Правильно ли я его пытаюсь завести? По образцу:
Код:
#include "pwm.c"

#define PWM_CHANNELS 5
#define SDK_PWM_PERIOD_COMPAT_MODE 1
const uint32_t period = 5000; // * 200ns ^= 1 kHz
uint32 pwm_duty_init[PWM_CHANNELS] = {500, 500, 500, 500, 500};

uint32 io_info[PWM_CHANNELS][3] = {
    // MUX, FUNC, PIN
    {PERIPHS_IO_MUX_MTDI_U,  FUNC_GPIO12, 12},
    {PERIPHS_IO_MUX_MTDO_U,  FUNC_GPIO15, 15},
    {PERIPHS_IO_MUX_MTCK_U,  FUNC_GPIO13, 13},
    {PERIPHS_IO_MUX_MTMS_U,  FUNC_GPIO14, 14},
    {PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5 ,  5},
};

void setup() {
  pwm_init(period, pwm_duty_init, PWM_CHANNELS, io_info);
  pwm_start();
}
void loop() {
}
В результате на пинах ноль.
 
Сверху Снизу