# How to Configure Analog Output Using MCP4725 DAC in DIY Sim-Racing FFB Pedal

> Configure analog output with MCP4725 DAC for your sim-racing FFB pedal. Learn how to wire and set voltage using simple code for DIY projects.

- Repository: [chrgri/diy-sim-racing-ffb-pedal](https://github.com/chrgri/diy-sim-racing-ffb-pedal)
- Tags: how-to-guide
- Published: 2026-02-27

---

**To configure analog output using the MCP4725 DAC, define `Using_analog_output_ESP32_S3` in [`Main.h`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Main.h), wire the DAC to GPIO 4 (SDA) and GPIO 5 (SCL), and call `dac.setVoltage()` with a 12-bit value scaled to 0–4095.**

The **diy-sim-racing-ffb-pedal** firmware supports external digital-to-analog conversion via the MCP4725 (or MCP4728) I²C DAC. This provides a clean 0–5 V analog signal for sim-racing interfaces that expect traditional voltage levels rather than PWM. Below is the complete configuration guide derived from the source code in `Firmware_for_V3/PedalFirmware/`.

## Enable MCP4725 Support in Firmware Configuration

All DAC-specific code is wrapped in conditional compilation blocks. You must explicitly enable the analog output path before the firmware will initialize the I²C bus or the DAC object.

### Defining the Preprocessor Flag in Main.h

Open the board-specific header file located at [`Firmware_for_V3/PedalFirmware/include/Main.h`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Firmware_for_V3/PedalFirmware/include/Main.h). Locate the analog output section (around lines 95–96) and uncomment the following definition:

```cpp
#define Using_analog_output_ESP32_S3

```

If you are compiling for a different board variant, you can also inject this flag via a custom [`platformio_override.ini`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/platformio_override.ini) file without modifying the source headers. Rebuild the firmware after making this change; the compiler will now include the MCP4725 initialization and update logic.

## Hardware Wiring and Pin Configuration

The firmware uses a dedicated I²C bus for the DAC to avoid conflicts with other peripherals. The default pin mapping is defined in [`Main.h`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Main.h) (lines 28–30):

| ESP32 Pin | MCP4725 Pin | Function |
|-----------|-------------|----------|
| GPIO 4 (`MCP_SDA`) | SDA | I²C Data |
| GPIO 5 (`MCP_SCL`) | SCL | I²C Clock |
| 3.3 V / 5 V | VCC | Power Supply |
| GND | GND | Common Ground |

Connect the MCP4725’s **A0** pin to GND to set the default I²C address to `0x60`. If you need multiple DACs on the same bus, tie A0 to VCC for address `0x61`, or use the MCP4728 variant which supports four channels at addresses `0x60`–`0x67`.

## Initialize the MCP4725 DAC in Code

The firmware automatically probes the I²C bus during the `setup()` phase in [`Firmware_for_V3/PedalFirmware/src/Main.cpp`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Firmware_for_V3/PedalFirmware/src/Main.cpp) (lines 650–690). It attempts to detect the DAC at any address in the range `0x60`–`0x67`:

```cpp
TwoWire MCP4725_I2C = TwoWire(1);
MCP4725_I2C.begin(MCP_SDA, MCP_SCL, 400000);

uint8_t i2c_address[8] = {0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67};
int found_address = 0;

for (int i = 0; i < 8; ++i) {
    MCP4725_I2C.beginTransmission(i2c_address[i]);
    if (MCP4725_I2C.endTransmission() == 0) {
        found_address = i;
        break;
    }
}

if (!dac.begin(i2c_address[found_address], &MCP4725_I2C)) {
    Serial.println("Couldn't find MCP, will not have analog output");
    MCP_status = false;
} else {
    Serial.println("MCP founded");
    MCP_status = true;
}

```

The `dac` object is an instance of `Adafruit_MCP4725`. If initialization fails, `MCP_status` is set to `false` and the firmware continues without analog output, ensuring the pedal remains functional even if the hardware is absent.

## Write Analog Output Values at Runtime

During each control-loop iteration, the firmware converts the normalized pedal position (0–10000 representing 0–100%) into a 12-bit DAC value (0–4095). This logic resides in [`Main.cpp`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Main.cpp) around lines 1545–1555:

```cpp
#ifdef Using_analog_output_ESP32_S3
if (MCP_status) {
    // Scale to 0-4095, limit to 90% of full scale (≈4.5V) to protect the MCU
    int dac_value = (int)(joystickNormalizedToInt32 * 4096 * 0.9 / 10000);
    dac.setVoltage(dac_value, false);   // false = no EEPROM write
}
#endif

```

The multiplication by `0.9` caps the output at approximately 4.5 V, providing a safety margin for downstream circuits. The `false` parameter prevents unnecessary EEPROM writes, extending the lifespan of the DAC’s internal non-volatile memory.

## Alternative: Native ESP32 PWM DAC

If you prefer not to use external hardware, the firmware supports the ESP32’s built-in 8-bit PWM DAC via `dacWrite()`. Enable this path by defining `Using_analog_output` (without the `_ESP32_S3` suffix) in [`Main.h`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Main.h). The runtime write occurs in the same control-loop location, but uses the native ESP32 driver instead of the MCP4725 library.

## Summary

- **Enable the feature** by uncommenting `#define Using_analog_output_ESP32_S3` in [`Firmware_for_V3/PedalFirmware/include/Main.h`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Firmware_for_V3/PedalFirmware/include/Main.h).
- **Wire the DAC** to GPIO 4 (SDA) and GPIO 5 (SCL) with pull-up resistors and appropriate power supply.
- **Library dependency** is handled automatically via `adafruit/Adafruit MCP4725 @ ^2.0.2` in [`platformio.ini`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/platformio.ini).
- **Initialization** scans I²C addresses 0x60–0x67 in [`Main.cpp`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Main.cpp) (lines 650–690) and sets `MCP_status` on success.
- **Runtime updates** convert pedal position to 12-bit values and call `dac.setVoltage()` at lines 1545–1555, capped at 90% for circuit protection.

## Frequently Asked Questions

### What is the default I²C address for the MCP4725?

The default address is **0x60** when the A0 pin is tied to ground. If you connect A0 to VCC, the address becomes **0x61**. The firmware automatically scans the full range 0x60–0x67 to accommodate multiple DACs or the MCP4728 variant.

### Can I use the MCP4728 instead of the MCP4725?

Yes. The **MCP4728** is a quad-channel version that uses the same I²C address range (0x60–0x67). The bridge firmware ([`Firmware_for_V3/BridgeFirmware/src/Main.cpp`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Firmware_for_V3/BridgeFirmware/src/Main.cpp)) demonstrates MCP4728 usage with the `setChannelValue()` method instead of `setVoltage()`. The initialization and wiring remain identical.

### Why is the DAC output limited to 90% of full scale?

The firmware multiplies the calculated DAC value by **0.9** to cap the output at approximately **4.5 V** instead of the full 5 V. This safety margin protects downstream microcontrollers or analog inputs from over-voltage conditions while still providing sufficient resolution for pedal position sensing.

### Which file contains the DAC initialization code?

The initialization logic resides in **[`Firmware_for_V3/PedalFirmware/src/Main.cpp`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Firmware_for_V3/PedalFirmware/src/Main.cpp)** between lines **650–690**. This block creates the `TwoWire` instance, scans for the MCP4725 at addresses 0x60–0x67, and calls `dac.begin()` to establish communication before setting the global `MCP_status` flag.