diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-05-21 20:55:41 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-05-21 20:55:41 +0000 |
| commit | 2d8ec70f7160a3672e5f8fd9e9751814429bfd8e (patch) | |
| tree | 78fb6094659b91a208e0a16495610ffb845b9757 | |
| parent | e85242af2c638b41772029a28be4a64bf43922dc (diff) | |
| parent | 07c2f169f50bb6cf52cfd3b2a815cfb7c2d34aa8 (diff) | |
Merge pull request #2853 from nautd/kkoppul2/tsc
TSC implementation
| -rw-r--r-- | embassy-stm32/build.rs | 32 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/tsc/enums.rs | 238 | ||||
| -rw-r--r-- | embassy-stm32/src/tsc/mod.rs | 936 |
4 files changed, 1208 insertions, 0 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index e615c6307..4eed6fe7d 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -1091,6 +1091,38 @@ fn main() { | |||
| 1091 | (("octospi", "NCS"), quote!(crate::ospi::NSSPin)), | 1091 | (("octospi", "NCS"), quote!(crate::ospi::NSSPin)), |
| 1092 | (("octospi", "CLK"), quote!(crate::ospi::SckPin)), | 1092 | (("octospi", "CLK"), quote!(crate::ospi::SckPin)), |
| 1093 | (("octospi", "NCLK"), quote!(crate::ospi::NckPin)), | 1093 | (("octospi", "NCLK"), quote!(crate::ospi::NckPin)), |
| 1094 | (("tsc", "G1_IO1"), quote!(crate::tsc::G1IO1Pin)), | ||
| 1095 | (("tsc", "G1_IO2"), quote!(crate::tsc::G1IO2Pin)), | ||
| 1096 | (("tsc", "G1_IO3"), quote!(crate::tsc::G1IO3Pin)), | ||
| 1097 | (("tsc", "G1_IO4"), quote!(crate::tsc::G1IO4Pin)), | ||
| 1098 | (("tsc", "G2_IO1"), quote!(crate::tsc::G2IO1Pin)), | ||
| 1099 | (("tsc", "G2_IO2"), quote!(crate::tsc::G2IO2Pin)), | ||
| 1100 | (("tsc", "G2_IO3"), quote!(crate::tsc::G2IO3Pin)), | ||
| 1101 | (("tsc", "G2_IO4"), quote!(crate::tsc::G2IO4Pin)), | ||
| 1102 | (("tsc", "G3_IO1"), quote!(crate::tsc::G3IO1Pin)), | ||
| 1103 | (("tsc", "G3_IO2"), quote!(crate::tsc::G3IO2Pin)), | ||
| 1104 | (("tsc", "G3_IO3"), quote!(crate::tsc::G3IO3Pin)), | ||
| 1105 | (("tsc", "G3_IO4"), quote!(crate::tsc::G3IO4Pin)), | ||
| 1106 | (("tsc", "G4_IO1"), quote!(crate::tsc::G4IO1Pin)), | ||
| 1107 | (("tsc", "G4_IO2"), quote!(crate::tsc::G4IO2Pin)), | ||
| 1108 | (("tsc", "G4_IO3"), quote!(crate::tsc::G4IO3Pin)), | ||
| 1109 | (("tsc", "G4_IO4"), quote!(crate::tsc::G4IO4Pin)), | ||
| 1110 | (("tsc", "G5_IO1"), quote!(crate::tsc::G5IO1Pin)), | ||
| 1111 | (("tsc", "G5_IO2"), quote!(crate::tsc::G5IO2Pin)), | ||
| 1112 | (("tsc", "G5_IO3"), quote!(crate::tsc::G5IO3Pin)), | ||
| 1113 | (("tsc", "G5_IO4"), quote!(crate::tsc::G5IO4Pin)), | ||
| 1114 | (("tsc", "G6_IO1"), quote!(crate::tsc::G6IO1Pin)), | ||
| 1115 | (("tsc", "G6_IO2"), quote!(crate::tsc::G6IO2Pin)), | ||
| 1116 | (("tsc", "G6_IO3"), quote!(crate::tsc::G6IO3Pin)), | ||
| 1117 | (("tsc", "G6_IO4"), quote!(crate::tsc::G6IO4Pin)), | ||
| 1118 | (("tsc", "G7_IO1"), quote!(crate::tsc::G7IO1Pin)), | ||
| 1119 | (("tsc", "G7_IO2"), quote!(crate::tsc::G7IO2Pin)), | ||
| 1120 | (("tsc", "G7_IO3"), quote!(crate::tsc::G7IO3Pin)), | ||
| 1121 | (("tsc", "G7_IO4"), quote!(crate::tsc::G7IO4Pin)), | ||
| 1122 | (("tsc", "G8_IO1"), quote!(crate::tsc::G8IO1Pin)), | ||
| 1123 | (("tsc", "G8_IO2"), quote!(crate::tsc::G8IO2Pin)), | ||
| 1124 | (("tsc", "G8_IO3"), quote!(crate::tsc::G8IO3Pin)), | ||
| 1125 | (("tsc", "G8_IO4"), quote!(crate::tsc::G8IO4Pin)), | ||
| 1094 | ].into(); | 1126 | ].into(); |
| 1095 | 1127 | ||
| 1096 | for p in METADATA.peripherals { | 1128 | for p in METADATA.peripherals { |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 029e01480..b4b9d5d12 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -105,6 +105,8 @@ pub mod sai; | |||
| 105 | pub mod sdmmc; | 105 | pub mod sdmmc; |
| 106 | #[cfg(spi)] | 106 | #[cfg(spi)] |
| 107 | pub mod spi; | 107 | pub mod spi; |
| 108 | #[cfg(tsc)] | ||
| 109 | pub mod tsc; | ||
| 108 | #[cfg(ucpd)] | 110 | #[cfg(ucpd)] |
| 109 | pub mod ucpd; | 111 | pub mod ucpd; |
| 110 | #[cfg(uid)] | 112 | #[cfg(uid)] |
diff --git a/embassy-stm32/src/tsc/enums.rs b/embassy-stm32/src/tsc/enums.rs new file mode 100644 index 000000000..0d34a43ec --- /dev/null +++ b/embassy-stm32/src/tsc/enums.rs | |||
| @@ -0,0 +1,238 @@ | |||
| 1 | use core::ops::BitOr; | ||
| 2 | |||
| 3 | /// Pin defines | ||
| 4 | #[allow(missing_docs)] | ||
| 5 | pub enum TscIOPin { | ||
| 6 | Group1Io1, | ||
| 7 | Group1Io2, | ||
| 8 | Group1Io3, | ||
| 9 | Group1Io4, | ||
| 10 | Group2Io1, | ||
| 11 | Group2Io2, | ||
| 12 | Group2Io3, | ||
| 13 | Group2Io4, | ||
| 14 | Group3Io1, | ||
| 15 | Group3Io2, | ||
| 16 | Group3Io3, | ||
| 17 | Group3Io4, | ||
| 18 | Group4Io1, | ||
| 19 | Group4Io2, | ||
| 20 | Group4Io3, | ||
| 21 | Group4Io4, | ||
| 22 | Group5Io1, | ||
| 23 | Group5Io2, | ||
| 24 | Group5Io3, | ||
| 25 | Group5Io4, | ||
| 26 | Group6Io1, | ||
| 27 | Group6Io2, | ||
| 28 | Group6Io3, | ||
| 29 | Group6Io4, | ||
| 30 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 31 | Group7Io1, | ||
| 32 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 33 | Group7Io2, | ||
| 34 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 35 | Group7Io3, | ||
| 36 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 37 | Group7Io4, | ||
| 38 | #[cfg(tsc_v3)] | ||
| 39 | Group8Io1, | ||
| 40 | #[cfg(tsc_v3)] | ||
| 41 | Group8Io2, | ||
| 42 | #[cfg(tsc_v3)] | ||
| 43 | Group8Io3, | ||
| 44 | #[cfg(tsc_v3)] | ||
| 45 | Group8Io4, | ||
| 46 | } | ||
| 47 | |||
| 48 | impl BitOr<TscIOPin> for u32 { | ||
| 49 | type Output = u32; | ||
| 50 | fn bitor(self, rhs: TscIOPin) -> Self::Output { | ||
| 51 | let rhs: u32 = rhs.into(); | ||
| 52 | self | rhs | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | impl BitOr<u32> for TscIOPin { | ||
| 57 | type Output = u32; | ||
| 58 | fn bitor(self, rhs: u32) -> Self::Output { | ||
| 59 | let val: u32 = self.into(); | ||
| 60 | val | rhs | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | impl BitOr for TscIOPin { | ||
| 65 | type Output = u32; | ||
| 66 | fn bitor(self, rhs: Self) -> Self::Output { | ||
| 67 | let val: u32 = self.into(); | ||
| 68 | let rhs: u32 = rhs.into(); | ||
| 69 | val | rhs | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | impl Into<u32> for TscIOPin { | ||
| 74 | fn into(self) -> u32 { | ||
| 75 | match self { | ||
| 76 | TscIOPin::Group1Io1 => 0x00000001, | ||
| 77 | TscIOPin::Group1Io2 => 0x00000002, | ||
| 78 | TscIOPin::Group1Io3 => 0x00000004, | ||
| 79 | TscIOPin::Group1Io4 => 0x00000008, | ||
| 80 | TscIOPin::Group2Io1 => 0x00000010, | ||
| 81 | TscIOPin::Group2Io2 => 0x00000020, | ||
| 82 | TscIOPin::Group2Io3 => 0x00000040, | ||
| 83 | TscIOPin::Group2Io4 => 0x00000080, | ||
| 84 | TscIOPin::Group3Io1 => 0x00000100, | ||
| 85 | TscIOPin::Group3Io2 => 0x00000200, | ||
| 86 | TscIOPin::Group3Io3 => 0x00000400, | ||
| 87 | TscIOPin::Group3Io4 => 0x00000800, | ||
| 88 | TscIOPin::Group4Io1 => 0x00001000, | ||
| 89 | TscIOPin::Group4Io2 => 0x00002000, | ||
| 90 | TscIOPin::Group4Io3 => 0x00004000, | ||
| 91 | TscIOPin::Group4Io4 => 0x00008000, | ||
| 92 | TscIOPin::Group5Io1 => 0x00010000, | ||
| 93 | TscIOPin::Group5Io2 => 0x00020000, | ||
| 94 | TscIOPin::Group5Io3 => 0x00040000, | ||
| 95 | TscIOPin::Group5Io4 => 0x00080000, | ||
| 96 | TscIOPin::Group6Io1 => 0x00100000, | ||
| 97 | TscIOPin::Group6Io2 => 0x00200000, | ||
| 98 | TscIOPin::Group6Io3 => 0x00400000, | ||
| 99 | TscIOPin::Group6Io4 => 0x00800000, | ||
| 100 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 101 | TscIOPin::Group7Io1 => 0x01000000, | ||
| 102 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 103 | TscIOPin::Group7Io2 => 0x02000000, | ||
| 104 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 105 | TscIOPin::Group7Io3 => 0x04000000, | ||
| 106 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 107 | TscIOPin::Group7Io4 => 0x08000000, | ||
| 108 | #[cfg(tsc_v3)] | ||
| 109 | TscIOPin::Group8Io1 => 0x10000000, | ||
| 110 | #[cfg(tsc_v3)] | ||
| 111 | TscIOPin::Group8Io2 => 0x20000000, | ||
| 112 | #[cfg(tsc_v3)] | ||
| 113 | TscIOPin::Group8Io3 => 0x40000000, | ||
| 114 | #[cfg(tsc_v3)] | ||
| 115 | TscIOPin::Group8Io4 => 0x80000000, | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | /// Spread Spectrum Deviation | ||
| 121 | #[derive(Copy, Clone)] | ||
| 122 | pub struct SSDeviation(u8); | ||
| 123 | impl SSDeviation { | ||
| 124 | /// Create new deviation value, acceptable inputs are 1-128 | ||
| 125 | pub fn new(val: u8) -> Result<Self, ()> { | ||
| 126 | if val == 0 || val > 128 { | ||
| 127 | return Err(()); | ||
| 128 | } | ||
| 129 | Ok(Self(val - 1)) | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | impl Into<u8> for SSDeviation { | ||
| 134 | fn into(self) -> u8 { | ||
| 135 | self.0 | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | /// Charge transfer pulse cycles | ||
| 140 | #[allow(missing_docs)] | ||
| 141 | #[derive(Copy, Clone, PartialEq)] | ||
| 142 | pub enum ChargeTransferPulseCycle { | ||
| 143 | _1, | ||
| 144 | _2, | ||
| 145 | _3, | ||
| 146 | _4, | ||
| 147 | _5, | ||
| 148 | _6, | ||
| 149 | _7, | ||
| 150 | _8, | ||
| 151 | _9, | ||
| 152 | _10, | ||
| 153 | _11, | ||
| 154 | _12, | ||
| 155 | _13, | ||
| 156 | _14, | ||
| 157 | _15, | ||
| 158 | _16, | ||
| 159 | } | ||
| 160 | |||
| 161 | impl Into<u8> for ChargeTransferPulseCycle { | ||
| 162 | fn into(self) -> u8 { | ||
| 163 | match self { | ||
| 164 | ChargeTransferPulseCycle::_1 => 0, | ||
| 165 | ChargeTransferPulseCycle::_2 => 1, | ||
| 166 | ChargeTransferPulseCycle::_3 => 2, | ||
| 167 | ChargeTransferPulseCycle::_4 => 3, | ||
| 168 | ChargeTransferPulseCycle::_5 => 4, | ||
| 169 | ChargeTransferPulseCycle::_6 => 5, | ||
| 170 | ChargeTransferPulseCycle::_7 => 6, | ||
| 171 | ChargeTransferPulseCycle::_8 => 7, | ||
| 172 | ChargeTransferPulseCycle::_9 => 8, | ||
| 173 | ChargeTransferPulseCycle::_10 => 9, | ||
| 174 | ChargeTransferPulseCycle::_11 => 10, | ||
| 175 | ChargeTransferPulseCycle::_12 => 11, | ||
| 176 | ChargeTransferPulseCycle::_13 => 12, | ||
| 177 | ChargeTransferPulseCycle::_14 => 13, | ||
| 178 | ChargeTransferPulseCycle::_15 => 14, | ||
| 179 | ChargeTransferPulseCycle::_16 => 15, | ||
| 180 | } | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | /// Prescaler divider | ||
| 185 | #[allow(missing_docs)] | ||
| 186 | #[derive(Copy, Clone, PartialEq)] | ||
| 187 | pub enum PGPrescalerDivider { | ||
| 188 | _1, | ||
| 189 | _2, | ||
| 190 | _4, | ||
| 191 | _8, | ||
| 192 | _16, | ||
| 193 | _32, | ||
| 194 | _64, | ||
| 195 | _128, | ||
| 196 | } | ||
| 197 | |||
| 198 | impl Into<u8> for PGPrescalerDivider { | ||
| 199 | fn into(self) -> u8 { | ||
| 200 | match self { | ||
| 201 | PGPrescalerDivider::_1 => 0, | ||
| 202 | PGPrescalerDivider::_2 => 1, | ||
| 203 | PGPrescalerDivider::_4 => 2, | ||
| 204 | PGPrescalerDivider::_8 => 3, | ||
| 205 | PGPrescalerDivider::_16 => 4, | ||
| 206 | PGPrescalerDivider::_32 => 5, | ||
| 207 | PGPrescalerDivider::_64 => 6, | ||
| 208 | PGPrescalerDivider::_128 => 7, | ||
| 209 | } | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | /// Max count | ||
| 214 | #[allow(missing_docs)] | ||
| 215 | #[derive(Copy, Clone)] | ||
| 216 | pub enum MaxCount { | ||
| 217 | _255, | ||
| 218 | _511, | ||
| 219 | _1023, | ||
| 220 | _2047, | ||
| 221 | _4095, | ||
| 222 | _8191, | ||
| 223 | _16383, | ||
| 224 | } | ||
| 225 | |||
| 226 | impl Into<u8> for MaxCount { | ||
| 227 | fn into(self) -> u8 { | ||
| 228 | match self { | ||
| 229 | MaxCount::_255 => 0, | ||
| 230 | MaxCount::_511 => 1, | ||
| 231 | MaxCount::_1023 => 2, | ||
| 232 | MaxCount::_2047 => 3, | ||
| 233 | MaxCount::_4095 => 4, | ||
| 234 | MaxCount::_8191 => 5, | ||
| 235 | MaxCount::_16383 => 6, | ||
| 236 | } | ||
| 237 | } | ||
| 238 | } | ||
diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs new file mode 100644 index 000000000..bf583f04c --- /dev/null +++ b/embassy-stm32/src/tsc/mod.rs | |||
| @@ -0,0 +1,936 @@ | |||
| 1 | //! TSC Peripheral Interface | ||
| 2 | //! | ||
| 3 | //! | ||
| 4 | //! # Example (stm32) | ||
| 5 | //! ``` rust, ignore | ||
| 6 | //! | ||
| 7 | //! let mut device_config = embassy_stm32::Config::default(); | ||
| 8 | //! { | ||
| 9 | //! device_config.rcc.mux = ClockSrc::MSI(Msirange::RANGE_4MHZ); | ||
| 10 | //! } | ||
| 11 | //! | ||
| 12 | //! let context = embassy_stm32::init(device_config); | ||
| 13 | //! | ||
| 14 | //! let config = tsc::Config { | ||
| 15 | //! ct_pulse_high_length: ChargeTransferPulseCycle::_2, | ||
| 16 | //! ct_pulse_low_length: ChargeTransferPulseCycle::_2, | ||
| 17 | //! spread_spectrum: false, | ||
| 18 | //! spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 19 | //! spread_spectrum_prescaler: false, | ||
| 20 | //! pulse_generator_prescaler: PGPrescalerDivider::_4, | ||
| 21 | //! max_count_value: MaxCount::_8191, | ||
| 22 | //! io_default_mode: false, | ||
| 23 | //! synchro_pin_polarity: false, | ||
| 24 | //! acquisition_mode: false, | ||
| 25 | //! max_count_interrupt: false, | ||
| 26 | //! channel_ios: TscIOPin::Group2Io2 | TscIOPin::Group7Io3, | ||
| 27 | //! shield_ios: TscIOPin::Group1Io3.into(), | ||
| 28 | //! sampling_ios: TscIOPin::Group1Io2 | TscIOPin::Group2Io1 | TscIOPin::Group7Io2, | ||
| 29 | //! }; | ||
| 30 | //! | ||
| 31 | //! let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new(); | ||
| 32 | //! g1.set_io2(context.PB13, PinType::Sample); | ||
| 33 | //! g1.set_io3(context.PB14, PinType::Shield); | ||
| 34 | //! | ||
| 35 | //! let mut g2: PinGroup<embassy_stm32::peripherals::TSC, G2> = PinGroup::new(); | ||
| 36 | //! g2.set_io1(context.PB4, PinType::Sample); | ||
| 37 | //! g2.set_io2(context.PB5, PinType::Channel); | ||
| 38 | //! | ||
| 39 | //! let mut g7: PinGroup<embassy_stm32::peripherals::TSC, G7> = PinGroup::new(); | ||
| 40 | //! g7.set_io2(context.PE3, PinType::Sample); | ||
| 41 | //! g7.set_io3(context.PE4, PinType::Channel); | ||
| 42 | //! | ||
| 43 | //! let mut touch_controller = tsc::Tsc::new( | ||
| 44 | //! context.TSC, | ||
| 45 | //! Some(g1), | ||
| 46 | //! Some(g2), | ||
| 47 | //! None, | ||
| 48 | //! None, | ||
| 49 | //! None, | ||
| 50 | //! None, | ||
| 51 | //! Some(g7), | ||
| 52 | //! None, | ||
| 53 | //! config, | ||
| 54 | //! ); | ||
| 55 | //! | ||
| 56 | //! touch_controller.discharge_io(true); | ||
| 57 | //! Timer::after_millis(1).await; | ||
| 58 | //! | ||
| 59 | //! touch_controller.start(); | ||
| 60 | //! | ||
| 61 | //! ``` | ||
| 62 | |||
| 63 | #![macro_use] | ||
| 64 | |||
| 65 | /// Enums defined for peripheral parameters | ||
| 66 | pub mod enums; | ||
| 67 | |||
| 68 | use core::marker::PhantomData; | ||
| 69 | |||
| 70 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 71 | pub use enums::*; | ||
| 72 | |||
| 73 | use crate::gpio::{AFType, AnyPin}; | ||
| 74 | use crate::pac::tsc::Tsc as Regs; | ||
| 75 | use crate::rcc::RccPeripheral; | ||
| 76 | use crate::{peripherals, Peripheral}; | ||
| 77 | |||
| 78 | #[cfg(tsc_v1)] | ||
| 79 | const TSC_NUM_GROUPS: u32 = 6; | ||
| 80 | #[cfg(tsc_v2)] | ||
| 81 | const TSC_NUM_GROUPS: u32 = 7; | ||
| 82 | #[cfg(tsc_v3)] | ||
| 83 | const TSC_NUM_GROUPS: u32 = 8; | ||
| 84 | |||
| 85 | /// Error type defined for TSC | ||
| 86 | #[derive(Debug)] | ||
| 87 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 88 | pub enum Error { | ||
| 89 | /// Test error for TSC | ||
| 90 | Test, | ||
| 91 | } | ||
| 92 | |||
| 93 | /// Pin type definition to control IO parameters | ||
| 94 | pub enum PinType { | ||
| 95 | /// Sensing channel pin connected to an electrode | ||
| 96 | Channel, | ||
| 97 | /// Sampling capacitor pin, one required for every pin group | ||
| 98 | Sample, | ||
| 99 | /// Shield pin connected to capacitive sensing shield | ||
| 100 | Shield, | ||
| 101 | } | ||
| 102 | |||
| 103 | /// Peripheral state | ||
| 104 | #[derive(PartialEq, Clone, Copy)] | ||
| 105 | pub enum State { | ||
| 106 | /// Peripheral is being setup or reconfigured | ||
| 107 | Reset, | ||
| 108 | /// Ready to start acquisition | ||
| 109 | Ready, | ||
| 110 | /// In process of sensor acquisition | ||
| 111 | Busy, | ||
| 112 | /// Error occured during acquisition | ||
| 113 | Error, | ||
| 114 | } | ||
| 115 | |||
| 116 | /// Individual group status checked after acquisition reported as complete | ||
| 117 | /// For groups with multiple channel pins, may take longer because acquisitions | ||
| 118 | /// are done sequentially. Check this status before pulling count for each | ||
| 119 | /// sampled channel | ||
| 120 | #[derive(PartialEq)] | ||
| 121 | pub enum GroupStatus { | ||
| 122 | /// Acquisition for channel still in progress | ||
| 123 | Ongoing, | ||
| 124 | /// Acquisition either not started or complete | ||
| 125 | Complete, | ||
| 126 | } | ||
| 127 | |||
| 128 | /// Group identifier used to interrogate status | ||
| 129 | #[allow(missing_docs)] | ||
| 130 | pub enum Group { | ||
| 131 | One, | ||
| 132 | Two, | ||
| 133 | Three, | ||
| 134 | Four, | ||
| 135 | Five, | ||
| 136 | Six, | ||
| 137 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 138 | Seven, | ||
| 139 | #[cfg(tsc_v3)] | ||
| 140 | Eight, | ||
| 141 | } | ||
| 142 | |||
| 143 | impl Into<usize> for Group { | ||
| 144 | fn into(self) -> usize { | ||
| 145 | match self { | ||
| 146 | Group::One => 0, | ||
| 147 | Group::Two => 1, | ||
| 148 | Group::Three => 2, | ||
| 149 | Group::Four => 3, | ||
| 150 | Group::Five => 4, | ||
| 151 | Group::Six => 5, | ||
| 152 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 153 | Group::Seven => 6, | ||
| 154 | #[cfg(tsc_v3)] | ||
| 155 | Group::Eight => 7, | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | /// Peripheral configuration | ||
| 161 | #[derive(Clone, Copy)] | ||
| 162 | pub struct Config { | ||
| 163 | /// Duration of high state of the charge transfer pulse | ||
| 164 | pub ct_pulse_high_length: ChargeTransferPulseCycle, | ||
| 165 | /// Duration of the low state of the charge transfer pulse | ||
| 166 | pub ct_pulse_low_length: ChargeTransferPulseCycle, | ||
| 167 | /// Enable/disable of spread spectrum feature | ||
| 168 | pub spread_spectrum: bool, | ||
| 169 | /// Adds variable number of periods of the SS clk to pulse high state | ||
| 170 | pub spread_spectrum_deviation: SSDeviation, | ||
| 171 | /// Selects AHB clock divider used to generate SS clk | ||
| 172 | pub spread_spectrum_prescaler: bool, | ||
| 173 | /// Selects AHB clock divider used to generate pulse generator clk | ||
| 174 | pub pulse_generator_prescaler: PGPrescalerDivider, | ||
| 175 | /// Maximum number of charge tranfer pulses that can be generated before error | ||
| 176 | pub max_count_value: MaxCount, | ||
| 177 | /// Defines config of all IOs when no ongoing acquisition | ||
| 178 | pub io_default_mode: bool, | ||
| 179 | /// Polarity of sync input pin | ||
| 180 | pub synchro_pin_polarity: bool, | ||
| 181 | /// Acquisition starts when start bit is set or with sync pin input | ||
| 182 | pub acquisition_mode: bool, | ||
| 183 | /// Enable max count interrupt | ||
| 184 | pub max_count_interrupt: bool, | ||
| 185 | /// Channel IO mask | ||
| 186 | pub channel_ios: u32, | ||
| 187 | /// Shield IO mask | ||
| 188 | pub shield_ios: u32, | ||
| 189 | /// Sampling IO mask | ||
| 190 | pub sampling_ios: u32, | ||
| 191 | } | ||
| 192 | |||
| 193 | impl Default for Config { | ||
| 194 | fn default() -> Self { | ||
| 195 | Self { | ||
| 196 | ct_pulse_high_length: ChargeTransferPulseCycle::_1, | ||
| 197 | ct_pulse_low_length: ChargeTransferPulseCycle::_1, | ||
| 198 | spread_spectrum: false, | ||
| 199 | spread_spectrum_deviation: SSDeviation::new(1).unwrap(), | ||
| 200 | spread_spectrum_prescaler: false, | ||
| 201 | pulse_generator_prescaler: PGPrescalerDivider::_1, | ||
| 202 | max_count_value: MaxCount::_255, | ||
| 203 | io_default_mode: false, | ||
| 204 | synchro_pin_polarity: false, | ||
| 205 | acquisition_mode: false, | ||
| 206 | max_count_interrupt: false, | ||
| 207 | channel_ios: 0, | ||
| 208 | shield_ios: 0, | ||
| 209 | sampling_ios: 0, | ||
| 210 | } | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | /// Pin struct that maintains usage | ||
| 215 | #[allow(missing_docs)] | ||
| 216 | pub struct TscPin<'d, T, C> { | ||
| 217 | _pin: PeripheralRef<'d, AnyPin>, | ||
| 218 | role: PinType, | ||
| 219 | phantom: PhantomData<(T, C)>, | ||
| 220 | } | ||
| 221 | |||
| 222 | enum GroupError { | ||
| 223 | NoSample, | ||
| 224 | ChannelShield, | ||
| 225 | } | ||
| 226 | |||
| 227 | /// Pin group definition | ||
| 228 | /// Pins are organized into groups of four IOs, all groups with a | ||
| 229 | /// sampling channel must also have a sampling capacitor channel. | ||
| 230 | #[allow(missing_docs)] | ||
| 231 | #[derive(Default)] | ||
| 232 | pub struct PinGroup<'d, T, C> { | ||
| 233 | d1: Option<TscPin<'d, T, C>>, | ||
| 234 | d2: Option<TscPin<'d, T, C>>, | ||
| 235 | d3: Option<TscPin<'d, T, C>>, | ||
| 236 | d4: Option<TscPin<'d, T, C>>, | ||
| 237 | } | ||
| 238 | |||
| 239 | impl<'d, T: Instance, C> PinGroup<'d, T, C> { | ||
| 240 | /// Create new sensing group | ||
| 241 | pub fn new() -> Self { | ||
| 242 | Self { | ||
| 243 | d1: None, | ||
| 244 | d2: None, | ||
| 245 | d3: None, | ||
| 246 | d4: None, | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | fn contains_shield(&self) -> bool { | ||
| 251 | let mut shield_count = 0; | ||
| 252 | |||
| 253 | if let Some(pin) = &self.d1 { | ||
| 254 | if let PinType::Shield = pin.role { | ||
| 255 | shield_count += 1; | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | if let Some(pin) = &self.d2 { | ||
| 260 | if let PinType::Shield = pin.role { | ||
| 261 | shield_count += 1; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | if let Some(pin) = &self.d3 { | ||
| 266 | if let PinType::Shield = pin.role { | ||
| 267 | shield_count += 1; | ||
| 268 | } | ||
| 269 | } | ||
| 270 | |||
| 271 | if let Some(pin) = &self.d4 { | ||
| 272 | if let PinType::Shield = pin.role { | ||
| 273 | shield_count += 1; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | shield_count == 1 | ||
| 278 | } | ||
| 279 | |||
| 280 | fn check_group(&self) -> Result<(), GroupError> { | ||
| 281 | let mut channel_count = 0; | ||
| 282 | let mut shield_count = 0; | ||
| 283 | let mut sample_count = 0; | ||
| 284 | if let Some(pin) = &self.d1 { | ||
| 285 | match pin.role { | ||
| 286 | PinType::Channel => { | ||
| 287 | channel_count += 1; | ||
| 288 | } | ||
| 289 | PinType::Shield => { | ||
| 290 | shield_count += 1; | ||
| 291 | } | ||
| 292 | PinType::Sample => { | ||
| 293 | sample_count += 1; | ||
| 294 | } | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | if let Some(pin) = &self.d2 { | ||
| 299 | match pin.role { | ||
| 300 | PinType::Channel => { | ||
| 301 | channel_count += 1; | ||
| 302 | } | ||
| 303 | PinType::Shield => { | ||
| 304 | shield_count += 1; | ||
| 305 | } | ||
| 306 | PinType::Sample => { | ||
| 307 | sample_count += 1; | ||
| 308 | } | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 312 | if let Some(pin) = &self.d3 { | ||
| 313 | match pin.role { | ||
| 314 | PinType::Channel => { | ||
| 315 | channel_count += 1; | ||
| 316 | } | ||
| 317 | PinType::Shield => { | ||
| 318 | shield_count += 1; | ||
| 319 | } | ||
| 320 | PinType::Sample => { | ||
| 321 | sample_count += 1; | ||
| 322 | } | ||
| 323 | } | ||
| 324 | } | ||
| 325 | |||
| 326 | if let Some(pin) = &self.d4 { | ||
| 327 | match pin.role { | ||
| 328 | PinType::Channel => { | ||
| 329 | channel_count += 1; | ||
| 330 | } | ||
| 331 | PinType::Shield => { | ||
| 332 | shield_count += 1; | ||
| 333 | } | ||
| 334 | PinType::Sample => { | ||
| 335 | sample_count += 1; | ||
| 336 | } | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | // Every group requires one sampling capacitor | ||
| 341 | if sample_count != 1 { | ||
| 342 | return Err(GroupError::NoSample); | ||
| 343 | } | ||
| 344 | |||
| 345 | // Each group must have at least one shield or channel IO | ||
| 346 | if shield_count == 0 && channel_count == 0 { | ||
| 347 | return Err(GroupError::ChannelShield); | ||
| 348 | } | ||
| 349 | |||
| 350 | // Any group can either contain channel ios or a shield IO | ||
| 351 | if shield_count != 0 && channel_count != 0 { | ||
| 352 | return Err(GroupError::ChannelShield); | ||
| 353 | } | ||
| 354 | |||
| 355 | // No more than one shield IO is allow per group and amongst all groups | ||
| 356 | if shield_count > 1 { | ||
| 357 | return Err(GroupError::ChannelShield); | ||
| 358 | } | ||
| 359 | |||
| 360 | Ok(()) | ||
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 364 | macro_rules! group_impl { | ||
| 365 | ($group:ident, $trait1:ident, $trait2:ident, $trait3:ident, $trait4:ident) => { | ||
| 366 | impl<'d, T: Instance> PinGroup<'d, T, $group> { | ||
| 367 | #[doc = concat!("Create a new pin1 for ", stringify!($group), " TSC group instance.")] | ||
| 368 | pub fn set_io1(&mut self, pin: impl Peripheral<P = impl $trait1<T>> + 'd, role: PinType) { | ||
| 369 | into_ref!(pin); | ||
| 370 | critical_section::with(|_| { | ||
| 371 | pin.set_low(); | ||
| 372 | pin.set_as_af( | ||
| 373 | pin.af_num(), | ||
| 374 | match role { | ||
| 375 | PinType::Channel => AFType::OutputPushPull, | ||
| 376 | PinType::Sample => AFType::OutputOpenDrain, | ||
| 377 | PinType::Shield => AFType::OutputPushPull, | ||
| 378 | }, | ||
| 379 | ); | ||
| 380 | self.d1 = Some(TscPin { | ||
| 381 | _pin: pin.map_into(), | ||
| 382 | role: role, | ||
| 383 | phantom: PhantomData, | ||
| 384 | }) | ||
| 385 | }) | ||
| 386 | } | ||
| 387 | |||
| 388 | #[doc = concat!("Create a new pin2 for ", stringify!($group), " TSC group instance.")] | ||
| 389 | pub fn set_io2(&mut self, pin: impl Peripheral<P = impl $trait2<T>> + 'd, role: PinType) { | ||
| 390 | into_ref!(pin); | ||
| 391 | critical_section::with(|_| { | ||
| 392 | pin.set_low(); | ||
| 393 | pin.set_as_af( | ||
| 394 | pin.af_num(), | ||
| 395 | match role { | ||
| 396 | PinType::Channel => AFType::OutputPushPull, | ||
| 397 | PinType::Sample => AFType::OutputOpenDrain, | ||
| 398 | PinType::Shield => AFType::OutputPushPull, | ||
| 399 | }, | ||
| 400 | ); | ||
| 401 | self.d2 = Some(TscPin { | ||
| 402 | _pin: pin.map_into(), | ||
| 403 | role: role, | ||
| 404 | phantom: PhantomData, | ||
| 405 | }) | ||
| 406 | }) | ||
| 407 | } | ||
| 408 | |||
| 409 | #[doc = concat!("Create a new pin3 for ", stringify!($group), " TSC group instance.")] | ||
| 410 | pub fn set_io3(&mut self, pin: impl Peripheral<P = impl $trait3<T>> + 'd, role: PinType) { | ||
| 411 | into_ref!(pin); | ||
| 412 | critical_section::with(|_| { | ||
| 413 | pin.set_low(); | ||
| 414 | pin.set_as_af( | ||
| 415 | pin.af_num(), | ||
| 416 | match role { | ||
| 417 | PinType::Channel => AFType::OutputPushPull, | ||
| 418 | PinType::Sample => AFType::OutputOpenDrain, | ||
| 419 | PinType::Shield => AFType::OutputPushPull, | ||
| 420 | }, | ||
| 421 | ); | ||
| 422 | self.d3 = Some(TscPin { | ||
| 423 | _pin: pin.map_into(), | ||
| 424 | role: role, | ||
| 425 | phantom: PhantomData, | ||
| 426 | }) | ||
| 427 | }) | ||
| 428 | } | ||
| 429 | |||
| 430 | #[doc = concat!("Create a new pin4 for ", stringify!($group), " TSC group instance.")] | ||
| 431 | pub fn set_io4(&mut self, pin: impl Peripheral<P = impl $trait4<T>> + 'd, role: PinType) { | ||
| 432 | into_ref!(pin); | ||
| 433 | critical_section::with(|_| { | ||
| 434 | pin.set_low(); | ||
| 435 | pin.set_as_af( | ||
| 436 | pin.af_num(), | ||
| 437 | match role { | ||
| 438 | PinType::Channel => AFType::OutputPushPull, | ||
| 439 | PinType::Sample => AFType::OutputOpenDrain, | ||
| 440 | PinType::Shield => AFType::OutputPushPull, | ||
| 441 | }, | ||
| 442 | ); | ||
| 443 | self.d4 = Some(TscPin { | ||
| 444 | _pin: pin.map_into(), | ||
| 445 | role: role, | ||
| 446 | phantom: PhantomData, | ||
| 447 | }) | ||
| 448 | }) | ||
| 449 | } | ||
| 450 | } | ||
| 451 | }; | ||
| 452 | } | ||
| 453 | |||
| 454 | group_impl!(G1, G1IO1Pin, G1IO2Pin, G1IO3Pin, G1IO4Pin); | ||
| 455 | group_impl!(G2, G2IO1Pin, G2IO2Pin, G2IO3Pin, G2IO4Pin); | ||
| 456 | group_impl!(G3, G3IO1Pin, G3IO2Pin, G3IO3Pin, G3IO4Pin); | ||
| 457 | group_impl!(G4, G4IO1Pin, G4IO2Pin, G4IO3Pin, G4IO4Pin); | ||
| 458 | group_impl!(G5, G5IO1Pin, G5IO2Pin, G5IO3Pin, G5IO4Pin); | ||
| 459 | group_impl!(G6, G6IO1Pin, G6IO2Pin, G6IO3Pin, G6IO4Pin); | ||
| 460 | group_impl!(G7, G7IO1Pin, G7IO2Pin, G7IO3Pin, G7IO4Pin); | ||
| 461 | group_impl!(G8, G8IO1Pin, G8IO2Pin, G8IO3Pin, G8IO4Pin); | ||
| 462 | |||
| 463 | /// Group 1 marker type. | ||
| 464 | pub enum G1 {} | ||
| 465 | /// Group 2 marker type. | ||
| 466 | pub enum G2 {} | ||
| 467 | /// Group 3 marker type. | ||
| 468 | pub enum G3 {} | ||
| 469 | /// Group 4 marker type. | ||
| 470 | pub enum G4 {} | ||
| 471 | /// Group 5 marker type. | ||
| 472 | pub enum G5 {} | ||
| 473 | /// Group 6 marker type. | ||
| 474 | pub enum G6 {} | ||
| 475 | /// Group 7 marker type. | ||
| 476 | pub enum G7 {} | ||
| 477 | /// Group 8 marker type. | ||
| 478 | pub enum G8 {} | ||
| 479 | |||
| 480 | /// TSC driver | ||
| 481 | pub struct Tsc<'d, T: Instance> { | ||
| 482 | _peri: PeripheralRef<'d, T>, | ||
| 483 | _g1: Option<PinGroup<'d, T, G1>>, | ||
| 484 | _g2: Option<PinGroup<'d, T, G2>>, | ||
| 485 | _g3: Option<PinGroup<'d, T, G3>>, | ||
| 486 | _g4: Option<PinGroup<'d, T, G4>>, | ||
| 487 | _g5: Option<PinGroup<'d, T, G5>>, | ||
| 488 | _g6: Option<PinGroup<'d, T, G6>>, | ||
| 489 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 490 | _g7: Option<PinGroup<'d, T, G7>>, | ||
| 491 | #[cfg(tsc_v3)] | ||
| 492 | _g8: Option<PinGroup<'d, T, G8>>, | ||
| 493 | state: State, | ||
| 494 | config: Config, | ||
| 495 | } | ||
| 496 | |||
| 497 | impl<'d, T: Instance> Tsc<'d, T> { | ||
| 498 | /// Create new TSC driver | ||
| 499 | pub fn new( | ||
| 500 | peri: impl Peripheral<P = T> + 'd, | ||
| 501 | g1: Option<PinGroup<'d, T, G1>>, | ||
| 502 | g2: Option<PinGroup<'d, T, G2>>, | ||
| 503 | g3: Option<PinGroup<'d, T, G3>>, | ||
| 504 | g4: Option<PinGroup<'d, T, G4>>, | ||
| 505 | g5: Option<PinGroup<'d, T, G5>>, | ||
| 506 | g6: Option<PinGroup<'d, T, G6>>, | ||
| 507 | #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, T, G7>>, | ||
| 508 | #[cfg(tsc_v3)] g8: Option<PinGroup<'d, T, G8>>, | ||
| 509 | config: Config, | ||
| 510 | ) -> Self { | ||
| 511 | // Need to check valid pin configuration input | ||
| 512 | let g1 = g1.filter(|b| b.check_group().is_ok()); | ||
| 513 | let g2 = g2.filter(|b| b.check_group().is_ok()); | ||
| 514 | let g3 = g3.filter(|b| b.check_group().is_ok()); | ||
| 515 | let g4 = g4.filter(|b| b.check_group().is_ok()); | ||
| 516 | let g5 = g5.filter(|b| b.check_group().is_ok()); | ||
| 517 | let g6 = g6.filter(|b| b.check_group().is_ok()); | ||
| 518 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 519 | let g7 = g7.filter(|b| b.check_group().is_ok()); | ||
| 520 | #[cfg(tsc_v3)] | ||
| 521 | let g8 = g8.filter(|b| b.check_group().is_ok()); | ||
| 522 | |||
| 523 | match Self::check_shields( | ||
| 524 | &g1, | ||
| 525 | &g2, | ||
| 526 | &g3, | ||
| 527 | &g4, | ||
| 528 | &g5, | ||
| 529 | &g6, | ||
| 530 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 531 | &g7, | ||
| 532 | #[cfg(tsc_v3)] | ||
| 533 | &g8, | ||
| 534 | ) { | ||
| 535 | Ok(()) => Self::new_inner( | ||
| 536 | peri, | ||
| 537 | g1, | ||
| 538 | g2, | ||
| 539 | g3, | ||
| 540 | g4, | ||
| 541 | g5, | ||
| 542 | g6, | ||
| 543 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 544 | g7, | ||
| 545 | #[cfg(tsc_v3)] | ||
| 546 | g8, | ||
| 547 | config, | ||
| 548 | ), | ||
| 549 | Err(_) => Self::new_inner( | ||
| 550 | peri, | ||
| 551 | None, | ||
| 552 | None, | ||
| 553 | None, | ||
| 554 | None, | ||
| 555 | None, | ||
| 556 | None, | ||
| 557 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 558 | None, | ||
| 559 | #[cfg(tsc_v3)] | ||
| 560 | None, | ||
| 561 | config, | ||
| 562 | ), | ||
| 563 | } | ||
| 564 | } | ||
| 565 | |||
| 566 | fn check_shields( | ||
| 567 | g1: &Option<PinGroup<'d, T, G1>>, | ||
| 568 | g2: &Option<PinGroup<'d, T, G2>>, | ||
| 569 | g3: &Option<PinGroup<'d, T, G3>>, | ||
| 570 | g4: &Option<PinGroup<'d, T, G4>>, | ||
| 571 | g5: &Option<PinGroup<'d, T, G5>>, | ||
| 572 | g6: &Option<PinGroup<'d, T, G6>>, | ||
| 573 | #[cfg(any(tsc_v2, tsc_v3))] g7: &Option<PinGroup<'d, T, G7>>, | ||
| 574 | #[cfg(tsc_v3)] g8: &Option<PinGroup<'d, T, G8>>, | ||
| 575 | ) -> Result<(), GroupError> { | ||
| 576 | let mut shield_count = 0; | ||
| 577 | |||
| 578 | if let Some(pin_group) = g1 { | ||
| 579 | if pin_group.contains_shield() { | ||
| 580 | shield_count += 1; | ||
| 581 | } | ||
| 582 | }; | ||
| 583 | if let Some(pin_group) = g2 { | ||
| 584 | if pin_group.contains_shield() { | ||
| 585 | shield_count += 1; | ||
| 586 | } | ||
| 587 | }; | ||
| 588 | if let Some(pin_group) = g3 { | ||
| 589 | if pin_group.contains_shield() { | ||
| 590 | shield_count += 1; | ||
| 591 | } | ||
| 592 | }; | ||
| 593 | if let Some(pin_group) = g4 { | ||
| 594 | if pin_group.contains_shield() { | ||
| 595 | shield_count += 1; | ||
| 596 | } | ||
| 597 | }; | ||
| 598 | if let Some(pin_group) = g5 { | ||
| 599 | if pin_group.contains_shield() { | ||
| 600 | shield_count += 1; | ||
| 601 | } | ||
| 602 | }; | ||
| 603 | if let Some(pin_group) = g6 { | ||
| 604 | if pin_group.contains_shield() { | ||
| 605 | shield_count += 1; | ||
| 606 | } | ||
| 607 | }; | ||
| 608 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 609 | if let Some(pin_group) = g7 { | ||
| 610 | if pin_group.contains_shield() { | ||
| 611 | shield_count += 1; | ||
| 612 | } | ||
| 613 | }; | ||
| 614 | #[cfg(tsc_v3)] | ||
| 615 | if let Some(pin_group) = g8 { | ||
| 616 | if pin_group.contains_shield() { | ||
| 617 | shield_count += 1; | ||
| 618 | } | ||
| 619 | }; | ||
| 620 | |||
| 621 | if shield_count > 1 { | ||
| 622 | return Err(GroupError::ChannelShield); | ||
| 623 | } | ||
| 624 | |||
| 625 | Ok(()) | ||
| 626 | } | ||
| 627 | |||
| 628 | fn extract_groups(io_mask: u32) -> u32 { | ||
| 629 | let mut groups: u32 = 0; | ||
| 630 | for idx in 0..TSC_NUM_GROUPS { | ||
| 631 | if io_mask & (0x0F << idx * 4) != 0 { | ||
| 632 | groups |= 1 << idx | ||
| 633 | } | ||
| 634 | } | ||
| 635 | groups | ||
| 636 | } | ||
| 637 | |||
| 638 | fn new_inner( | ||
| 639 | peri: impl Peripheral<P = T> + 'd, | ||
| 640 | g1: Option<PinGroup<'d, T, G1>>, | ||
| 641 | g2: Option<PinGroup<'d, T, G2>>, | ||
| 642 | g3: Option<PinGroup<'d, T, G3>>, | ||
| 643 | g4: Option<PinGroup<'d, T, G4>>, | ||
| 644 | g5: Option<PinGroup<'d, T, G5>>, | ||
| 645 | g6: Option<PinGroup<'d, T, G6>>, | ||
| 646 | #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, T, G7>>, | ||
| 647 | #[cfg(tsc_v3)] g8: Option<PinGroup<'d, T, G8>>, | ||
| 648 | config: Config, | ||
| 649 | ) -> Self { | ||
| 650 | into_ref!(peri); | ||
| 651 | |||
| 652 | T::enable_and_reset(); | ||
| 653 | |||
| 654 | T::REGS.cr().modify(|w| { | ||
| 655 | w.set_tsce(true); | ||
| 656 | w.set_ctph(config.ct_pulse_high_length.into()); | ||
| 657 | w.set_ctpl(config.ct_pulse_low_length.into()); | ||
| 658 | w.set_sse(config.spread_spectrum); | ||
| 659 | // Prevent invalid configuration for pulse generator prescaler | ||
| 660 | if config.ct_pulse_low_length == ChargeTransferPulseCycle::_1 | ||
| 661 | && (config.pulse_generator_prescaler == PGPrescalerDivider::_1 | ||
| 662 | || config.pulse_generator_prescaler == PGPrescalerDivider::_2) | ||
| 663 | { | ||
| 664 | w.set_pgpsc(PGPrescalerDivider::_4.into()); | ||
| 665 | } else if config.ct_pulse_low_length == ChargeTransferPulseCycle::_2 | ||
| 666 | && config.pulse_generator_prescaler == PGPrescalerDivider::_1 | ||
| 667 | { | ||
| 668 | w.set_pgpsc(PGPrescalerDivider::_2.into()); | ||
| 669 | } else { | ||
| 670 | w.set_pgpsc(config.pulse_generator_prescaler.into()); | ||
| 671 | } | ||
| 672 | w.set_ssd(config.spread_spectrum_deviation.into()); | ||
| 673 | w.set_sspsc(config.spread_spectrum_prescaler); | ||
| 674 | |||
| 675 | w.set_mcv(config.max_count_value.into()); | ||
| 676 | w.set_syncpol(config.synchro_pin_polarity); | ||
| 677 | w.set_am(config.acquisition_mode); | ||
| 678 | }); | ||
| 679 | |||
| 680 | // Set IO configuration | ||
| 681 | // Disable Schmitt trigger hysteresis on all used TSC IOs | ||
| 682 | T::REGS | ||
| 683 | .iohcr() | ||
| 684 | .write(|w| w.0 = !(config.channel_ios | config.shield_ios | config.sampling_ios)); | ||
| 685 | |||
| 686 | // Set channel and shield IOs | ||
| 687 | T::REGS.ioccr().write(|w| w.0 = config.channel_ios | config.shield_ios); | ||
| 688 | |||
| 689 | // Set sampling IOs | ||
| 690 | T::REGS.ioscr().write(|w| w.0 = config.sampling_ios); | ||
| 691 | |||
| 692 | // Set the groups to be acquired | ||
| 693 | T::REGS | ||
| 694 | .iogcsr() | ||
| 695 | .write(|w| w.0 = Self::extract_groups(config.channel_ios)); | ||
| 696 | |||
| 697 | // Disable interrupts | ||
| 698 | T::REGS.ier().modify(|w| { | ||
| 699 | w.set_eoaie(false); | ||
| 700 | w.set_mceie(false); | ||
| 701 | }); | ||
| 702 | |||
| 703 | // Clear flags | ||
| 704 | T::REGS.icr().modify(|w| { | ||
| 705 | w.set_eoaic(true); | ||
| 706 | w.set_mceic(true); | ||
| 707 | }); | ||
| 708 | |||
| 709 | Self { | ||
| 710 | _peri: peri, | ||
| 711 | _g1: g1, | ||
| 712 | _g2: g2, | ||
| 713 | _g3: g3, | ||
| 714 | _g4: g4, | ||
| 715 | _g5: g5, | ||
| 716 | _g6: g6, | ||
| 717 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 718 | _g7: g7, | ||
| 719 | #[cfg(tsc_v3)] | ||
| 720 | _g8: g8, | ||
| 721 | state: State::Ready, | ||
| 722 | config, | ||
| 723 | } | ||
| 724 | } | ||
| 725 | |||
| 726 | /// Start charge transfer acquisition | ||
| 727 | pub fn start(&mut self) { | ||
| 728 | self.state = State::Busy; | ||
| 729 | |||
| 730 | // Disable interrupts | ||
| 731 | T::REGS.ier().modify(|w| { | ||
| 732 | w.set_eoaie(false); | ||
| 733 | w.set_mceie(false); | ||
| 734 | }); | ||
| 735 | |||
| 736 | // Clear flags | ||
| 737 | T::REGS.icr().modify(|w| { | ||
| 738 | w.set_eoaic(true); | ||
| 739 | w.set_mceic(true); | ||
| 740 | }); | ||
| 741 | |||
| 742 | // Set the touch sensing IOs not acquired to the default mode | ||
| 743 | T::REGS.cr().modify(|w| { | ||
| 744 | w.set_iodef(self.config.io_default_mode); | ||
| 745 | }); | ||
| 746 | |||
| 747 | // Start the acquisition | ||
| 748 | T::REGS.cr().modify(|w| { | ||
| 749 | w.set_start(true); | ||
| 750 | }); | ||
| 751 | } | ||
| 752 | |||
| 753 | /// Start charge transfer acquisition with interrupts enabled | ||
| 754 | pub fn start_it(&mut self) { | ||
| 755 | self.state = State::Busy; | ||
| 756 | |||
| 757 | // Enable interrupts | ||
| 758 | T::REGS.ier().modify(|w| { | ||
| 759 | w.set_eoaie(true); | ||
| 760 | w.set_mceie(self.config.max_count_interrupt); | ||
| 761 | }); | ||
| 762 | |||
| 763 | // Clear flags | ||
| 764 | T::REGS.icr().modify(|w| { | ||
| 765 | w.set_eoaic(true); | ||
| 766 | w.set_mceic(true); | ||
| 767 | }); | ||
| 768 | |||
| 769 | // Set the touch sensing IOs not acquired to the default mode | ||
| 770 | T::REGS.cr().modify(|w| { | ||
| 771 | w.set_iodef(self.config.io_default_mode); | ||
| 772 | }); | ||
| 773 | |||
| 774 | // Start the acquisition | ||
| 775 | T::REGS.cr().modify(|w| { | ||
| 776 | w.set_start(true); | ||
| 777 | }); | ||
| 778 | } | ||
| 779 | |||
| 780 | /// Stop charge transfer acquisition | ||
| 781 | pub fn stop(&mut self) { | ||
| 782 | T::REGS.cr().modify(|w| { | ||
| 783 | w.set_start(false); | ||
| 784 | }); | ||
| 785 | |||
| 786 | // Set the touch sensing IOs in low power mode | ||
| 787 | T::REGS.cr().modify(|w| { | ||
| 788 | w.set_iodef(false); | ||
| 789 | }); | ||
| 790 | |||
| 791 | // Clear flags | ||
| 792 | T::REGS.icr().modify(|w| { | ||
| 793 | w.set_eoaic(true); | ||
| 794 | w.set_mceic(true); | ||
| 795 | }); | ||
| 796 | |||
| 797 | self.state = State::Ready; | ||
| 798 | } | ||
| 799 | |||
| 800 | /// Stop charge transfer acquisition and clear interrupts | ||
| 801 | pub fn stop_it(&mut self) { | ||
| 802 | T::REGS.cr().modify(|w| { | ||
| 803 | w.set_start(false); | ||
| 804 | }); | ||
| 805 | |||
| 806 | // Set the touch sensing IOs in low power mode | ||
| 807 | T::REGS.cr().modify(|w| { | ||
| 808 | w.set_iodef(false); | ||
| 809 | }); | ||
| 810 | |||
| 811 | // Disable interrupts | ||
| 812 | T::REGS.ier().modify(|w| { | ||
| 813 | w.set_eoaie(false); | ||
| 814 | w.set_mceie(false); | ||
| 815 | }); | ||
| 816 | |||
| 817 | // Clear flags | ||
| 818 | T::REGS.icr().modify(|w| { | ||
| 819 | w.set_eoaic(true); | ||
| 820 | w.set_mceic(true); | ||
| 821 | }); | ||
| 822 | |||
| 823 | self.state = State::Ready; | ||
| 824 | } | ||
| 825 | |||
| 826 | /// Wait for end of acquisition | ||
| 827 | pub fn poll_for_acquisition(&mut self) { | ||
| 828 | while self.get_state() == State::Busy {} | ||
| 829 | } | ||
| 830 | |||
| 831 | /// Get current state of acquisition | ||
| 832 | pub fn get_state(&mut self) -> State { | ||
| 833 | if self.state == State::Busy { | ||
| 834 | if T::REGS.isr().read().eoaf() { | ||
| 835 | if T::REGS.isr().read().mcef() { | ||
| 836 | self.state = State::Error | ||
| 837 | } else { | ||
| 838 | self.state = State::Ready | ||
| 839 | } | ||
| 840 | } | ||
| 841 | } | ||
| 842 | self.state | ||
| 843 | } | ||
| 844 | |||
| 845 | /// Get the individual group status to check acquisition complete | ||
| 846 | pub fn group_get_status(&mut self, index: Group) -> GroupStatus { | ||
| 847 | // Status bits are set by hardware when the acquisition on the corresponding | ||
| 848 | // enabled analog IO group is complete, cleared when new acquisition is started | ||
| 849 | let status = match index { | ||
| 850 | Group::One => T::REGS.iogcsr().read().g1s(), | ||
| 851 | Group::Two => T::REGS.iogcsr().read().g2s(), | ||
| 852 | Group::Three => T::REGS.iogcsr().read().g3s(), | ||
| 853 | Group::Four => T::REGS.iogcsr().read().g4s(), | ||
| 854 | Group::Five => T::REGS.iogcsr().read().g5s(), | ||
| 855 | Group::Six => T::REGS.iogcsr().read().g6s(), | ||
| 856 | #[cfg(any(tsc_v2, tsc_v3))] | ||
| 857 | Group::Seven => T::REGS.iogcsr().read().g7s(), | ||
| 858 | #[cfg(tsc_v3)] | ||
| 859 | Group::Eight => T::REGS.iogcsr().read().g8s(), | ||
| 860 | }; | ||
| 861 | match status { | ||
| 862 | true => GroupStatus::Complete, | ||
| 863 | false => GroupStatus::Ongoing, | ||
| 864 | } | ||
| 865 | } | ||
| 866 | |||
| 867 | /// Get the count for the acquisiton, valid once group status is set | ||
| 868 | pub fn group_get_value(&mut self, index: Group) -> u16 { | ||
| 869 | T::REGS.iogcr(index.into()).read().cnt() | ||
| 870 | } | ||
| 871 | |||
| 872 | /// Discharge the IOs for subsequent acquisition | ||
| 873 | pub fn discharge_io(&mut self, status: bool) { | ||
| 874 | // Set the touch sensing IOs in low power mode | ||
| 875 | T::REGS.cr().modify(|w| { | ||
| 876 | w.set_iodef(!status); | ||
| 877 | }); | ||
| 878 | } | ||
| 879 | } | ||
| 880 | |||
| 881 | impl<'d, T: Instance> Drop for Tsc<'d, T> { | ||
| 882 | fn drop(&mut self) { | ||
| 883 | T::disable(); | ||
| 884 | } | ||
| 885 | } | ||
| 886 | |||
| 887 | pub(crate) trait SealedInstance { | ||
| 888 | const REGS: Regs; | ||
| 889 | } | ||
| 890 | |||
| 891 | /// TSC instance trait | ||
| 892 | #[allow(private_bounds)] | ||
| 893 | pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} | ||
| 894 | |||
| 895 | foreach_peripheral!( | ||
| 896 | (tsc, $inst:ident) => { | ||
| 897 | impl SealedInstance for peripherals::$inst { | ||
| 898 | const REGS: Regs = crate::pac::$inst; | ||
| 899 | } | ||
| 900 | |||
| 901 | impl Instance for peripherals::$inst {} | ||
| 902 | }; | ||
| 903 | ); | ||
| 904 | |||
| 905 | pin_trait!(G1IO1Pin, Instance); | ||
| 906 | pin_trait!(G1IO2Pin, Instance); | ||
| 907 | pin_trait!(G1IO3Pin, Instance); | ||
| 908 | pin_trait!(G1IO4Pin, Instance); | ||
| 909 | pin_trait!(G2IO1Pin, Instance); | ||
| 910 | pin_trait!(G2IO2Pin, Instance); | ||
| 911 | pin_trait!(G2IO3Pin, Instance); | ||
| 912 | pin_trait!(G2IO4Pin, Instance); | ||
| 913 | pin_trait!(G3IO1Pin, Instance); | ||
| 914 | pin_trait!(G3IO2Pin, Instance); | ||
| 915 | pin_trait!(G3IO3Pin, Instance); | ||
| 916 | pin_trait!(G3IO4Pin, Instance); | ||
| 917 | pin_trait!(G4IO1Pin, Instance); | ||
| 918 | pin_trait!(G4IO2Pin, Instance); | ||
| 919 | pin_trait!(G4IO3Pin, Instance); | ||
| 920 | pin_trait!(G4IO4Pin, Instance); | ||
| 921 | pin_trait!(G5IO1Pin, Instance); | ||
| 922 | pin_trait!(G5IO2Pin, Instance); | ||
| 923 | pin_trait!(G5IO3Pin, Instance); | ||
| 924 | pin_trait!(G5IO4Pin, Instance); | ||
| 925 | pin_trait!(G6IO1Pin, Instance); | ||
| 926 | pin_trait!(G6IO2Pin, Instance); | ||
| 927 | pin_trait!(G6IO3Pin, Instance); | ||
| 928 | pin_trait!(G6IO4Pin, Instance); | ||
| 929 | pin_trait!(G7IO1Pin, Instance); | ||
| 930 | pin_trait!(G7IO2Pin, Instance); | ||
| 931 | pin_trait!(G7IO3Pin, Instance); | ||
| 932 | pin_trait!(G7IO4Pin, Instance); | ||
| 933 | pin_trait!(G8IO1Pin, Instance); | ||
| 934 | pin_trait!(G8IO2Pin, Instance); | ||
| 935 | pin_trait!(G8IO3Pin, Instance); | ||
| 936 | pin_trait!(G8IO4Pin, Instance); | ||
