kellerkindt / onewire

OneWire bus implementation in Rust using embedded-hal
Apache License 2.0
35 stars 14 forks source link

Can't find devices #3

Closed riaqn closed 5 years ago

riaqn commented 5 years ago

I'm trying to run a ds18b20 on my stm32f103. The code is as follows ( pretty much copied from README). the program gives me

search for devices
search finished

which means no device is found. But if I remove the 4.7k resistor from the circuit, it will actually complain missing pullups, so I assume my circuit connection is correct.

#![no_std]
#![no_main]

extern crate panic_halt;

use onewire::{
    OneWire,
    DeviceSearch,
    ds18b20,
};

use stm32f1xx_hal::{
    prelude::*,
    pac,
    delay,
};
use cortex_m_rt::entry;

use cortex_m_semihosting::{hprintln};

#[entry]
fn main() -> ! {
   let mut cp: cortex_m::Peripherals = cortex_m::Peripherals::take().unwrap();
    let mut dp = pac::Peripherals::take().unwrap();
    let mut flash = dp.FLASH.constrain();

    let mut rcc = dp.RCC.constrain();

    let clocks = rcc.cfgr.freeze(&mut flash.acr);

    let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);

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

    let mut one = gpiob
        .pb11
        .into_open_drain_output(&mut gpiob.crh)
        .downgrade();

    let mut wire = OneWire::new(&mut one, false);

    if wire.reset(&mut delay).is_err() {
        hprintln!("missing pullup, or error on-line");
        loop {}
    }

    hprintln!("search for devices");

    // search for devices
    let mut search = DeviceSearch::new();
    while let Some(device) = wire.search_next(&mut search, &mut delay).unwrap() {
        match device.address[0] {
            ds18b20::FAMILY_CODE => {
                let mut ds18b20 = ds18b20::DS18B20::new(device).unwrap();

                // request sensor to measure temperature
                let resolution = ds18b20.measure_temperature(&mut wire, &mut delay).unwrap();

                // wait for compeltion, depends on resolution 
                delay.delay_ms(resolution.time_ms());

                // read temperature
                let temperature = ds18b20.read_temperature(&mut wire, &mut delay).unwrap();
                hprintln!("{0}", temperature);
            },
            _ => {
                hprintln!("unknown device type");
            }
        }
    }
    hprintln!("search finished");
    loop {}
}
riaqn commented 5 years ago

Another finding: If I don't connect the data pin at all, I actually get devices but unrecognized:

00:00:00:00:00:00:00:00
unknown device type
00:00:00:00:00:00:00:80
unknown device type
00:00:00:00:00:00:00:40
unknown device type
00:00:00:00:00:00:00:c0
unknown device type
00:00:00:00:00:00:00:20
unknown device type
00:00:00:00:00:00:00:a0
unknown device type
00:00:00:00:00:00:00:60
unknown device type
00:00:00:00:00:00:00:e0
unknown device type
00:00:00:00:00:00:00:10
unknown device type
00:00:00:00:00:00:00:90
unknown device type
00:00:00:00:00:00:00:50
unknown device type
00:00:00:00:00:00:00:d0
unknown device type
00:00:00:00:00:00:00:30
unknown device type

and this go on and on ad infinitum.

chernomor commented 5 years ago

@riaqn try to set frequency of MCU, something like this:

rcc.cfgr
        .sysclk(64.mhz())
        .pclk1(32.mhz());

after this line: let mut rcc = dp.RCC.constrain();

riaqn commented 5 years ago

@chernomor Thanks for the reply. I did this change; now it's

    let mut rcc = dp.RCC.constrain();

        let clocks = rcc.cfgr.sysclk(64.mhz())
        .pclk1(32.mhz()).freeze(&mut flash.acr);

which is not exactly what you said but I need to convince the borrow checker. However the error persist.

kellerkindt commented 5 years ago

Hmm, I had similar issues, when I had it run the debug artifact and when I had semihosting in use. Could you try it without that and in release mode? Maybe blink an LED depending on the result...

riaqn commented 5 years ago

@kellerkindt Well. the problem is that I kind of need semihosting to print something to see if it's working. but I guess I can use the serial instead. I will try this out later.

EDIT: Ahh, I just realized what you mean ( blinking an LED depending on the result). I will try that.

riaqn commented 5 years ago

