-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Using ledcWriteTone cause I2C memory fail #3555
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@tatarmiki I haven't seen any memory leak in i2c before this issue. I added some additional debug code to your example, can you run it and capture the output. Lets see if we can localize the problem. #include <Wire.h>
#include <Adafruit_LEDBackpack.h>
#include <Adafruit_GFX.h>
#include <SPI.h>
Adafruit_7segment seven_segment_display = Adafruit_7segment();
int counter = 0;
int freq = 2000;
int channel = 0;
int resolution = 8;
int cycle = 0;
int32_t lastFreeSpace = 0;
void setup() {
Wire.begin();
lastFreeSpace = ESP.getFreeHeap();
ledcSetup(channel, freq, resolution);
ledcAttachPin(26, channel);
Serial.begin(115200);
seven_segment_display.begin(0x70);
}
void loop() {
// Print the free heap every minute
if (counter == 600) {
counter = 0;
Serial.printf("Cycle: %d\n", cycle++);
Serial.printf("FreeHeap/min: %i bytes\n", ESP.getFreeHeap());
Serial.printf("I2C status = %d - (%s)\n", Wire.lastError(), Wire.getErrorText(Wire.lastError()));
}
// create sample for the 7 segment to display
int seconds = counter % 60;
int minutes = counter / 60;
int min_first_digit = minutes / 10;
int min_second_digit = minutes % 10;
int sec_first_digit = seconds / 10;
int sec_second_digit = seconds % 10;
// write to 7 segment
int32_t currentFreeSpace = ESP.getFreeHeap();
if(currentFreeSpace != lastFreeSpace){
Serial.printf("cycle[%06d] top of loop freespace change, last =%d, current = %d, delta =%d\n",cycle,lastFreeSpace,currentFreeSpace,(currentFreeSpace-lastFreeSpace));
lastFreeSpace = currentFreeSpace;
}
seven_segment_display.drawColon(true);
seven_segment_display.writeDigitNum(0, min_first_digit);
seven_segment_display.writeDigitNum(1, min_second_digit);
seven_segment_display.writeDigitNum(3, sec_first_digit);
seven_segment_display.writeDigitNum(4, sec_second_digit);
currentFreeSpace = ESP.getFreeHeap();
if(currentFreeSpace != lastFreeSpace){
Serial.printf("cycle[%06d] after draw display, freespace change, last =%d, current = %d, delta =%d\n",cycle,lastFreeSpace,currentFreeSpace,(currentFreeSpace-lastFreeSpace));
lastFreeSpace = currentFreeSpace;
}
seven_segment_display.writeDisplay();
currentFreeSpace = ESP.getFreeHeap();
if(currentFreeSpace != lastFreeSpace){
Serial.printf("cycle[%06d] after write through I2C, freespace change, last =%d, current = %d, delta =%d\n",cycle,lastFreeSpace,currentFreeSpace,(currentFreeSpace-lastFreeSpace));
lastFreeSpace = currentFreeSpace;
}
// generate beep sound for buzzer
ledcWriteTone(channel, freq);
// beep sound length is 50 ms
//delay(50);
// stop beep
ledcWriteTone(channel, 0);
//delay(950);
counter++;
}
Chuck. |
Thanks for the fast response. Here's the output. I only changed my counter to 60 to see more separately the cycles.
|
@tatarmiki So, it looks like the problem is in everytime around the loop 28 bytes is lost. Also I looks like I use the wrong To verify my supposition is correct, change the bottom of // generate beep sound for buzzer
ledcWriteTone(channel, freq);
currentFreeSpace = ESP.getFreeHeap();
if(currentFreeSpace != lastFreeSpace){
Serial.printf("cycle[%06d] after ledCWriteTone(%d), freespace change, last =%d, current = %d, delta =%d\n",counter, freq, lastFreeSpace,currentFreeSpace,(currentFreeSpace-lastFreeSpace));
lastFreeSpace = currentFreeSpace;
}
// beep sound length is 50 ms
//delay(50);
// stop beep
ledcWriteTone(channel, 0);
currentFreeSpace = ESP.getFreeHeap();
if(currentFreeSpace != lastFreeSpace){
Serial.printf("cycle[%06d] after ledCWriteTone(0), freespace change, last =%d, current = %d, delta =%d\n",counter, lastFreeSpace,currentFreeSpace,(currentFreeSpace-lastFreeSpace));
lastFreeSpace = currentFreeSpace;
}
//delay(950); I'll look at Chuck. |
@tatarmiki found the leak. There was an error using a locking semaphore. You can manually apply these fixes to Chuck. |
Great! Thanks for your help. |
I applied your fix manually, but the leak not disappear. |
@tatarmiki what does the console log show? Chuck. |
Yes.
|
@tatarmiki I can't imagine why my change did not fix the problem for you. Add some debug logging to #if !CONFIG_DISABLE_HAL_LOCKS
if( _ledc_sys_lock == NULL) {
_ledc_sys_lock = xSemaphoreCreateMutex();
log_e("sem=%d",_ledc_sys_lock);
}
#endif Set the Core Debug Level to at least ERROR, then try it. I'll take another look through the Chuck. |
@tatarmiki nope, I'm an idiot. the problem is at the end of Chuck. |
I added it but is not showing in debug logging. I added a simple log_e() into the ledcWritetone function first line, and that showed in debug log, so
is never called |
Your correct. that When I read through it first I missed: static bool tHasStarted = false;
if(!tHasStarted) {
tHasStarted = true;
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
LEDC.conf.apb_clk_sel = 1;//LS use apb clock
#if !CONFIG_DISABLE_HAL_LOCKS
if( _ledc_sys_lock == NULL) _ledc_sys_lock = xSemaphoreCreateMutex();
#endif
}
The "REAL" problem is the call : uint32_t iarg = chan;
addApbChangeCallback((void*)iarg, _on_apb_change); It adds a callback to support CPU frequency change every time the timer is reconfigured. I'm think about how to efficiently handle this problem. there needs to be ONE callback registered for Each Active channel. I could call `removeAPBChangeCallback() each time the freq changed, but that is wasteful. I think a bit mask is better. Chuck. |
@tatarmiki #3560 works for me. I don't have a 7 segment display I tested it with a SSD1306 OLED using adafruits gfx library. no more memory leak!
|
It's working!! No more memory leak. Thanks for your help. |
@tatarmiki The current pr#3560 branch code is still a work in progress. I'm still testing. Hopefully I'll get it finished and merged into Master in the next couple of weeks. so, I'll close this issue and just update the pr. Chuck. |
* `ledcWriteTone()` added a `apbcallback()` evertime the tone value was non zero. * `addApbChangeCallback()` did not detect duplicate callbacks. * changed the apbcallback list to a double link to support roll forward, roll back execution. This made the sequences of clock change callback start with the newest registered -> to oldest on the `before` then oldest -> newest after the clock change. This made the UART debug log output have minimal gibberish during the clock change. * change how the UART callback handled the MUTEX because if any `apbchangeCallback()` executed a `log_x()` a deadlock would occur. This fixes #3555
Hardware:
Board: ESP32 DevKitV1
Core Installation version: 1.0.4
IDE name: Arduino IDE 1.8.10
Flash Frequency: 80Mhz
PSRAM enabled: no
Upload Speed: 921600
Computer OS: Windows 10
Description:
I try to make a counting device with a 4 Digit 7-Segment HT16K33 I2C Digital Led Display Module, and a beep sound every second count. My problem is with the ledcWriteTone function. When i use it to generate the beep sound with buzzer, after a certain of time it's aprox 165 min, the I2C communication fail with MEMORY error. If i not use the ledcWriteTone, everething is fine. Every 10 min count the below sketch print the free heap, and the I2C last error state. Anyone can tell me what's wrong with my code?
Sketch:
Debug Messages:
The text was updated successfully, but these errors were encountered: