AD7190 SPI interface issue

shaheen.johnson
Posts: 3
Joined: Fri Feb 13, 2026 9:39 am

AD7190 SPI interface issue

Postby shaheen.johnson » Fri Feb 13, 2026 10:03 am

Hi All,

I'm the process of porting a project to ESP32-S3 and I'm using ESP-IDF. I'm configuring an ADC AD7190. I can read and write to various registers reliably. but have an issue with one register in particular, the CONF register. The ADC is set to continuous mode and the board has CS routed to GND - it is the only device on the SPI bus.

When reading the register on startup the default value should be 0x117. But I always read 0x116. So I've written 0x3FF as a test, and I read back 0x3FE. the LSB is always zero no matter what I write to it. However the MODE register read/write works correctly.

The original project was on an Arduino RP2040 nano connect and uses the Arduino SPI library writing 0x257 to CONF and reading it back as 0x257 at all times. There's probably some "under the hood magic" happening. I'm in the process of porting it to ESP-IDF and getting into the low level SPI issues at the moment.

SPI Frequency set to 500000
Using HSPI pins

this is my init code

Code: Select all

esp_err_t ad7190_spi_init(void) {
    const char *TAG = "AD7190_SPI_INIT";
    esp_err_t ret;

    spi_bus_config_t bus_config = {
        .miso_io_num = SPI_MISO_PIN,
        .mosi_io_num = SPI_MOSI_PIN,
        .sclk_io_num = SPI_SCLK_PIN,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 32, 
    };

    spi_device_interface_config_t device_config = {
        .clock_speed_hz = SPI_FREQUENCY,
        .mode = 3, 
        .spics_io_num = -1,
        .queue_size = 1,
        .flags = 0
    };

    ret = spi_bus_initialize(SPI2_HOST, &bus_config, SPI_DMA_CH_AUTO);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize SPI bus (%s)", esp_err_to_name(ret));
        return ret;
    }

    ret = spi_bus_add_device(SPI2_HOST, &device_config, &spi_handle);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to add SPI device (%s)", esp_err_to_name(ret));
        return ret;
    }

    ESP_LOGI(TAG, "SPI device initialized successfully");    
    
    return ESP_OK;
}
Write register and read register functions

Code: Select all

void ad7190_write_register_value(uint8_t reg, uint32_t value, uint8_t num_bytes) {
    const char *TAG = "write register value";
    uint8_t tx[4] = {0};
    uint8_t rx[4] = {0};
        
    tx[0] = AD7190_COMM(reg, AD7190_COMM_WRITE);
    ESP_LOGI(TAG, "Writing register 0x%02X with command byte 0x%02X", reg, tx[0]);

    for (int i = 0; i < num_bytes; i++) {
        tx[i + 1] = (value >> (8 * (num_bytes - 1 - i))) & 0xFF;
    }

    // Debug: Print raw received bytes
    ESP_LOGI(TAG, "TX raw: %02X %02X %02X %02X",
        tx[0], tx[1], tx[2], tx[3]);

    spi_transaction_t t = {0};
    t.length = (num_bytes + 1) * 8; // Command byte + data bytes
    t.tx_buffer = tx;
    t.rx_buffer = rx;

    esp_err_t ret = spi_device_transmit(spi_handle, &t);

    ESP_LOGI(TAG, "RX during write: %02X %02X %02X %02X", rx[0], rx[1], rx[2], rx[3]);  // See what comes back

    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to transmit SPI data (%s)", esp_err_to_name(ret));
    }
}



uint32_t ad7190_get_register_value(uint8_t reg, uint8_t num_bytes) {
    const char *TAG = "get register value";
    uint8_t tx[5] = {0};
    uint8_t rx[5] = {0};

    tx[0] = AD7190_COMM(reg, AD7190_COMM_READ);
    ESP_LOGI(TAG, "Reading register 0x%02X with command byte 0x%02X", reg, tx[0]);

    for (int i = 1; i <= num_bytes; i++) {
        tx[i] = 0xFF; // Dummy bytes to clock out the data
        //ESP_LOGI(TAG, "Dummy Data: 0x%02X", tx[i]);
    }

    // Debug: Print raw received bytes
    ESP_LOGI(TAG, "TX raw: %02X %02X %02X %02X",
         tx[0], tx[1], tx[2], tx[3]);

    spi_transaction_t t = {0};
    t.length = (num_bytes + 1) * 8; // Command byte + data bytes
    t.tx_buffer = tx;
    t.rx_buffer = rx;

    spi_device_transmit(spi_handle, &t);
    
    // Debug: Print raw received bytes
    ESP_LOGI(TAG, "RX raw: %02X %02X %02X %02X",
         rx[0], rx[1], rx[2], rx[3]);

    uint32_t value = 0;

    for (int i = 0; i < num_bytes; i++) {
        value <<= 8;
        value |= rx[i + 1]; // Skip command response
    }

    return value;
}
Writing to the CONF register - the debug messages will show what's written and received

