Soft UART (Uart-bitbang) on nRF52 DK (nrf52832) fails with

Hi all hope you all are fine and doing well.

I am trying to use the Soft UART (uart-bitbang.c driver) on nRF52 DK for a low-speed UART connection. The initialization fails with the following error: <err> uart_bitbang: Couldn't configure tx counter. 

This happens repeatedly and I cannot transmit data using the software UART (bitbang).

Board & SDK:

  • nRF52 DK (nRF52832)

  • nRF Connect SDK Toolchain v3.2.0 (VS code Extension) / Zephyr v4.2.99

  • Baudrate: 2400

Problem:

  • Soft UART (uart-bitbang) fails to initialize.

  • Error seen: <err> uart_bitbang: Couldn't configure tx counter

  • Cannot transmit data using software UART (bitbang).

Setup:

  • Device Tree overlay configured with uart-bitbang on P0.13 (TX) and P0.14 (RX).

  • prj.conf enables GPIO, SERIAL, UART_BITBANG, and logging.

  • main.c uses uart_poll_out() for TX.

Steps to Reproduce:

  1. Build Soft UART project using Zephyr SDK v4.2.99 for nRF52 DK

  2. Use overlay and prj.conf as below

  3. Flash on nRF52 DK

  4. Observe error in logs (Serial monitor of VS Code with default baudrate of 115200)

Questions / Help needed:

  1. Why does the TX counter fail to configure?

  2. Are there limitations of uart-bitbang on nRF52 DK?

  3. Is there an example of Soft UART initialization for nRF52 DK?

nrf52dk_nrf52832.overlay file

/ {
    uart_bb0: uart_bitbang_0 {
        compatible = "zephyr,uart-bitbang";
        status = "okay";

        label = "UART_BB0";

        tx-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
        rx-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;

        current-speed = <2400>;      /* numeric, correct property */

        data-bits = <8>;      
        stop-bits = "1";    
        parity = "none";    
    };
};
Prj.conf file
# GPIO and Hardware
CONFIG_GPIO=y

# Counter support (required for uart-bitbang timing)
# The driver uses counter API internally, counter driver will be auto-selected
CONFIG_COUNTER=y

# UART
CONFIG_SERIAL=y

CONFIG_UART_BITBANG=y
CONFIG_UART_INTERRUPT_DRIVEN=n
CONFIG_PRINTK=y

# Logging
CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3
CONFIG_LOG_BACKEND_UART=y
CONFIG_USE_SEGGER_RTT=n

# System Settings
CONFIG_REBOOT=y

CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_LOG_MODE_IMMEDIATE=y


Sample.yaml
sample:
  name: UART Bitbang Test

tests:
  uart.bitbang.basic:
    platform_allow:
      - nrf52dk_nrf52832
    tags:
      - uart
      - bitbang
    harness: console
main.c
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/sys/printk.h>

#define UART_LABEL "UART_BB0"  // Must match the label in your DTS overlay

static uint32_t tx_count = 0;
static uint32_t rx_count = 0;

int main(void)
{
    const struct device *uart = device_get_binding(UART_LABEL);

    if (!uart) {
        printk("ERROR: Could not get UART device binding!\n");
        return 0;
    }

    if (!device_is_ready(uart)) {
        printk("ERROR: Soft UART device not ready!\n");
        return 0;
    }

    printk("Soft UART ready @ %lld ms\n", k_uptime_get());

    const char msg[] = "Hello UART Bitbang\r\n";

    while (1) {
        printk("\nTX loop start @ %lld ms\n", k_uptime_get());

        // Use uart_poll_out for blocking transmission (simpler for bit-bang)
        for (size_t i = 0; i < sizeof(msg) - 1; i++) {
            uart_poll_out(uart, msg[i]);
        }
        tx_count += sizeof(msg) - 1;
        printk("TX done, total TX chars = %u\n", tx_count);

        // Non-blocking RX check
        uint8_t rx;
        int ret = uart_poll_in(uart, &rx);
        if (ret == 0) {
            printk("RX[%u]: '%c' (0x%02X)\n", rx_count, rx, rx);
            rx_count++;
        } else {
            printk("RX: no data available\n");
        }

        k_sleep(K_SECONDS(2));
    }
}
Output Result

