stm32l4xx_hal/
tsc.rs

1//! Touch sense controller
2//!
3//! From STM32 (https://www.st.com/content/ccc/resource/technical/document/application_note/9d/be/03/8c/5d/8c/49/50/DM00088471.pdf/files/DM00088471.pdf/jcr:content/translations/en.DM00088471.pdf):
4//!
5//! The Cs capacitance is a key parameter for sensitivity. For touchkey sensors, the Cs value is
6//! usually comprised between 8.7nF to 22nF. For linear and rotary touch sensors, the value is
7//! usually comprised between 47nF and 100nF. These values are given as reference for an
8//! electrode fitting a human finger tip size across a few millimeters dielectric panel.
9
10use crate::gpio::gpiob::{PB4, PB5, PB6, PB7};
11use crate::gpio::{Alternate, OpenDrain, PushPull};
12use crate::rcc::{Enable, Reset, AHB1};
13use crate::stm32::TSC;
14
15#[derive(Clone, Copy, Debug, PartialEq)]
16pub enum Event {
17    /// Max count error
18    MaxCountError,
19    /// End of acquisition
20    EndOfAcquisition,
21}
22
23#[derive(Clone, Copy, Debug, PartialEq)]
24pub enum Error {
25    /// Max count error
26    MaxCountError,
27    /// Wrong GPIO for reading - returns the ioccr register
28    InvalidPin(u32),
29}
30
31pub trait SamplePin<TSC> {
32    const GROUP: u32;
33    const OFFSET: u32;
34}
35impl SamplePin<TSC> for PB4<Alternate<OpenDrain, 9>> {
36    const GROUP: u32 = 2;
37    const OFFSET: u32 = 0;
38}
39impl SamplePin<TSC> for PB5<Alternate<OpenDrain, 9>> {
40    const GROUP: u32 = 2;
41    const OFFSET: u32 = 1;
42}
43impl SamplePin<TSC> for PB6<Alternate<OpenDrain, 9>> {
44    const GROUP: u32 = 2;
45    const OFFSET: u32 = 2;
46}
47impl SamplePin<TSC> for PB7<Alternate<OpenDrain, 9>> {
48    const GROUP: u32 = 2;
49    const OFFSET: u32 = 3;
50}
51
52pub trait ChannelPin<TSC> {
53    const GROUP: u32;
54    const OFFSET: u32;
55}
56impl ChannelPin<TSC> for PB4<Alternate<PushPull, 9>> {
57    const GROUP: u32 = 2;
58    const OFFSET: u32 = 0;
59}
60impl ChannelPin<TSC> for PB5<Alternate<PushPull, 9>> {
61    const GROUP: u32 = 2;
62    const OFFSET: u32 = 1;
63}
64impl ChannelPin<TSC> for PB6<Alternate<PushPull, 9>> {
65    const GROUP: u32 = 2;
66    const OFFSET: u32 = 2;
67}
68impl ChannelPin<TSC> for PB7<Alternate<PushPull, 9>> {
69    const GROUP: u32 = 2;
70    const OFFSET: u32 = 3;
71}
72
73pub struct Tsc<SPIN> {
74    sample_pin: SPIN,
75    tsc: TSC,
76}
77
78#[derive(Clone, Copy, Debug, PartialEq)]
79pub struct Config {
80    pub clock_prescale: Option<ClockPrescaler>,
81    pub max_count_error: Option<MaxCountError>,
82    pub charge_transfer_high: Option<ChargeDischargeTime>,
83    pub charge_transfer_low: Option<ChargeDischargeTime>,
84    /// Spread spectrum deviation - a value between 0 and 128
85    pub spread_spectrum_deviation: Option<u8>,
86}
87
88#[derive(Clone, Copy, Debug, PartialEq)]
89pub enum ClockPrescaler {
90    Hclk = 0b000,
91    HclkDiv2 = 0b001,
92    HclkDiv4 = 0b010,
93    HclkDiv8 = 0b011,
94    HclkDiv16 = 0b100,
95    HclkDiv32 = 0b101,
96    HclkDiv64 = 0b110,
97    HclkDiv128 = 0b111,
98}
99
100#[derive(Clone, Copy, Debug, PartialEq)]
101pub enum MaxCountError {
102    /// 000: 255
103    U255 = 0b000,
104    /// 001: 511
105    U511 = 0b001,
106    /// 010: 1023
107    U1023 = 0b010,
108    /// 011: 2047
109    U2047 = 0b011,
110    /// 100: 4095
111    U4095 = 0b100,
112    /// 101: 8191
113    U8191 = 0b101,
114    /// 110: 16383
115    U16383 = 0b110,
116}
117
118#[derive(Clone, Copy, Debug, PartialEq)]
119/// How many tsc cycles are spent charging / discharging
120pub enum ChargeDischargeTime {
121    C1 = 0b0000,
122    C2 = 0b0001,
123    C3 = 0b0010,
124    C4 = 0b0011,
125    C5 = 0b0100,
126    C6 = 0b0101,
127    C7 = 0b0110,
128    C8 = 0b0111,
129    C9 = 0b1000,
130    C10 = 0b1001,
131    C11 = 0b1010,
132    C12 = 0b1011,
133    C13 = 0b1100,
134    C14 = 0b1101,
135    C15 = 0b1110,
136    C16 = 0b1111,
137}
138
139impl<SPIN> Tsc<SPIN> {
140    pub fn tsc(tsc: TSC, sample_pin: SPIN, ahb: &mut AHB1, cfg: Option<Config>) -> Self
141    where
142        SPIN: SamplePin<TSC>,
143    {
144        /* Enable the peripheral clock */
145        TSC::enable(ahb);
146        TSC::reset(ahb);
147
148        let config = cfg.unwrap_or(Config {
149            clock_prescale: None,
150            max_count_error: None,
151            charge_transfer_high: None,
152            charge_transfer_low: None,
153            spread_spectrum_deviation: None,
154        });
155
156        tsc.cr.write(|w| unsafe {
157            w.ctph()
158                .bits(
159                    config
160                        .charge_transfer_high
161                        .unwrap_or(ChargeDischargeTime::C2) as u8,
162                )
163                .ctpl()
164                .bits(
165                    config
166                        .charge_transfer_low
167                        .unwrap_or(ChargeDischargeTime::C2) as u8,
168                )
169                .pgpsc()
170                .bits(config.clock_prescale.unwrap_or(ClockPrescaler::Hclk) as u8)
171                .mcv()
172                .bits(config.max_count_error.unwrap_or(MaxCountError::U8191) as u8)
173                .sse()
174                .bit(config.spread_spectrum_deviation.is_some())
175                .ssd()
176                .bits(config.spread_spectrum_deviation.unwrap_or(0u8))
177                .tsce()
178                .set_bit()
179        });
180
181        let bit_pos = SPIN::OFFSET + (4 * (SPIN::GROUP - 1));
182
183        // Schmitt trigger hysteresis on sample IOs
184        tsc.iohcr.write(|w| unsafe { w.bits(1 << bit_pos) });
185
186        // Set the sampling pin
187        tsc.ioscr.write(|w| unsafe { w.bits(1 << bit_pos) });
188
189        // set the acquisitiuon groups based of the channel pins, stm32l432xx only has group 2
190        tsc.iogcsr.write(|w| w.g2e().set_bit());
191
192        // clear interrupt & flags
193        tsc.icr.write(|w| w.eoaic().set_bit().mceic().set_bit());
194
195        Tsc { tsc, sample_pin }
196    }
197
198    /// Starts a charge acquisition
199    pub fn start<PIN>(&self, _input: &mut PIN)
200    where
201        PIN: ChannelPin<TSC>,
202    {
203        self.clear(Event::EndOfAcquisition);
204        self.clear(Event::MaxCountError);
205
206        // discharge the caps ready for a new reading
207        self.tsc.cr.modify(|_, w| w.iodef().clear_bit());
208
209        let bit_pos = PIN::OFFSET + (4 * (PIN::GROUP - 1));
210
211        // Set the channel pin
212        self.tsc.ioccr.write(|w| unsafe { w.bits(1 << bit_pos) });
213
214        self.tsc.cr.modify(|_, w| w.start().set_bit());
215    }
216
217    /// Clear interrupt & flags
218    pub fn clear(&self, event: Event) {
219        match event {
220            Event::EndOfAcquisition => {
221                self.tsc.icr.write(|w| w.eoaic().set_bit());
222            }
223            Event::MaxCountError => {
224                self.tsc.icr.write(|w| w.mceic().set_bit());
225            }
226        }
227    }
228
229    /// Blocks waiting for a acquisition to complete or for a Max Count Error
230    pub fn acquire<PIN>(&self, input: &mut PIN) -> Result<u16, Error>
231    where
232        PIN: ChannelPin<TSC>,
233    {
234        // start the acq
235        self.start(input);
236
237        let result = loop {
238            let isr = self.tsc.isr.read();
239            if isr.eoaf().bit_is_set() {
240                self.tsc.icr.write(|w| w.eoaic().set_bit());
241                break Ok(self.read_unchecked());
242            } else if isr.mcef().bit_is_set() {
243                self.tsc.icr.write(|w| w.mceic().set_bit());
244                break Err(Error::MaxCountError);
245            }
246        };
247        self.tsc.ioccr.write(|w| unsafe { w.bits(0b0) }); // clear channel register
248        result
249    }
250
251    /// Reads the tsc group 2 count register
252    pub fn read<PIN>(&self, _input: &mut PIN) -> Result<u16, Error>
253    where
254        PIN: ChannelPin<TSC>,
255    {
256        let bit_pos = PIN::OFFSET + (4 * (PIN::GROUP - 1));
257        // Read the current channel config
258        let channel = self.tsc.ioccr.read().bits();
259        // if they are equal we have the right pin
260        if channel == (1 << bit_pos) {
261            Ok(self.read_unchecked())
262        } else {
263            Err(Error::InvalidPin(channel))
264        }
265    }
266
267    /// Reads the tsc group 2 count register
268    /// WARNING, just returns the contents of the register! No validation of the correct pin
269    pub fn read_unchecked(&self) -> u16 {
270        self.tsc.iog2cr.read().cnt().bits()
271    }
272
273    /// Is the tsc performing an aquisition
274    pub fn in_progress(&mut self) -> bool {
275        self.tsc.cr.read().start().bit_is_set()
276    }
277
278    /// Enables an interrupt event
279    pub fn listen(&mut self, event: Event) {
280        match event {
281            Event::EndOfAcquisition => {
282                self.tsc.ier.modify(|_, w| w.eoaie().set_bit());
283            }
284            Event::MaxCountError => {
285                self.tsc.ier.modify(|_, w| w.mceie().set_bit());
286            }
287        }
288    }
289
290    /// Disables an interrupt event
291    pub fn unlisten(&self, event: Event) {
292        match event {
293            Event::EndOfAcquisition => {
294                self.tsc.ier.modify(|_, w| w.eoaie().clear_bit());
295            }
296            Event::MaxCountError => {
297                self.tsc.ier.modify(|_, w| w.mceie().clear_bit());
298            }
299        }
300    }
301
302    /// Releases the TSC peripheral and associated pins
303    pub fn free(self) -> (TSC, SPIN) {
304        (self.tsc, self.sample_pin)
305    }
306}