Code: Select all

ESP_LOGI(TAG, "Writing CONF register");
ad7190_write_register_value(AD7190_CONF_REG, 0x000257, 3);
vTaskDelay(pdMS_TO_TICKS(100));

ESP_LOGI(TAG, "Reading CONF register");
uint32_t conf_reg = ad7190_get_register_value(AD7190_CONF_REG, 3);
ESP_LOGI(TAG, "CONF: %" PRIx32, conf_reg); 

Code: Select all

I (535) app main: Writing CONF register
I (535) write register value: Writing register 0x02 with command byte 0x10
I (535) write register value: TX raw: 10 00 02 57
I (535) write register value: RX during write: 00 01 FF FF

I (705) app main: Reading CONF register
I (705) get register value: Reading register 0x02 with command byte 0x50
I (715) get register value: TX raw: 50 FF FF FF
I (725) get register value: RX raw: 00 00 02 56
I (725) app main: CONF: 256
the LSB is always 0 no matter what I try. Is there something in my spi init that can be changed? Writing and Reading from the other registers is working. I've spend around 8 to 12 hrs trying to get to the bottom of this. I would appreciate assistance.

Thanks.

Sprite
Espressif staff
Espressif staff
Posts: 10617
Joined: Thu Nov 26, 2015 4:08 am

Re: AD7190 SPI interface issue

Postby Sprite » Sun Feb 15, 2026 12:15 am

Strange. I don't see anything that you're obviously doing wrong. Do you happen to have a logic analyzer or scope or something that allows you to see the signal on the wires?

shaheen.johnson
Posts: 3
Joined: Fri Feb 13, 2026 9:39 am

Re: AD7190 SPI interface issue

Postby shaheen.johnson » Tue Feb 17, 2026 3:54 pm

It's a timing issue when reading back the CONF register. I'm actually successfully writing 0x000257 to the register, and the last 3-bits sets the gain 0x07 = 128. I can confirm the gain to be 128 by the ADC counts. So writing is fine, just reading the LSB for CONF register is off by (presumably) one clock cycle.

I have since tested the ADC operation and having no issues, zero and calibration functions are correct. I have to do a sanity test with CS, but unfortunately there's no track to cut, pad is tied with spokes to the GND plane. I can carefully lift the pin or wait for a spare board.

I'm guessing the ESP32 has tighter SCK timing compared to the Arduino SPI Library? I'll measure with a scope when I'm back in the office later this week.

mikemoy
Posts: 690
Joined: Fri Jan 12, 2018 9:10 pm

Re: AD7190 SPI interface issue

Postby mikemoy » Thu Feb 19, 2026 2:20 pm

Sounds more like you need to change the SPI operating mode. " .mode "
I would try all of them for this to see if you get back that last bit value.

shaheen.johnson
Posts: 3
Joined: Fri Feb 13, 2026 9:39 am

Re: AD7190 SPI interface issue

Postby shaheen.johnson » Fri Mar 27, 2026 10:27 am

This topic can be closed now.

I was geting stable ADC readings and carried on with other features in the mean time. I still had the LSB issue when reading the CONF register.

As stated before, by this design the AD7190 CS is permanently pulled LOW. This meant that the only way I could reliably frame register reads were to "sync" with DRDY pin.

Code: Select all

// Wait for conversion complete
while (gpio_get_level(AD7190_DRDY_PIN) == 1);  // Wait for falling edge (data ready)

// Wait for DRDY to go back high (conversion cycle complete)
while (gpio_get_level(AD7190_DRDY_PIN) == 0);  // Wait for rising edge

// Small settling delay
esp_rom_delay_us(10);  // Let internal state settle

// NOW it's safe to read/write registers
ad7190_get_register_value(AD7190_CONF_REG, 3);
This test code above, solved the LSB error when reading the conf register. The lack of CS control caused edge case framing errors.

Moving forward I will address this in the PCB design and make CS controlled via GPIO. There were probably reasons the original design had tied CS to GND, so i'll keep that option on the PCB with a jumper.

Who is online

Users browsing this forum: trendictionbot and 2 guests