Bootloader not entering Update mode due to Software?

So I am having an odd thing and the purpose of this question is just to see if anyone else has experienced this at all..

The issue is I have a program that has 4 Sections (all do similar things, but use different sets of data and class instances). Cant upload code due to proprietary reasons. So I am just wondering if others have seen this, dealt with this, or have any work arounds.

Anyway , when I have 3 of the 4 sections running (just the processing of the sections all the Class instances are still created into memory that are used for all 4 sections. everything works fine.. AVR Dude is able to put the ProMicro Clone into Bootloader mode, upload the firmware and start running again.. this can be repeated and all is good.

HOWEVER, when I enable that fourth section along with the other three so everything is running processes. the actual running of the program works absolutely fine, everything is good, everything works.. BUT.. when I try to re-upload the program (say if I needed a remote firmware update) something now is blocking the devices ability to go into bootloader mode and it fails to do so stopping at the "Baudrate Override 57600" in the verbose logging..

Resetting the device with the RST/GND works to get it to reload but I really need it to auto enter the bootloader mode (with all portions of the program running)

At first I thought it was possibly a RAM issue but using the Heap monitor code it is showing I have 372 bytes left. which given nothing else creates or destroys this seems adequate. the RAM remaining when the 3 working sections are running is 384 bytes so a 12 byte more usage for processing.

I just noticed that If I get it to Fail this error comes up - "avrdude: ser_drain(): read error: Device not configured"

Anyway any ideas as to why this might be??

Quick Update:
it appears that this is not working

Performing 1200-bps touch reset on serial port /dev/cu.usbmodemHIDEK1

as it finds an upload port BUT it is the wrong port, it should be /dev/cu.usbmodem11201 the port it finds is the same one it does the touch reset on...

So I think I found the issue I just don't know how to correct it...

Which operating system? I suspect that it's a Mac in which case I can't really assist.

So this is the wrong port?

And that would be the correct port when you only have 3 sections?

If the answer to both is yes, the likelyhood that your program is the issue is close to 100%. You should be able to select that /dev/cu.usbmodem11201 port but I assume that you can't.

Just in case you don't know, part of the code that you upload contains the functionality to first of all provide the board detection and second of all the functionality to react on the Performing 1200-bps touch reset.

Bugs in your code can result in the fact that one or both of those don't work because your program destroys variables used by those functionalities.

What is the Heap monitor code? If it's the IDE report, you're skating on very thin ice. Be aware that function calls, variables declared in functions and variables saved to stack when an interrupt happens are not counted in that memory usage report. If it's some FreeMem code (or whatever it is called exactly), you basically need to call it at the deepest level (interrupts and various places in libraries).

Yes, the /dev/cu.usbmodemHIDEK1 is the port name that is used when the Program is running, the /dev/cu.usbmodem11201 is the port which is used when the Firmware is updated. Same device I am not sure why it changes name completely but it does..

The Compiler places both the Program and Dynamic Memory use around 60% however I know I do have some dynamic instance creation that happens at start-up (which is used constantly during use) so it doesn't get deleted so I am thinking it is not due to Memory Fragmentation.

OK I didn't realize that there was code added to allow the touch to happen, though I thought that was done through a soft reset of the device.. I would also think that code would be put into the firmware Flash which isn't touched but I could be completely wrong here..

The Heap Monitor code is the code which is located on this page " https://docs.arduino.cc/learn/programming/memory-guide/ " under SRAM Memory Measurement which is supposed to give a running value of the Remaining bytes at the top of the heap. I have it running every loop, but as I mentioned the Program itself doesn't actually crash, it runs fine after being uploaded.. It just for some reason kills the ability for the Arduino IDE to auto setup the bootloader port on a refresh.

I was thinking it could be something as you said where I am accidentally overwriting a Variable or something that would be a helper Im a little at a loss as to where it could be.

The reason is that all of the Set-up classes and everything get placed into memory whether I run the three or Four sections. so it cant be happening at set-up otherwise the 3 section code would be failing this process as well.. So the only place it could be would be in the implementation routine..

Thinking about it though it MIGHT not be an issue it is just concerning as with the main program that controls the device we manually trigger bootloader mode with the pulsing of the Serial port and then upload through terminal level commands.

It would be nice though to figure out what is causing so just so we know what to avoid.. which is sort of the, curiosity question just in case someone else has run into the same thing and has figured out what it is that is actually causing the issue..

We did run into bad variables crashing the whole thing but that would just totally shut down the serial, that has since been fixed though.

Oh and yes it is a Mac M1 running the Arduino 2.2.1 IDE
I guess I also failed to mention in the first post that it is a Leonardo/ProMicro Clone so it does the secondary port for the Bootloader

That might not be sufficient to find the problem; it will indicate if memory leaks but it will not indicate the amount of memory used when a function called or an interrupt is happens.

That is unfortunately not quite a reference :wink: Adding or removing an innocent statement like a serial print can change the memory layout of your code and your code might no longer be running properly.


Some hints that I can think of to try to help

  1. Check for writing outside the boundaries of arrays. This will destroy other variables. To a lesser extend, check boundaries as well when reading; it might make your code misbehave.
  2. Try to avoid use of String (capital S) objects. If you use them, make sure that you use them correctly. strResult = strA + strB + strC; will create temporary String objects and due to that you might run out of memory. Use += or concat.
  3. Do not pass objects to functions; that will place a full copy of the object on the stack. Rather use a reference (or pointer).

OK well a Whole heck of a lot of refactoring and actually being smart enough to USE some class Functions that I set up has reduced the IDE estimated Dynamic Memory by about 4% which has allowed everything to work again. It did increase the Program Memory use estimate by about the same amount.

As for the hints in relation to this particular thing..

#1 - I did have that in a couple of places, which were fixed, this of course was totally crashing the program and/or easy to spot with bad data being delivered to places within the program.

#2 - I had read this before so I have Very Very minimal use of strings in general.. the ONLY string I have is a Serial.println() for output over serial in bytes. this happens on a timer or on demand depending on other things. I have of course used Serial.print to check variables along the way to make sure correct data is being transferred at different places for debugging but those go away as soon as things are worked out.

#3 - I do have a couple of places where an object is passed now AFTER the refactoring, While this is probably wrong as you mentioned there might be some good to the passing as is since the data I am reading at the time of passing does sort of have to be frozen (which a pointer might not do, but just the fact of linear processing would) so it might be worth it for me to delve further here.. Pointers are still fairly new to me so I do believe I tried that but couldn't get the syntax correct so the pass is currently

XXX.function(object) -> XXX class function(OBJECT object) {}

Ill have to delve deeper and look up (figure out) the actual correct syntax for that and try it since it should reduce the memory weight even more.

In any case things are working currently. and though I don't know the exacts I must be right at the EDGE of max memory usage. There are a few more things I have to do in order to get things working FULLY how I need them to which of course may break things again but at least I have some direction as to what is going on.

I did forget one thing; use F-macro when printing fixed text.

Serial.println("Hello world");
Serial.println(F("Hello world"));

That is for any printing (Serial. LCD, nertwork, ...); it can significantly reduce RAM usage. It will only be pulled into RAM when you print that text leaving more space.

Yes already do that with static strings.. That one I didn't actually know at all about until this adventure.. Checking the Memory with that loop. all of the refactoring as dropped the RAM usage on that continual basis by about 49 bytes.. enough to open up the bootloader detection..

And Yes I understand what you mentioned about that might not be sufficient as far as pinpoint usage.. Not that knowledgeable yet to set debugging interrupts :-).. Also I do understand your point with regard to it currently working correctly not always being a good reference to if things are ACTUALLY working correctly.

