Git Product home page Git Product logo

Comments (7)

pdgilbert avatar pdgilbert commented on May 26, 2024 1

I tried using the actual driver type, switching from linux to no std, etc. I have

type Adc = Ads1x1x<I2cInterface<BlockingI2c<I2C2, impl Pins<I2C2>>>, Ads1015, Resolution16Bit, ads1x1x::mode::OneShot>;

but then I get

`impl Trait` in type aliases is unstable

and it looks downhill from there. I guess I have to spell out the whole concrete type for every hal. I have a reasonable work around just leaving that one read in the main loop ( I just have to disambiguate), so I think I will leave it like that until there is an easy way to make it clean.

from ads1x1x-rs.

eldruin avatar eldruin commented on May 26, 2024

If you split read_adc() into two functions so that you can change the FSR outside of it, you could have two functions that simply take the ADC as an embedded_hal::adc::OneShot trait.
Would that be a solution for you?

from ads1x1x-rs.

pdgilbert avatar pdgilbert commented on May 26, 2024

Yes, this would work. But now I'm stuck trying to figure out the type arguments

error[E0107]: wrong number of type arguments: expected 3, found 0
  --> examples/zz.rs:64:27
   |
64 | fn read_adc_a(adc_a: impl embedded_hal::adc::OneShot) -> (i16, i16, i16) {
   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 3 type arguments

(I expect there should be an easy way to find type arguments in documentation or compiler error messages, but I have not figure it out.)

from ads1x1x-rs.

eldruin avatar eldruin commented on May 26, 2024

Ah, that solution I proposed cannot work because the OneShot trait is channel-specific and you want to pass the whole ADC and measure several channels inside the function.
You can use your function as initially proposed if you define the concrete types of the ADC.
An example of doing this is in this example.
You will only need to replace I2cdev with something like BlockingI2c<I2C2, ...> although putting the pin types there will bloat the type up a bit.
I have a look at adding a trait to simplify this.

from ads1x1x-rs.

eldruin avatar eldruin commented on May 26, 2024

I have added the DynamicOneShot trait to ease the usage in functions in release 0.2.2. See this example.
Closing.

from ads1x1x-rs.

pdgilbert avatar pdgilbert commented on May 26, 2024

Thanks for adding this trait. It works well except when I try to use the method .set_full_scale_range in the read function. (I do this because I am measuring a voltage across a shunt resistor and also to ground.) I'm not sure if I just don't have the proper syntax figured out, I am a newbie still, or if there is a problem de-referencing the method. I have tried various syntax without luck:

113 |     adc_a.set_full_scale_range(FullScaleRange::Within4_096V).unwrap();
    |           ^^^^^^^^^^^^^^^^^^^^ method not found in `&mut A`

113 |     *adc_a.set_full_scale_range(FullScaleRange::Within4_096V).unwrap();
    |            ^^^^^^^^^^^^^^^^^^^^ method not found in `&mut A`

113 |     (*adc_a).set_full_scale_range(FullScaleRange::Within4_096V).unwrap();
    |              ^^^^^^^^^^^^^^^^^^^^ method not found in `A`

A stripped down version of the code follows.

Click to expand
//  setup for bluepill   stm32f1xx_hal

#![deny(unsafe_code)]
#![no_std]
#![no_main]

#[cfg(debug_assertions)]
use panic_semihosting as _;

#[cfg(not(debug_assertions))]
use panic_halt as _;

use cortex_m_rt::entry;

use ads1x1x::{Ads1x1x, ChannelSelection, DynamicOneShot, FullScaleRange, SlaveAddr};

use core::fmt::Write;

use embedded_graphics::{
    mono_font::{ascii::FONT_8X13, MonoTextStyle, MonoTextStyleBuilder}, //FONT_6X10  FONT_8X13
    pixelcolor::BinaryColor,
    prelude::*,
    text::{Baseline, Text},
};

use ssd1306::{mode::BufferedGraphicsMode, prelude::*, I2CDisplayInterface, Ssd1306};

use nb::block;

pub trait LED {
    fn on(&mut self) -> ();
    fn off(&mut self) -> ();

    // default methods
    fn blink(&mut self, time: u16, delay: &mut Delay) -> () {
        self.on();
        delay.delay_ms(time);
        self.off()
    }
}

use stm32f1xx_hal::{
    delay::Delay,
    device::I2C2,
    gpio::{gpioc::PC13, Output, PushPull},
    i2c::{BlockingI2c, DutyCycle, Mode, Pins},
    pac::{CorePeripherals, Peripherals},
    prelude::*,
};

fn setup() -> (BlockingI2c<I2C2, impl Pins<I2C2>>, impl LED, Delay) {
    let cp = CorePeripherals::take().unwrap();
    let p = Peripherals::take().unwrap();

    let rcc = p.RCC.constrain();
    let clocks = rcc.cfgr.freeze(&mut p.FLASH.constrain().acr);

    let mut gpiob = p.GPIOB.split(); // for i2c scl and sda

    let i2c = BlockingI2c::i2c2(
        p.I2C2,
        (
            gpiob.pb10.into_alternate_open_drain(&mut gpiob.crh), // scl on PB10
            gpiob.pb11.into_alternate_open_drain(&mut gpiob.crh), // sda on PB11
        ),
        Mode::Fast {
            frequency: 100_000.hz(),
            duty_cycle: DutyCycle::Ratio2to1,
        },
        clocks,
        1000,
        10,
        1000,
        1000,
    );

    let delay = Delay::new(cp.SYST, clocks);

    // led
    let mut gpioc = p.GPIOC.split();
    let led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); // led on pc13

    impl LED for PC13<Output<PushPull>> {
        fn on(&mut self) -> () {
            self.set_low()
        }
        fn off(&mut self) -> () {
            self.set_high()
        }
    }

    (i2c, led, delay)
}

