|
| 1 | +//! Asynchronous analog-digital conversion traits. |
| 2 | +
|
| 3 | +pub use embedded_hal::adc::{Error, ErrorKind, ErrorType}; |
| 4 | + |
| 5 | +/// Read data from an ADC. |
| 6 | +/// |
| 7 | +/// # Examples |
| 8 | +/// |
| 9 | +/// In the first naive example, [`read`](crate::adc::AdcChannel::read) is implemented |
| 10 | +/// using a spin loop and only returns once data is ready. |
| 11 | +/// |
| 12 | +/// ``` |
| 13 | +/// # use embedded_hal_async::adc::{AdcChannel, ErrorKind, ErrorType, Error}; |
| 14 | +/// # |
| 15 | +/// struct MySpinningAdc; |
| 16 | +/// |
| 17 | +/// impl MySpinningAdc { |
| 18 | +/// pub fn is_ready(&mut self) -> bool { |
| 19 | +/// // Just pretend this returns `false` the first few times. |
| 20 | +/// true |
| 21 | +/// } |
| 22 | +/// |
| 23 | +/// pub fn data(&mut self) -> u32 { |
| 24 | +/// 42 |
| 25 | +/// } |
| 26 | +/// } |
| 27 | +/// |
| 28 | +/// impl ErrorType for MySpinningAdc { |
| 29 | +/// type Error = ErrorKind; |
| 30 | +/// } |
| 31 | +/// |
| 32 | +/// impl AdcChannel for MySpinningAdc { |
| 33 | +/// async fn read(&mut self) -> Result<u32, Self::Error> { |
| 34 | +/// while !self.is_ready() { |
| 35 | +/// core::hint::spin_loop(); |
| 36 | +/// } |
| 37 | +/// |
| 38 | +/// Ok(self.data()) |
| 39 | +/// } |
| 40 | +/// } |
| 41 | +/// ``` |
| 42 | +/// |
| 43 | +/// The second example assumes an ADC that supports a “ready pin” which implements [`Wait`](crate::digital::Wait). |
| 44 | +/// When the “ready pin” goes high, data is ready. |
| 45 | +/// |
| 46 | +/// ``` |
| 47 | +/// # use embedded_hal_async::{adc::{self, ErrorKind, ErrorType, Error, AdcChannel}, digital::{self, Wait, Error as _, ErrorType as _}}; |
| 48 | +/// # |
| 49 | +/// struct MyWaitingAdc<T> { |
| 50 | +/// ready_pin: T, |
| 51 | +/// }; |
| 52 | +/// |
| 53 | +/// impl<T> MyWaitingAdc<T> { |
| 54 | +/// pub fn data(&mut self) -> u32 { |
| 55 | +/// 42 |
| 56 | +/// } |
| 57 | +/// } |
| 58 | +/// |
| 59 | +/// impl<T> adc::ErrorType for MyWaitingAdc<T> { |
| 60 | +/// type Error = adc::ErrorKind; |
| 61 | +/// } |
| 62 | +/// |
| 63 | +/// impl<T: Wait> AdcChannel for MyWaitingAdc<T> { |
| 64 | +/// async fn read(&mut self) -> Result<u32, Self::Error> { |
| 65 | +/// match self.ready_pin.wait_for_high().await { |
| 66 | +/// Ok(()) => (), |
| 67 | +/// Err(err) => return Err(match err.kind() { |
| 68 | +/// digital::ErrorKind::Other => adc::ErrorKind::Other, |
| 69 | +/// _ => adc::ErrorKind::Other, |
| 70 | +/// }) |
| 71 | +/// } |
| 72 | +/// |
| 73 | +/// Ok(self.data()) |
| 74 | +/// } |
| 75 | +/// } |
| 76 | +/// ``` |
| 77 | +pub trait AdcChannel: ErrorType { |
| 78 | + /// Reads data from the ADC. |
| 79 | + /// |
| 80 | + /// # Note for Implementers |
| 81 | + /// |
| 82 | + /// This should wait until data is ready and then read it. |
| 83 | + /// If the ADC's precision is less than 32 bits, the value must be scaled accordingly. |
| 84 | + async fn read(&mut self) -> Result<u32, Self::Error>; |
| 85 | +} |
| 86 | + |
| 87 | +impl<T> AdcChannel for &mut T |
| 88 | +where |
| 89 | + T: AdcChannel + ?Sized, |
| 90 | +{ |
| 91 | + #[inline] |
| 92 | + async fn read(&mut self) -> Result<u32, Self::Error> { |
| 93 | + (*self).read().await |
| 94 | + } |
| 95 | +} |
| 96 | + |
| 97 | +#[cfg(test)] |
| 98 | +mod test { |
| 99 | + use super::*; |
| 100 | + |
| 101 | + /// Scale an integer containing `bits` bits to 32 bits. |
| 102 | + fn scale_bits(raw_data: u32, bits: u32) -> u32 { |
| 103 | + let mut scaled_data: u32 = 0; |
| 104 | + |
| 105 | + let mut remaining_bits = u32::BITS; |
| 106 | + while remaining_bits > 0 { |
| 107 | + let shl = bits.min(remaining_bits); |
| 108 | + scaled_data = (scaled_data.wrapping_shl(shl)) | (raw_data.wrapping_shr(bits - shl)); |
| 109 | + remaining_bits -= shl; |
| 110 | + } |
| 111 | + |
| 112 | + scaled_data |
| 113 | + } |
| 114 | + |
| 115 | + #[test] |
| 116 | + fn scale_bits_i8_to_i32() { |
| 117 | + let raw_data = u32::from(i8::MIN as u8); |
| 118 | + let scaled_data = scale_bits(raw_data, 8); |
| 119 | + assert!(i32::MIN <= (scaled_data as i32) && (scaled_data as i32) <= (i32::MIN + 1 << 8)); |
| 120 | + } |
| 121 | + |
| 122 | + macro_rules! impl_adc { |
| 123 | + ($Adc:ident, $bits:literal, $uint:ty) => { |
| 124 | + struct $Adc($uint); |
| 125 | + |
| 126 | + impl $Adc { |
| 127 | + const MAX: $uint = !(<$uint>::MAX.wrapping_shl($bits - 1).wrapping_shl(1)); |
| 128 | + |
| 129 | + pub fn data(&mut self) -> $uint { |
| 130 | + self.0 |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + impl ErrorType for $Adc { |
| 135 | + type Error = core::convert::Infallible; |
| 136 | + } |
| 137 | + |
| 138 | + impl AdcChannel for $Adc { |
| 139 | + async fn read(&mut self) -> Result<u32, Self::Error> { |
| 140 | + Ok(scale_bits(u32::from(self.data()), $bits)) |
| 141 | + } |
| 142 | + } |
| 143 | + }; |
| 144 | + } |
| 145 | + |
| 146 | + macro_rules! test_adc { |
| 147 | + ($Adc:ident, $bits:literal, $uint:ty) => {{ |
| 148 | + impl_adc!($Adc, $bits, $uint); |
| 149 | + |
| 150 | + // 0 should always be scaled to 0. |
| 151 | + let mut adc_0 = $Adc(0); |
| 152 | + assert_eq!(adc_0.read().await, Ok(0)); |
| 153 | + |
| 154 | + // `$Adc::MAX` should always be scaled to `u32::MAX`. |
| 155 | + let mut adc_max = $Adc($Adc::MAX); |
| 156 | + assert_eq!(adc_max.read().await, Ok(u32::MAX)); |
| 157 | + }}; |
| 158 | + } |
| 159 | + |
| 160 | + #[tokio::test] |
| 161 | + async fn test_8_bit() { |
| 162 | + test_adc!(Adc8, 8, u8); |
| 163 | + } |
| 164 | + |
| 165 | + #[tokio::test] |
| 166 | + async fn test_12_bit() { |
| 167 | + test_adc!(Adc12, 12, u16); |
| 168 | + } |
| 169 | + |
| 170 | + #[tokio::test] |
| 171 | + async fn test_16_bit() { |
| 172 | + test_adc!(Adc16, 16, u16); |
| 173 | + } |
| 174 | + |
| 175 | + #[tokio::test] |
| 176 | + async fn test_24_bit() { |
| 177 | + test_adc!(Adc24, 24, u32); |
| 178 | + } |
| 179 | + |
| 180 | + #[tokio::test] |
| 181 | + async fn test_32_bit() { |
| 182 | + test_adc!(Adc32, 32, u32); |
| 183 | + } |
| 184 | +} |
0 commit comments