ElTangas / jtag2updi

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

UPDI programming with level translation #41

Open vladbelous opened 3 years ago

vladbelous commented 3 years ago

Thanks again for your work on jtag2updi!

In the README.md you mention you haven't tried using a level shifter -- I thought I'd share my results/issues here and maybe add a suggestion.

In all cases I use atmega328p as the programmer, and attiny1614 as the target MCU. The programmer (atmega328p) is running at 5V, and I'm level-shifting down to 2.5V on the target.

Level translation with TXB0104 This one seems to work just fine both at max UPDI_BAUD (225k) and min (80k). TXB0104 chip is an auto-direction-sensing translator, intended for push-pull applications.

I tried it with the series resistor (on UPDI line) on both side of the translator, on either one side, as well as neither side - works in all combinations.

Level translation with PI4ULS The full name is PI4ULS5V201 (datasheet) - could NOT get it to work, no matter what I tried. Which is a shame, because it's a small single-channel auto-direction-sensing translator. The datasheet for it claims support for 20Mbit/s for push-pull (should more than enough) and 2Mbit/s for open-drain applications.

This IC has integrated 10k pull-up resistors - could this be throwing off the UPDI protocol? On the other hand, it does claim to support push-pull applications in any case (not sure how that works with pull-ups).

I also tried recompiling jtag2updi to reduce UPDI_BAUD to minimum (80k) -- still no luck.

I've verified that the translator IC itself appears to function as expected by manually connecting either side to VCC/GND with a jumper cable and observing correct change on the other side (I've done this on the PCB itself, i.e. physically same IC).

I've attached logs of avrdude -v -v -v ... runs with TXB0104 (working) and PI4ULS (not working) in case this gives you any clue: logs-txb0104-new.txt logs-pi4uls-new.txt

Feature request: expose data direction on a separate output pin? I've generally found auto-direction sensing translators can be finicky, where as translators with a DIR pin seem more reliable (also faster and cheaper). I'm wondering if we could have jtag2updi expose "current data direction" on a pin, which could then be hooked up to the DIR pin on the translator -- this would allow more parts to choose from. Any thoughts about this?

One would probably need 2 data direction pins of opposite polarity, actually (to support all configurations).

ElTangas commented 3 years ago

Actually I never tried a level shifter, because most use pull-ups and I knew these would not work due to the way jtag2updi operates. It's related to the collision detection present in the UPDI unit, it's on by default and I decided to leave it like that for safety. You can read more about why pull-ups mess with communication here: https://www.avrfreaks.net/comment/2330171#comment-2330171

The UPDI collision detector can be disabled, and I could add an option to jtag2updi to do that. I'll also consider your feature request of a direction pin, but I don't have a lot of different level shifters to test.

vladbelous commented 3 years ago

Thanks for the reference -- this collision detection seems a probable explanation. Although I'm slightly surprised TXB0104 works.

I tried tinkering with the code to add the collision-detection-disable command in void UPDI_io::init(void) (same sequence as in pyupdi), but the whole thing stopped working -- I'm probably missing something about jtag2updi entry point and where to properly insert the sequence.

If you like, you can tell me where/how exactly to insert this updi command and I'll test it for you with both TXB0104 and PI4ULS.

Regarding direction pin - if you decide to work on this, I can help you test it with some level shifters.

ElTangas commented 3 years ago

I think it should be enough to modify JTAG2::set_device_descriptor() function. Immediately after the write to the UPDI CTRL A register, do a write to CTRL B with the correct value to disable the collision detection.

vladbelous commented 3 years ago

Great! I applied this change:

diff --git a/source/JTAG2.cpp b/source/JTAG2.cpp
index e405891..bada7bd 100644
--- a/source/JTAG2.cpp
+++ b/source/JTAG2.cpp
@@ -164,6 +164,12 @@ void JTAG2::set_device_descriptor() {
   /* Initialize or enable UPDI */
   UPDI_io::put(UPDI_io::double_break);
   UPDI::stcs(UPDI::reg::Control_A, 0x06);
+
+  // Disable collision detector:
+  UPDI_io::put(0x55);
+  UPDI_io::put(uint8_t(0xC0 + 0x03));
+  UPDI_io::put(uint8_t(1 << 3));
+
   set_nvm_version();
   JTAG2::ConnectedTo |= 0x01; // connected to target
   set_status(RSP_OK);

And that indeed made it work with the PI4ULS level shifter. One caveat: I had to short out one of the series resistors - the one between PI4ULS and the programmer (one between attiny1614 and PI4ULS is ok). Shorting out both resistors also works fine.

Anyway, how actually significant is the risk of removing collision detection?

ElTangas commented 3 years ago

Anyway, how actually significant is the risk of removing collision detection?

Well, in theory collisions will never happen. Both the series resistor and collision detection are there just in case, but they are not really required.

Anyway, if the 4.7k resistor doesn't work with your setup, I would at least leave some smaller value resistor as protection, maybe 1k or 470 ohm will work.

In sum, yeah, the risk of burning an I/O due to collision is very low when things are running smoothly, but if there are communication errors it's possible.

maxstrauch commented 2 years ago

I came across this issue since I need to program a AVR128DA28 in-circuit at 3V3 (max. voltage for other components) and I'm having no luck with a voltage divider and a TXS0104E. Based on @vladbelous I created this circuit:

image

But I always get:

# avrdude -c jtag2updi -P /dev/cu.usbserial-2120 -p avr128da28

avrdude: AVR device initialized and ready to accept instructions

Reading |                                                    | 0% 0.00savrdude: jtagmkII_program_enable(): bad response to enter progmode command: RSP_ILLEGAL_MCU_STATE
avrdude: jtagmkII_program_enable(): bad response to enter progmode command: RSP_NO_TARGET_POWER
avrdude: jtagmkII_read_byte(): bad response to read memory command: RSP_NO_TARGET_POWER
avr_read(): error reading address 0x0000
    read operation not supported for memory "signature"
avrdude: error reading signature data for part "AVR128DA28", rc=-2
avrdude: error reading signature data, rc=-2
avrdude: jtagmkII_program_disable(): bad response to leave progmode command: RSP_NO_TARGET_POWER

avrdude done.  Thank you.

(avrdude: Version 7.0)

By any chance: do you have any idea if I'm doing something wrong?

(programming the AVR128DA28 directly using 5V works fine; programming the AVR128DA28 via pyprog (RaspberryPi) works fine - so the IC is good and connections checked and working)

PeterDuesentrieb commented 1 year ago

"RSP_NO_TARGET_POWER"

Hi, a collegue of my (Jochen) solved it by adding a row in "JTAG2.cpp" row 177. just press one time enter and insert now into the empty row 178: UPDI::stcs(UPDI::reg::Control_A, 0x06); I tried to program a Tiny826 with an arduino Nano but it never worked, also not with USB to serial ttl-programmer.

2023-05-16 16_57_29-jtag2updiohneControl - JTAG2 cpp _ Arduino 1 8 19 (Windows Store 1 8 57 0)