Page 1 of 1

uart half duplex one line

Posted: Tue May 28, 2024 3:45 am
by realfspin
I am trying to create a updi programmer out of an esp32-c3-mini and I am able to configure the hardware uart like this and I can snoop on UPDI commands sent by things like jtag2updi successfully.

uart_config_t uart_config = {
.baud_rate = UPDI_BAUD,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_EVEN,
.stop_bits = UART_STOP_BITS_2,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 0,
.source_clk = UART_SCLK_APB,
};

However when I try to send commands and flip the direction to read results I never seem to get anything back.

Without going into too much detail about all the approaches I've taken, does anybody have any insight on what I might be doing wrong or what I need to do?

Re: uart half duplex one line

Posted: Wed May 29, 2024 12:42 am
by HaydosR
Interested in this also - have a board with an ESP32-S3 main processor and an Attiny1616 for background input monitoring. Would love to be able to UPDI program the Attiny via the ESP.

Don't have any suggestions unfortunately. Just leaving a comment to get notified of replies

Re: uart half duplex one line

Posted: Fri May 31, 2024 7:45 pm
by realfspin
Bump, after some insight from another thread I feel I may have sorted out what is effectively half-duplex by merging a tx/rx line together and then doing something like this:

Code: Select all

  // UART configuration
  uart_config_t uart_config = {
  .baud_rate = UPDI_BAUD,
  .data_bits = UART_DATA_8_BITS,
  .parity = UART_PARITY_EVEN,
  .stop_bits = UART_STOP_BITS_2,
  .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
  .rx_flow_ctrl_thresh = 0,
  .source_clk = UART_SCLK_APB,
  };

  // Configure UART parameters
  uart_param_config(UPDI_UART_NUM, &uart_config);
  // Set UART pins
  uart_set_pin(UPDI_UART_NUM, UPDI_RX_PIN, UPDI_TX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
  // Install UART driver
  uart_driver_install(UPDI_UART_NUM, 1024 * 2, 0, 0, NULL, 0);

  // Set UART read timeout
  uart_set_rx_timeout(UPDI_UART_NUM, 50);
  const gpio_config_t pin_cfg {
    .pin_bit_mask = (1ul << GPIO_NUM_8) | (1ul << GPIO_NUM_2),
    .mode = GPIO_MODE_INPUT_OUTPUT_OD, // Input and Output w/ open-drain!
    .pull_up_en = GPIO_PULLUP_ENABLE, // Open-drain requires a pull-up.
    .pull_down_en = GPIO_PULLDOWN_DISABLE,
    .intr_type = GPIO_INTR_DISABLE
  };

  gpio_config(&pin_cfg);

  esp_rom_gpio_connect_out_signal(UPDI_TX_PIN, UART_PERIPH_SIGNAL(UPDI_UART_NUM, SOC_UART_TX_PIN_IDX), false, false);
  esp_rom_gpio_connect_in_signal(UPDI_RX_PIN, UART_PERIPH_SIGNAL(UPDI_UART_NUM, SOC_UART_RX_PIN_IDX), false);    
At least, I am able to snoop on an active connection between two devices when I have both my rx/tx line connected in and use this -- I can also send on my tx and immediately read it back on my rx.

However, I'm still having trouble getting a response from my attiny so I can't confirm whether this is the full solution.

Any other input would be appreciated!

Re: uart half duplex one line

Posted: Sun Jun 02, 2024 3:49 am
by modulusmath
Does this help https://github.com/jouellnyc/UART/blob/ ... /README.md ?

I know it's not the same but it's similar and different :) - and it's micropython.

I basically quickly made a wire a sender and then a receiver via a UART and RS-485

Re: uart half duplex one line

Posted: Mon Jun 10, 2024 8:49 am
by MicroController
Any other input would be appreciated!
I guess my reply in the other thread wasn't very visible, so:
UPDI wants a BREAK signal to reset/synchronize communication. When you were snooping on the communication, the BREAK that was sent may well have gone unnoticed by your code, but you'll have to send one at the start of your own exchange.
Did you already do that? If yes, how did you do it (GPIO vs. UART driver)?

Re: uart half duplex one line

Posted: Thu Jun 13, 2024 2:20 am
by realfspin
So I have way too many details to cover here, but I think I am pretty confident the issue is still line contention.

