avrdudes / avrdude

AVRDUDE is a utility to program AVR microcontrollers
GNU General Public License v2.0
696 stars 136 forks source link

High voltage UPDI #861

Closed MCUdude closed 2 years ago

MCUdude commented 2 years ago

According to this Avrfreaks forum thread, the Pickit4, Powerdebugger and the MPLAB ICE4 are the only official UPDI compatible programmers that supports "high voltage" UPDI programming for those who wants to recover an ATtiny chip where the UPDI pin has been set to a GPIO.

This option can be enabled deep inside MPLAB X (ugh!), but also by using pymcuprog's -H {tool-toggle-power,user-toggle-power,simple-unsafe-pulse} flag.

This is something we should think about borrowing from pymcuprog. I believe I should be capable of doing this, I could atleast give it a try. I also have an ATtiny1616 I need to recover, this this might turn out to be a good exercise.

The question is, where does this belong? Perhaps in terminal mode?

dl8dtl commented 2 years ago

For the older Atmel programmers, HV programming has always been a separate programmer entry. However, their handling was completely different in that respect anyway. Terminal mode might be an idea, but in order to trigger it straight from commandline, a -x extended option would certainly make sense.

MCUdude commented 2 years ago

Yes, adding HV UPDI under the -x flag seems like a good idea. I'll start working on this first and then perhaps add it to terminal mode later

MCUdude commented 2 years ago

Minor update:

I'm able to recover an ATtiny416 using a Pickit4 and Avrdude by adding the following code to jtag3_initialize().

//jtag3.c - jtag3_initialize()
  parm[0] = PARAM3_UPDI_HV_SIMPLE_PULSE;
  if (jtag3_setparm(pgm, SCOPE_AVR, 3, PARM3_OPT_12V_UPDI_ENABLE, parm, 1) < 0)
    return -1;

// jtag3_private.h
#define PARM3_UPDI_HV_NONE              0x00  /* Do not use high-voltage */
#define PARM3_UPDI_HV_SIMPLE_PULSE      0x01  /* Issue a single high-voltage pulse immediately*/
#define PARM3_UPDI_HV_AUTO_POWER_TOGGLE 0x02  /* Toggle power automatically and then apply a high-voltage pulse */
#define PARM3_UPDI_HV_USER_POWER_TOGGLE 0x03  /* The user toggles power, and the tool applies a high-voltage pulse on power-up */

However, the first time I run Avrdude I get a jtag connection error. If I run the same command again, I'm able to communicate with the target until I power cycle it. I haven't figured out how communicate wit the target by running the Avrdude command once, and even though it works as expected in Pymcuprog, it's very difficult (for a non-python programmer) to keep track of the program flow to figure out what's really going on when running:

$ pymcuprog -t pickit4 -d attiny416 ping -H simple-unsafe-pulse
janegilruud commented 2 years ago

Just some inputs...

In the recent DFPs for UPDI devices Microchip has introduced a new property in the UPDI_INTERFACE property group, HV_IMPLEMENTATION. `

`

The value can be interpreted as follows: HV_IMPLEMENTATION 0 => Shared UPDI pin, HV on UPDI pin 1 => Dedicated UPDI pin, no HV 2 => Shared UPDI pin, HV on _RESET

Examples: ATtiny817 is type 0, AVR128DA64 and ATmega4809 are type 1, AVR64EA48 is type 2.

