> Complete documentation index: [llms.txt](/llms.txt). Markdown versions of all pages are available by appending `.md` to page URLs.

# Target Voltage (VTARG)

> How VTARG works on Binho adapters, how to choose between adapter-powered and target-powered modes, and how to recover when the voltage looks wrong.

The **target voltage (VTARG)** pin on each port sets the logic level of the bus. It works in one of two ways:

* **The adapter powers the target.** The adapter drives VTARG at the set voltage, and the target runs from it.
* **The target powers itself.** The adapter stops driving VTARG, reads the target's own supply on that pin, and matches its logic levels to it.

Never let both happen at once. Two supplies on one rail is how a target gets damaged. This page shows how to pick the right mode, what changes across firmware versions, and how to recover when something looks wrong.

:::danger
**On firmware 4.6.x and earlier, the adapter does not check the port before it powers it.** Any voltage set (from Mission Control 3, a script, or a voltage saved at startup) connects the adapter's supply to VTARG, even if the target already powers that pin. If the target has its own supply, update to firmware 4.7.0 or later (coming soon) before connecting it, or follow [Target powers itself](#target-powers-itself) exactly.

:::

## The Rails

Each adjustable rail is a 500 mA LDO whose output voltage is set by a DAC, followed by a load switch to the VTARG pin. Setting 0 V opens the switch. The adapter measures VTARG on the connector side of that switch, so a reading shows whatever is on the pin, whoever supplies it.

| Adapter | Port | Rail | Voltage range | Output current (recommended max) | Saved across power cycles |
| ------- | ---- | ---- | ------------- | -------------------------------- | ------------------------- |
| Supernova | Multifunction + Dedicated I2C (I2C, SPI, UART, GPIO) | Multifunction | 1.2–3.3 V | 200 mA | Yes, optional |
| Supernova | I3C High-Voltage | I3C HV | 1.2–3.3 V | 200 mA | No |
| Supernova | I3C Low-Voltage | I3C LV | 0.8–1.2 V | 350 mA | No |
| Pulsar | Multifunction + Dedicated I2C (I2C, SPI, UART, GPIO) | Multifunction | 1.2–3.3 V | 200 mA | Yes, optional |
| Pulsar | RS-485 + CAN-FD | Differential | Fixed 5 V, not configurable | 200 mA | Not applicable |

Sources: Supernova datasheet rev 1.6 and Pulsar datasheet rev 1.3, Recommended Operating Conditions.

* **The multifunction rail is shared.** I2C, SPI, UART and GPIO all use it. Setting the voltage from any of them moves all four.
* **The two I3C ports are exclusive.** When the HV port is in use, the LV port is not available, and the reverse.
* **I3C voltage is never saved.** The I3C rails are set by DACs with no memory, so the I3C ports start unpowered every time the adapter starts. Set the I3C voltage in every session.
* **Pulsar's 1-Wire port** (Nova compatibility mode, firmware 4.4.0 and later) runs at 3.3 V or 5 V, independent of the multifunction rail.

Absolute maximum ratings (Supernova datasheet rev 1.6, Pulsar datasheet rev 1.3): 4.2 V on VTARG and any signal pin of the multifunction ports, on both adapters (the Pulsar 1-Wire pin: 5.5 V). Supernova only: on the I3C HV port, 5.5 V on the power input (VTARG) and 3.6 V on SCL and SDA; 2.5 V on the I3C LV port, power input and signal pins. An external supply above the operating range is not refused by the adapter, so keep it within the ranges in the table.

## Choose a Mode

| Target | Use | PyCosmicSDK call |
| ----------- | --- | ---------------- |
| Has no supply of its own | The adapter powers it | `set_voltage(voltage_mv)` |
| Has its own supply, battery or bench supply | The target powers itself | `use_external_voltage()` |
| Is powered by another Binho adapter on the same bus | One adapter powers, the other uses external | `set_voltage` on one, `use_external_voltage` on the other |

The calls exist on each interface that owns a rail:

| Interface | Set | Use the target's supply | Read |
| --------- | --- | ----------------------- | ---- |
| `dev.i2c()` | `set_voltage(voltage_mv, persist=False)` | `use_external_voltage(persist=False)` | `get_bus_voltage()` → mV |
| `dev.spi()` | `set_voltage(voltage_mv, persist=False)` | `use_external_voltage(persist=False)` | `get_bus_voltage()` → mV |
| `dev.uart()` | `set_voltage(voltage_mv, persist=False)` | `use_external_voltage(persist=False)` | `get_bus_voltage()` → mV |
| `dev.gpio()` | `set_voltage(voltage_mv, persist=False)` | `use_external_voltage(persist=False)` | `get_voltage()` → mV |
| `dev.i3c()` (Supernova) | `set_voltage(voltage_mv)` | `use_external_voltage(persist=False)` | `get_bus_voltage()` → `(hv_mv, lv_mv)` |

