esp-rs / esp-idf-hal

embedded-hal implementation for Rust on ESP32 and ESP-IDF
https://docs.esp-rs.org/esp-idf-hal/
Apache License 2.0
417 stars 171 forks source link

Is there example for continuous ADC? #446

Open phuongtran7 opened 5 days ago

phuongtran7 commented 5 days ago

Hi,

I'm trying to piece together and example on how to continuously read ADC. But I'm struggling at what to create for channels. This is currently what I have.

According to the Config.toml generate by the template project. I'm using esp-idf-svc version 0.49 and esp-idf-hal version 0.44.

use esp_idf_svc::hal::adc::AdcContConfig;
use esp_idf_svc::hal::adc::AdcContDriver;
use esp_idf_svc::hal::peripherals::Peripherals;
use std::thread;
use std::time::Duration;

fn main() -> anyhow::Result<()> {
    // It is necessary to call this function once. Otherwise some patches to the runtime
    // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
    esp_idf_svc::sys::link_patches();

    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    let peripherals = Peripherals::take()?;

    let config = AdcContConfig::default();

    // How do I create channels here?
    let adc = AdcContDriver::new(peripherals.adc1, &config, &channels)?;

    let mut data: [u8; 1024];

    loop {
        thread::sleep(Duration::from_millis(100));
        println!("ADC value: {}", adc.read_bytes(&mut data, 10)?);
    }
}

Thank you so much for your time and help.

phuongtran7 commented 4 days ago

I finally got the program to compile and run on the ESP32-C3-DevKit-RUST-1. I don't know if this is correct as I don't have input yet unfortunately. But it seems to run just fine. I get 400 bytes every loop, consistent with the default config of 100 measurements.

use esp_idf_svc::hal::adc::{AdcContConfig, AdcContDriver};
use esp_idf_svc::hal::peripherals::Peripherals;
use esp_idf_svc::hal::units::Hertz;

fn main() -> anyhow::Result<()> {
    // It is necessary to call this function once. Otherwise some patches to the runtime
    // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
    esp_idf_svc::sys::link_patches();

    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    let peripherals = Peripherals::take()?;

    let config = AdcContConfig::default();

    let mut adc_1_channel_2 = peripherals.pins.gpio2;

    let mut adc = AdcContDriver::new(peripherals.adc1, &config, &mut adc_1_channel_2)?;

    adc.start()?;

    let mut data: [u8; 1024] = [0x0; 1024];

    loop {
        if let Ok(num_read) = adc.read_bytes(&mut data, 10) {
            println!("Read {} bytes.", num_read);
        }
    }
}
phuongtran7 commented 1 day ago

My ESP32-C3-Lyra finally arrived so I was able to test the code. Below is the working code that uses the onboard mic. I was able to get the ADC reading, send it over the network and playback the audio with Rodio on desktop. I don't know if there is an example somewhere, but if needed I can try and create a PR for this example too.

use esp_idf_svc::hal::adc::{AdcContConfig, AdcContDriver, AdcMeasurement, Attenuated};
use esp_idf_svc::hal::modem::Modem;
use esp_idf_svc::hal::peripherals::Peripherals;
use esp_idf_svc::sys::EspError;
use log::{info, debug};

fn main() -> anyhow::Result<()> {
    // It is necessary to call this function once. Otherwise some patches to the runtime
    // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
    esp_idf_svc::sys::link_patches();

    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    let peripherals = Peripherals::take()?;

    let config = AdcContConfig::default();

    let adc_1_channel_0 = Attenuated::db11(peripherals.pins.gpio0);

    let mut adc = AdcContDriver::new(peripherals.adc1, &config, adc_1_channel_0)?;

    adc.start()?;

    // Default to just read 100 measurements per each read
    let mut samples: [AdcMeasurement; 100] = [Default::default(); 100];

    loop {
        if let Ok(num_read) = adc.read(&mut samples, 10) {
            debug!("Read {} measurement.", num_read);
            for index in 0..num_read {
                debug!("{}", samples[index].data());
            }
        }
    }
}
Vollbrecht commented 1 day ago

If you feel like working on a PR, i might suggest instead of creating a separate example for the continues ADC, to add a bit of docstrings to the modules and public API, as we currently lag it for the adc drivers. Since otherwise the continues Driver is similar to the oneshot one.

phuongtran7 commented 1 day ago

Got it. I can definitely try and add some docstrings for the ADC module. I think that was problem when I first tried too.