控制两个 LED 串时 ESP32 内核冻结
ESP32 Cores are freezing when controlling two LED strings
上周,我一直在处理 ESP32 的问题。有关背景信息,我正在从事 Music Meter 项目。我的目标是让 ESP32 对两个音频信号进行采样,并让两组 LED 灯串对两个相应的音频信号做出反应。当我同时使用两个内核时(使用 Arduino IDE),我一直遇到的问题是,当我对音频进行采样时,其中一个内核经常冻结。我知道核心正在冻结并且它不会卡在循环中,因为我设置了一个条件,如果长时间没有任何 activity,其中一个 LED 将改变颜色,并且它从未改变颜色。
同样奇怪的是作为基线测试,我想看看我是否可以只控制 LED,但有一个简单的 for 循环来打开和关闭每个条带,而且效果很好。只有当我开始在多个内核上对音频进行采样并且 LED 做出反应时,问题才会出现。如果我单独做每个核心,那么核心永远不会冻结,它会按照我想要的方式工作。
/* This is in Core 1 */
for (int i = 0; i < MIDDLE_LED_COUNT; i++) {
middle_strip.setPixelColor(i, color);
middle_strip.show();
}
for (int i = (MIDDLE_LED_COUNT - 1); i >= 0 ; i--) {
middle_strip.setPixelColor(i, 0, 0, 0, 0);
middle_strip.show();
}
/* This is in Core 0 */
for (int i = 0; i < LOWER_LED_COUNT; i++) {
lower_strip.setPixelColor(i, color);
lower_strip.show();
}
for (int i = (LOWER_LED_COUNT - 1); i >= 0 ; i--) {
lower_strip.setPixelColor(i, 0, 0, 0, 0);
lower_strip.show();
}
其他注意事项:当 ESP 通过 WiFi.mode( WIFI_MODE_NULL ) 处于“Music Visualizer”模式时,WiFi 已断开连接。
我已将所有可能发生变化的变量设置为 volatile 只是为了看看这是否会使它变得更好。它稍微改进了它,但没有解决问题。
在这一点上,我 运行 束手无策,我不知道如何解决这个问题。我当前的代码包含在下面:
/* Core 1 */
void musicVisualizer(void) {
middle_strip.clear();
upper_strip.clear();
middle_strip.show();
upper_strip.show();
WiFi.mode( WIFI_MODE_NULL );
delay(100);
// Add code to tell Core 0 to wait until LED's are cleared.
while (vu_meter) {
tweeter_prev = tweeter;
if (analogRead(tweeter_sample) <= 490)
tweeter_adc = 0;
else {
tweeter_adc = (analogRead(tweeter_sample) - 490);
if (tweeter_adc < 0)
tweeter_adc = 0; // Filter for changing reference voltage
}
tweeter_filter.Filter(tweeter_adc);
tweeter = tweeter_filter.Current() * 4; // 6 scaler is for when Alexa is at Volume Level 4
/* LED's turning on and off in response to audio */
if ((tweeter > tweeter_prev) && (tweeter < MIDDLE_LED_COUNT)) {
for (int x = tweeter_prev; x <= tweeter; x++) {
middle_strip.setPixelColor(x, 0, 0, middle_strip.gamma32(BRIGHTNESS));
}
middle_strip.setPixelColor(0, 0, 0, middle_strip.gamma32(BRIGHTNESS)); // Removes status LED if active
tweeter_count = 0;
middle_strip.show();
}
else if (tweeter_prev > tweeter) {
for (int x = tweeter_prev; x >= tweeter; x--) {
middle_strip.setPixelColor(x, 0, 0, 0);
}
middle_strip.setPixelColor(0, 0, 0, middle_strip.gamma32(BRIGHTNESS)); // Removes status LED if active
tweeter_count = 0;
middle_strip.show();
}
else {
tweeter_count += 1;
if (tweeter_count < 1000)
middle_strip.setPixelColor(0, middle_strip.gamma32(BRIGHTNESS), 0, 0, 0);
else
middle_strip.setPixelColor(0, 0, 0, 0, middle_strip.gamma32(BRIGHTNESS));
middle_strip.show();
}
// Blynk.run();
}
/* Leaving VU Meter, returning to current lamp color set */
if (led_on) {
if (!color_white) {
for (int i = 0; i < LOWER_LED_COUNT; i++) {
lower_strip.setPixelColor(i, color);
lower_strip.show();
}
for (int i = 0; i < MIDDLE_LED_COUNT; i++) {
middle_strip.setPixelColor(i, color);
middle_strip.show();
}
for (int i = 0; i < UPPER_LED_COUNT; i++) {
upper_strip.setPixelColor(i, color);
upper_strip.show();
}
}
else {
for (int i = 0; i < LOWER_LED_COUNT; i++) {
lower_strip.setPixelColor(i, 0, 0, 0, lower_strip.gamma32(BRIGHTNESS));
lower_strip.show();
}
for (int i = 0; i < MIDDLE_LED_COUNT; i++) {
middle_strip.setPixelColor(i, 0, 0, 0, middle_strip.gamma32(BRIGHTNESS));
middle_strip.show();
}
for (int i = 0; i < UPPER_LED_COUNT; i++) {
upper_strip.setPixelColor(i, 0, 0, 0, upper_strip.gamma32(BRIGHTNESS));
upper_strip.show();
}
}
}
else {
upper_strip.clear();
middle_strip.clear();
lower_strip.clear();
upper_strip.show();
middle_strip.show();
lower_strip.show();
}
}
/* Core 0 */
void vu_meter_sub(void * parameter) {
while (true) {
esp_task_wdt_init(30, false);
if (vu_meter) {
lower_strip.clear();
lower_strip.show();
while (vu_meter) {
sub_prev = sub;
sub_adc = analogRead(sub_sample);
sub_filter.Filter(sub_adc);
sub = sub_filter.Current();
if ((sub > sub_prev) && (sub < LOWER_LED_COUNT)) {
for (int x = sub_prev; x <= sub; x++) {
lower_strip.setPixelColor(x, 0, lower_strip.gamma32(BRIGHTNESS), 0);
}
lower_strip.setPixelColor(0, 0, lower_strip.gamma32(BRIGHTNESS), 0);
sub_count = 0;
lower_strip.show();
}
else if (sub_prev > sub) {
for (int x = sub_prev; x >= sub; x--) {
lower_strip.setPixelColor(x, 0, 0, 0);
}
lower_strip.setPixelColor(0, 0, lower_strip.gamma32(BRIGHTNESS), 0);
sub_count = 0;
lower_strip.show();
}
else {
sub_count += 1;
if (sub_count < 1000)
lower_strip.setPixelColor(0, lower_strip.gamma32(BRIGHTNESS), 0, 0, 0);
else
lower_strip.setPixelColor(0, 0, 0, 0, lower_strip.gamma32(BRIGHTNESS));
lower_strip.show();
}
}
}
}
}
故障排除后,我想我找到了问题,我想 post 为将来可能遇到此问题的任何人post。
在我的程序中,我需要为两个内核中的两个 music_visualizer 函数添加 1 毫秒的延迟,以防止 CPU 的 运行 时间不足(我相信这就是正在发生的事情)。这样做大大提高了固件的成功率。我注意到,如果 Blynk(控制 lamp 的应用程序)未被注释,并且可以自由使用 运行 多次,CPU 之一挨饿的可能性就会增加。为了解决这个问题,我所做的是使用 millis() 计时器来跟踪调用 Blynk 之前经过了多少时间。 1000 毫秒后,将调用一次 Blynk 函数,然后再等待 1000 毫秒。由于我证明这是可行的,因此不需要 WIFI_MODE_NULL,因为不需要禁用 WiFi。
上周,我一直在处理 ESP32 的问题。有关背景信息,我正在从事 Music Meter 项目。我的目标是让 ESP32 对两个音频信号进行采样,并让两组 LED 灯串对两个相应的音频信号做出反应。当我同时使用两个内核时(使用 Arduino IDE),我一直遇到的问题是,当我对音频进行采样时,其中一个内核经常冻结。我知道核心正在冻结并且它不会卡在循环中,因为我设置了一个条件,如果长时间没有任何 activity,其中一个 LED 将改变颜色,并且它从未改变颜色。
同样奇怪的是作为基线测试,我想看看我是否可以只控制 LED,但有一个简单的 for 循环来打开和关闭每个条带,而且效果很好。只有当我开始在多个内核上对音频进行采样并且 LED 做出反应时,问题才会出现。如果我单独做每个核心,那么核心永远不会冻结,它会按照我想要的方式工作。
/* This is in Core 1 */
for (int i = 0; i < MIDDLE_LED_COUNT; i++) {
middle_strip.setPixelColor(i, color);
middle_strip.show();
}
for (int i = (MIDDLE_LED_COUNT - 1); i >= 0 ; i--) {
middle_strip.setPixelColor(i, 0, 0, 0, 0);
middle_strip.show();
}
/* This is in Core 0 */
for (int i = 0; i < LOWER_LED_COUNT; i++) {
lower_strip.setPixelColor(i, color);
lower_strip.show();
}
for (int i = (LOWER_LED_COUNT - 1); i >= 0 ; i--) {
lower_strip.setPixelColor(i, 0, 0, 0, 0);
lower_strip.show();
}
其他注意事项:当 ESP 通过 WiFi.mode( WIFI_MODE_NULL ) 处于“Music Visualizer”模式时,WiFi 已断开连接。 我已将所有可能发生变化的变量设置为 volatile 只是为了看看这是否会使它变得更好。它稍微改进了它,但没有解决问题。
在这一点上,我 运行 束手无策,我不知道如何解决这个问题。我当前的代码包含在下面:
/* Core 1 */
void musicVisualizer(void) {
middle_strip.clear();
upper_strip.clear();
middle_strip.show();
upper_strip.show();
WiFi.mode( WIFI_MODE_NULL );
delay(100);
// Add code to tell Core 0 to wait until LED's are cleared.
while (vu_meter) {
tweeter_prev = tweeter;
if (analogRead(tweeter_sample) <= 490)
tweeter_adc = 0;
else {
tweeter_adc = (analogRead(tweeter_sample) - 490);
if (tweeter_adc < 0)
tweeter_adc = 0; // Filter for changing reference voltage
}
tweeter_filter.Filter(tweeter_adc);
tweeter = tweeter_filter.Current() * 4; // 6 scaler is for when Alexa is at Volume Level 4
/* LED's turning on and off in response to audio */
if ((tweeter > tweeter_prev) && (tweeter < MIDDLE_LED_COUNT)) {
for (int x = tweeter_prev; x <= tweeter; x++) {
middle_strip.setPixelColor(x, 0, 0, middle_strip.gamma32(BRIGHTNESS));
}
middle_strip.setPixelColor(0, 0, 0, middle_strip.gamma32(BRIGHTNESS)); // Removes status LED if active
tweeter_count = 0;
middle_strip.show();
}
else if (tweeter_prev > tweeter) {
for (int x = tweeter_prev; x >= tweeter; x--) {
middle_strip.setPixelColor(x, 0, 0, 0);
}
middle_strip.setPixelColor(0, 0, 0, middle_strip.gamma32(BRIGHTNESS)); // Removes status LED if active
tweeter_count = 0;
middle_strip.show();
}
else {
tweeter_count += 1;
if (tweeter_count < 1000)
middle_strip.setPixelColor(0, middle_strip.gamma32(BRIGHTNESS), 0, 0, 0);
else
middle_strip.setPixelColor(0, 0, 0, 0, middle_strip.gamma32(BRIGHTNESS));
middle_strip.show();
}
// Blynk.run();
}
/* Leaving VU Meter, returning to current lamp color set */
if (led_on) {
if (!color_white) {
for (int i = 0; i < LOWER_LED_COUNT; i++) {
lower_strip.setPixelColor(i, color);
lower_strip.show();
}
for (int i = 0; i < MIDDLE_LED_COUNT; i++) {
middle_strip.setPixelColor(i, color);
middle_strip.show();
}
for (int i = 0; i < UPPER_LED_COUNT; i++) {
upper_strip.setPixelColor(i, color);
upper_strip.show();
}
}
else {
for (int i = 0; i < LOWER_LED_COUNT; i++) {
lower_strip.setPixelColor(i, 0, 0, 0, lower_strip.gamma32(BRIGHTNESS));
lower_strip.show();
}
for (int i = 0; i < MIDDLE_LED_COUNT; i++) {
middle_strip.setPixelColor(i, 0, 0, 0, middle_strip.gamma32(BRIGHTNESS));
middle_strip.show();
}
for (int i = 0; i < UPPER_LED_COUNT; i++) {
upper_strip.setPixelColor(i, 0, 0, 0, upper_strip.gamma32(BRIGHTNESS));
upper_strip.show();
}
}
}
else {
upper_strip.clear();
middle_strip.clear();
lower_strip.clear();
upper_strip.show();
middle_strip.show();
lower_strip.show();
}
}
/* Core 0 */
void vu_meter_sub(void * parameter) {
while (true) {
esp_task_wdt_init(30, false);
if (vu_meter) {
lower_strip.clear();
lower_strip.show();
while (vu_meter) {
sub_prev = sub;
sub_adc = analogRead(sub_sample);
sub_filter.Filter(sub_adc);
sub = sub_filter.Current();
if ((sub > sub_prev) && (sub < LOWER_LED_COUNT)) {
for (int x = sub_prev; x <= sub; x++) {
lower_strip.setPixelColor(x, 0, lower_strip.gamma32(BRIGHTNESS), 0);
}
lower_strip.setPixelColor(0, 0, lower_strip.gamma32(BRIGHTNESS), 0);
sub_count = 0;
lower_strip.show();
}
else if (sub_prev > sub) {
for (int x = sub_prev; x >= sub; x--) {
lower_strip.setPixelColor(x, 0, 0, 0);
}
lower_strip.setPixelColor(0, 0, lower_strip.gamma32(BRIGHTNESS), 0);
sub_count = 0;
lower_strip.show();
}
else {
sub_count += 1;
if (sub_count < 1000)
lower_strip.setPixelColor(0, lower_strip.gamma32(BRIGHTNESS), 0, 0, 0);
else
lower_strip.setPixelColor(0, 0, 0, 0, lower_strip.gamma32(BRIGHTNESS));
lower_strip.show();
}
}
}
}
}
故障排除后,我想我找到了问题,我想 post 为将来可能遇到此问题的任何人post。
在我的程序中,我需要为两个内核中的两个 music_visualizer 函数添加 1 毫秒的延迟,以防止 CPU 的 运行 时间不足(我相信这就是正在发生的事情)。这样做大大提高了固件的成功率。我注意到,如果 Blynk(控制 lamp 的应用程序)未被注释,并且可以自由使用 运行 多次,CPU 之一挨饿的可能性就会增加。为了解决这个问题,我所做的是使用 millis() 计时器来跟踪调用 Blynk 之前经过了多少时间。 1000 毫秒后,将调用一次 Blynk 函数,然后再等待 1000 毫秒。由于我证明这是可行的,因此不需要 WIFI_MODE_NULL,因为不需要禁用 WiFi。