A matching property has also been introduced in the tool xml files (Located here: C:\Program Files (x86)\Atmel\Studio\7.0\tools, and will be introduced in the Tool Packs (TP, https://packs.download.microchip.com/#collapse-Microchip-PowerDebugger-TP-pdsc)). For PICkit4 it looks like this, a space separated list of the types which the tool supports: <HV_IMPLEMENTATION>0 1 2</HV_IMPLEMENTATION> For PowerDebugger it looks like this: <HV_IMPLEMENTATION>0 1</HV_IMPLEMENTATION>

This might be a property worth introducing in avrdude.conf if you want to support UPDI HV.

mcuee commented 2 years ago

I do not have the PICKit 4 now. I guess the pkobn (PICkit Onboard Nano) does not support this feature. I have the AVR128DB48 Curiosity Nano board.

MCUdude commented 2 years ago

However, the first time I run Avrdude I get a jtag connection error. If I run the same command again, I'm able to communicate with the target until I power cycle it.

After pulling all the recent changes into my avrdude hv-updi branch, I am for some reason able to communicate with the target immediately after the HV pulse is issued. This means that we have an HV UPDI implementation that actually works!

The next step would be to enable this feature by using the -x flag. Perhaps -cpickit4_updi -x hvupdi?

In the recent DFPs for UPDI devices Microchip has introduced a new property in the UPDI_INTERFACE property group, HV_IMPLEMENTATION.

@janegilruud this would be a nice feature to have. This can prevent users from applying a HV pulse to a target that doesn't support it. But how would HV UPDI on a "type 2 target", where the pulse is applied to the RESET pin work? Would the Pickit4 output the pulse on a different pin (instead of pin 3 as of today), or would external hardware be needed to clap the voltageon the UPDI pin and instead connect this to the RESET PIN.

Bottom line: Enabling HV UPDI by using the -x hvupdi flag should be an easy task. However, I'm not very good with the bison, so I'm not sure how to implement a new property in avrdude.conf. I'll have a look at it to see if I can figure something out though.

MCUdude commented 2 years ago

The bison part wasn't too difficult to figure out.

The HV UPDI implementation I'm working on only supports HV UPDI for tinyAVRs at the moment, but AVR-EA's shouldn't be difficult to add later. https://github.com/MCUdude/avrdude/tree/hv-updi

I've added a new parameter to avrdude.conf, hvupdi_variant. This number is used to determine whether a chip supports HV UPDI or not. If hvupdi_variant isn't a suitable name, I'm open to other suggestions!

HW UPDI can be utilized like so:

$ ./avrdude -cpickit4_updi -pattiny1616 -Usyscfg0:r:-:h

         Vtarget                      : 5.08 V
         JTAG clock megaAVR/program   : 1000 kHz
         JTAG clock megaAVR/debug     : 100 kHz
         PDI/UPDI clock Xmega/megaAVR : 100 kHz

avrdude: initialization failed, rc=-1
         Double check connections and try again, or use -F to override
         this check.

avrdude done.  Thank you.

$ ./avrdude -cpickit4_updi -pattiny1616 -Usyscfg0:r:-:h -x hvupdi

         Vtarget                      : 5.08 V
         JTAG clock megaAVR/program   : 1000 kHz
         JTAG clock megaAVR/debug     : 100 kHz
         PDI/UPDI clock Xmega/megaAVR : 100 kHz

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e9421 (probably t1616)
avrdude: reading fuse5/syscfg0 memory:

Reading | ################################################## | 100% 0.01s

avrdude: writing output file "<stdout>"
0xf2

avrdude done.  Thank you.

We obviously need this to be tested by other users that happen to own a Pickit4 or a Powerdebugger. I also need to update the docs.

janegilruud commented 2 years ago

@janegilruud this would be a nice feature to have. This can prevent users from applying a HV pulse to a target that doesn't support it. But how would HV UPDI on a "type 2 target", where the pulse is applied to the RESET pin work? Would the Pickit4 output the pulse on a different pin (instead of pin 3 as of today), or would external hardware be needed to clap the voltageon the UPDI pin and instead connect this to the RESET PIN.

Yes, the PICkit4 will output the HV pulse on the _RESET pin, not the UPDI pin, on a type 2 target. But it has to be told that the target is a type 2, other wise it will default to send the HV pulse on the UPDI pin which might actually break the type 2 devices. If we get the type info into avrdude.conf it will be a simple addition to the _updi_devicedesc in jtag3.c. So the way this works is that you configure the type in the device description when connecting to the tool, and then issue the HV pulse command which you have successfully done on a tiny1616.

Configuring the type is only important for the type 2 targets, but I suggest we add the type info to all UPDI targets, and deny use of HV pulse unless the type is configured, just to be safe.

MCUdude commented 2 years ago

@janegilruud see PR #1050 for my proposal. Is the jtag3 command the same for "type 2" UPDI targets?

janegilruud commented 2 years ago

Yes, the command for doing the HV pulse is the same, which is why I think we should add the type information in the device description to avoid accidentally frying any type 2 targets.

MCUdude commented 2 years ago

which is why I think we should add the type information in the device description to avoid accidentally frying any type 2 targets.

I've already done that. From #1015

part parent ".avr8x"
     id                = ".avr8x_tiny";
     desc              = "AVR8X tiny family common values";
     family_id      = "tinyAVR";
     # Shared UPDI pin, HV on UPDI pin
     hvupdi_variant = 0;

...

part parent ".avr8x"
     id                = ".avr8x_mega";
     desc              = "AVR8X mega family common values";
     family_id       = "megaAVR";
     # Dedicated UPDI pin, no HV
     hvupdi_variant = 1;

...

part parent ".avrdx"
     id                = ".avrex";
     desc              = "AVR-Ex family common values";
     # Shared UPDI pin, HV on _RESET
     hvupdi_variant = 2;
janegilruud commented 2 years ago

Yes, so now you're only two small lines from the final goal ;-) I've created a PR to your branch (https://github.com/MCUdude/avrdude/pull/1).

janegilruud commented 2 years ago

I realized that we talk about different "device descriptions". You talk about the one in avrdude.conf, and it needs to be added there too. Your implementation is exactly as I would have done it. But it also needs to be added to the "device description" sent to the tool when initializing communication, the _updi_devicedesc struct in _jtag3private.h. This is what tells the tool which HV pulse procedure/output to use.

janegilruud commented 2 years ago

What if we added _hvupdivariant to the programmer description too, like this:

programmer
  id    = "pickit4_updi";
  desc  = "MPLAB(R) PICkit 4 in UPDI mode";
  type  = "jtagice3_updi";
  connection_type = usb;
  usbpid = 0x2177, 0x2178, 0x2179;
  hvupdi_variant = "0 1 2";
;

Then add a check to see if the target _hvupdivariant matches any of the ones listed in the programmer _hvupdivariant.