arduino / Arduino

Arduino IDE 1.x
https://www.arduino.cc/en/software
Other
14.11k stars 7k forks source link

Flash bootloader with JTAG ICE3 over JTAG immediately disables JTAG and fails #9285

Open Detzi88 opened 4 years ago

Detzi88 commented 4 years ago

Hello, selecting "JTAGICE3 JTAG" in the arduino IDE and trying to burn the bootloader results in an error. I tryed to discuss it on the forum before i came here but with little response: https://forum.arduino.cc/index.php?topic=639257.0

Expected behaviour: IDE flashes bootloader over the JTAG interface using JTAGICE3

Actual Behaviour: IDE disables JTAG on the Target and fails flashing the bootloader

All the details are on the forum, to make it short, the first thing the ide does is set the fused to:

avrdude: writing lock (1 bytes): 0x3F avrdude: writing efuse (1 bytes): 0xcb avrdude: writing hfuse (1 bytes): 0xd8 avrdude: writing lfuse (1 bytes): 0xff

Which disables JTAG. Since this happens right at the start it obviously can't continue flashing the bootloader.

What i suggest is leaving the JTAG fuse active when starting the "burn bootloader" process and possibly not disabling it at all.

matthijskooijman commented 4 years ago

Hm, interesting problem. I think that in general (when using ISP for programming), keeping JTAG disabled makes sense, since that keeps the pins free for other uses. When using a JTAG-programmer, this is of course silly and you need to keep the JTAG pins enabled.

Unfortunately, there is currently (AFAIK) no way to change the fuses based on the programmer used (and even if there was, you would still have the challenge of enabling the JTAG fuses for the first time, usually through ISP).

What could be done is to add an option of the board in boards.txt (e.g. similar to the various cpu options). AFAIK it should be possible to set the fuses based on such an option (selectable through the Tools menu). However, that does mean that the option is made available to all users, regardless of whether they use the serial upload, ISP programmer or JTAG programmer. This might cause a confusing option for novice users that have never heard of JTAG (or might suggest you can enable JTAG through the serial upload, which is also not true).

Of course, you can modify your own boards.txt with the fuses you need. A more robust way (i.e. not overwritten when the AVR core is updated) is to make a custom core, that inherits from the Arduino AVR core and just defines the boards that you need. You'd end up duplicating the complete board definition in boards.txt, but none of the code and you'd be safe when updating.

Detzi88 commented 4 years ago

I agree on actually everything you said. Expect the challenging part of enabling the JTAG fuse in the first place. If you buy a standard at32u4 or whatever "arduino compatible" avr, it comes with the JTAG fuse enabled. This shure is only relevant if you do use a non standard board but that also is mostly true for using JTAG. Following your argumentation what about:

As it is, for users having spun their own board and having no ISP header (:D like me), its like a "brick me" button. I had a hard time finding out what went wrong especially because i thought the arduino ide had not found my ICE3 in the first place.

per1234 commented 3 years ago

Unfortunately, there is currently (AFAIK) no way to change the fuses based on the programmer used

You can associate arbitrary properties with programmer definitions. It turns out (at least with the latest Arduino IDE/CLI build, I didn't check the behavior of older versions) that programmers.txt has override priority over boards.txt. So you can define a programmer-specific fuse value which will override the default property value defined in boards.txt. You wouldn't want to universally override bootloader.high_fuses because that will affect all boards of that programmer's platform, so a dedicated property should be used for this purpose, and that property only used in the relevant boards. Because we only care about the JTAGEN bit, you can define the value of that bit alone, leaving the state of the rest of the fuse bits to be defined in the board definition, then concatenated with the other fuse bit values.

Here is an example of this being done for the arduino:avr:jtag3 programmer and the arduino:avr:leonardo board:

--- a/programmers.txt
+++ b/programmers.txt
@@ -102,2 +102,3 @@ jtag3.communication=usb
 jtag3.protocol=jtag3
+jtag3.bootloader.jtagen=0
 jtag3.program.protocol=jtag3
--- a/boards.txt
+++ b/boards.txt
@@ -302,3 +302,4 @@ leonardo.bootloader.tool=avrdude
 leonardo.bootloader.low_fuses=0xff
-leonardo.bootloader.high_fuses=0xd8
+leonardo.bootloader.jtagen=1
+leonardo.bootloader.high_fuses=0b1{bootloader.jtagen}011000
 leonardo.bootloader.extended_fuses=0xcb

After this change, when Burn Bootloader is performed on the Leonardo with the "Atmel JTAGICE3 (JTAG mode)" programmer selected, the high fuse will be set to 0b10011000, when performed with any other programmer selected it will be set to 0b11011000

matthijskooijman commented 3 years ago

@per1234 Interesting approach, I can indeed imagine that will work. Reading, I thought about another approach: Let a board define both bootloader.high_fuses and bootloader.jtag_high_fuses, and let the JTAG entries in programmers.txt set e.g. jtag3.bootloader.high_fuses={bootloader.jtag_high_fuses}. Not entirely sure if this works, but I can imagine it does (if the properties are loaded in the right order). One advantage of this approach is that it gives full control over the fuses to the board entries (they can change more than one pin, or control a pin that is inverted somehow, etc. A downside is that it might not scale as well if there's multiple (orthogonal) properties that affect the fuses (e.g. something like JTAG/non-JTAG and bootloader-upload/programmer-upload, or some better example).