The four multifunction readers return the same number: they all read the one shared rail. For I3C, the voltage selects the port: 800–1199 mV drives the LV port, 1200–3300 mV the HV port. `0` switches the rail off on any interface.

Full reference: [PyCosmicSDK I2C guide](https://binhollc.github.io/pycosmicsdk/guides/i2c.html), [I3C guide](https://binhollc.github.io/pycosmicsdk/guides/i3c.html), [GPIO guide](https://binhollc.github.io/pycosmicsdk/guides/gpio.html).

## Safe Sequences

### The Adapter Powers the Target

1. Disconnect the target, or make sure its own supply is off.
2. Set the voltage, then read it back.
3. Configure the bus and start talking.

```python
from pycosmicsdk import Device, I2cPullUp

with Device.open() as dev:
    i2c = dev.i2c()
    i2c.set_voltage(1800)                        # 1.8 V on the shared rail
    print("VTARG:", i2c.get_bus_voltage(), "mV")  # expect about 1800
    i2c.initialize(400_000, I2cPullUp.KOHM_2_2)
    print("Found:", sorted(i2c.scan().addresses_7bit))
```

If the reading does not match the voltage set, stop. Another source is on the rail: see [Troubleshooting](#troubleshooting).

### Target Powers Itself

1. Power the target from its own supply.
2. Call `use_external_voltage()` **before** any `set_voltage`. Never call `set_voltage` on this port.
3. Read the voltage the adapter measured. It should match the target's supply.

```python
from pycosmicsdk import Device, I2cPullUp

with Device.open() as dev:
    i2c = dev.i2c()
    i2c.use_external_voltage()                   # adapter stops driving VTARG
    print("Target supply:", i2c.get_bus_voltage(), "mV")
    i2c.initialize(400_000, I2cPullUp.KOHM_2_2)
```

For I3C on the Supernova, exactly one I3C port must be powered by the target when `dev.i3c().use_external_voltage()` is called. With neither powered the adapter answers `FW_I3C_PORTS_NOT_POWERED` (`0x0104`); with both, `FW_BOTH_I3C_PORTS_POWERED` (`0x0105`).

### Handle a Self-Powered Target on Firmware 4.7.0 and Later (Coming Soon)

From firmware 4.7.0, the adapter measures the port before it powers it. If the pin already reads above 500 mV with the adapter's switch open, the set is refused with `FW_EXTERNAL_VOLTAGE_DETECTED` (`0x0102`) and VTARG stays off. A refused `persist=True` set stores nothing. This applies to the multifunction rail on both adapters and to both I3C ports.

Scripts that used to set a voltage over a self-powered target now get this error. Catch it and switch to the target's supply:

```python
from pycosmicsdk import Device, StatusCode, SystemFirmwareError

with Device.open() as dev:
    i2c = dev.i2c()
    try:
        i2c.set_voltage(3300)
    except SystemFirmwareError as exc:
        if exc.status_code is not StatusCode.FW_EXTERNAL_VOLTAGE_DETECTED:
            raise
        i2c.use_external_voltage()               # the target already powers VTARG
    print("VTARG:", i2c.get_bus_voltage(), "mV")
```

:::caution
This fallback protects only on firmware 4.7.0 and later. On 4.6.x and earlier the `set_voltage` call succeeds and connects the adapter's supply to the target. Check the firmware version first: `dev.info.fw_version`, or `fw_version` in `list_devices()`.

:::

### Power-Cycle a Target the Adapter Powers

Setting 0 V and then the working voltage again power-cycles a target that the adapter powers. Use it to recover a peripheral that holds SDA low.

```python
i2c.set_voltage(0)
i2c.set_voltage(3300)
```

This works only when nothing else drives the rail. On a bench with two adapters sharing the rail, call `use_external_voltage()` on the other adapter first, then read the rail back.

## Saving the Voltage (`persist=True`)

`set_voltage(voltage_mv, persist=True)` on the multifunction rail stores the voltage in the adapter. The adapter then powers the target as soon as it gets USB power, before any software connects. Use it for a target that must come up on its own.

* Only the multifunction rail can be saved. I3C cannot.
* `use_external_voltage(persist=True)` stores the voltage measured at that moment, not "external". After a power cycle the rail state is not defined; do not use this with a self-powered target.
* To stop powering the target at startup, call `set_voltage(0, persist=True)`.

### After a Reboot, Firmware Update or DFU



**Firmware 4.7.0 and later**

After a reboot, a firmware update or a DFU, the rail comes up at the **saved** voltage. If a target supply is present on the pin at startup, the adapter leaves VTARG off.



**Firmware 4.6.x and earlier**

:::danger
If a voltage was saved and the rail was later set to another value without saving it (for example `set_voltage(0)`), a reboot, firmware update or DFU brings the rail up at **about 3.3 V**, not the saved voltage. A 1.8 V target gets 3.3 V before any host connects. Measured on a Supernova with 1.8 V saved: 3299 mV after each of three reboots.

:::

Until the update:

* Disconnect the target before rebooting the adapter or updating its firmware.
* Unplug and replug USB instead of a software reboot. A full power cycle loads the saved voltage correctly.
* Or save the voltage actually wanted before rebooting, so the saved and current values match.



## Pins While the Rail Is Off

| Firmware | SPI, UART, GPIO pins at 0 V | I2C pull-ups at 0 V |
| -------- | --------------------------- | ------------------- |
| 4.5.1 and earlier | Keep driving. A GPIO output or an idle chip select at 3.3 V can power an unpowered target through its I/O. | Stay powered |
| 4.6.x | Stop driving. They come back with the configuration when the rail returns. | Stay powered |
| 4.7.0 and later | Stop driving | Disconnected while the rail is off, restored when it returns |

**I2C pull-ups on 4.6.x and earlier:** with the rail at 0 V, the adapter's I2C pull-ups stay powered and feed an unpowered target through SDA and SCL. The target's supply pin then lifts VTARG. Measured on a Supernova with a sensor board on the I2C port, rail off: 645 mV with 2.2 kΩ pull-ups, 1089 mV with 470 Ω, 1496 mV with 150 Ω, 1 mV with pull-ups disabled. Before switching the rail off, either disconnect the target or disable the pull-ups:

```python
i2c.set_pull_up(I2cPullUp.DISABLE)   # needs dev.capabilities.i2c_runtime_reconfigurable
i2c.set_voltage(0)
```

On 4.5.1 and earlier, also return GPIO outputs to inputs before switching the rail off.

## Mission Control 3

Mission Control 3 sets the target voltage when a tool connects.

1. Choose the voltage **before** clicking **Connect**. The SPI, GPIO and Serial Terminal tools show a **Voltage** setting; the I3C tool has a **VOLTAGE** field with presets and a **Set** button.
2. The multifunction rail is shared: a voltage set in the SPI tool also applies to I2C, UART and GPIO on the same adapter.
3. With a self-powered target:
   * In the I3C tool, use **Switch to external bus voltage**.
   * On firmware 4.7.0 and later, if the target already powers the pin, the adapter refuses the voltage and Mission Control 3 reports **bus voltage was not applied: an external supply on VTARG defines the rail**. The tool keeps working on the target's supply.
   * On firmware 4.6.x and earlier, Mission Control 3 connects the adapter's supply to the pin. Update the firmware first. See [Updating Firmware](/guides/firmware-updates/).

## Troubleshooting

| Symptom | Cause | Fix |
| ------- | ----- | --- |
| The target gets about 3.3 V after a reboot, firmware update or DFU | Firmware 4.6.x and earlier, with a saved voltage and a different unsaved value set later | Update to 4.7.0. Until then, disconnect the target before rebooting or updating, or replug USB instead. |
| A self-powered target is pulled toward the adapter's voltage | Firmware 4.6.x and earlier: a voltage set connected both supplies | Disconnect, then use `use_external_voltage()` and never `set_voltage` on that port. Update to 4.7.0. |
| `set_voltage` raises `SystemFirmwareError` with `FW_EXTERNAL_VOLTAGE_DETECTED` (`0x0102`) | Firmware 4.7.0 and later found more than 500 mV on the pin: the target, or a second adapter, already powers it | Call `use_external_voltage()`. If the target should be unpowered, find what powers the pin: its own supply, a second adapter, or a USB cable to the target. |
| `set_voltage` succeeds but `get_bus_voltage()` does not change | Another source on the rail: a powered target or a second adapter. The adapter's regulator sources current but does not sink it, so the other source wins. | Turn the other source off, or hand it over with `use_external_voltage()` on the other adapter. Firmware 4.7.0 reports this as `0x0102`. |
| VTARG reads several hundred mV to 1.5 V with the rail at 0 V | Firmware 4.6.x and earlier: I2C pull-ups feeding an unpowered target | Disable the pull-ups or disconnect the target before switching off. Update to 4.7.0. |
| An unpowered target stays partly alive with the rail at 0 V | Firmware 4.5.1 and earlier: SPI, UART or GPIO pins still driving | Return outputs to inputs first, or update to 4.6.0 or later. |
| `set_voltage` raises `FW_VOLTAGE_OUT_OF_RANGE` (`0x0101`) | Value outside the port's range | Use 0 or 1200–3300 mV on the multifunction rail; 0 or 800–3300 mV on I3C. |
| `dev.i3c().use_external_voltage()` raises `0x0104` or `0x0105` | No I3C port, or both, powered by the target | Power exactly one I3C port from the target. |
| The I3C port is unpowered after replugging the adapter | I3C voltage is never saved | Set the I3C voltage again in each session. |
| A peripheral holds SDA low and the bus stays stuck | The peripheral is hung | If the adapter powers it, power-cycle it with `set_voltage(0)` and back. |

Still stuck? Send the adapter's serial number, firmware version, the calls made and the voltages read to [support@binho.io](mailto:support@binho.io). See [Adapter Stops Responding](/support/troubleshooting/adapter-stops-responding/) for how to collect them.