diff --git a/embassy-stm32/src/cordic/enums.rs b/embassy-stm32/src/cordic/enums.rs
index 37c73f549..4b92a6cf8 100644
--- a/embassy-stm32/src/cordic/enums.rs
+++ b/embassy-stm32/src/cordic/enums.rs
@@ -1,6 +1,7 @@
 /// CORDIC function
 #[allow(missing_docs)]
-#[derive(Clone, Copy)]
+#[derive(Debug, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum Function {
     Cos = 0,
     Sin,
@@ -16,7 +17,7 @@ pub enum Function {
 
 /// CORDIC precision
 #[allow(missing_docs)]
-#[derive(Clone, Copy, Default)]
+#[derive(Debug, Clone, Copy, Default)]
 pub enum Precision {
     Iters4 = 1,
     Iters8,
@@ -37,25 +38,25 @@ pub enum Precision {
 }
 
 /// CORDIC scale
-#[allow(non_camel_case_types)]
 #[allow(missing_docs)]
-#[derive(Clone, Copy, Default, PartialEq)]
+#[derive(Debug, Clone, Copy, Default, PartialEq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum Scale {
     #[default]
-    A1_R1 = 0,
-    A1o2_R2,
-    A1o4_R4,
-    A1o8_R8,
-    A1o16_R16,
-    A1o32_R32,
-    A1o64_R64,
-    A1o128_R128,
+    Arg1Res1 = 0,
+    Arg1o2Res2,
+    Arg1o4Res4,
+    Arg1o8Res8,
+    Arg1o16Res16,
+    Arg1o32Res32,
+    Arg1o64Res64,
+    Arg1o128Res128,
 }
 
-/// CORDIC argument/result count
+/// CORDIC argument/result register access count
 #[allow(missing_docs)]
 #[derive(Clone, Copy, Default)]
-pub enum Count {
+pub enum AccessCount {
     #[default]
     One,
     Two,
diff --git a/embassy-stm32/src/cordic/errors.rs b/embassy-stm32/src/cordic/errors.rs
new file mode 100644
index 000000000..d0b2dc618
--- /dev/null
+++ b/embassy-stm32/src/cordic/errors.rs
@@ -0,0 +1,95 @@
+use super::{Function, Scale};
+
+/// Error for [Cordic](super::Cordic)
+#[derive(Debug)]
+pub enum CordicError {
+    /// Config error
+    ConfigError(ConfigError),
+    /// Argument error
+    ArgError(ArgError),
+    /// Output buffer length error
+    OutputLengthNotEnough,
+}
+
+#[cfg(feature = "defmt")]
+impl defmt::Format for CordicError {
+    fn format(&self, fmt: defmt::Formatter) {
+        use CordicError::*;
+
+        match self {
+            ConfigError(e) => defmt::write!(fmt, "{}", e),
+            ArgError(e) => defmt::write!(fmt, "{}", e),
+            OutputLengthNotEnough => defmt::write!(fmt, "Output buffer length is not long enough"),
+        }
+    }
+}
+
+/// Error dring parsing [Cordic::Config](super::Config)
+#[derive(Debug)]
+pub struct ConfigError {
+    pub(super) func: Function,
+    pub(super) scale_range: [u8; 2],
+}
+
+#[cfg(feature = "defmt")]
+impl defmt::Format for ConfigError {
+    fn format(&self, fmt: defmt::Formatter) {
+        defmt::write!(fmt, "For FUNCTION: {},", self.func);
+
+        if self.scale_range[0] == self.scale_range[1] {
+            defmt::write!(fmt, " SCALE value should be {}", self.scale_range[0])
+        } else {
+            defmt::write!(
+                fmt,
+                " SCALE value should be {} <= SCALE <= {}",
+                self.scale_range[0],
+                self.scale_range[1]
+            )
+        }
+    }
+}
+
+/// Error on checking input arguments
+#[derive(Debug)]
+pub struct ArgError {
+    pub(super) func: Function,
+    pub(super) scale: Option<Scale>,
+    pub(super) arg_range: [f32; 2], // only for debug display, f32 is ok
+    pub(super) inclusive_upper_bound: bool,
+    pub(super) arg_type: ArgType,
+}
+
+#[cfg(feature = "defmt")]
+impl defmt::Format for ArgError {
+    fn format(&self, fmt: defmt::Formatter) {
+        defmt::write!(fmt, "For FUNCTION: {},", self.func);
+
+        if let Some(scale) = self.scale {
+            defmt::write!(fmt, " when SCALE is {},", scale);
+        }
+
+        let arg_string = match self.arg_type {
+            ArgType::Arg1 => "ARG1",
+            ArgType::Arg2 => "ARG2",
+        };
+
+        defmt::write!(fmt, " {} should be", arg_string);
+
+        let inclusive_string = if self.inclusive_upper_bound { "=" } else { "" };
+
+        defmt::write!(
+            fmt,
+            " {} <= {} <{} {}",
+            self.arg_range[0],
+            arg_string,
+            inclusive_string,
+            self.arg_range[1]
+        )
+    }
+}
+
+#[derive(Debug)]
+pub(super) enum ArgType {
+    Arg1,
+    Arg2,
+}
diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs
index a4b98a770..5ac9addd8 100644
--- a/embassy-stm32/src/cordic/mod.rs
+++ b/embassy-stm32/src/cordic/mod.rs
@@ -1,4 +1,4 @@
-//! CORDIC co-processor
+//! coordinate rotation digital computer (CORDIC)
 
 use embassy_hal_internal::drop::OnDrop;
 use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
@@ -8,6 +8,9 @@ use crate::{dma, peripherals};
 mod enums;
 pub use enums::*;
 
+mod errors;
+pub use errors::*;
+
 pub mod utils;
 
 pub(crate) mod sealed;
@@ -30,33 +33,55 @@ pub struct Cordic<'d, T: Instance> {
 pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral {}
 
 /// CORDIC configuration
+#[derive(Debug)]
 pub struct Config {
     function: Function,
     precision: Precision,
     scale: Scale,
-    first_result: bool,
+    res1_only: bool,
 }
 
 impl Config {
     /// Create a config for Cordic driver
-    pub fn new(function: Function, precision: Option<Precision>, scale: Option<Scale>, first_result: bool) -> Self {
-        Self {
+    pub fn new(function: Function, precision: Precision, scale: Scale, res1_only: bool) -> Result<Self, CordicError> {
+        let config = Self {
             function,
-            precision: precision.unwrap_or_default(),
-            scale: scale.unwrap_or_default(),
-            first_result,
-        }
+            precision,
+            scale,
+            res1_only,
+        };
+
+        config.check_scale()?;
+
+        Ok(config)
     }
 
-    fn check_scale(&self) -> bool {
+    fn check_scale(&self) -> Result<(), CordicError> {
+        use Function::*;
+
         let scale_raw = self.scale as u8;
 
-        match self.function {
-            Function::Cos | Function::Sin | Function::Phase | Function::Modulus => 0 == scale_raw,
-            Function::Arctan => (0..=7).contains(&scale_raw),
-            Function::Cosh | Function::Sinh | Function::Arctanh => 1 == scale_raw,
-            Function::Ln => (1..=4).contains(&scale_raw),
-            Function::Sqrt => (0..=2).contains(&scale_raw),
+        let err_range = match self.function {
+            Cos | Sin | Phase | Modulus if !(0..=0).contains(&scale_raw) => Some([0, 0]),
+
+            Arctan if !(0..=7).contains(&scale_raw) => Some([0, 7]),
+
+            Cosh | Sinh | Arctanh if !(1..=1).contains(&scale_raw) => Some([1, 1]),
+
+            Ln if !(1..=4).contains(&scale_raw) => Some([1, 4]),
+
+            Sqrt if !(0..=2).contains(&scale_raw) => Some([0, 2]),
+
+            Cos | Sin | Phase | Modulus | Arctan | Cosh | Sinh | Arctanh | Ln | Sqrt => None,
+        };
+
+        if let Some(range) = err_range {
+            Err(CordicError::ConfigError(ConfigError {
+                func: self.function,
+                scale_range: range,
+            }))
+        } else {
+            Ok(())
         }
     }
 }
@@ -73,10 +98,6 @@ impl<'d, T: Instance> Cordic<'d, T> {
 
         into_ref!(peri);
 
-        if !config.check_scale() {
-            panic!("Scale value is not compatible with Function")
-        }
-
         let mut instance = Self { peri, config };
 
         instance.reconfigure();
@@ -91,21 +112,12 @@ impl<'d, T: Instance> Cordic<'d, T> {
     }
 
     /// Set extra config for data count and data width.
-    pub fn extra_config(&mut self, arg_cnt: Count, arg_width: Width, res_width: Width) {
+    pub fn extra_config(&mut self, arg_cnt: AccessCount, arg_width: Width, res_width: Width) {
         self.peri.set_argument_count(arg_cnt);
         self.peri.set_data_width(arg_width, res_width);
     }
 
     fn reconfigure(&mut self) {
-        if self.peri.ready_to_read() {
-            warn!("At least 1 result hasn't been read, reconfigure will cause DATA LOST");
-        };
-
-        // clean RRDY flag
-        while self.peri.ready_to_read() {
-            self.peri.read_result();
-        }
-
         self.peri.set_func(self.config.function);
         self.peri.set_precision(self.config.precision);
         self.peri.set_scale(self.config.scale);
@@ -113,6 +125,47 @@ impl<'d, T: Instance> Cordic<'d, T> {
         // we don't set NRES in here, but to make sure NRES is set each time user call "calc"-ish functions,
         // since each "calc"-ish functions can have different ARGSIZE and RESSIZE, thus NRES should be change accrodingly.
     }
+
+    async fn launch_a_dma_transfer(
+        &mut self,
+        write_dma: impl Peripheral<P = impl WriteDma<T>>,
+        read_dma: impl Peripheral<P = impl ReadDma<T>>,
+        input: &[u32],
+        output: &mut [u32],
+    ) {
+        into_ref!(write_dma, read_dma);
+
+        let write_req = write_dma.request();
+        let read_req = read_dma.request();
+
+        self.peri.enable_write_dma();
+        self.peri.enable_read_dma();
+
+        let _on_drop = OnDrop::new(|| {
+            self.peri.disable_write_dma();
+            self.peri.disable_read_dma();
+        });
+
+        unsafe {
+            let write_transfer = dma::Transfer::new_write(
+                &mut write_dma,
+                write_req,
+                input,
+                T::regs().wdata().as_ptr() as *mut _,
+                Default::default(),
+            );
+
+            let read_transfer = dma::Transfer::new_read(
+                &mut read_dma,
+                read_req,
+                T::regs().rdata().as_ptr() as *mut _,
+                output,
+                Default::default(),
+            );
+
+            embassy_futures::join::join(write_transfer, read_transfer).await;
+        }
+    }
 }
 
 impl<'d, T: Instance> Drop for Cordic<'d, T> {
@@ -124,25 +177,31 @@ impl<'d, T: Instance> Drop for Cordic<'d, T> {
 // q1.31 related
 impl<'d, T: Instance> Cordic<'d, T> {
     /// Run a blocking CORDIC calculation in q1.31 format
-    pub fn blocking_calc_32bit(&mut self, arg1s: &[f64], arg2s: Option<&[f64]>, output: &mut [f64]) -> usize {
+    pub fn blocking_calc_32bit(
+        &mut self,
+        arg1s: &[f64],
+        arg2s: Option<&[f64]>,
+        output: &mut [f64],
+    ) -> Result<usize, CordicError> {
         if arg1s.is_empty() {
-            return 0;
+            return Ok(0);
         }
 
-        assert!(
-            match self.config.first_result {
-                true => output.len() >= arg1s.len(),
-                false => output.len() >= 2 * arg1s.len(),
-            },
-            "Output buf length is not long enough"
-        );
+        let output_length_enough = match self.config.res1_only {
+            true => output.len() >= arg1s.len(),
+            false => output.len() >= 2 * arg1s.len(),
+        };
 
-        self.check_input_f64(arg1s, arg2s);
+        if !output_length_enough {
+            return Err(CordicError::OutputLengthNotEnough);
+        }
 
-        self.peri.set_result_count(if self.config.first_result {
-            Count::One
+        self.check_input_f64(arg1s, arg2s)?;
+
+        self.peri.set_result_count(if self.config.res1_only {
+            AccessCount::One
         } else {
-            Count::Two
+            AccessCount::Two
         });
 
         self.peri.set_data_width(Width::Bits32, Width::Bits32);
@@ -155,10 +214,10 @@ impl<'d, T: Instance> Cordic<'d, T> {
         // handle 2 input args calculation
         //
 
-        if arg2s.is_some() && !arg2s.expect("It's infailable").is_empty() {
-            let arg2s = arg2s.expect("It's infailable");
+        if arg2s.is_some() && !arg2s.unwrap().is_empty() {
+            let arg2s = arg2s.unwrap();
 
-            self.peri.set_argument_count(Count::Two);
+            self.peri.set_argument_count(AccessCount::Two);
 
             // Skip 1st value from arg1s, this value will be manually "preload" to cordic, to make use of cordic preload function.
             // And we preserve last value from arg2s, since it need to manually write to cordic, and read the result out.
@@ -191,7 +250,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
         let input_left = &arg1s[consumed_input_len..];
 
         if !input_left.is_empty() {
-            self.peri.set_argument_count(Count::One);
+            self.peri.set_argument_count(AccessCount::One);
 
             // "preload" value to cordic (at this moment, cordic start to calculating)
             self.blocking_write_f64(input_left[0]);
@@ -207,7 +266,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
             self.blocking_read_f64_to_buf(output, &mut output_count);
         }
 
-        output_count
+        Ok(output_count)
     }
 
     fn blocking_read_f64_to_buf(&mut self, result_buf: &mut [f64], result_index: &mut usize) {
@@ -216,7 +275,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
 
         // We don't care about whether the function return 1 or 2 results,
         // the only thing matter is whether user want 1 or 2 results.
-        if !self.config.first_result {
+        if !self.config.res1_only {
             result_buf[*result_index] = utils::q1_31_to_f64(self.peri.read_result());
             *result_index += 1;
         }
@@ -234,27 +293,28 @@ impl<'d, T: Instance> Cordic<'d, T> {
         arg1s: &[f64],
         arg2s: Option<&[f64]>,
         output: &mut [f64],
-    ) -> usize {
+    ) -> Result<usize, CordicError> {
         if arg1s.is_empty() {
-            return 0;
+            return Ok(0);
         }
 
-        assert!(
-            match self.config.first_result {
-                true => output.len() >= arg1s.len(),
-                false => output.len() >= 2 * arg1s.len(),
-            },
-            "Output buf length is not long enough"
-        );
+        let output_length_enough = match self.config.res1_only {
+            true => output.len() >= arg1s.len(),
+            false => output.len() >= 2 * arg1s.len(),
+        };
 
-        self.check_input_f64(arg1s, arg2s);
+        if !output_length_enough {
+            return Err(CordicError::OutputLengthNotEnough);
+        }
+
+        self.check_input_f64(arg1s, arg2s)?;
 
         into_ref!(write_dma, read_dma);
 
-        self.peri.set_result_count(if self.config.first_result {
-            Count::One
+        self.peri.set_result_count(if self.config.res1_only {
+            AccessCount::One
         } else {
-            Count::Two
+            AccessCount::Two
         });
 
         self.peri.set_data_width(Width::Bits32, Width::Bits32);
@@ -269,9 +329,9 @@ impl<'d, T: Instance> Cordic<'d, T> {
         //
 
         if !arg2s.unwrap_or_default().is_empty() {
-            let arg2s = arg2s.expect("It's infailable");
+            let arg2s = arg2s.unwrap();
 
-            self.peri.set_argument_count(Count::Two);
+            self.peri.set_argument_count(AccessCount::Two);
 
             let double_input = arg1s.iter().zip(arg2s);
 
@@ -320,7 +380,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
         if arg1s.len() > consumed_input_len {
             let input_remain = &arg1s[consumed_input_len..];
 
-            self.peri.set_argument_count(Count::One);
+            self.peri.set_argument_count(AccessCount::One);
 
             for &arg in input_remain {
                 input_buf[input_buf_len] = utils::f64_to_q1_31(arg);
@@ -356,7 +416,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
             }
         }
 
-        output_count
+        Ok(output_count)
     }
 
     // this function is highly coupled with async_calc_32bit, and is not intended to use in other place
@@ -369,11 +429,6 @@ impl<'d, T: Instance> Cordic<'d, T> {
         output: &mut [f64],             // caller uses should this as a final output array
         output_start_index: &mut usize, // the index of start point of the output for this round of calculation
     ) {
-        into_ref!(write_dma, read_dma);
-
-        let write_req = write_dma.request();
-        let read_req = read_dma.request();
-
         // output_buf is the place to store raw value from CORDIC (via DMA).
         // For buf size, we assume in this round of calculation:
         // all input is 1 arg, and all calculation need 2 output,
@@ -381,7 +436,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
         let mut output_buf = [0u32; INPUT_BUF_MAX_LEN * 2];
 
         let mut output_buf_size = input_buf.len();
-        if !self.config.first_result {
+        if !self.config.res1_only {
             // if we need 2 result for 1 input, then output_buf length should be 2x long.
             output_buf_size *= 2;
         };
@@ -392,35 +447,8 @@ impl<'d, T: Instance> Cordic<'d, T> {
 
         let active_output_buf = &mut output_buf[..output_buf_size];
 
-        self.peri.enable_write_dma();
-        self.peri.enable_read_dma();
-
-        let on_drop = OnDrop::new(|| {
-            self.peri.disable_write_dma();
-            self.peri.disable_read_dma();
-        });
-
-        unsafe {
-            let write_transfer = dma::Transfer::new_write(
-                &mut write_dma,
-                write_req,
-                input_buf,
-                T::regs().wdata().as_ptr() as *mut _,
-                Default::default(),
-            );
-
-            let read_transfer = dma::Transfer::new_read(
-                &mut read_dma,
-                read_req,
-                T::regs().rdata().as_ptr() as *mut _,
-                active_output_buf,
-                Default::default(),
-            );
-
-            embassy_futures::join::join(write_transfer, read_transfer).await;
-        }
-
-        drop(on_drop);
+        self.launch_a_dma_transfer(write_dma, read_dma, input_buf, active_output_buf)
+            .await;
 
         for &mut output_u32 in active_output_buf {
             output[*output_start_index] = utils::q1_31_to_f64(output_u32);
@@ -432,24 +460,30 @@ impl<'d, T: Instance> Cordic<'d, T> {
 // q1.15 related
 impl<'d, T: Instance> Cordic<'d, T> {
     /// Run a blocking CORDIC calculation in q1.15 format
-    pub fn blocking_calc_16bit(&mut self, arg1s: &[f32], arg2s: Option<&[f32]>, output: &mut [f32]) -> usize {
+    pub fn blocking_calc_16bit(
+        &mut self,
+        arg1s: &[f32],
+        arg2s: Option<&[f32]>,
+        output: &mut [f32],
+    ) -> Result<usize, CordicError> {
         if arg1s.is_empty() {
-            return 0;
+            return Ok(0);
         }
 
-        assert!(
-            match self.config.first_result {
-                true => output.len() >= arg1s.len(),
-                false => output.len() >= 2 * arg1s.len(),
-            },
-            "Output buf length is not long enough"
-        );
+        let output_length_enough = match self.config.res1_only {
+            true => output.len() >= arg1s.len(),
+            false => output.len() >= 2 * arg1s.len(),
+        };
 
-        self.check_input_f32(arg1s, arg2s);
+        if !output_length_enough {
+            return Err(CordicError::OutputLengthNotEnough);
+        }
+
+        self.check_input_f32(arg1s, arg2s)?;
 
         // In q1.15 mode, 1 write/read to access 2 arguments/results
-        self.peri.set_argument_count(Count::One);
-        self.peri.set_result_count(Count::One);
+        self.peri.set_argument_count(AccessCount::One);
+        self.peri.set_result_count(AccessCount::One);
 
         self.peri.set_data_width(Width::Bits16, Width::Bits16);
 
@@ -472,9 +506,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
                 .chain(core::iter::repeat(&arg2_default_value)),
         );
 
-        let (&arg1, &arg2) = args
-            .next()
-            .expect("This should be infallible, since arg1s is not empty");
+        let (&arg1, &arg2) = args.next().unwrap();
 
         // preloading 1 pair of arguments
         self.blocking_write_f32(arg1, arg2);
@@ -487,7 +519,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
         // read last pair of value from cordic
         self.blocking_read_f32_to_buf(output, &mut output_count);
 
-        output_count
+        Ok(output_count)
     }
 
     fn blocking_write_f32(&mut self, arg1: f32, arg2: f32) {
@@ -505,7 +537,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
 
         // We don't care about whether the function return 1 or 2 results,
         // the only thing matter is whether user want 1 or 2 results.
-        if !self.config.first_result {
+        if !self.config.res1_only {
             result_buf[*result_index] = res2;
             *result_index += 1;
         }
@@ -519,26 +551,27 @@ impl<'d, T: Instance> Cordic<'d, T> {
         arg1s: &[f32],
         arg2s: Option<&[f32]>,
         output: &mut [f32],
-    ) -> usize {
+    ) -> Result<usize, CordicError> {
         if arg1s.is_empty() {
-            return 0;
+            return Ok(0);
         }
 
-        assert!(
-            match self.config.first_result {
-                true => output.len() >= arg1s.len(),
-                false => output.len() >= 2 * arg1s.len(),
-            },
-            "Output buf length is not long enough"
-        );
+        let output_length_enough = match self.config.res1_only {
+            true => output.len() >= arg1s.len(),
+            false => output.len() >= 2 * arg1s.len(),
+        };
 
-        self.check_input_f32(arg1s, arg2s);
+        if !output_length_enough {
+            return Err(CordicError::OutputLengthNotEnough);
+        }
+
+        self.check_input_f32(arg1s, arg2s)?;
 
         into_ref!(write_dma, read_dma);
 
         // In q1.15 mode, 1 write/read to access 2 arguments/results
-        self.peri.set_argument_count(Count::One);
-        self.peri.set_result_count(Count::One);
+        self.peri.set_argument_count(AccessCount::One);
+        self.peri.set_result_count(AccessCount::One);
 
         self.peri.set_data_width(Width::Bits16, Width::Bits16);
 
@@ -584,7 +617,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
             .await;
         }
 
-        output_count
+        Ok(output_count)
     }
 
     // this function is highly coupled with async_calc_16bit, and is not intended to use in other place
@@ -596,45 +629,13 @@ impl<'d, T: Instance> Cordic<'d, T> {
         output: &mut [f32], // caller uses should this as a final output array
         output_start_index: &mut usize, // the index of start point of the output for this round of calculation
     ) {
-        into_ref!(write_dma, read_dma);
-
-        let write_req = write_dma.request();
-        let read_req = read_dma.request();
-
         // output_buf is the place to store raw value from CORDIC (via DMA).
         let mut output_buf = [0u32; INPUT_BUF_MAX_LEN];
 
         let active_output_buf = &mut output_buf[..input_buf.len()];
 
-        self.peri.enable_write_dma();
-        self.peri.enable_read_dma();
-
-        let on_drop = OnDrop::new(|| {
-            self.peri.disable_write_dma();
-            self.peri.disable_read_dma();
-        });
-
-        unsafe {
-            let write_transfer = dma::Transfer::new_write(
-                &mut write_dma,
-                write_req,
-                input_buf,
-                T::regs().wdata().as_ptr() as *mut _,
-                Default::default(),
-            );
-
-            let read_transfer = dma::Transfer::new_read(
-                &mut read_dma,
-                read_req,
-                T::regs().rdata().as_ptr() as *mut _,
-                active_output_buf,
-                Default::default(),
-            );
-
-            embassy_futures::join::join(write_transfer, read_transfer).await;
-        }
-
-        drop(on_drop);
+        self.launch_a_dma_transfer(write_dma, read_dma, input_buf, active_output_buf)
+            .await;
 
         for &mut output_u32 in active_output_buf {
             let (res1, res2) = utils::u32_to_f32_res(output_u32);
@@ -642,7 +643,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
             output[*output_start_index] = res1;
             *output_start_index += 1;
 
-            if !self.config.first_result {
+            if !self.config.res1_only {
                 output[*output_start_index] = res2;
                 *output_start_index += 1;
             }
@@ -654,104 +655,131 @@ impl<'d, T: Instance> Cordic<'d, T> {
 macro_rules! check_input_value {
     ($func_name:ident, $float_type:ty) => {
         impl<'d, T: Instance> Cordic<'d, T> {
-            fn $func_name(&self, arg1s: &[$float_type], arg2s: Option<&[$float_type]>) {
+            fn $func_name(&self, arg1s: &[$float_type], arg2s: Option<&[$float_type]>) -> Result<(), CordicError> {
                 let config = &self.config;
 
                 use Function::*;
 
-                // check SCALE value
-                match config.function {
-                    Cos | Sin | Phase | Modulus => assert!(Scale::A1_R1 == config.scale, "SCALE should be 0"),
-                    Arctan => assert!(
-                        (0..=7).contains(&(config.scale as u8)),
-                        "SCALE should be: 0 <= SCALE <= 7"
-                    ),
-                    Cosh | Sinh | Arctanh => assert!(Scale::A1o2_R2 == config.scale, "SCALE should be 1"),
-
-                    Ln => assert!(
-                        (1..=4).contains(&(config.scale as u8)),
-                        "SCALE should be: 1 <= SCALE <= 4"
-                    ),
-                    Sqrt => assert!(
-                        (0..=2).contains(&(config.scale as u8)),
-                        "SCALE should be: 0 <= SCALE <= 2"
-                    ),
+                struct Arg1ErrInfo {
+                    scale: Option<Scale>,
+                    range: [f32; 2],
+                    inclusive_upper_bound: bool,
                 }
 
                 // check ARG1 value
-                match config.function {
-                    Cos | Sin | Phase | Modulus | Arctan => {
-                        assert!(
-                            arg1s.iter().all(|v| (-1.0..=1.0).contains(v)),
-                            "ARG1 should be: -1 <= ARG1 <= 1"
-                        );
+                let err_info = match config.function {
+                    Cos | Sin | Phase | Modulus | Arctan if arg1s.iter().any(|v| !(-1.0..=1.0).contains(v)) => {
+                        Some(Arg1ErrInfo {
+                            scale: None,
+                            range: [-1.0, 1.0],
+                            inclusive_upper_bound: true,
+                        })
                     }
 
-                    Cosh | Sinh => assert!(
-                        arg1s.iter().all(|v| (-0.559..=0.559).contains(v)),
-                        "ARG1 should be: -0.559 <= ARG1 <= 0.559"
-                    ),
+                    Cosh | Sinh if arg1s.iter().any(|v| !(-0.559..=0.559).contains(v)) => Some(Arg1ErrInfo {
+                        scale: None,
+                        range: [-0.559, 0.559],
+                        inclusive_upper_bound: true,
+                    }),
 
-                    Arctanh => assert!(
-                        arg1s.iter().all(|v| (-0.403..=0.403).contains(v)),
-                        "ARG1 should be: -0.403 <= ARG1 <= 0.403"
-                    ),
+                    Arctanh if arg1s.iter().any(|v| !(-0.403..=0.403).contains(v)) => Some(Arg1ErrInfo {
+                        scale: None,
+                        range: [-0.403, 0.403],
+                        inclusive_upper_bound: true,
+                    }),
 
-                    Ln => {
-                        match config.scale {
-                            Scale::A1o2_R2 => assert!(
-                                arg1s.iter().all(|v| (0.05354..0.5).contains(v)),
-                                "When SCALE set to 1, ARG1 should be: 0.05354 <= ARG1 < 0.5"
-                            ),
-                            Scale::A1o4_R4 => assert!(
-                                arg1s.iter().all(|v| (0.25..0.75).contains(v)),
-                                "When SCALE set to 2, ARG1 should be: 0.25 <= ARG1 < 0.75"
-                            ),
-                            Scale::A1o8_R8 => assert!(
-                                arg1s.iter().all(|v| (0.375..0.875).contains(v)),
-                                "When SCALE set to 3, ARG1 should be: 0.375 <= ARG1 < 0.875"
-                            ),
-                            Scale::A1o16_R16 => assert!(
-                                arg1s.iter().all(|v| (0.4375..0.584).contains(v)),
-                                "When SCALE set to 4, ARG1 should be: 0.4375 <= ARG1 < 0.584"
-                            ),
-                            _ => unreachable!(),
-                        };
-                    }
+                    Ln => match config.scale {
+                        Scale::Arg1o2Res2 if arg1s.iter().any(|v| !(0.0535..0.5).contains(v)) => Some(Arg1ErrInfo {
+                            scale: Some(Scale::Arg1o2Res2),
+                            range: [0.0535, 0.5],
+                            inclusive_upper_bound: false,
+                        }),
+                        Scale::Arg1o4Res4 if arg1s.iter().any(|v| !(0.25..0.75).contains(v)) => Some(Arg1ErrInfo {
+                            scale: Some(Scale::Arg1o4Res4),
+                            range: [0.25, 0.75],
+                            inclusive_upper_bound: false,
+                        }),
+                        Scale::Arg1o8Res8 if arg1s.iter().any(|v| !(0.375..0.875).contains(v)) => Some(Arg1ErrInfo {
+                            scale: Some(Scale::Arg1o8Res8),
+                            range: [0.375, 0.875],
+                            inclusive_upper_bound: false,
+                        }),
+                        Scale::Arg1o16Res16 if arg1s.iter().any(|v| !(0.4375..0.584).contains(v)) => {
+                            Some(Arg1ErrInfo {
+                                scale: Some(Scale::Arg1o16Res16),
+                                range: [0.4375, 0.584],
+                                inclusive_upper_bound: false,
+                            })
+                        }
+
+                        Scale::Arg1o2Res2 | Scale::Arg1o4Res4 | Scale::Arg1o8Res8 | Scale::Arg1o16Res16 => None,
 
-                    Sqrt => match config.scale {
-                        Scale::A1_R1 => assert!(
-                            arg1s.iter().all(|v| (0.027..0.75).contains(v)),
-                            "When SCALE set to 0, ARG1 should be: 0.027 <= ARG1 < 0.75"
-                        ),
-                        Scale::A1o2_R2 => assert!(
-                            arg1s.iter().all(|v| (0.375..0.875).contains(v)),
-                            "When SCALE set to 1, ARG1 should be: 0.375 <= ARG1 < 0.875"
-                        ),
-                        Scale::A1o4_R4 => assert!(
-                            arg1s.iter().all(|v| (0.4375..0.585).contains(v)),
-                            "When SCALE set to 2, ARG1 should be: 0.4375  <= ARG1 < 0.585"
-                        ),
                         _ => unreachable!(),
                     },
+
+                    Sqrt => match config.scale {
+                        Scale::Arg1Res1 if arg1s.iter().any(|v| !(0.027..0.75).contains(v)) => Some(Arg1ErrInfo {
+                            scale: Some(Scale::Arg1Res1),
+                            range: [0.027, 0.75],
+                            inclusive_upper_bound: false,
+                        }),
+                        Scale::Arg1o2Res2 if arg1s.iter().any(|v| !(0.375..0.875).contains(v)) => Some(Arg1ErrInfo {
+                            scale: Some(Scale::Arg1o2Res2),
+                            range: [0.375, 0.875],
+                            inclusive_upper_bound: false,
+                        }),
+                        Scale::Arg1o4Res4 if arg1s.iter().any(|v| !(0.4375..0.584).contains(v)) => Some(Arg1ErrInfo {
+                            scale: Some(Scale::Arg1o4Res4),
+                            range: [0.4375, 0.584],
+                            inclusive_upper_bound: false,
+                        }),
+                        Scale::Arg1Res1 | Scale::Arg1o2Res2 | Scale::Arg1o4Res4 => None,
+                        _ => unreachable!(),
+                    },
+
+                    Cos | Sin | Phase | Modulus | Arctan | Cosh | Sinh | Arctanh => None,
+                };
+
+                if let Some(err) = err_info {
+                    return Err(CordicError::ArgError(ArgError {
+                        func: config.function,
+                        scale: err.scale,
+                        arg_range: err.range,
+                        inclusive_upper_bound: err.inclusive_upper_bound,
+                        arg_type: ArgType::Arg1,
+                    }));
                 }
 
                 // check ARG2 value
                 if let Some(arg2s) = arg2s {
-                    match config.function {
-                        Cos | Sin => assert!(
-                            arg2s.iter().all(|v| (0.0..=1.0).contains(v)),
-                            "ARG2 should be: 0 <= ARG2 <= 1"
-                        ),
+                    struct Arg2ErrInfo {
+                        range: [f32; 2],
+                    }
 
-                        Phase | Modulus => assert!(
-                            arg2s.iter().all(|v| (-1.0..=1.0).contains(v)),
-                            "ARG2 should be: -1 <= ARG2 <= 1"
-                        ),
+                    let err_info = match config.function {
+                        Cos | Sin if arg2s.iter().any(|v| !(0.0..=1.0).contains(v)) => {
+                            Some(Arg2ErrInfo { range: [0.0, 1.0] })
+                        }
 
-                        _ => (),
+                        Phase | Modulus if arg2s.iter().any(|v| !(-1.0..=1.0).contains(v)) => {
+                            Some(Arg2ErrInfo { range: [-1.0, 1.0] })
+                        }
+
+                        Cos | Sin | Phase | Modulus | Arctan | Cosh | Sinh | Arctanh | Ln | Sqrt => None,
+                    };
+
+                    if let Some(err) = err_info {
+                        return Err(CordicError::ArgError(ArgError {
+                            func: config.function,
+                            scale: None,
+                            arg_range: err.range,
+                            inclusive_upper_bound: true,
+                            arg_type: ArgType::Arg2,
+                        }));
                     }
                 }
+
+                Ok(())
             }
         }
     };
diff --git a/embassy-stm32/src/cordic/sealed.rs b/embassy-stm32/src/cordic/sealed.rs
index 0f00e380c..f9521ff7a 100644
--- a/embassy-stm32/src/cordic/sealed.rs
+++ b/embassy-stm32/src/cordic/sealed.rs
@@ -66,21 +66,21 @@ pub trait Instance {
     }
 
     /// Set NARGS value
-    fn set_argument_count(&self, n: Count) {
+    fn set_argument_count(&self, n: AccessCount) {
         Self::regs().csr().modify(|v| {
             v.set_nargs(match n {
-                Count::One => vals::Num::NUM1,
-                Count::Two => vals::Num::NUM2,
+                AccessCount::One => vals::Num::NUM1,
+                AccessCount::Two => vals::Num::NUM2,
             })
         })
     }
 
     /// Set NRES value
-    fn set_result_count(&self, n: Count) {
+    fn set_result_count(&self, n: AccessCount) {
         Self::regs().csr().modify(|v| {
             v.set_nres(match n {
-                Count::One => vals::Num::NUM1,
-                Count::Two => vals::Num::NUM2,
+                AccessCount::One => vals::Num::NUM1,
+                AccessCount::Two => vals::Num::NUM2,
             });
         })
     }