Best Regards
Nabeel
Parents
  • Hello,

    What sample are you using to test this? Is the nRF52832 defined as a supported board for this application? I have not seen this driver before (I see that it is new in v3.2.1 (3.2.0?))

    In uart_bitbang.c, there are two cases this error will be printed. One of these return true:

    config->tx_countr == NULL

    !device_is_ready(config->tx_counter)

    Why do you want to use a UART bitbang? There are several instances of HW UART on the nrf52832, is it not better to use any of these?

    Best regards,

    Edvin

Reply
  • Hello,

    What sample are you using to test this? Is the nRF52832 defined as a supported board for this application? I have not seen this driver before (I see that it is new in v3.2.1 (3.2.0?))

    In uart_bitbang.c, there are two cases this error will be printed. One of these return true:

    config->tx_countr == NULL

    !device_is_ready(config->tx_counter)

    Why do you want to use a UART bitbang? There are several instances of HW UART on the nrf52832, is it not better to use any of these?

    Best regards,

    Edvin

Children
  • Hi  ,

    Thank you for your response.

    This is not a Zephyr sample application, I am currently testing the uart_bitbang (soft UART) driver using two GPIOs in a loopback configuration (TX → RX) as part of my project validation.

    My goal is to use the UART bitbang technique to run a Modbus RTU slave at a baud rate of 2400. I was not fully aware whether the nRF52832 is officially supported for uart_bitbang, so this test is mainly to verify feasibility on this board.

    I am using nRF Connect SDK v3.2.0, and as far as I can see, the uart-bitbang driver was recently added like 8 months ago. The reason I want to use a software UART is that my hardware UART is already occupied by an LD2402 motion detection sensor, and in my final design I plan to connect multiple Modbus slave devices (3–4) to a single master, which requires an additional UART interface.

    I understand that using a hardware UART is generally preferable, but due to this constraint, I am exploring the soft UART option.

    Currently, I have enabled the following configuration for uart bitbang in my prj.conf:

    CONFIG_UART_BITBANG=y
    CONFIG_UART_INTERRUPT_DRIVEN=n
    CONFIG_COUNTER=y
    

    And this is my board overlay (nrf52dk_nrf52832.overlay):

    / {
        uart_bb0: uart_bitbang_0 {
            compatible = "zephyr,uart-bitbang";
            status = "okay";
            label = "UART_BB0";
    
            tx-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
            rx-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
    
            current-speed = <2400>;
            data-bits = <8>;
            stop-bits = "1";
            parity = "none";
        };
    };
    

    At the moment, I am only trying to perform a basic loopback test, where data sent on the TX GPIO (for example, "Hello UART Bitbang") should be received on the RX GPIO.

    Please let me know if I am missing something in the configuration (for example, related to the TX counter setup), or if there are known limitations of uart-bitbang on the nRF52832 that would prevent this from working?

  • I've looked into the dts binding, you are missing the RX and TX timer. Those are required in the DTS overlay.

    The code does not throw an error because the timers are technically optional in half duplex mode.

  • I see. In general, I am not convinced uart bitbanging is a good idea in applications that typically run in our chips. The baudrate is fairly low, but you still have 2400 bits per second, or 0.4ms per bit. If you have some softdevice/bluetooth interrupt that it needs to handle at the same time as you are trying to bitbang, you will loose some of these bits. 

    As   says, try setting the rx and tx timers, and see if that helps. But as you see here, if each bitbanged uart requires two timer instances, then you will quickly run out of these.

    Do you intend to use these UARTs at the same point in time? Or is it typically one after the other?

    I suggest you look into using the nrfx drivers directly, instead of via the zephyr uart drivers. If you do that, you can stop an uart instance, change the gpios, and start it again, and this way, communicate with many different UART devices, using only one UART instance. 

    For reference, you can check out:

    NCS\modules\hal\nordic\nrfx\samples\src\nrfx_uarte

    I see that it doesn't have an overlay file: nrf52dk_nrf52832.overlay, but you can copy the one for nRF52840, and do some modifications to test. The pins are defined in v3.2.1\modules\hal\nordic\nrfx\samples\common\boards\<board_name>_config.h, but you can also just declare these pins in your own files.

    Best regards,

    Edvin

Related