I am sending the exact same break + updi commands in the exact same serial format as jtag2updi but I don't get a response.

I thought I would test something, I connected jtag2updi in together with my tx/rx and target device, I was able to program the device with jtag2updi, then I initialized my serial tx/rx and sent a updi handshake and updi command, after that I tried to use jtag2updi and it wouldn't work reporting no device power.

When I unplug the tx line (but leave the rx line connected) jtag2updi begins to work.

So very clearly my tx line is still causing contention, even with open-drain, any tips?

Re: uart half duplex one line

Posted: Fri Mar 07, 2025 4:55 am
by HaydosR
We got this working several months ago but forgot to update. Hope its not too late to help. Have no problems flashing an ATTINY1616 anywhere from 9600 baud to 230400 baud

Can't give exact source code but:
```

Code: Select all

bool COM_Open(const updiprog_com_port_t com_port) {
  esp_err_t err;

  // Configure UPDI Pin as Free-floating OpenDrain Output
  err = gpio_config(&(gpio_config_t){
      .pin_bit_mask = ((uint64_t) 1) << com_port.gpio_num,
      .mode         = GPIO_MODE_INPUT_OUTPUT_OD, // Input and Output w/ open-drain!
      .pull_up_en   = GPIO_PULLUP_DISABLE,       // Open-drain requires a pull-up.
      .pull_down_en = GPIO_PULLDOWN_DISABLE,
      .intr_type    = GPIO_INTR_DISABLE,
  });
  if (err != ESP_OK) {
    ESP_LOGE(TAG, "Failed to configure GPIO for UPDI, error code: 0x%X (%s)", err, esp_err_to_name(err));
    return false;
  }

  // Instantiate UART with 8E2 Polarity
  err = uart_param_config(
      com_port.uart_port,
      &(uart_config_t){
          .baud_rate = com_port.baud_rate,
          .data_bits = UART_DATA_8_BITS,
          .parity    = UART_PARITY_EVEN,
          .stop_bits = UART_STOP_BITS_2,
          .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
      }
  );
  if (err != ESP_OK) {
    ESP_LOGE(TAG, "Failed to configure UART params for UPDI, error code: 0x%X (%s)", err, esp_err_to_name(err));
    return false;
  }

  err = uart_driver_install(com_port.uart_port, UPDI_RX_BUFFER_SIZE, 0, 0, NULL, 0);
  if (err != ESP_OK) {
    ESP_LOGE(TAG, "Failed to install UART driver for UPDI, error code: 0x%X (%s)", err, esp_err_to_name(err));
    return false;
  }

  // Mux the UART Tx and Rx inputs to the GPIO pin via GPIO Matrix
  // Stolen from https://esp32.com/viewtopic.php?t=1089
  esp_rom_gpio_connect_out_signal(com_port.gpio_num, UART_PERIPH_SIGNAL(com_port.uart_port, SOC_UART_TX_PIN_IDX), false, false);
  esp_rom_gpio_connect_in_signal(com_port.gpio_num, UART_PERIPH_SIGNAL(com_port.uart_port, SOC_UART_RX_PIN_IDX), false);

  return true;
}

int COM_Write(const updiprog_com_port_t com_port, const void *const data, const uint16_t len) {
  const int bytes_written = uart_write_bytes(com_port.uart_port, data, len);
  return bytes_written >= 0 ? 0 : bytes_written;
}

int COM_Read(const updiprog_com_port_t com_port, void *const data, const uint16_t len) {
  (void) uart_flush(com_port.uart_port);

  // Read and return num bytes
  return uart_read_bytes(com_port.uart_port, data, len, pdMS_TO_TICKS(((16 * len * 1000 / com_port.baud_rate) + 1) + 30));
}

void COM_Close(const updiprog_com_port_t com_port) {
  const esp_err_t err = uart_driver_delete(com_port.uart_port);
  if (err != ESP_OK) {
    ESP_LOGW(TAG, "Could not delete UART driver for UART port %d", com_port.uart_port);
  }

  // not important to reset GPIO at this time
}
```

Re: uart half duplex one line