The good thing is that I did learn that all uploading issues DON'T require the drastic steps of reloading the bootloader and the program can actually mess with it more than you might think.

My point is that it might seem to work correctly but that does not necessarily mean that there isn't a bug in your code. And that bug can show its ugly face when you make a minor change.

Long ago I had a bug in a C program for a PC; to debug, I did add printf statements and the bug magically did not show its face. So the code with the printf statements worked as expected but it still had the bug. At the end of the day it was a strcat where the resulting c-string was larger than the allocated space (that is, writing outside the boundaries if the char array).

So I guess that function calls and interrupt handlers chewed away your remaining 372 bytes and as a result the heap and stack ended up with a conflict. I think that your project is at the edge of memory usage. be careful when adding more stuff; but at least you have a pointer where to look if you loose the upload capability again :wink:

Right that is what I was understanding you to say with regard to it not really being a reference point.. As because of restructuring by the compiler things get hidden..

Yes.. I am thinking I am at the edges of the Dynamic Memory.. at this point though luckily the things being added should not increase memory use by much as it is mainly processing with variables that are already in place ( I know it uses some for underlying localization). so If I can find further places to properly use a pointer (and not screw up its implementation) along with having additional localized variables for things that are to be one time use. I THINK I can get it all to work.. Starting this I didn't think I would push the bounds of the memory but it is looking that is the case.