@kellerkindt OK so I tried it with semihosting off (out of Cargo.toml) and debug off (under profile.release) But it's still not working.

EDIT: ok obviously I need to run cargo run --release. The --release is what got me.

I will try this with semihosting on.

EDIT: so even with semihosting on it still works. So the problem seem to be just release mode vs debug mode. I don't know why. Maybe someone could explain to me.

tim-seoss commented 5 years ago

FWIW, I stuck a logic analyser on the example code (and also added some debugging with itm) I got:

rustc 1.36.0-nightly (5d20ff4d2 2019-04-18) development build shows a brief 32µs pull down, followed 140µs later by a 604µs reset pulse (with the correct presence response), followed 8.97ms later by another 604µs reset pulse (and correct presense response). There's then nothing else (debug output shows the search complete, but the bus never went low again.

rustc 1.36.0-nightly (5d20ff4d2 2019-04-18) release build shows a 6µs initial pulldown, followed 6µs later by a 484µs reset pulse (with 104µs presence response), followed 486µs later (much quicker) by another 484µs reset pulse and response. The search sequence starts 416µs later.

riaqn commented 5 years ago

@tim-seoss Thanks for the investigation. Let's wait someone familir with Cargo to explain.

chernomor commented 5 years ago

It seems rust version is important, I build my project with nightly-2018-11-01. Next builds (december or january) don't works, so I return to nightly-2018-11-01.

riaqn commented 5 years ago

Yeah, I used release version of rust, 1.31 I believe.

On Fri, Apr 19, 2019 at 10:32 AM Sergey Chernomorets < notifications@github.com> wrote:

It seems rust version is important, I build my project with nightly-2018-11-01. Next builds (december or january) don't works, so I return to nightly-2018-11-01.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/kellerkindt/onewire/issues/3#issuecomment-484913969, or mute the thread https://github.com/notifications/unsubscribe-auth/AASZEVUC5MJINRC7AA7YWQLPRHJXVANCNFSM4HENO7ZQ .

tim-seoss commented 5 years ago

FWIW, it looks like opt-level impacts whether it works. Putting:

[profile.release]
opt-level = 2

in Cargo.toml gets it working, but the other options like 0 or 'z' don't work. You may need to run cargo clean to ensure everything is rebuilt with the correct optimisation level.

riaqn commented 5 years ago

OK so my guess is that un-optimized code is too slow and screwed up some time-sensitive initialization?

tim-seoss commented 5 years ago

OK so my guess is that un-optimized code is too slow and screwed up some time-sensitive initialization?

I don't think that explains the behaviour that I was seeing with the signal analyser (edit: actually perhaps it's missing the presence pulse because it's not sampling it soon enough? I'll check.)

kellerkindt commented 5 years ago

Hmm. Because of similar issues I once had (as mentioned above) similar timing issues. I would like to refactor the sleeping/timing part, using the CountDown timer from embedded_hal. But it seems that the time unit (CountDown::Time) would make it platform/chip-hal dependent? For example, in stm32f1xx-hal CountDown is implemented using Hertz which is located in stm32f1xx-hal.

Am I missing something?

tim-seoss commented 5 years ago

I'm not at all sure, but depending on what you have in mind, I suppose it might be possible to have the user supply an optional closure to be used for higher resolution sleeping/timing?

riaqn commented 5 years ago

Hey guys, I'm again having this issue (no device found), here is my Cargo.toml:

[profile.release]
debug = false
opt-level = 2

rustc version is 1.35.0 (this is what I get with rustc -V. Does that reflect the arm toolchain?)

riaqn commented 5 years ago

I tried nightly (1.37.0 20180605) and got the same result.

riaqn commented 5 years ago

@chernomor Could you please post the working Cargo.toml you were using with nightly-2018-11-01? I tried with this nightly as well and doesn't work.

chernomor commented 5 years ago

@riaqn

` [package] name = "heat-control-f103" version = "0.1.2" edition = "2018"

[dependencies] stm32f103xx-hal = { git="https://github.com/japaric/stm32f103xx-hal.git", rev="45ff8686f16ed0d9d97adfbafb73c21e9e9ee7e8" } cortex-m-rt = "0.6.3" panic-halt = "0.2.0" heapless = "0.3.7" onewire = "0.3.10"

[dependencies.stm32f103xx] features = ["rt"] version = "*"

[dev-dependencies] cortex-m-rt = "0.6.3"

[build-dependencies] chrono = "*"

[dependencies.cortex-m] version-m = "0.5.6" features = ["inline-asm"]

[dependencies.embedded-hal] features = ["unproven"] version = "0.2.1"

[profile.release] codegen-units = 1 debug = true lto = true panic = 'abort'

[features] doc = [] rt = ["stm32f103xx/rt"] `

