diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index 147349de6..c13264819 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -1,16 +1,37 @@
+use core::future::poll_fn;
+use core::marker::PhantomData;
+use core::task::Poll;
+
 use embassy_hal_internal::into_ref;
 use embedded_hal_02::blocking::delay::DelayUs;
 
 use crate::adc::{Adc, AdcPin, Instance, SampleTime};
 use crate::rcc::get_freqs;
 use crate::time::Hertz;
-use crate::Peripheral;
+use crate::{interrupt, Peripheral};
 
 pub const VDDA_CALIB_MV: u32 = 3300;
 pub const ADC_MAX: u32 = (1 << 12) - 1;
 // No calibration data for F103, voltage should be 1.2v
 pub const VREF_INT: u32 = 1200;
 
+/// Interrupt handler.
+pub struct InterruptHandler<T: Instance> {
+    _phantom: PhantomData<T>,
+}
+
+impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
+    unsafe fn on_interrupt() {
+        if T::regs().sr().read().eoc() {
+            T::regs().cr1().modify(|w| w.set_eocie(false));
+        } else {
+            return;
+        }
+
+        T::state().waker.wake();
+    }
+}
+
 pub struct Vref;
 impl<T: Instance> AdcPin<T> for Vref {}
 impl<T: Instance> super::sealed::AdcPin<T> for Vref {
@@ -95,18 +116,28 @@ impl<'d, T: Instance> Adc<'d, T> {
     }
 
     /// Perform a single conversion.
-    fn convert(&mut self) -> u16 {
+    async fn convert(&mut self) -> u16 {
         T::regs().cr2().modify(|reg| {
             reg.set_adon(true);
             reg.set_swstart(true);
         });
-        while T::regs().cr2().read().swstart() {}
-        while !T::regs().sr().read().eoc() {}
+        T::regs().cr1().modify(|w| w.set_eocie(true));
+
+        poll_fn(|cx| {
+            T::state().waker.register(cx.waker());
+
+            if !T::regs().cr2().read().swstart() && T::regs().sr().read().eoc() {
+                Poll::Ready(())
+            } else {
+                Poll::Pending
+            }
+        })
+        .await;
 
         T::regs().dr().read().0 as u16
     }
 
-    pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
+    pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
         Self::set_channel_sample_time(pin.channel(), self.sample_time);
         T::regs().cr1().modify(|reg| {
             reg.set_scan(false);
@@ -123,7 +154,7 @@ impl<'d, T: Instance> Adc<'d, T> {
 
         // Configure the channel to sample
         T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel()));
-        self.convert()
+        self.convert().await
     }
 
     fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
@@ -135,3 +166,11 @@ impl<'d, T: Instance> Adc<'d, T> {
         }
     }
 }
+
+impl<'d, T: Instance> Drop for Adc<'d, T> {
+    fn drop(&mut self) {
+        T::regs().cr2().modify(|reg| reg.set_adon(false));
+
+        T::disable();
+    }
+}
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index 5d2ea1daa..7c13f8106 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -173,3 +173,23 @@ impl<'d, T: Instance> Adc<'d, T> {
         }
     }
 }