Posted: Fri Mar 14, 2025 4:14 am
by bmf80253
We got this working several months ago but forgot to update. Hope its not too late to help. Have no problems flashing an ATTINY1616 anywhere from 9600 baud to 230400 baud
How do you have the Attiny connected? Any resistors? Or just a direct connection from that "combined" ESP32 pin to the UPDI pin?

Re: uart half duplex one line

Posted: Sat Mar 15, 2025 9:46 pm
by HaydosR
Direct connection between the esp gpio and the attiny updi/reset pin.

10K pull-up near the attiny to let it power on (100nF cap had to be removed as it screwed with updi comms)

No internal pullups or pulldowns enabled on the esp gpio

Re: uart half duplex one line

Posted: Sun Jan 11, 2026 11:37 am
by TcSHaris
We got this working several months ago but forgot to update. Hope its not too late to help. Have no problems flashing an ATTINY1616 anywhere from 9600 baud to 230400 baud

Can't give exact source code but:
```

Code: Select all

bool COM_Open(const updiprog_com_port_t com_port) {
  esp_err_t err;

  // Configure UPDI Pin as Free-floating OpenDrain Output
  err = gpio_config(&(gpio_config_t){
      .pin_bit_mask = ((uint64_t) 1) << com_port.gpio_num,
      .mode         = GPIO_MODE_INPUT_OUTPUT_OD, // Input and Output w/ open-drain!
      .pull_up_en   = GPIO_PULLUP_DISABLE,       // Open-drain requires a pull-up.
      .pull_down_en = GPIO_PULLDOWN_DISABLE,
      .intr_type    = GPIO_INTR_DISABLE,
  });
  if (err != ESP_OK) {
    ESP_LOGE(TAG, "Failed to configure GPIO for UPDI, error code: 0x%X (%s)", err, esp_err_to_name(err));
    return false;
  }

  // Instantiate UART with 8E2 Polarity
  err = uart_param_config(
      com_port.uart_port,
      &(uart_config_t){
          .baud_rate = com_port.baud_rate,
          .data_bits = UART_DATA_8_BITS,
          .parity    = UART_PARITY_EVEN,
          .stop_bits = UART_STOP_BITS_2,
          .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
      }
  );
  if (err != ESP_OK) {
    ESP_LOGE(TAG, "Failed to configure UART params for UPDI, error code: 0x%X (%s)", err, esp_err_to_name(err));
    return false;
  }

  err = uart_driver_install(com_port.uart_port, UPDI_RX_BUFFER_SIZE, 0, 0, NULL, 0);
  if (err != ESP_OK) {
    ESP_LOGE(TAG, "Failed to install UART driver for UPDI, error code: 0x%X (%s)", err, esp_err_to_name(err));
    return false;
  }

  // Mux the UART Tx and Rx inputs to the GPIO pin via GPIO Matrix
  // Stolen from https://esp32.com/viewtopic.php?t=1089
  esp_rom_gpio_connect_out_signal(com_port.gpio_num, UART_PERIPH_SIGNAL(com_port.uart_port, SOC_UART_TX_PIN_IDX), false, false);
  esp_rom_gpio_connect_in_signal(com_port.gpio_num, UART_PERIPH_SIGNAL(com_port.uart_port, SOC_UART_RX_PIN_IDX), false);

  return true;
}

int COM_Write(const updiprog_com_port_t com_port, const void *const data, const uint16_t len) {
  const int bytes_written = uart_write_bytes(com_port.uart_port, data, len);
  return bytes_written >= 0 ? 0 : bytes_written;
}

int COM_Read(const updiprog_com_port_t com_port, void *const data, const uint16_t len) {
  (void) uart_flush(com_port.uart_port);

  // Read and return num bytes
  return uart_read_bytes(com_port.uart_port, data, len, pdMS_TO_TICKS(((16 * len * 1000 / com_port.baud_rate) + 1) + 30));
}

void COM_Close(const updiprog_com_port_t com_port) {
  const esp_err_t err = uart_driver_delete(com_port.uart_port);
  if (err != ESP_OK) {
    ESP_LOGW(TAG, "Could not delete UART driver for UART port %d", com_port.uart_port);
  }

  // not important to reset GPIO at this time
}
```
If anyone is still here, please tell me how to write this code.
Also, please tell me which GPIO pin on the ESP32 you connected the attiny1616 pin to.
I'm Japanese. I'm using machine translation.