ElTangas / jtag2updi

UPDI programmer software for Arduino (targets Tiny AVR-0/1/2, Mega AVR-0 and AVR-DA/DB MCUs)
MIT License
330 stars 90 forks source link

Using JTAG2UPDI to inject NVMPROG key #19

Closed MCUdude closed 1 year ago

MCUdude commented 5 years ago

Hi!

A while ago I made a small PCB that basically lets you use an Arduino Pro Micro as an mEDBG programmer. It's a nice programmer, but it sucks that the firmware is closed source.

Optiboot support for the new mega0/tiny0/tiny1 series is starting to mature, but as you may already know, Optiboot uses the RST pin to enter bootloader mode in order to upload code. This is perfectly fine on mega0's, but on the tiny0/1's the RST pin is shared with UPDI. This means that you'll have to "lock yourself out" if you want to use a bootloader for uploading.

And thus the need for a 12V programmer occurs. Sadly, Microchip's documentation is lagging behind; and it turns out that the "newer" tiny0/tiny1's needs a 12V pulse before receiving the NVMPROG key within 65ms. This is nearly impossible difficult to do manually.

I was hoping to design a board where I can just push a button to re-enable the UDPI interface. When I push the button a ~500us pulse has to be injected to the UPDI line, and the NVMPROG key also has to be sent from some device within 65ms.

I was hoping to achieve this with as little hardware as possible. A small microcontroller could drive a voltage multiplier to generate 12V, read the pushbutton, time the 12V pulse and hopefully "inject" the NVMPROG key. Then we can run Avrdude without having to worry about the timeout anymore IIRC.

The question is: How can I use this project to just establish communication with the target (after the 12V pulse) and inject the NVMPROG key? And can this be done with an 8-pin ATtiny(25/45/85) if I remove all the hardware UART related stuff?

Thanks!

ElTangas commented 5 years ago

The UPDI interface code (including the NWMPROG key) is in UPDI_lo_lvl.cpp UPDI_lo_lvl.h and also UPDI_hi_lvl.cpp UPDI_hi_lvl.h You (hopefully) don't need to modify the previous files since they are hardware independent.

However, they depend on hardware configuration files (these you will probably need to edit) sys.cpp sys.h

and the bitbang UART that comes in 2 versions, probably you need updi_io_soft.cpp updi_io.cpp updi_io.h updi_io_soft.cpp

To see how the UPDI functions are used check out the JTAG2.cpp file, in particular the enter_progmode() function.

MCUdude commented 5 years ago

Thanks! I'll have to dive into this.

Is the code written specifically for a CPU running at 16 MHz, or 8 MHz fine too? So in theory, If I modify sys.cpp and sys.h to support ATtiny25/45/85, all that's needed to run after the 12V pulse have been injected is to run JTAG2::enter_progmode()?

I'm also curious to see if the target has some kind of timeout after the NVM_PROG key has been received.

MCUdude commented 5 years ago

Here's some simple pseudo-code to show what I want to achieve.

void setup()
{
  SYS::init();
  UPDI_io::init();
}

void loop()
{
  if(digitalRead(pushButton) == LOW)
  {
    while(digitalRead(pushButton) == LOW)
      delay(250); // Primitive debounce
    apply12V(true);
    delayMicroseconds(500);
    apply12V(false);
    JTAG2::enter_progmode();
  }
}
ElTangas commented 5 years ago

If you want to actually program the chip, inserting the program key is not enough, you also need to do a reset afterwards. Again, I direct you to the enter_progmode() function. This will put the CPU in programming mode.

You will notice that I also do a reset before sending the program key in enter_progmode(), this is to prevent the WDT, if enabled, to do a reset at some random inconvenient moment.

This also means that you can reset the chip from the UPDI pin (in UPDI mode, not RESET mode) if you send the proper commands, this would activate the bootloader.

In other words, you don't get "locked out" of the bootloader if the pin is in UPDI mode, it's just that you need to send something a bit more complicated than a reset pulse to get there.

Oh, I forgot, yes, you can run at 8MHz. If you need, you can reduce the UPDI baud rate. Fine tuning all this requires a bit of testing, so I hope you have a scope and/or logic analyser available.

MCUdude commented 5 years ago

If you want to actually program the chip, inserting the program key is not enough, you also need to do a reset afterwards. Again, I direct you to the enter_progmode() function.

The idea is to use the 12V pulse + the ATtiny25/45/85 to enable the UPDI interface. When the interface is enabled (until the next power-on reset) we can use the microUPDI board to program and/or change the target fuses without having to worry about any timeout. The board I'd like to design is similar to microUPDI, but with a pushbutton too.

Oh, I forgot, yes, you can run at 8MHz. If you need, you can reduce the UPDI baud rate. Fine tuning all this requires a bit of testing, so I hope you have a scope and/or logic analyzer available.

Awesome! I think the ATtiny has an internal 16 MHz PLL, but I've never used this before. I have plenty of test equipment I can use if I'm having timing issues.