uart half duplex one line

realfspin
Posts: 10
Joined: Sat Apr 06, 2024 9:29 pm

uart half duplex one line

Postby realfspin » Tue May 28, 2024 3:45 am

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?

HaydosR
Posts: 9
Joined: Fri Sep 02, 2022 6:32 am

Re: uart half duplex one line

Postby HaydosR » Wed May 29, 2024 12:42 am

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

realfspin
Posts: 10
Joined: Sat Apr 06, 2024 9:29 pm

Re: uart half duplex one line

Postby realfspin » Fri May 31, 2024 7:45 pm

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!

modulusmath
Posts: 4
Joined: Tue Oct 04, 2022 2:04 am

Re: uart half duplex one line

Postby modulusmath » Sun Jun 02, 2024 3:49 am

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

MicroController
Posts: 2661
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: uart half duplex one line

Postby MicroController » Mon Jun 10, 2024 8:49 am

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)?

realfspin
Posts: 10
Joined: Sat Apr 06, 2024 9:29 pm

Re: uart half duplex one line

Postby realfspin » Thu Jun 13, 2024 2:20 am

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?

HaydosR
Posts: 9
Joined: Fri Sep 02, 2022 6:32 am

Re: uart half duplex one line

Postby HaydosR » Fri Mar 07, 2025 4:55 am

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
}
```

bmf80253
Posts: 1
Joined: Fri Mar 14, 2025 4:02 am

Re: uart half duplex one line

Postby bmf80253 » Fri Mar 14, 2025 4:14 am

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?

HaydosR
Posts: 9
Joined: Fri Sep 02, 2022 6:32 am

Re: uart half duplex one line

Postby HaydosR » Sat Mar 15, 2025 9:46 pm

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

TcSHaris
Posts: 1
Joined: Sun Jan 11, 2026 11:33 am

Re: uart half duplex one line

Postby TcSHaris » Sun Jan 11, 2026 11:37 am

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.
Last edited by TcSHaris on Sun Jan 11, 2026 11:41 am, edited 1 time in total.

Who is online

Users browsing this forum: Google [Bot], Qwantbot and 7 guests