stm32f0xx_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::*;
11use crate::pac::TSC;
12use crate::rcc::Rcc;
13
14#[derive(Debug)]
15pub enum Event {
16    /// Max count error
17    MaxCountError,
18    /// End of acquisition
19    EndOfAcquisition,
20}
21
22#[derive(Debug)]
23pub enum Error {
24    /// Max count error
25    MaxCountError,
26    /// Wrong GPIO for reading
27    InvalidPin,
28}
29
30pub trait TscPin<TSC> {
31    type GROUP;
32    type OFFSET;
33
34    /// Returns the group a pin belongs to
35    fn group() -> Self::GROUP;
36
37    /// Returns the offset of the pin within the control registers
38    fn offset() -> Self::OFFSET;
39}
40
41macro_rules! tsc_pins {
42    ($($pin:ty => ($group:expr,$offset:expr)),+ $(,)*) => {
43        $(
44            impl TscPin<TSC> for $pin {
45                type GROUP = u8;
46                type OFFSET = u8;
47
48                fn group() -> u8 { $group }
49                fn offset() -> u8 { $offset }
50            }
51        )+
52    };
53}
54
55tsc_pins!(
56    gpioa::PA0<Alternate<AF3>> => (1_u8, 1_u8),
57    gpioa::PA1<Alternate<AF3>> => (1_u8, 2_u8),
58    gpioa::PA2<Alternate<AF3>> => (1_u8, 3_u8),
59    gpioa::PA3<Alternate<AF3>> => (1_u8, 4_u8),
60);
61
62tsc_pins!(
63    gpioa::PA4<Alternate<AF3>> => (2_u8, 1_u8),
64    gpioa::PA5<Alternate<AF3>> => (2_u8, 2_u8),
65    gpioa::PA6<Alternate<AF3>> => (2_u8, 3_u8),
66    gpioa::PA7<Alternate<AF3>> => (2_u8, 4_u8),
67);
68
69// all with a TSC minus 42 and 48
70#[cfg(any(
71    feature = "stm32f051",
72    feature = "stm32f058",
73    feature = "stm32f071",
74    feature = "stm32f072",
75    feature = "stm32f078",
76    feature = "stm32f091",
77    feature = "stm32f098"
78))]
79tsc_pins!( gpioc::PC5<Alternate<AF0>> => (3_u8, 1_u8) );
80
81tsc_pins!(
82    gpiob::PB0<Alternate<AF3>> => (3_u8, 2_u8),
83    gpiob::PB1<Alternate<AF3>> => (3_u8, 3_u8),
84);
85
86// all with a TCS minus 58, 78 and 98
87#[cfg(any(
88    feature = "stm32f042",
89    feature = "stm32f048",
90    feature = "stm32f051",
91    feature = "stm32f071",
92    feature = "stm32f072",
93    feature = "stm32f091"
94))]
95tsc_pins!( gpiob::PB2<Alternate<AF3>> => (3_u8, 4_u8) );
96
97tsc_pins!(
98    gpioa::PA9<Alternate<AF3>> => (4_u8, 1_u8),
99    gpioa::PA10<Alternate<AF3>> => (4_u8, 2_u8),
100    gpioa::PA11<Alternate<AF3>> => (4_u8, 3_u8),
101    gpioa::PA12<Alternate<AF3>> => (4_u8, 4_u8),
102);
103
104tsc_pins!(
105    gpiob::PB3<Alternate<AF3>> => (5_u8, 1_u8),
106    gpiob::PB4<Alternate<AF3>> => (5_u8, 2_u8),
107    gpiob::PB6<Alternate<AF3>> => (5_u8, 3_u8),
108    gpiob::PB7<Alternate<AF3>> => (5_u8, 4_u8),
109);
110
111// all with a TSC minus 42 and 48
112#[cfg(any(
113    feature = "stm32f051",
114    feature = "stm32f058",
115    feature = "stm32f071",
116    feature = "stm32f072",
117    feature = "stm32f078",
118    feature = "stm32f091",
119    feature = "stm32f098"
120))]
121tsc_pins!(
122    gpiob::PB11<Alternate<AF3>> => (6_u8, 1_u8),
123    gpiob::PB12<Alternate<AF3>> => (6_u8, 2_u8),
124    gpiob::PB13<Alternate<AF3>> => (6_u8, 3_u8),
125    gpiob::PB14<Alternate<AF3>> => (6_u8, 4_u8),
126);
127
128// all with a TSC and gpioe
129#[cfg(any(
130    feature = "stm32f071",
131    feature = "stm32f072",
132    feature = "stm32f078",
133    feature = "stm32f091",
134    feature = "stm32f098"
135))]
136tsc_pins!(
137    gpioe::PE2<Alternate<AF3>> => (7_u8, 1_u8),
138    gpioe::PE3<Alternate<AF3>> => (7_u8, 2_u8),
139    gpioe::PE4<Alternate<AF3>> => (7_u8, 3_u8),
140    gpioe::PE5<Alternate<AF3>> => (7_u8, 4_u8),
141);
142
143// all with a TSC and gpiod
144#[cfg(any(
145    feature = "stm32f071",
146    feature = "stm32f072",
147    feature = "stm32f078",
148    feature = "stm32f091",
149    feature = "stm32f098"
150))]
151tsc_pins!(
152    gpiod::PD12<Alternate<AF3>> => (8_u8, 1_u8),
153    gpiod::PD13<Alternate<AF3>> => (8_u8, 2_u8),
154    gpiod::PD14<Alternate<AF3>> => (8_u8, 3_u8),
155    gpiod::PD15<Alternate<AF3>> => (8_u8, 4_u8),
156);
157
158pub struct Tsc {
159    tsc: TSC,
160}
161
162#[derive(Debug)]
163pub struct Config {
164    pub clock_prescale: Option<ClockPrescaler>,
165    pub max_count: Option<MaxCount>,
166    pub charge_transfer_high: Option<ChargeDischargeTime>,
167    pub charge_transfer_low: Option<ChargeDischargeTime>,
168}
169
170#[derive(Debug)]
171pub enum ClockPrescaler {
172    Hclk = 0b000,
173    HclkDiv2 = 0b001,
174    HclkDiv4 = 0b010,
175    HclkDiv8 = 0b011,
176    HclkDiv16 = 0b100,
177    HclkDiv32 = 0b101,
178    HclkDiv64 = 0b110,
179    HclkDiv128 = 0b111,
180}
181
182#[derive(Debug)]
183pub enum MaxCount {
184    /// 000: 255
185    U255 = 0b000,
186    /// 001: 511
187    U511 = 0b001,
188    /// 010: 1023
189    U1023 = 0b010,
190    /// 011: 2047
191    U2047 = 0b011,
192    /// 100: 4095
193    U4095 = 0b100,
194    /// 101: 8191
195    U8191 = 0b101,
196    /// 110: 16383
197    U16383 = 0b110,
198}
199
200#[derive(Debug)]
201/// How many tsc cycles are spent charging / discharging
202pub enum ChargeDischargeTime {
203    C1 = 0b0000,
204    C2 = 0b0001,
205    C3 = 0b0010,
206    C4 = 0b0011,
207    C5 = 0b0100,
208    C6 = 0b0101,
209    C7 = 0b0110,
210    C8 = 0b0111,
211    C9 = 0b1000,
212    C10 = 0b1001,
213    C11 = 0b1010,
214    C12 = 0b1011,
215    C13 = 0b1100,
216    C14 = 0b1101,
217    C15 = 0b1110,
218    C16 = 0b1111,
219}
220
221impl Tsc {
222    /// Initialise the touch controller peripheral
223    pub fn tsc(tsc: TSC, rcc: &mut Rcc, cfg: Option<Config>) -> Self {
224        // Enable the peripheral clock
225        rcc.regs.ahbenr.modify(|_, w| w.tscen().set_bit());
226        rcc.regs.ahbrstr.modify(|_, w| w.tscrst().set_bit());
227        rcc.regs.ahbrstr.modify(|_, w| w.tscrst().clear_bit());
228
229        let config = cfg.unwrap_or(Config {
230            clock_prescale: None,
231            max_count: None,
232            charge_transfer_high: None,
233            charge_transfer_low: None,
234        });
235
236        tsc.cr.write(|w| unsafe {
237            w.ctph()
238                .bits(
239                    config
240                        .charge_transfer_high
241                        .unwrap_or(ChargeDischargeTime::C2) as u8,
242                )
243                .ctpl()
244                .bits(
245                    config
246                        .charge_transfer_low
247                        .unwrap_or(ChargeDischargeTime::C2) as u8,
248                )
249                .sse()
250                .set_bit()
251                .ssd()
252                .bits(16)
253                .pgpsc()
254                .bits(config.clock_prescale.unwrap_or(ClockPrescaler::HclkDiv16) as u8)
255                .mcv()
256                .bits(config.max_count.unwrap_or(MaxCount::U8191) as u8)
257                .tsce()
258                .set_bit()
259        });
260
261        // clear interrupt & flags
262        tsc.icr.write(|w| w.eoaic().set_bit().mceic().set_bit());
263
264        Tsc { tsc }
265    }
266
267    /// Set up sample group
268    pub fn setup_sample_group<PIN>(&mut self, _: &mut PIN)
269    where
270        PIN: TscPin<TSC, GROUP = u8, OFFSET = u8>,
271    {
272        let bit_pos = PIN::offset() - 1 + (4 * (PIN::group() - 1));
273        let group_pos = PIN::group() - 1;
274
275        // Schmitt trigger hysteresis on sample IOs
276        self.tsc
277            .iohcr
278            .modify(|r, w| unsafe { w.bits(r.bits() | 1 << bit_pos) });
279
280        // Set the sampling pin
281        self.tsc
282            .ioscr
283            .modify(|r, w| unsafe { w.bits(r.bits() | 1 << bit_pos) });
284
285        // Set the acquisition group based on the channel pins
286        self.tsc
287            .iogcsr
288            .modify(|r, w| unsafe { w.bits(r.bits() | 1 << group_pos) });
289    }
290
291    /// Add a GPIO for use as a channel
292    pub fn enable_channel<PIN>(&self, _channel: &mut PIN)
293    where
294        PIN: TscPin<TSC, GROUP = u8, OFFSET = u8>,
295    {
296        let bit_pos = PIN::offset() - 1 + (4 * (PIN::group() - 1));
297
298        // Set a channel pin
299        self.tsc
300            .ioccr
301            .modify(|r, w| unsafe { w.bits(r.bits() | 1 << bit_pos) });
302    }
303
304    /// Remove a GPIO from use as a channel
305    pub fn disable_channel<PIN>(&self, _channel: &mut PIN)
306    where
307        PIN: TscPin<TSC, GROUP = u8, OFFSET = u8>,
308    {
309        let bit_pos = PIN::offset() - 1 + (4 * (PIN::group() - 1));
310
311        // Remove a channel pin
312        self.tsc
313            .ioccr
314            .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << bit_pos)) });
315    }
316
317    /// Starts a charge acquisition
318    pub fn start(&self) {
319        self.clear(Event::EndOfAcquisition);
320        self.clear(Event::MaxCountError);
321
322        // Discharge the caps ready for a new reading
323        self.tsc.cr.modify(|_, w| w.iodef().clear_bit());
324        self.tsc.cr.modify(|_, w| w.start().set_bit());
325    }
326
327    /// Check for events on the TSC
328    pub fn check_event(&self) -> Option<Event> {
329        let isr = self.tsc.isr.read();
330        if isr.eoaf().bit_is_set() {
331            Some(Event::EndOfAcquisition)
332        } else if isr.mcef().bit_is_set() {
333            Some(Event::MaxCountError)
334        } else {
335            None
336        }
337    }
338
339    /// Clear interrupt & flags
340    pub fn clear(&self, event: Event) {
341        match event {
342            Event::EndOfAcquisition => {
343                self.tsc.icr.write(|w| w.eoaic().set_bit());
344            }
345            Event::MaxCountError => {
346                self.tsc.icr.write(|w| w.mceic().set_bit());
347            }
348        }
349    }
350
351    /// Blocks waiting for a acquisition to complete or for a Max Count Error
352    pub fn acquire(&self) -> Result<(), Error> {
353        // Start the acquisition
354        self.start();
355
356        loop {
357            match self.check_event() {
358                Some(Event::MaxCountError) => {
359                    self.clear(Event::MaxCountError);
360                    break Err(Error::MaxCountError);
361                }
362                Some(Event::EndOfAcquisition) => {
363                    self.clear(Event::EndOfAcquisition);
364                    break Ok(());
365                }
366                None => {}
367            }
368        }
369    }
370
371    /// Reads the group count register
372    pub fn read<PIN>(&self, _input: &mut PIN) -> Result<u16, Error>
373    where
374        PIN: TscPin<TSC, GROUP = u8, OFFSET = u8>,
375    {
376        let bit_pos = PIN::offset() - 1 + (4 * (PIN::group() - 1));
377
378        // Read the current channel config
379        let channel = self.tsc.ioccr.read().bits();
380
381        // Check whether one of the enabled pins was supplied
382        if channel & (1 << bit_pos) != 0 {
383            Ok(self.read_unchecked(PIN::group()))
384        } else {
385            Err(Error::InvalidPin)
386        }
387    }
388
389    /// Reads the tsc group count register
390    pub fn read_unchecked(&self, group: u8) -> u16 {
391        match group {
392            1 => self.tsc.iog1cr.read().cnt().bits(),
393            2 => self.tsc.iog2cr.read().cnt().bits(),
394            3 => self.tsc.iog3cr.read().cnt().bits(),
395            4 => self.tsc.iog4cr.read().cnt().bits(),
396            5 => self.tsc.iog5cr.read().cnt().bits(),
397            6 => self.tsc.iog6cr.read().cnt().bits(),
398            _ => 0,
399        }
400    }
401
402    /// Enables an interrupt event
403    pub fn listen(&mut self, event: Event) {
404        match event {
405            Event::EndOfAcquisition => {
406                self.tsc.ier.modify(|_, w| w.eoaie().set_bit());
407            }
408            Event::MaxCountError => {
409                self.tsc.ier.modify(|_, w| w.mceie().set_bit());
410            }
411        }
412    }
413
414    /// Disables an interrupt event
415    pub fn unlisten(&self, event: Event) {
416        match event {
417            Event::EndOfAcquisition => {
418                self.tsc.ier.modify(|_, w| w.eoaie().clear_bit());
419            }
420            Event::MaxCountError => {
421                self.tsc.ier.modify(|_, w| w.mceie().clear_bit());
422            }
423        }
424    }
425
426    /// Releases the TSC peripheral
427    pub fn free(self) -> TSC {
428        self.tsc
429    }
430}