Skip to content

Implement Observable POC #157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 8, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,11 @@ name = "cordic"
required-features = ["cordic"]

[[test]]
name = "tests"
name = "nucleo-g474"
harness = false

[[test]]
name = "nucleo-g474_w_jumpers"
harness = false

[lib]
Expand Down
8 changes: 4 additions & 4 deletions examples/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rt::entry;

#[entry]
fn main() -> ! {
use hal::comparator::{ComparatorExt, ComparatorSplit, Config, Hysteresis, RefintInput};
use hal::comparator::{refint_input, ComparatorExt, ComparatorSplit, Config, Hysteresis};
use hal::gpio::GpioExt;
use hal::prelude::OutputPin;
use hal::rcc::RccExt;
Expand All @@ -31,16 +31,16 @@ fn main() -> ! {

let pa1 = gpioa.pa1.into_analog();
let pa0 = gpioa.pa0.into_analog();
let comp1 = comp1.comparator(&pa1, pa0, Config::default(), &rcc.clocks);
let comp1 = comp1.comparator(pa1, pa0, Config::default(), &rcc.clocks);
let comp1 = comp1.enable();

// led1 pa1 will be updated manually when to match comp1 value
let mut led1 = gpioa.pa5.into_push_pull_output();

let pa7 = gpioa.pa7.into_analog();
let comp2 = comp2.comparator(
&pa7,
RefintInput::VRefintM12,
pa7,
refint_input::VRefintM12,
Config::default()
.hysteresis(Hysteresis::None)
.output_inverted(),
Expand Down
8 changes: 5 additions & 3 deletions examples/comp_w_dac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ fn main() -> ! {
use hal::delay::SYSTDelayExt;
use hal::gpio::GpioExt;
use hal::rcc::RccExt;
use hal::stasis::Freeze;
use hal::stm32;
use stm32g4xx_hal as hal;

Expand All @@ -29,15 +30,16 @@ fn main() -> ! {
// Set up DAC to output to pa4 and to internal signal Dac1IntSig1
// which just so happens is compatible with comp1
let dac1ch1 = dp.DAC1.constrain((gpioa.pa4, Dac1IntSig1), &mut rcc);
let mut dac = dac1ch1.calibrate_buffer(&mut delay).enable(&mut rcc);
let dac = dac1ch1.calibrate_buffer(&mut delay).enable(&mut rcc);
let (mut dac, [dac_token]) = dac.freeze();

let (comp1, _comp2, ..) = dp.COMP.split(&mut rcc);
let pa1 = gpioa.pa1.into_analog();

// Set up comparator with pa1 as positive, and the DAC as negative input
let comp = comp1.comparator(
&pa1,
&dac,
pa1,
dac_token,
comparator::Config::default().hysteresis(comparator::Hysteresis::None),
&rcc.clocks,
);
Expand Down
58 changes: 58 additions & 0 deletions examples/observe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//#![deny(warnings)]
#![deny(unsafe_code)]
#![no_main]
#![no_std]

mod utils;
use utils::logger::info;
extern crate cortex_m_rt as rt;

use fugit::ExtU32 as _;
use hal::{
adc::AdcClaim as _,
comparator::{ComparatorExt, ComparatorSplit, Config},
delay::SYSTDelayExt as _,
gpio::GpioExt,
rcc::RccExt,
stm32,
};
use rt::entry;
use stm32g4xx_hal::{self as hal, adc::config::SampleTime, delay::DelayExt as _, stasis::Freeze};

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

let gpioa = dp.GPIOA.split(&mut rcc);

let (comp1, ..) = dp.COMP.split(&mut rcc);

let (pa1, [pa1_token]) = gpioa // <- The pin to keep track of
.pa1
.into_analog()
.freeze();
let pa0 = gpioa.pa0.into_analog(); // <- Reference voltage

// Only pa1_token and pa0 consumed here
let comp1 = comp1.comparator(pa1_token, pa0, Config::default(), &rcc.clocks);
let _comp1 = comp1.enable(); // <-- TODO: Do things with comparator

let mut delay = cp.SYST.delay(&rcc.clocks);
let mut adc = dp.ADC1.claim_and_configure(
stm32g4xx_hal::adc::ClockSource::SystemClock,
&rcc,
stm32g4xx_hal::adc::config::AdcConfig::default(),
&mut delay,
false,
);

// Can not reconfigure pa1 here
loop {
// Can still use pa1 here
let sample = adc.convert(&pa1, SampleTime::Cycles_640_5);
info!("Reading: {}", sample);
delay.delay(1000.millis());
}
}
28 changes: 14 additions & 14 deletions examples/opamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use stm32g4xx_hal::adc::AdcClaim;
use stm32g4xx_hal::adc::ClockSource;
use stm32g4xx_hal::opamp::{Gain, InternalOutput};
use stm32g4xx_hal::opamp::Gain;
use stm32g4xx_hal::prelude::*;
use stm32g4xx_hal::pwr::PwrExt;

Expand Down Expand Up @@ -34,12 +34,20 @@ fn main() -> ! {
// setup opamps
let (opamp1, opamp2, opamp3, ..) = dp.OPAMP.split(&mut rcc);

let pa1 = gpioa.pa1.into_analog();
let pa2 = gpioa.pa2.into_analog();
let pa7 = gpioa.pa7.into_analog();

let pb0 = gpiob.pb0.into_analog();
let pb1 = gpiob.pb1.into_analog();
let pb2 = gpiob.pb2.into_analog();

// Set up opamp1 and opamp2 in follower mode
let opamp1 = opamp1.follower(gpioa.pa1, gpioa.pa2);
let opamp2 = opamp2.follower(gpioa.pa7, InternalOutput);
let opamp1 = opamp1.follower(pa1).enable_output(pa2);
let opamp2 = opamp2.follower(pa7);

// Set up opamp1 and opamp2 in open loop mode
let opamp3 = opamp3.open_loop(gpiob.pb0, gpiob.pb2, gpiob.pb1);
let opamp3 = opamp3.open_loop(pb0, pb2).enable_output(pb1);

// disable opamps
let (opamp1, pa1, pa2) = opamp1.disable();
Expand All @@ -48,18 +56,10 @@ fn main() -> ! {
let (_opamp3, _pb0, _pb2, _pb1) = opamp3.disable();

// Configure opamp1 with pa1 as non-inverting input and set gain to x2
let _opamp1 = opamp1.pga(
pa1,
pa2, // Route output to pin pa2
Gain::Gain2,
);
let _opamp1 = opamp1.pga(pa1, Gain::Gain2).enable_output(pa2); // Route output to pin pa2

// Configure op with pa7 as non-inverting input and set gain to x4
let opamp2 = opamp2.pga(
pa7,
InternalOutput, // Do not route output to any external pin, use internal AD instead
Gain::Gain4,
);
let opamp2 = opamp2.pga(pa7, Gain::Gain4); // Do not route output to any external pin, use internal AD instead

// Lock opamp2. After the opamp is locked its registers cannot be written
// until the device is reset (even if using unsafe register accesses).
Expand Down
75 changes: 45 additions & 30 deletions src/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

//use crate::dma::traits::PeriAddress;
use crate::stasis;
pub use crate::time::U32Ext as _;
use crate::{
dma::{mux::DmaMuxResources, traits::TargetAddress, PeripheralToMemory},
Expand Down Expand Up @@ -51,12 +52,16 @@ impl Vref {
Self::sample_to_millivolts_ext(sample, VDDA_CALIB, config::Resolution::Twelve)
}
}
impl stasis::Freeze for Vref {}

/// Vbat internal signal, used for monitoring the battery (if used)
pub struct Vbat;
impl stasis::Freeze for Vbat {}

/// Core temperature internal signal
pub struct Temperature;
impl stasis::Freeze for Temperature {}

impl Temperature {
/// Precompute the inverse of `VTEMP_CAL_VREFANALOG`, in volts,
/// for floating point calculations
Expand Down Expand Up @@ -131,39 +136,49 @@ impl Temperature {
}
}

// TODO: Is there any way to avoid this wrapper to overcome the orphan rule
/// Wrapper to side step orphan rule
pub struct Ad<T>(T);
macro_rules! adc_channel_helper {
($adc:ident, $chan:expr, $r:ty, $($a:ident),*) => {
impl<$($a,)*> Channel<Ad<stm32::$adc>> for stasis::Entitlement<$r> {
type ID = u8;
fn channel() -> u8 {
$chan
}
}

impl<const N: usize, $($a,)*> Channel<Ad<stm32::$adc>> for stasis::Frozen<$r, N> {
type ID = u8;
fn channel() -> u8 {
$chan
}
}

impl<$($a,)*> Channel<Ad<stm32::$adc>> for $r {
type ID = u8;
fn channel() -> u8 {
$chan
}
}
};
}

macro_rules! adc_pins {
($($pin:ty => ($adc:ident, $chan:expr)),+ $(,)*) => {
$(
impl Channel<stm32::$adc> for $pin {
type ID = u8;
fn channel() -> u8 { $chan }
}
adc_channel_helper!($adc, $chan, $pin,);
)+
};
}

macro_rules! adc_opamp {
($($opamp:ty => ($adc:ident, $chan:expr)),+ $(,)*) => {
$(
impl<A> Channel<stm32::$adc> for opamp::Follower<$opamp, A, InternalOutput> {
type ID = u8;
fn channel() -> u8 { $chan }
}

impl<A, B> Channel<stm32::$adc> for opamp::OpenLoop<$opamp, A, B, InternalOutput> {
type ID = u8;
fn channel() -> u8 { $chan }
}

impl<A> Channel<stm32::$adc> for opamp::Pga<$opamp, A, InternalOutput> {
type ID = u8;
fn channel() -> u8 { $chan }
}

impl Channel<stm32::$adc> for opamp::Locked<$opamp, InternalOutput> {
type ID = u8;
fn channel() -> u8 { $chan }
}
adc_channel_helper!($adc, $chan, opamp::Follower<$opamp, A, InternalOutput>, A);
adc_channel_helper!($adc, $chan, opamp::OpenLoop<$opamp, A, B, InternalOutput>, A, B);
adc_channel_helper!($adc, $chan, opamp::Pga<$opamp, A, InternalOutput>, A);
adc_channel_helper!($adc, $chan, opamp::Locked<$opamp, InternalOutput>,);
)+
};
}
Expand Down Expand Up @@ -1898,7 +1913,7 @@ macro_rules! adc {
/// to sample for at a given ADC clock frequency
pub fn configure_channel<CHANNEL>(&mut self, _channel: &CHANNEL, sequence: config::Sequence, sample_time: config::SampleTime)
where
CHANNEL: Channel<stm32::$adc_type, ID=u8>
CHANNEL: Channel<Ad<stm32::$adc_type>, ID=u8>
{

//Check the sequence is long enough
Expand Down Expand Up @@ -1964,7 +1979,7 @@ macro_rules! adc {
/// Note that it reconfigures the adc sequence and doesn't restore it
pub fn convert<PIN>(&mut self, pin: &PIN, sample_time: config::SampleTime) -> u16
where
PIN: Channel<stm32::$adc_type, ID=u8>
PIN: Channel<Ad<stm32::$adc_type>, ID=u8>
{
let saved_config = self.config;
unsafe {
Expand Down Expand Up @@ -2410,7 +2425,7 @@ macro_rules! adc {
#[inline(always)]
pub fn configure_channel<CHANNEL>(&mut self, channel: &CHANNEL, sequence: config::Sequence, sample_time: config::SampleTime)
where
CHANNEL: Channel<stm32::$adc_type, ID=u8>
CHANNEL: Channel<Ad<stm32::$adc_type>, ID=u8>
{
self.adc.configure_channel(channel, sequence, sample_time)
}
Expand All @@ -2420,7 +2435,7 @@ macro_rules! adc {
#[inline(always)]
pub fn convert<PIN>(&mut self, pin: &PIN, sample_time: config::SampleTime) -> u16
where
PIN: Channel<stm32::$adc_type, ID=u8>
PIN: Channel<Ad<stm32::$adc_type>, ID=u8>
{
self.adc.convert(pin, sample_time)
}
Expand Down Expand Up @@ -2463,7 +2478,7 @@ macro_rules! adc {
#[inline(always)]
pub fn convert<PIN>(&mut self, pin: &PIN, sample_time: config::SampleTime) -> u16
where
PIN: Channel<stm32::$adc_type, ID=u8>
PIN: Channel<Ad<stm32::$adc_type>, ID=u8>
{
self.adc.reset_sequence();
self.adc.configure_channel(pin, config::Sequence::One, sample_time);
Expand Down Expand Up @@ -2604,9 +2619,9 @@ macro_rules! adc {
const REQUEST_LINE: Option<u8> = Some($mux as u8);
}

impl<PIN> OneShot<stm32::$adc_type, u16, PIN> for Adc<stm32::$adc_type, Disabled>
impl<PIN> OneShot<Ad<stm32::$adc_type>, u16, PIN> for Adc<stm32::$adc_type, Disabled>
where
PIN: Channel<stm32::$adc_type, ID=u8>,
PIN: Channel<Ad<stm32::$adc_type>, ID=u8>,
{
type Error = ();

Expand Down
Loading
Loading