+
+impl<'d, T: Instance> Drop for Adc<'d, T> {
+    fn drop(&mut self) {
+        use crate::pac::adc::vals;
+
+        T::regs().cr().modify(|w| w.set_adstp(true));
+
+        while T::regs().cr().read().adstp() {}
+
+        T::regs().cr().modify(|w| w.set_addis(true));
+
+        while T::regs().cr().read().aden() {}
+
+        // Disable the adc regulator
+        T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
+        T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED));
+
+        T::disable();
+    }
+}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 2f8f8f9e3..365738a31 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -31,15 +31,15 @@ pub struct Adc<'d, T: Instance> {
 }
 
 pub(crate) mod sealed {
-    #[cfg(any(adc_f3, adc_v1))]
+    #[cfg(any(adc_f1, adc_f3, adc_v1))]
     use embassy_sync::waitqueue::AtomicWaker;
 
-    #[cfg(any(adc_f3, adc_v1))]
+    #[cfg(any(adc_f1, adc_f3, adc_v1))]
     pub struct State {
         pub waker: AtomicWaker,
     }
 
-    #[cfg(any(adc_f3, adc_v1))]
+    #[cfg(any(adc_f1, adc_f3, adc_v1))]
     impl State {
         pub const fn new() -> Self {
             Self {
@@ -58,11 +58,14 @@ pub(crate) mod sealed {
         fn common_regs() -> crate::pac::adccommon::AdcCommon;
         #[cfg(adc_f3)]
         fn frequency() -> crate::time::Hertz;
-        #[cfg(any(adc_f3, adc_v1))]
+        #[cfg(any(adc_f1, adc_f3, adc_v1))]
         fn state() -> &'static State;
     }
 
     pub trait AdcPin<T: Instance> {
+        #[cfg(any(adc_v1, adc_v2))]
+        fn set_as_analog(&mut self) {}
+
         fn channel(&self) -> u8;
     }
 
@@ -96,7 +99,7 @@ foreach_adc!(
                 unsafe { crate::rcc::get_freqs() }.$clock.unwrap()
             }
 
-            #[cfg(any(adc_f3, adc_v1))]
+            #[cfg(any(adc_f1, adc_f3, adc_v1))]
             fn state() -> &'static sealed::State {
                 static STATE: sealed::State = sealed::State::new();
                 &STATE
@@ -120,6 +123,11 @@ macro_rules! impl_adc_pin {
         impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {}
 
         impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin {
+            #[cfg(any(adc_v1, adc_v2))]
+            fn set_as_analog(&mut self) {
+                <Self as crate::gpio::sealed::Pin>::set_as_analog(self);
+            }
+
             fn channel(&self) -> u8 {
                 $ch
             }
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 15b2dc593..fded26e40 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -5,7 +5,7 @@ use core::task::Poll;
 use embassy_hal_internal::into_ref;
 use embedded_hal_02::blocking::delay::DelayUs;
 
-use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
+use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
 use crate::interrupt::typelevel::Interrupt;
 use crate::peripherals::ADC;
 use crate::{interrupt, Peripheral};
@@ -31,24 +31,24 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
 }
 
 pub struct Vbat;
-impl InternalChannel<ADC> for Vbat {}
-impl super::sealed::InternalChannel<ADC> for Vbat {
+impl AdcPin<ADC> for Vbat {}
+impl super::sealed::AdcPin<ADC> for Vbat {
     fn channel(&self) -> u8 {
         18
     }
 }
 
 pub struct Vref;
-impl InternalChannel<ADC> for Vref {}
-impl super::sealed::InternalChannel<ADC> for Vref {
+impl AdcPin<ADC> for Vref {}
+impl super::sealed::AdcPin<ADC> for Vref {
     fn channel(&self) -> u8 {
         17
     }
 }
 
 pub struct Temperature;
-impl InternalChannel<ADC> for Temperature {}
-impl super::sealed::InternalChannel<ADC> for Temperature {
+impl AdcPin<ADC> for Temperature {}
+impl super::sealed::AdcPin<ADC> for Temperature {
     fn channel(&self) -> u8 {
         16
     }
@@ -134,18 +134,14 @@ impl<'d, T: Instance> Adc<'d, T> {
         T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
     }
 
-    pub async fn read<P>(&mut self, pin: &mut P) -> u16
-    where
-        P: AdcPin<T> + crate::gpio::sealed::Pin,
-    {
+    pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
         let channel = pin.channel();
         pin.set_as_analog();
-        self.read_channel(channel).await
-    }
 
-    pub async fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
-        let channel = channel.channel();
-        self.read_channel(channel).await
+        // A.7.5 Single conversion sequence code example - Software trigger
+        T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true));
+
+        self.convert().await
     }
 
     async fn convert(&mut self) -> u16 {
@@ -171,13 +167,6 @@ impl<'d, T: Instance> Adc<'d, T> {
 
         T::regs().dr().read().data()
     }
-
-    async fn read_channel(&mut self, channel: u8) -> u16 {
-        // A.7.5 Single conversion sequence code example - Software trigger
-        T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true));
-
-        self.convert().await
-    }
 }
 
 impl<'d, T: Instance> Drop for Adc<'d, T> {
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index f583c08a9..a669013c9 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,7 +1,6 @@
 use embassy_hal_internal::into_ref;
 use embedded_hal_02::blocking::delay::DelayUs;
 
-use super::InternalChannel;
 use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
 use crate::peripherals::ADC1;
 use crate::time::Hertz;
@@ -16,8 +15,8 @@ pub const VREF_CALIB_MV: u32 = 3300;
 pub const ADC_POWERUP_TIME_US: u32 = 3;
 
 pub struct VrefInt;
-impl InternalChannel<ADC1> for VrefInt {}
-impl super::sealed::InternalChannel<ADC1> for VrefInt {
+impl AdcPin<ADC1> for VrefInt {}
+impl super::sealed::AdcPin<ADC1> for VrefInt {
     fn channel(&self) -> u8 {
         17
     }
@@ -31,8 +30,8 @@ impl VrefInt {
 }
 
 pub struct Temperature;
-impl InternalChannel<ADC1> for Temperature {}
-impl super::sealed::InternalChannel<ADC1> for Temperature {
+impl AdcPin<ADC1> for Temperature {}
+impl super::sealed::AdcPin<ADC1> for Temperature {
     fn channel(&self) -> u8 {
         cfg_if::cfg_if! {
             if #[cfg(any(stm32f40, stm32f41))] {
@@ -52,8 +51,8 @@ impl Temperature {
 }
 
 pub struct Vbat;
-impl InternalChannel<ADC1> for Vbat {}
-impl super::sealed::InternalChannel<ADC1> for Vbat {
+impl AdcPin<ADC1> for Vbat {}
+impl super::sealed::AdcPin<ADC1> for Vbat {
     fn channel(&self) -> u8 {
         18
     }
@@ -176,22 +175,11 @@ where
         T::regs().dr().read().0 as u16
     }
 
-    pub fn read<P>(&mut self, pin: &mut P) -> u16
-    where
-        P: AdcPin<T>,
-        P: crate::gpio::sealed::Pin,
-    {
+    pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
         pin.set_as_analog();
 
-        self.read_channel(pin.channel())
-    }
-
-    pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
-        self.read_channel(channel.channel())
-    }
-
-    fn read_channel(&mut self, channel: u8) -> u16 {
         // Configure ADC
+        let channel = pin.channel();
 
         // Select channel
         T::regs().sqr3().write(|reg| reg.set_sq(0, channel));
@@ -199,9 +187,7 @@ where
         // Configure channel
         Self::set_channel_sample_time(channel, self.sample_time);
 
-        let val = self.convert();
-
-        val
+        self.convert()
     }
 
     fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
@@ -216,6 +202,10 @@ where
 
 impl<'d, T: Instance> Drop for Adc<'d, T> {
     fn drop(&mut self) {
+        T::regs().cr2().modify(|reg| {
+            reg.set_adon(false);
+        });
+
         T::disable();
     }
 }
diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs
index 2ed46a944..1564ecfc0 100644
--- a/examples/stm32f0/src/bin/adc.rs
+++ b/examples/stm32f0/src/bin/adc.rs
@@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
     let mut pin = p.PA1;
 
     let mut vrefint = adc.enable_vref(&mut Delay);
-    let vrefint_sample = adc.read_internal(&mut vrefint).await;
+    let vrefint_sample = adc.read(&mut vrefint).await;
     let convert_to_millivolts = |sample| {
         // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf
         // 6.3.4 Embedded reference voltage
diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs
index ed59e2799..30947c3c2 100644
--- a/examples/stm32f1/src/bin/adc.rs
+++ b/examples/stm32f1/src/bin/adc.rs
@@ -5,9 +5,15 @@
 use defmt::*;
 use embassy_executor::Spawner;
 use embassy_stm32::adc::Adc;
+use embassy_stm32::peripherals::ADC1;
+use embassy_stm32::{adc, bind_interrupts};
 use embassy_time::{Delay, Duration, Timer};
 use {defmt_rtt as _, panic_probe as _};
 
+bind_interrupts!(struct Irqs {
+    ADC1_2 => adc::InterruptHandler<ADC1>;
+});
+
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let p = embassy_stm32::init(Default::default());
@@ -17,7 +23,7 @@ async fn main(_spawner: Spawner) {
     let mut pin = p.PB1;
 
     let mut vrefint = adc.enable_vref(&mut Delay);
-    let vrefint_sample = adc.read(&mut vrefint);
+    let vrefint_sample = adc.read(&mut vrefint).await;
     let convert_to_millivolts = |sample| {
         // From http://www.st.com/resource/en/datasheet/CD00161566.pdf
         // 5.3.4 Embedded reference voltage
@@ -27,7 +33,7 @@ async fn main(_spawner: Spawner) {
     };
 
     loop {
-        let v = adc.read(&mut pin);
+        let v = adc.read(&mut pin).await;
         info!("--> {} - {} mV", v, convert_to_millivolts(v));
         Timer::after(Duration::from_millis(100)).await;
     }
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 1c9a0b35d..dd10385c4 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
     // Startup delay can be combined to the maximum of either
     delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us()));
 
-    let vrefint_sample = adc.read_internal(&mut vrefint);
+    let vrefint_sample = adc.read(&mut vrefint);
 
     let convert_to_millivolts = |sample| {
         // From http://www.st.com/resource/en/datasheet/DM00071990.pdf
@@ -55,12 +55,12 @@ async fn main(_spawner: Spawner) {
         info!("PC1: {} ({} mV)", v, convert_to_millivolts(v));
 
         // Read internal temperature
-        let v = adc.read_internal(&mut temp);
+        let v = adc.read(&mut temp);
         let celcius = convert_to_celcius(v);
         info!("Internal temp: {} ({} C)", v, celcius);
 
         // Read internal voltage reference
-        let v = adc.read_internal(&mut vrefint);
+        let v = adc.read(&mut vrefint);
         info!("VrefInt: {}", v);
 
         Timer::after(Duration::from_millis(100)).await;
diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs
index 70b3b2a75..bc4ed2892 100644
--- a/examples/stm32f7/src/bin/adc.rs
+++ b/examples/stm32f7/src/bin/adc.rs
@@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) {
     let mut pin = p.PA3;
 
     let mut vrefint = adc.enable_vrefint();
-    let vrefint_sample = adc.read_internal(&mut vrefint);
+    let vrefint_sample = adc.read(&mut vrefint);
     let convert_to_millivolts = |sample| {
         // From http://www.st.com/resource/en/datasheet/DM00273119.pdf
         // 6.3.27 Reference voltage