Skip to content

Instantly share code, notes, and snippets.

@Slabity

Slabity/adc.rs Secret

Created May 4, 2024 00:12
Show Gist options
  • Save Slabity/feba4721928b557d5b117beec684d284 to your computer and use it in GitHub Desktop.
Save Slabity/feba4721928b557d5b117beec684d284 to your computer and use it in GitHub Desktop.
use embassy_rp::peripherals;
use embassy_rp::i2c;
use embassy_rp::gpio;
use ads1x1x;
// These aliases make our tasks' function signatures simpler
// In the future this won't be necessary, as we won't need to pass the I2C0/I2C1
// generics to the I2c struct and can just use it directly.
// See https://github.com/embassy-rs/embassy/pull/980
#[allow(dead_code)]
pub type I2C0<'a, T> = i2c::I2c<'a, peripherals::I2C0, T>;
#[allow(dead_code)]
pub type I2C1<'a, T> = i2c::I2c<'a, peripherals::I2C1, T>;
pub struct AdcPeripherals {
pub i2c: I2C0<'static, i2c::Blocking>,
pub interrupt: gpio::Input<'static>,
}
// Number of values we want to read on a channel before switching.
const AVG_WINDOW: usize = 8;
// Number of extra values to read that will be cutoff.
const AVG_CUTOFF: usize = 2;
// Full size of the array to store readings in.
const AVG_LENGTH: usize = AVG_WINDOW + (AVG_CUTOFF * 2);
#[embassy_executor::task]
pub async fn adc_task(mut adc_p: AdcPeripherals) {
use ads1x1x;
// Initialize the ADS1115 driver
let mut adc = ads1x1x::Ads1x1x::new_ads1115(adc_p.i2c, ads1x1x::SlaveAddr::Gnd);
adc.set_full_scale_range(ads1x1x::FullScaleRange::Within6_144V).unwrap();
adc.set_data_rate(ads1x1x::DataRate16Bit::Sps860).unwrap();
let mut adc = match adc.into_continuous() {
Err(ads1x1x::ModeChangeError::I2C(e, _)) => {
panic!("{:?}", e);
},
Ok(adc) => adc
};
adc.use_alert_rdy_pin_as_ready().unwrap();
adc.set_comparator_queue(ads1x1x::ComparatorQueue::One).unwrap();
// Store the ADC readings into arrays
let mut readings_0 = [0i16; AVG_LENGTH];
let mut readings_1 = [0i16; AVG_LENGTH];
loop {
adc.select_channel(ads1x1x::channel::DifferentialA0A1).unwrap();
adc_p.interrupt.wait_for_falling_edge().await;
adc.read().unwrap();
for value in readings_0.iter_mut() {
*value = -adc.read().unwrap();
}
adc.select_channel(ads1x1x::channel::DifferentialA2A3).unwrap();
adc_p.interrupt.wait_for_falling_edge().await;
adc.read().unwrap();
for value in readings_1.iter_mut() {
*value = -adc.read().unwrap();
}
let avg_0 = average_readings(&mut readings_0);
let avg_1 = average_readings(&mut readings_1);
defmt::info!("A0A1: {}\tA0A3: {}", avg_0, avg_1);
}
}
fn average_readings(readings: &mut [i16]) -> i32 {
let mut avg = 0;
readings.sort_unstable();
let window = &readings[AVG_CUTOFF..(AVG_LENGTH-AVG_CUTOFF)];
for val in window {
avg += *val as i32;
}
avg /= window.len() as i32;
avg
}
#![feature(impl_trait_in_assoc_type)]
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor;
use embassy_futures;
use embassy_rp::bind_interrupts;
use embassy_rp::peripherals;
use embassy_rp::multicore;
use embassy_rp::usb;
use embassy_rp::i2c;
use embassy_rp::gpio;
use embassy_time::{Duration, Timer};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
mod adc;
static mut CORE1_STACK: multicore::Stack<4096> = multicore::Stack::new();
static mut CORE1_EXEC: StaticCell<embassy_executor::Executor> = StaticCell::new();
bind_interrupts!(struct Irqs {
USBCTRL_IRQ => usb::InterruptHandler<peripherals::USB>;
});
#[embassy_executor::main]
async fn main(_spawner: embassy_executor::Spawner) {
let p = embassy_rp::init(Default::default());
let mut led = gpio::Output::new(p.PIN_25, gpio::Level::Low);
Timer::after_millis(3000).await;
defmt::info!("Starting program");
// Set up i2c device
let sda = p.PIN_16;
let scl = p.PIN_17;
let i2c = i2c::I2c::new_blocking(p.I2C0, scl, sda, i2c::Config::default());
// Use alert pulse to determine when new ADC value is available
let interrupt = gpio::Input::new(p.PIN_18, gpio::Pull::None);
// Outputs that send signal through potentiometers
let output_0 = gpio::Output::new(p.PIN_0, gpio::Level::Low);
let output_1 = gpio::Output::new(p.PIN_3, gpio::Level::Low);
let adc_p = adc::AdcPeripherals {
i2c,
interrupt,
};
defmt::info!("Spawning ADC process");
multicore::spawn_core1(
p.CORE1,
unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) },
move || {
let executor = unsafe {
CORE1_EXEC.init(embassy_executor::Executor::new())
};
executor.run(|spawner| spawner.spawn(adc::adc_task(adc_p)).unwrap());
}
);
defmt::info!("Entering main loop");
loop {
led.set_high();
Timer::after(Duration::from_millis(250)).await;
led.set_low();
Timer::after(Duration::from_millis(750)).await;
embassy_futures::yield_now().await
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment