Uploading via programmer after burning bootloader #245
Replies: 5 comments
-
A UPDI upload always erases the bootloader. It also sets the "safe fuses", including the one that tells the chip whether there is a bootloader present. The consequence of the safe fuses being set is that it will also no longer think there is a bootloader there (prior to I think 1.2.something, you could upload with a non-bootloader definition, and it would erase the bootloader (chip erase) but the bootsize fuse would remain unchanged. The board would still think there was a bootloader, and so would place the interrupt vectors on the first "non-bootloader" page, which would generally result in a bootloop or hang as it jumped to the middle of the sketch when the first millis timer interrupt fired. "Burn bootloader" is still needed, on all boards - even with a non-optiboot board selected, in order to set the "unsafe fuses" (those that could brick the board if set incorrectly - this is just the BOD configuration on DA and DB, (since you could have the part soldered onto a board along with parts with max voltage 3.6v, set the BOD threshold to 4.3, and be screwed). Syscfg0 will also be "unsafe" on AVR DD-series because you can disable the UPDI pin and that requires HV programming to undo - but the DD's aren't even shipping yet, so that's beside the point) as well as fuses that are never set by the core (this is WDTCFG only on DxCore) - those get reinitialized to the factory default such that burn bootloader should always restore the chip to a known state. What do you mean, you "can no longer upload a program after burning a bootloader"? You are talking about uploading a program through the serial port using the bootloader? That bug was fixed in 1.4.5 to my knowledge, so if there is still a situation in which uploads through the bootloader do not work, that is a critical bug that warrants an urgent bugfix release (note: latest version should be 1.4.7, but I just realized I probably didn't kick the server that hosts the json file after uploading everything late last night.. Please tell me more about this! If older versions worked with the same connections (ie, it is not a wiring problem, or lack of installed bootloader on the chip, this is a critical issue that demands my full and immediate attention. |
Beta Was this translation helpful? Give feedback.
-
There's no issue on your part. Thanks for the explanation I understand now. What I meant in retrospect about "I can no longer upload a program after burning a bootloader" is that in previous cores <=1.3.6 I could burn a bootloader with the bootloader option then immediately upload a program via the programmer without changing to the no boot loader option. I did not get the error/warning like in in 1.4.7 I did not understand that I was erasing the bootloader because as I said I haven't tested that yet. So now I understand that my workflow sequence should be this:
So when I export the production bin file which option do I choose: bootloader or no bootloader? What is the address I program to using Atmel Studio. Thanks. |
Beta Was this translation helpful? Give feedback.
-
If you are uploading via UPDI, then that never should have worked. I mean, it would work in the sense that code would be uploaded, but unless the code never used any interrupts, including millis, it was guaranteed not to work: Ever since the change where I made it so burn bootloader with "no bootloader" selected wasn't necessary for a sketch uploaded via UPDI to work on a board that formerly had a bootloader on it- but the result that you would get when doing so would not work correctly. At compiletime, the size of the bootloader must be known, because in contrast to classic AVRs which put the bootloader at the end of the flash, modern avrs put it at the beginning. I don't know exactly why, but they do. And that means that the hex file needs to start at a different address depending on the size of the bootloader - no bootloader has to start at 0x0000, a 512b bootloader requires the sketch to be compiled suich that it starts at 0x0200 and so on. And since the interrupt vectors are all located at the beginning of the app section, if you uploaded a sketch was built for a 512b bootloader to a bootloaderless chip, all the interrupt vectors would be pointed at addresesses before the application started. Empty flash. It would jump to the vector, landing on 0xFFFF, which while not a legal opcode, is interpreted as sbrs r32,7 (skip next instruction if bit 7 in working register 31 is set). It would thus skid along the empty flash, executing either every instruction or every other instruction until it finally reached the application code, where it would either execute the reset vector, or execute the first vector after that (that's usually the NMI, which is rarely defined in Arduino land, and hence would jump to BADISR, which then jumps to 0x0000 - so one way ort another you'd end up at the reset vector, with CPUINT.STATUS LVL0EX = 1 (priority level 0 interrupt currently executing - hence no other priority 0 interrupts would execute). With interrupts broken you would likely end up in a hang or bootloop. (You will end up in a similar situation if you ijmp to a location past the end of the program, or if you overwrite the return pointer on the stack with either 0's or a number larger than the address of the last word of code ("smash the stack") and then execute ret (return); most of the time, you'd end up the program counter at 0x0000, without a hardware reset executing. Leading to the initialization code running again, but this time prodicing unpredictable results, because it all assumes registers are in their power on reset state, but they aren't at that point. That's why DxCore and megaTinyCore now both check the RSTCTRL reset cause flags, clear them if any are set, and issue a software reset if they aren't (on the grounds that you got there through a dirty reset and nothing would work. I'm convinced that this was the cause of almost every issue where an Arduino would get into a bad state that you had to use the reset button to break out of. ..... Why would you "burn bootloader" with the optiboot version of the board if you planned to upload code via UPDI? You should do burn bootloader with the (no bootloader) version, so it just sets fuses. Is this another user who has been thrown off by the naming of that menu option? "Burn bootloader" should really read something like "Set fuses and install bootloader (if any)", since it has two essential functions: It configures the fuses (on classic AVRs, it was the only thing that would set fuses; it wasn't that it was in any way hard to make an ISP upload write the fuses. The problem was that on classic AVRs, typically EVERY FUSE had at least one bit that, if set incorrectly, would brick the chip * ). Eventually I realized that my adherance to convention was non-constructive on the modern AVRs, particularly on megaTinyCore, where close to 50% of bug reports and support inquiries were because people hadn't used "burn bootloader" to set the clock to be derived from 16 MHz vs 20 MHz. Once I'd decided to make OSCCFG be set on upload, I realized many other fuses could be safely set as well - I set any fuses that can't brick the chip and have one or more option to adjust them exposed in a menu (other ones - WDTCFG comes to mind - we assume if they're not in their factory state, the user changed them intentionally so we should leave them be.
|
Beta Was this translation helpful? Give feedback.
-
This has nothing to do with setting proper fuses (at least for me). I normally do that using atmel studio. But sometimes it is convenient to do it in Arduino. Really all I want to know is what I am trying to do make sense? Does nobody ever remote upgrade AVR firmware using a secondary WiFi chip? Is this not a thing?
step 4 requires step 1 Somewhere in what you wrote I think you said that if I use a 512k bootloader (ie optiboot) then the starting address for the program would be 0x0200 But you didn't mention if I should compile the program WITH or WITHOUT the bootloader option to (presumably) generate the correct interrupt vectors. Okay I just realized something else I might not have understood that will answer my question. If I export a bin file with the bootloader option then what do I get? Bootloader + program to be burned (by some method) at 0x0000? This would combine steps 1 and 2? |
Beta Was this translation helpful? Give feedback.
-
If you export a binary from bootloader using definition, you get a binary without the bootloader which starts from 0x200 (for optiboot). A combined binary is not produced. I have seen such binaries produced by other cores, but opinion on whether they work has been mixed. 1. We do not have a mechanism currently in place that generates a valid hex file containing both bootloader and the sketch though this is the "easy part"
2. That hex file would still require fuses to be set appropriately or it would not function. As the Intel Hex format was not designed for parts which included fuses, a "vanilla" hex file is incapable of storing the data required to ensure that the code will behave as esxpected when uploaded without the fuse settings.
a. I believe Microchip has a non-standard extension to the hex format which includes the fuse settings.
b. I do not know what that format is or whether it is documented.
3. From 2b, it follows that the fuse settings are not included in the binaries generated by the core.
4. Furthermore, we do not know whether, were they included with the hex file that:
a. Upload tools would recognize that and correctly program the fuses.
b. Upload tools would recognize the files as valid at all.
5. megaTinyCore an DxCore both make a distinction between three types of fuses
a. "safe" fuses which we always set upon updi programming - these include the bootloader related ones, and all others that could never impede further UPDI programming
b. "unsafe" fuses which are only set on burn bootloader because an incorrect setting could make it impossible to reprogram or use to part (ex: BOD set to 2.85 (IIRC the maximum on these parts), yet board was running at 2v, soldered to a board alongside components that are not tolerant of voltages above the BOD threshold, and are tied to Vcc. This would require likely challenging rework to remove those parts so that the chip could be reprogrammed to lower the BOD threshold, or those that disable the UPDI pin and turn it into a GPIO pin, available on tinyAVR and the AVR DD-series and it would appear, planned for the EA series as well. Note that the CRC settings do not make a fuse unsafe, as they do not prevent further uploads via UPDI
c. "none-of-our-business" fuses which are only set on burn bootloader (so that it shall always return the chip to a known state), but have no exposed settings and are written to their default value. If the user has changed them after bootloading manually, the assumption was that it was intentional.
6. I do not see how, even supposing the other problems were solved, we could handle that distinction between fuses in a coherent manner so that uploads via bootloader and via combined image resulted in the same behavior in all cases.
So in summary, I do not see a route to a mechanism to generate consistent and reliable behavior in the case of a through combined bootloader + sketch binaries.
On the second point - I originally voted for optiboot as strongly preferred. My position on this issue has evolved, as demand for a standalone programming tool has become apparent, as has demand for an open source, performant HV programming tool.
The UPDI protocol is not particularly complicated, and in practice SerialUPDI, particularly on tinyAVR and any other device with paged writes, is greatly limited by reliance on multiple round trips of data for each programming attempt, because USB devices have a "latency timer" to reduce CPU load at the expense of slower response time. At high baud rates, the majority of the time spent programming a tinyAVR is due to usb latency, not any other factor, and the latency is not insignficant at the maximum baud rates on a Dx-series either.
Therefore, I already expect to write code to run on a Dx-series and perform UPDI progamming. This is made somewhat easier thanks to the one-wire half duplex mode that the modern AVR USARTs support - Combined with the use of the SRAM as a much larger buffer binary data on an intermediary Dx-series (4k, 8k, or 16k, most of which could be used as a buffer for reading or writing as appropriate, allowing much larger chunks of data to be sent by the computer, potentially at a higher baud than the UPDI data was sent at. A tight loop (which dispensed with the serial wrapper altogether) could realize a very dramatic improvement in tinyAVR programmign speed and a modest one in Dx-series programming. The mechanics underlying it would also readily lend themselves to use as a standalone programmer; data stored either on the excess flash of an avr programming it, or on an external memory chip storing many flash images, with code to keep tabs on what flash images were stored in said memory could permit highly performant standalone programming, provided the memory in question was appropriate. So sooner or later I'm going to be writing a UPDI programmer that runs on a Dx, sourcing data from either a new serial upload protocol that uses much larger chunks sent less frequently (making USB latency a non-issue, as we could continue uploading during that time, because we would have plenty of data buffered. I am working on hardware that will do this for serial uploads, and adding support for storing it to flash would not be particularly challenging (though it would require a 32-pin Dx rather than the 20 pin DD I'm currrenly using. My plan for that extension, which is still not completely specified, would be the data would be stored on external flash or EEPROM chips, and images could be loaded by "uploading" with the same programming tool as for HyperUPDI, with just a few more commands, as well as through a UI on the device (presented for example on an LCD screen). And both of these could use MVIO to use one programmer running at 5v to program a device at a lower voltage - put a 3.3v reg on board, to get the most common speed, and a "Use whatever voltage the target is using" option for lower voltages or for programming things running directly from a lipo battery.
So yeah, these are my updated thoughts.
|
Beta Was this translation helpful? Give feedback.
-
I just installed the latest core 1.4.7 and discovered I can no longer upload a program after burning a bootloader. I was able to do this in previous versions. I switched to the non-bootloader board and uploaded the program. Does this wipe out the bootloader? Here's my use case:
I have already done this for an ESP8266 and ATMEG2560 but haven't adapted the code yet. On the latest revision of my board I've added an in-field UPDI programming circuit connected between the AVR and ESP32. But that will require adapting the python program to C. This is the longer term goal but in short term would like to use bootloader. Thanks.
Beta Was this translation helpful? Give feedback.
All reactions