OK So for an update (for anyone that finds this later) .. I have figured out what the cause of the Failure to install new firmware is and it actually has to do with the memory footprint of the Currently installed program (NOT the program to be installed)

This is on the Arduino Leonardo (ProMicro)

Anyway I went through and found out that that when the program was running I was within 4 bytes of failure so every time I would add something to the systems that used a bit more either static or Dynamic RAM it would cause the boot loader to fail to enter upload mode. and would exit with the normal -1 on AVRDUDE.

So I went through and Optimized the memory size of everything to be as small as I possibly could.. i.e. most everything is a uint8_t.. I did the suggestion above on any printed static string using the F() function, as well everything that could be Passed as a reference was done (ESPECIALLY if they are Arrays or objects being passed as the copies are big).

I have a bunch of stuff added to memory UPON start-up which of course dynamically allocates so the Compiler has no idea bout the actual sizing of those items so I was sitting at 52% on both reference values..

Anyway this does go to show that not all cases of boot loader failure do have to go to the extreme of reinstalling the boot loader on this device as excess memory allocation can break the ability to put the boot loader automatically into boot loader mode.

I am guessing the design of the architecture is to allow a certain amount of excess RAM use that the boot loader normally uses to keep a program from failing as even though the boot loader didn't work the larger program did still function properly I just couldn't upload new firmware automatically.

BTW when this problem occurs you can use the board reset to upload the oversized sketch still so it is ONLY the Auto reset that gets messed with.

You must differentiate between the bootloader and the sketch

  1. The bootloader is not active at all when your sketch is running so it does not use RAM :wink: Therefore the bootloader can not prevent a program from failing (and nothing else will except your understanding of the upload process and coding skills). Your bootloader did work, else you would not have been able to upload.
  2. Your basic problem was that the uploaded code no longer could react on the command that resets the microcontroller.

I'm glad you got it sorted; you can mark the topic as "solved" by clicking the check button under the most useful reply.

Yea that is sort of what I meant.. in that the Command from AVRDUDE to run the function that allows the boot loader to set itself up for auto updating must not have had enough RAM left available to it to actually run, causing the issue.. While the reset runs that Function first therefore having enough RAM in place to allow the port close and switch.

the command to enter the bootloader relies on USB being operational.
If your sketch causes USB to stop working, the auto-reset won't work. (and being very low on memory could certainly do that, I think.)

USB is operational when this situation happens, All serial and HID systems fully work.

You should rephrase that. "Some of the USB is operational". The fact that you can print and that the HID functionality does work does not mean that other USB functionality works.

Compare the full USB functionality with a car. It has an engine, alternator, battery, lights etc. The fact that the engine runs does not necessarily mean that the alternator is working to charge the battery or that the lights work.

However, Not sure what else would not be operational though if it is communicating properly on the Data Lines to be able to transmit and receive Serial and HID information properly.. as really USB is "Universal Serial Bus" so if it fails it would fail completely as all it is in implementation is a dual link Serial Link standard with HID or serial interfacing.

So this goes back to the Auto Bootloader implementation must need a small amount of RAM to be available to tell the microprocessor to Shut down and Open a new serial port.. When it tries the Original serial port USB Interface remains connected and functional it just never disconnects and reconnects under the 1200baud to start the boot loader so that is where the issue port is never opened on the device.

So USB is functioning properly. This doesn't have anything to do with the USB connection itself, however, the auto port switch function is not (since as mentioned there seems to not be enough memory for it to implement) and that would be on the arduino itself. The times that I found USB function was compromised were due to processor crashing as opposed the memory used.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.