commit
8ac5c1a963
3
ci.sh
3
ci.sh
@ -201,6 +201,9 @@ cargo batch \
|
|||||||
$BUILD_EXTRA
|
$BUILD_EXTRA
|
||||||
|
|
||||||
|
|
||||||
|
rm out/tests/stm32wb55rg/wpan_mac
|
||||||
|
rm out/tests/stm32wb55rg/wpan_ble
|
||||||
|
|
||||||
|
|
||||||
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
|
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
|
||||||
echo No teleprobe token found, skipping running HIL tests
|
echo No teleprobe token found, skipping running HIL tests
|
||||||
|
@ -59,7 +59,7 @@ sdio-host = "0.5.0"
|
|||||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
atomic-polyfill = "1.0.1"
|
atomic-polyfill = "1.0.1"
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ee2862086886cd8ebaf5fd5e3bd6cfbe5baa840" }
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-06d13dfd245cc9bf86fd88c35b401bdb84c079c4" }
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
bxcan = "0.7.0"
|
bxcan = "0.7.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
proc-macro2 = "1.0.36"
|
proc-macro2 = "1.0.36"
|
||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ee2862086886cd8ebaf5fd5e3bd6cfbe5baa840", default-features = false, features = ["metadata"]}
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-06d13dfd245cc9bf86fd88c35b401bdb84c079c4", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -810,6 +810,20 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if regs.kind == "opamp" {
|
||||||
|
if !pin.signal.starts_with("VP") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let peri = format_ident!("{}", p.name);
|
||||||
|
let pin_name = format_ident!("{}", pin.pin);
|
||||||
|
let ch: u8 = pin.signal.strip_prefix("VP").unwrap().parse().unwrap();
|
||||||
|
|
||||||
|
g.extend(quote! {
|
||||||
|
impl_opamp_pin!( #peri, #pin_name, #ch);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// DAC is special
|
// DAC is special
|
||||||
if regs.kind == "dac" {
|
if regs.kind == "dac" {
|
||||||
let peri = format_ident!("{}", p.name);
|
let peri = format_ident!("{}", p.name);
|
||||||
|
@ -49,6 +49,8 @@ pub mod i2s;
|
|||||||
pub mod ipcc;
|
pub mod ipcc;
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
pub mod low_power;
|
pub mod low_power;
|
||||||
|
#[cfg(opamp)]
|
||||||
|
pub mod opamp;
|
||||||
#[cfg(quadspi)]
|
#[cfg(quadspi)]
|
||||||
pub mod qspi;
|
pub mod qspi;
|
||||||
#[cfg(rng)]
|
#[cfg(rng)]
|
||||||
|
133
embassy-stm32/src/opamp.rs
Normal file
133
embassy-stm32/src/opamp.rs
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#![macro_use]
|
||||||
|
|
||||||
|
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||||
|
|
||||||
|
use crate::Peripheral;
|
||||||
|
|
||||||
|
#[cfg(opamp_f3)]
|
||||||
|
pub struct OpAmpOutput<'d, 'p, T: Instance, P: NonInvertingPin<T>> {
|
||||||
|
_inner: &'d OpAmp<'d, T>,
|
||||||
|
_input: &'p mut P,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OpAmp<'d, T: Instance> {
|
||||||
|
_inner: PeripheralRef<'d, T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> OpAmp<'d, T> {
|
||||||
|
pub fn new(opamp: impl Peripheral<P = T> + 'd) -> Self {
|
||||||
|
Self::new_inner(opamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_inner(opamp: impl Peripheral<P = T> + 'd) -> Self {
|
||||||
|
into_ref!(opamp);
|
||||||
|
|
||||||
|
#[cfg(opamp_f3)]
|
||||||
|
T::regs().opampcsr().modify(|w| {
|
||||||
|
w.set_opampen(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(opamp_g4)]
|
||||||
|
T::regs().opamp_csr().modify(|w| {
|
||||||
|
w.set_opaen(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
Self { _inner: opamp }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(opamp_f3)]
|
||||||
|
pub fn buffer_for<'a, 'b, P>(&'a mut self, pin: &'b mut P) -> OpAmpOutput<'a, 'b, T, P>
|
||||||
|
where
|
||||||
|
P: NonInvertingPin<T>,
|
||||||
|
{
|
||||||
|
#[cfg(opamp_f3)]
|
||||||
|
T::regs().opampcsr().modify(|w| {
|
||||||
|
w.set_vp_sel(pin.channel());
|
||||||
|
});
|
||||||
|
|
||||||
|
OpAmpOutput {
|
||||||
|
_inner: self,
|
||||||
|
_input: pin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Instance: sealed::Instance + 'static {}
|
||||||
|
|
||||||
|
pub(crate) mod sealed {
|
||||||
|
pub trait Instance {
|
||||||
|
fn regs() -> crate::pac::opamp::Opamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NonInvertingPin<T: Instance> {
|
||||||
|
fn channel(&self) -> u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait InvertingPin<T: Instance> {
|
||||||
|
fn channel(&self) -> u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {}
|
||||||
|
|
||||||
|
pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {}
|
||||||
|
|
||||||
|
#[cfg(opamp_f3)]
|
||||||
|
macro_rules! impl_opamp_output {
|
||||||
|
($inst:ident, $adc:ident, $ch:expr) => {
|
||||||
|
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::sealed::AdcPin<crate::peripherals::$adc>
|
||||||
|
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
|
||||||
|
{
|
||||||
|
fn channel(&self) -> u8 {
|
||||||
|
$ch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::AdcPin<crate::peripherals::$adc>
|
||||||
|
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(opamp_f3)]
|
||||||
|
foreach_peripheral!(
|
||||||
|
(opamp, OPAMP1) => {
|
||||||
|
impl_opamp_output!(OPAMP1, ADC1, 3);
|
||||||
|
};
|
||||||
|
(opamp, OPAMP2) => {
|
||||||
|
impl_opamp_output!(OPAMP2, ADC2, 3);
|
||||||
|
};
|
||||||
|
(opamp, OPAMP3) => {
|
||||||
|
impl_opamp_output!(OPAMP3, ADC3, 1);
|
||||||
|
};
|
||||||
|
(opamp, OPAMP4) => {
|
||||||
|
impl_opamp_output!(OPAMP4, ADC4, 3);
|
||||||
|
};
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach_peripheral! {
|
||||||
|
(opamp, $inst:ident) => {
|
||||||
|
impl sealed::Instance for crate::peripherals::$inst {
|
||||||
|
fn regs() -> crate::pac::opamp::Opamp {
|
||||||
|
crate::pac::$inst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for crate::peripherals::$inst {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
macro_rules! impl_opamp_pin {
|
||||||
|
($inst:ident, $pin:ident, $ch:expr) => {
|
||||||
|
impl crate::opamp::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {}
|
||||||
|
impl crate::opamp::sealed::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {
|
||||||
|
fn channel(&self) -> u8 {
|
||||||
|
$ch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
59
examples/stm32f334/src/bin/opamp.rs
Normal file
59
examples/stm32f334/src/bin/opamp.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use defmt::info;
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_stm32::adc::{Adc, SampleTime};
|
||||||
|
use embassy_stm32::opamp::OpAmp;
|
||||||
|
use embassy_stm32::peripherals::ADC2;
|
||||||
|
use embassy_stm32::rcc::AdcClockSource;
|
||||||
|
use embassy_stm32::time::mhz;
|
||||||
|
use embassy_stm32::{adc, bind_interrupts, Config};
|
||||||
|
use embassy_time::{Delay, Duration, Timer};
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
ADC1_2 => adc::InterruptHandler<ADC2>;
|
||||||
|
});
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) -> ! {
|
||||||
|
let mut config = Config::default();
|
||||||
|
config.rcc.sysclk = Some(mhz(64));
|
||||||
|
config.rcc.hclk = Some(mhz(64));
|
||||||
|
config.rcc.pclk1 = Some(mhz(32));
|
||||||
|
config.rcc.pclk2 = Some(mhz(64));
|
||||||
|
config.rcc.adc = Some(AdcClockSource::PllDiv1);
|
||||||
|
|
||||||
|
let mut p = embassy_stm32::init(config);
|
||||||
|
|
||||||
|
info!("create adc...");
|
||||||
|
|
||||||
|
let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay);
|
||||||
|
let mut opamp = OpAmp::new(p.OPAMP2);
|
||||||
|
|
||||||
|
adc.set_sample_time(SampleTime::Cycles601_5);
|
||||||
|
|
||||||
|
info!("enable vrefint...");
|
||||||
|
|
||||||
|
let mut vrefint = adc.enable_vref(&mut Delay);
|
||||||
|
let mut temperature = adc.enable_temperature();
|
||||||
|
let mut buffer = opamp.buffer_for(&mut p.PA7);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let vref = adc.read(&mut vrefint).await;
|
||||||
|
info!("read vref: {} (should be {})", vref, vrefint.value());
|
||||||
|
|
||||||
|
let temp = adc.read(&mut temperature).await;
|
||||||
|
info!("read temperature: {}", temp);
|
||||||
|
|
||||||
|
let buffer = adc.read(&mut buffer).await;
|
||||||
|
info!("read buffer: {}", buffer);
|
||||||
|
|
||||||
|
let pin_mv = (buffer as u32 * vrefint.value() as u32 / vref as u32) * 3300 / 4095;
|
||||||
|
info!("computed pin mv: {}", pin_mv);
|
||||||
|
|
||||||
|
Timer::after(Duration::from_millis(500)).await;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user