pub fn read_all<E, A: DynamicOneShot<Error = E>>(adc_a: &mut A, adc_b: &mut A
      ) -> (i16, i16, i16, i16, [i16; 3]) {
    let scale_cur = 10; // calibrated to get mA/mV depends on FullScaleRange above and values of shunt resistors
    let scale_a = 2; // calibrated to get mV    depends on FullScaleRange
    let scale_b = 2; // calibrated to get mV    depends on FullScaleRange

    let scale_temp = 5; //divides
    let offset_temp = 50;

    let bat_ma  = block!(adc_a.read(ChannelSelection::DifferentialA1A3)).unwrap_or(8091) / scale_cur;
    let load_ma = block!(adc_a.read(ChannelSelection::DifferentialA2A3)).unwrap_or(8091) / scale_cur;

    // toggle FullScaleRange to measure battery voltage, not just diff across shunt resistor
    // set FullScaleRange to measure expected max voltage.
    // This is very small for diff across low value shunt resistors
    //   but up to 5v for single pin with usb power.
    // +- 6.144v , 4.096v, 2.048v, 1.024v, 0.512v, 0.256v

    adc_a.set_full_scale_range(FullScaleRange::Within4_096V).unwrap();
    let bat_mv = block!(adc_a.read(ChannelSelection::SingleA0)).unwrap_or(8091) * scale_a;
    adc_a.set_full_scale_range(FullScaleRange::Within0_256V).unwrap();

    // second adc
    let values_b = [
        block!(adc_b.read(ChannelSelection::SingleA0)).unwrap_or(8091) * scale_b,
        block!(adc_b.read(ChannelSelection::SingleA1)).unwrap_or(8091) * scale_b,
        block!(adc_b.read(ChannelSelection::SingleA2)).unwrap_or(8091) * scale_b,
    ];

    let temp_c = block!(adc_b.read(ChannelSelection::SingleA3)).unwrap_or(8091) / scale_temp
        - offset_temp;

    (bat_mv, bat_ma, load_ma, temp_c, values_b )
}

fn display<S>(
    bat_mv: i16,
    bat_ma: i16,
    load_ma: i16,
    temp_c: i16,
    values_b: [i16; 3],
    text_style: MonoTextStyle<BinaryColor>,
    disp: &mut Ssd1306<impl WriteOnlyDataCommand, S, BufferedGraphicsMode<S>>,
) -> ()
where
    S: DisplaySize,
{
    let mut lines: [heapless::String<32>; 4] = [
        heapless::String::new(),
        heapless::String::new(),
        heapless::String::new(),
        heapless::String::new(),
    ];

    // Many SSD1306 modules have a yellow strip at the top of the display, so first line may be yellow.
    // it is now possible to use \n in place of separate writes, with one line rather than vector.
    write!(lines[0], "bat:{:4}mV{:4}mA", bat_mv, bat_ma).unwrap();
    write!(lines[1], "load:    {:5}mA", load_ma).unwrap();
    write!(
        lines[2],
        "B:{:4} {:4} {:4}",
        values_b[0], values_b[1], values_b[2]
    )
    .unwrap();
    write!(lines[3], "temperature{:3} C", temp_c).unwrap();

    disp.clear();
    for i in 0..lines.len() {
        // start from 0 requires that the top is used for font baseline
        Text::with_baseline(
            &lines[i],
            Point::new(0, i as i32 * 16),
            text_style,
            Baseline::Top,
        )
        .draw(&mut *disp)
        .unwrap();
    }
    disp.flush().unwrap();
    ()
}

#[entry]
fn main() -> ! {
    let (i2c, mut led, mut delay) = setup();

    let manager = shared_bus::BusManager::<cortex_m::interrupt::Mutex<_>, _>::new(i2c);
    let interface = I2CDisplayInterface::new(manager.acquire());

    let mut disp = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
        .into_buffered_graphics_mode();
    disp.init().unwrap();

    let text_style = MonoTextStyleBuilder::new()
        .font(&FONT_8X13) //.&FONT_6X10  &FONT_8X13
        .text_color(BinaryColor::On)
        .build();

    Text::with_baseline("Display initialized ...", Point::zero(), text_style, Baseline::Top)
        .draw(&mut disp)
        .unwrap();

    let mut adc_a = Ads1x1x::new_ads1015(manager.acquire(), SlaveAddr::Alternative(false, false)); //addr = GND
    let mut adc_b = Ads1x1x::new_ads1015(manager.acquire(), SlaveAddr::Alternative(false, true)); //addr =  V

    adc_a.set_full_scale_range(FullScaleRange::Within4_096V).unwrap();
    adc_b.set_full_scale_range(FullScaleRange::Within4_096V).unwrap();

    loop {
        // Blink LED to check that everything is actually running.
        led.blink(10_u16, &mut delay);

        let (bat_mv, bat_ma, load_ma, temp_c, values_b ) = read_all(&mut adc_a, &mut adc_b);

        display(bat_mv, bat_ma, load_ma, temp_c, values_b, text_style, &mut disp);

        delay.delay_ms(2000_u16); // sleep for 2s
    }
}

from ads1x1x-rs.

eldruin avatar eldruin commented on May 26, 2024

Ah, I forgot about that. Could you just use the actual driver type then, instead of this trait?
You just need to use the concrete type (Depending on your IDE, it might help you there) like here
Then you can use it easily in a function like here
I would start with adc_a only.

from ads1x1x-rs.

Related Issues (13)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.