riaqn commented 5 years ago

@chernomor Thank you very much. There is lots of things in your file I don't understand.

  1. what is version-m?
  2. I think stm32f103xx is deprecated and we should use stm32f1xx-hal

Also, actually do you mind sharing the whole codebase? I just want to want to make sure my rustc version is ok and my wiring is working.

chernomor commented 5 years ago

@riaqn

  1. version-m - it's bug, it should be version (in fact in lock-file cortex-m has version 0.5.8)
  2. i try to migrate to stm32f1xx-hal, but not successful. So i still use old version.

I will try to make an example and check it in some days.

riaqn commented 5 years ago

OK I got it working. Obviously I still need the clock trick, as @chernomor mentioned.

   let clocks = rcc.cfgr.sysclk(64.mhz()).pclk1(32.mhz()).freeze(&mut flash.acr);

Curiously enough, I was able to get away without this in the past.

For future record, this is my Cargo.toml.

[package]
authors = ["Zesen Qian <github@riaqn.org>"]
edition = "2018"
readme = "README.md"
name = "dollhouse"
version = "0.1.0"

[dependencies]
cortex-m = "0.6.0"
cortex-m-rt = "0.6.8"
panic-semihosting = "0.5.2"
onewire = "0.3.10"

[dependencies.stm32f1xx-hal]
version = "0.3.0"
features = ["stm32f103", "rt"]

[dependencies.arrayvec]
version = "0.4.10"
default-features = false
features = []

[profile.release]
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash
opt-level = 2
lto = true # better optimizations

this is the main.rs

#![no_std]
#![no_main]

extern crate panic_semihosting;

use arrayvec::ArrayVec;

use onewire::{
    OneWire,
    DeviceSearch,
    ds18b20,
};

use self::ds18b20::{DS18B20, split_temp};

use stm32f1xx_hal::{
    prelude::*,
    pac,
    delay,
};
use cortex_m_rt::entry;

#[entry]
fn main() -> ! {
    let cp = cortex_m::Peripherals::take().unwrap();
    let dp = pac::Peripherals::take().unwrap();
    let mut flash = dp.FLASH.constrain();
    let mut rcc = dp.RCC.constrain();

    let clocks = rcc.cfgr.sysclk(64.mhz()).pclk1(32.mhz()).freeze(&mut flash.acr);
    let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);
    let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);

    let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);

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

    let mut one = gpiob
        .pb9
        .into_open_drain_output(&mut gpiob.crh)
        .downgrade();

    let mut wire = OneWire::new(&mut one, false);

    if wire.reset(&mut delay).is_err() {
        panic!("missing pullup or error on line");
    }

    const N_SENS : usize = 2;
    const TARGET : f32 = 30.0;
    let mut vec = ArrayVec::<[_; N_SENS]>::new();

    // search for devices
    let mut search = DeviceSearch::new();
    while let Some(device) = wire.search_next(&mut search, &mut delay).unwrap() {
        match device.address[0] {
            ds18b20::FAMILY_CODE => {
                vec.push(DS18B20::new(device).unwrap());
            },
            _ => {
                panic!("unrecognized device {}", device);
            }
        }
    }

    assert_eq!(vec.len(), N_SENS);

    loop {
        let mut switch = true;
        for i in 0..vec.len() {
                // request sensor to measure temperature
                let resolution = vec[i].measure_temperature(&mut wire, &mut delay).unwrap();

                // wait for compeltion, depends on resolution 
                delay.delay_ms(resolution.time_ms());

                // read temperature
                let temperature = vec[i].read_temperature(&mut wire, &mut delay).unwrap();

                let (d, f) = split_temp(temperature);
                let t : f32 = d as f32 + f as f32 / 10000 as f32;
                if t >= TARGET {
                    switch = false;
                }
        }
        if switch {
            led.set_high();
        } else {
            led.set_low();
        }
    }
}