I've got some code running on a Uno that drives a pair of automotive LED fog lights. The code gives the illusion that the LEDs are part of a rotating beacon.
After running for about a day the software locks up and the LEDs are lit continuously at some intermediate brightness.
Are there any functions with known memory leaks or other issues that could contribute to my problem? I want to ask this as a general question before I go posting my code for review & suggestions.
Asking that question without code is pointless. There are no such known functions in Arduino IDE, the issue is definitely in your code or in libraries.
This seems like the cart leading the horse to me. If you post your code (using code tags) and a schematic (even hand drawn), you will attract more helpers who may see something right away that is causing you woes.
You will also attract the helpers who have the level of expertise required (someone besides me) to answer your general question about a memory leak. Failure to post your code, schematic and parts list will certainly keep a few of the gurus away, as it's the culture to for the OP to do the things I mentioned.
Well I didnt say I wasnt going to post my code. Ive read in several places of warnings about memory leaks in some corners of the IDE. Just thought I would ask for more info on that before I jumped into a full scale debugging adventure.
Yes, using String objects on Arduino Uno, and of course, errors in your code.
Have a look at the "How to get the best out of this forum" post, and post the code, using code tags, plus a wiring diagram and links to the components.
I moved your topic to an appropriate forum category @wingsy .
In the future, please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.
char dahsNdits[]="-.-. --.- -.-. --.- -.-. --.- -.. . "
" .-. .. ...- . .-. ...- .. . .-- -.. .-. "
"-.-. --- -- . - -- . ..- .--. ... .- -.-- .... . .-.. .-.. --- "
" .-. .. ...- . .-. ...- .. . .-- -.. .-. "
"-.-. --- -- . ... .- -.-- .... . .-.. .-.. --- \0";
int PWMout = 9; // LED & beacon light connected to digital pin 9
int analogPin = A0; // phototransistor connected to analog pin A0
int val = 0; // variable used as brightness control. 0-255 for zero to max brightness
bool nighttime = true; // true only at night.
int MorseCountdown = 120; // 1 down count per loop, do Morse at 0. 480 counts ~= 1hr.
int filter = 0; // Filter provides hysterisis in switching to/from daytime & nighttime.
int PhotoTransistor; // Photosensor for day/night detection.
void setup() {
pinMode(PWMout, OUTPUT); // sets the pin as output
//Serial.begin(9600);
}
void loop() {
if (nighttime) { // is true at night. Do beacon and (maybe) do Morse.
if (MorseCountdown <= 0) { // When 0 we'll do the Morse thing.
MorseCountdown = 480; // Reset to 1 hr (480 * 7.5 sec) when zero.
sendMorseMsg(); // Send the Morse code message.
}
doOneBeaconCycle(); // Do 1 cycle of the lighthouse beacon.
MorseCountdown--; // Counts down at night, approx 1hr timeout.
}
else // Is daytime. Nothing to do except check for nighttime.
{
delay(7500); //Delay 7.5 sec, roughly same as doOneBeaconCycle duration.
}
// So no matter if we do the beacon (at night) or just mark time for
// 7.5sec ( during the day), the time to get here is the same.
// So now we can check for daytime or nighttime, with hysteresis.
analogWrite(PWMout, 0); // Turn off the LED while measuring ambient.
delay(10);
PhotoTransistor = analogRead(analogPin); // Reads the sensor about every 7.5 sec.
analogWrite(PWMout, val); // Restore LED brightness.
// PhotoTransistor is <= 862 during day and is >= 987 during nighttime.
if (nighttime) { //This code executes during the night.
if (PhotoTransistor <= 862) // Light detected when true.
{
filter--; // Decrement filter in daylight.
if (filter <= -4) { // True when we've been in daylight for several loops.
filter = -4; // Hold filter at -4.
nighttime = false; // After filtering set flag to false in daytime.
}
}
} else // Here at daylight.
{
if (PhotoTransistor >= 987) // Is dark when true.
{
filter++; // Increment filter when dark.
if (filter >= +4) {
filter = +4; // Hold filter at +4.
nighttime = true; // After filtering set flag to true at night.
}
}
}
//Serial.print(PhotoTransistor);
//Serial.println();
}
// END OF MAIN LOOP. Start of functions.
void doOneBeaconCycle() {
rampto(10,4);
rampto(10,7);
rampto(10,10);
rampto(8,20);
rampto(6,50);
rampto(3,250);
rampto(6,50);
rampto(8,20);
rampto(10,10);
rampto(10,3);
int x=0; int y=0;
do {
// Idle time between ramps. Now show some slight movement.
y = random(20,200); x=x+y;
rampto(y,random(3,8));
}
while (x < 1600);
analogWrite(PWMout, val);
//delay(1000);
}
void rampto(int slope, int brightness){
// slope is the speed at which the LED brightness increases/decreases.
// brightness is the target brightness the LED is ramped up/down to.
if (brightness>=val) // True when we're to increase brightness.
{
do {
val++; //increase brightness by 1.
analogWrite(PWMout, val); // Update with new PWM on/off times.
delay(slope); //Hold at that brightness for (slope) mSec.
} while (val<=brightness); // Until we ramp up to target (brightness).
}
else if (brightness<=val) // True when we're to decrease brightness.
{
do {
val--; //decrease brightness by 1.
analogWrite(PWMout, val); // Update with new PWM on/off times.
delay(slope); //Hold at that brightness for (slope) mSec.
} while (val>=brightness); // Until was ramp back to initial brightness.
}
}
void sendMorseMsg() {
int charindex = 0; // Index into dahsNdits.
int ditfactor; // Used in Morse timing. ditfactor * dittime is on time.
char M; // Charactor in dahsNdits array @charindex.
int dittime = 100; // Timing refetence, 100ms is 1 dot time,
M=dahsNdits[charindex]; // Get next dot or dash or space.
do {
switch (M) {
case '.': ditfactor=1;val=64;break; // 1 dittime, 25% brightnes.
case '-': ditfactor=3;val=64;break; // 3 dittimes, 25% brightnes.
case ' ': ditfactor=3;val=0;break; // 3 dittimes, 0% brightnes.
default: break;
}
analogWrite(PWMout, val); // Light on for dot or dash, else LED off.
delay(ditfactor*dittime); // for dittime * didfactor.
analogWrite(PWMout, 0); // Then LED off.
delay(dittime); // Always 1 dittime of LED off after any dot or dash.
charindex++;
M=dahsNdits[charindex];
} while (M != '\0');
}
Did you design anything into your code to indicate that it's running its normal course? I notice no Serial debug statements; maybe try the built in LED to at least let you narrow it down and/or confirm your suspicion.
If you set the warning level in file/preferences to all and compile, you will get one warning that you might not want to ignore
C:\Users\bugge\AppData\Local\Temp\.arduinoIDE-unsaved20241112-2656-tldcz6.tf38\sketch_dec12b\sketch_dec12b.ino:154:21: warning: 'ditfactor' may be used uninitialized in this function [-Wmaybe-uninitialized]
delay(ditfactor * dittime); // for dittime * didfactor.
I do believe you're on it. (Had a heck of a time reading the warning -- the warning flashed on my screen then disappeared in a flash. Had to take out my phone and make a movie of the screen so I could scrub to the one frame containing the warning.) Warning was "ditfactor may be used uninitialized". Sure enough, in the last loop around line 154 when M=null, ditfactor would have never been assigned a value, making the delay undefined. My code is probably patiently waiting for the delay to expire, years from now.
Changed: int ditfactor; // Used in Morse timing. ditfactor * dittime is on time.
To: int ditfactor = 1; // Used in Morse timing. ditfactor * dittime is on time.
Not sure what you mean by that.
Two possible options
You can scroll trough the output window of the IDE.
You can click in the output window of the IDE, select all text, copy it and paste it in a normal text editor.
In general I prefer the second option.
Note:
There is usually no need to have verbose output during compilation enabled. Disabling it will reduce the amount of output making it easier to spot warnings while the scroll along.
When the device is in this "locked" state does covering or shining a light on the photo transistor free it ?
Does it lock up each time at approximately the same light level?
The dead period, which you have implemented for hysteresis may give the impression the system is locked if this persists for an extended period.
When I compile, the output window displays a multi line message that is far too brief to read. Also there is nothing to scroll... it didnt scroll off screen, it just disappeared. I used my phone to video the screen so I could scrub to the text that was flashed onto the screen.
Memory leaks occur when a program allocates memory on the heap but fails to release it, causing unused memory to remain inaccessible until the program ends.
➜ Heap fragmentation is not a memory leak. The memory is available for use if you request small blocks, it's not lost to the developer and the situation can be improved also when the String gets deleted (returning further blocks to the heap).
Also on the UNO / AVR — memory allocation for growing a String has actually some code to prevent over allocating, the operations just fail without notification but memory is handled "reasonably" (as long as you consider that dynamic allocation is necessary).
A leak is where you reserve memory (malloc or new), without deallocating the reserved memory (free or delete) when you do not need it anymore.
As an example:
If you make a linked list, and remove nodes from the list, you need to free (or delete) the nodes before removal. Otherwise you will have nothing pointing to those nodes and there is no way to reclaim the memory.
Took me 10 min so J-M-L posted more or less the same..