eldruin / ads1x1x-rs

Platform-agnostic Rust driver for the ADS1x1x ultra-small, low-power analog-to-digital converters (ADC). Compatible with ADS1013, ADS1014, ADS1015, ADS1113, ADS1114 and ADS1115
https://blog.eldruin.com/ads1x1x-analog-to-digital-converter-driver-in-rust/
Apache License 2.0
32 stars 8 forks source link

Duplicated values when reading from an ADC in a loop. #28

Closed emshotton closed 1 month ago

emshotton commented 1 month ago

Hi!

Thanks for the library. I think I've found a bug, but it seems pretty strange. I'm running on an rp2040 and communicating with an ADS1115 using rustc 1.82.0-nightly. ChannelA0 is connected to 3.3V and ChannelA1 is connected to 0v. I'm using a local copy of latest version of the library from git.

It seems like reading from the ADC in a loop is causing the last value read in the loop to be duplicated. Here's the simplest reproduction I can make.

let mut count = 0;
let mut adc = ads1x1x::Ads1x1x::new_ads1115(i2c, ads1x1x::SlaveAddr::default());
loop {
    info!("Reading pot_0 ADC values");
    let pot_0 = nb::block!(adc.read(ads1x1x::channel::SingleA0)).unwrap();
    info!("0: {}", pot_0);
    info!("Reading pot_1 ADC values");
    let pot_1 = nb::block!(adc.read(ads1x1x::channel::SingleA1)).unwrap();
    info!("1: {}", pot_1);
    // Loop twice then stop
    if count == 1 {
        loop {}
    }
    count += 1;
    info!("====================loop====================");
}

Here's the output. The first time around the loop everything is fine, but the second time around the loop it seems to only be repeating the last read value from channel SingleA1.

INFO  Reading pot_0 ADC values
INFO  0: 32767
INFO  Reading pot_1 ADC values
INFO  1: 1
INFO  ====================loop====================
INFO  Reading pot_0 ADC values
INFO  0: 1
INFO  Reading pot_1 ADC values
INFO  1: 1

If the loop is allowed to run continuously, changing the voltage of the channel SingleA1 has no effect on the output. The first value that was read get's repeated.

Additionally, it seems to only happen when reading the channels in a loop, reading the same channels twice in a row is fine, and only breaks on the second time around the loop.

let mut count = 0;
let mut adc = ads1x1x::Ads1x1x::new_ads1115(i2c, ads1x1x::SlaveAddr::default());
loop {

    info!("Reading pot_0 ADC values");
    let pot_0 = nb::block!(adc.read(ads1x1x::channel::SingleA0)).unwrap();
    info!("0: {}", pot_0);
    info!("Reading pot_1 ADC values");
    let pot_1 = nb::block!(adc.read(ads1x1x::channel::SingleA1)).unwrap();
    info!("1: {}", pot_1);

    info!("Reading pot_0 ADC values");
    let pot_0 = nb::block!(adc.read(ads1x1x::channel::SingleA0)).unwrap();
    info!("0: {}", pot_0);
    info!("Reading pot_1 ADC values");
    let pot_1 = nb::block!(adc.read(ads1x1x::channel::SingleA1)).unwrap();
    info!("1: {}", pot_1);

    // Loop twice then stop
    if count == 1 {
        loop {}
    }
    count += 1;
    info!("====================loop====================");
}
INFO  Program start
INFO  Reading pot_0 ADC values
INFO  0: 32767
INFO  Reading pot_1 ADC values
INFO  1: 2
INFO  Reading pot_0 ADC values
INFO  0: 32767
INFO  Reading pot_1 ADC values
INFO  1: 1
INFO  ====================loop====================
INFO  Reading pot_0 ADC values
INFO  0: 1
INFO  Reading pot_1 ADC values
INFO  1: 1
INFO  Reading pot_0 ADC values
INFO  0: 1
INFO  Reading pot_1 ADC values
INFO  1: 1

I'll try and reproduce this on another platform to rule out hardware issues when I get some time.

emshotton commented 1 month ago

Using the exact same ADC board, but a raspberry pi and the linux_embedded_hal I get the expected behavior for the 2nd example (two changes to the code, the i2c bus initialization and switching from defmt for printing to println!)

Reading pot_0 ADC values
0: 32767
Reading pot_1 ADC values
1: 527
Reading pot_0 ADC values
0: 32767
Reading pot_1 ADC values
1: 527
====================loop====================
Reading pot_0 ADC values
0: 32767
Reading pot_1 ADC values
1: 527
Reading pot_0 ADC values
0: 32767
Reading pot_1 ADC values
1: 527
emshotton commented 1 month ago

Closing the issue because I think this is more likely related to the rp2040_hal or something about the hardware of my I2C bus.

The bug seems to be correlated with reading from the I2C bus too quickly in the loop or via nb::block!. The following worked as a workaround by adding a 100us delay to each iteration of the loop.

    let mut adc = ads1x1x::Ads1x1x::new_ads1115(i2c, ads1x1x::SlaveAddr::default());
    let mut channel_index = 0;
    loop {
        match channel_index {
            0 => match adc.read(ads1x1x::channel::SingleA0) {
                Ok(pot_0) => {
                    info!("0: {}", pot_0);
                    channel_index = 1;
                }
                Err(nb::Error::WouldBlock) => {}
                Err(_) => {
                    info!("Error");
                }
            },
            1 => match adc.read(ads1x1x::channel::SingleA1) {
                Ok(pot_1) => {
                    info!("1: {}", pot_1);
                    channel_index = 0;
                }
                Err(nb::Error::WouldBlock) => {}
                Err(_) => {
                    info!("Error");
                }
            },
            _ => {
                info!("Error");
            }
        }
        delay.delay_us(100u32);
    }