stm32l4_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::rcc::AHB1;
11use crate::stm32::{TSC};
12use crate::gpio::gpiob::{PB4, PB5, PB6, PB7};
13use crate::gpio::{AF9, Alternate, Output, OpenDrain, PushPull};
14
15#[derive(Debug)]
16pub enum Event {
17    /// Max count error
18    MaxCountError,
19    /// End of acquisition
20    EndOfAcquisition
21}
22
23#[derive(Debug)]
24pub enum Error {
25    /// Max count error
26    MaxCountError,
27    /// Wrong GPIO for reading
28    InvalidPin
29}
30
31pub trait SamplePin<TSC> {
32    const GROUP: u32;
33    const OFFSET: u32;
34}
35impl SamplePin<TSC> for PB4<Alternate<AF9, Output<OpenDrain>>> {
36    const GROUP: u32 = 2;
37    const OFFSET: u32 = 0;
38}
39impl SamplePin<TSC> for PB5<Alternate<AF9, Output<OpenDrain>>> {
40    const GROUP: u32 = 2;
41    const OFFSET: u32 = 1;
42}
43impl SamplePin<TSC> for PB6<Alternate<AF9, Output<OpenDrain>>> {
44    const GROUP: u32 = 2;
45    const OFFSET: u32 = 2;
46}
47impl SamplePin<TSC> for PB7<Alternate<AF9, Output<OpenDrain>>> {
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<AF9, Output<PushPull>>> {
57    const GROUP: u32 = 2;
58    const OFFSET: u32 = 0;
59}
60impl ChannelPin<TSC> for PB5<Alternate<AF9, Output<PushPull>>> {
61    const GROUP: u32 = 2;
62    const OFFSET: u32 = 1;
63}
64impl ChannelPin<TSC> for PB6<Alternate<AF9, Output<PushPull>>> {
65    const GROUP: u32 = 2;
66    const OFFSET: u32 = 2;
67}
68impl ChannelPin<TSC> for PB7<Alternate<AF9, Output<PushPull>>> {
69    const GROUP: u32 = 2;
70    const OFFSET: u32 = 3;
71}
72
73
74pub struct Tsc<SPIN> {
75    sample_pin: SPIN,
76    tsc: TSC
77}
78
79pub struct Config {
80    pub clock_prescale: Option<ClockPrescaler>,
81    pub max_count_error: Option<MaxCountError>,
82}
83
84pub enum ClockPrescaler {
85    Hclk = 0b000,
86    HclkDiv2 = 0b001,
87    HclkDiv4 = 0b010,
88    HclkDiv8 = 0b011,
89    HclkDiv16 = 0b100,
90    HclkDiv32 = 0b101,
91    HclkDiv64 = 0b110,
92    HclkDiv128 = 0b111,
93}
94
95pub enum MaxCountError {
96    /// 000: 255
97    U255 = 000,
98    /// 001: 511
99    U511 = 001,
100    /// 010: 1023
101    U1023 = 010,
102    /// 011: 2047
103    U2047 = 011,
104    /// 100: 4095
105    U4095 = 100,
106    /// 101: 8191
107    U8191 = 101,
108    /// 110: 16383
109    U16383 = 110
110}
111
112impl<SPIN> Tsc<SPIN> {
113    pub fn tsc(tsc: TSC, sample_pin: SPIN, ahb: &mut AHB1, cfg: Option<Config>) -> Self
114        where SPIN: SamplePin<TSC>
115    {
116        /* Enable the peripheral clock */
117        ahb.enr().modify(|_, w| w.tscen().set_bit());
118        ahb.rstr().modify(|_, w| w.tscrst().set_bit());
119        ahb.rstr().modify(|_, w| w.tscrst().clear_bit());
120
121        let config = cfg.unwrap_or(Config {
122            clock_prescale: None,
123            max_count_error: None
124        });
125
126        tsc.cr.write(|w| unsafe {
127            w.ctph()
128                .bits((1 << 28) as u8)
129                .ctpl()
130                .bits((1 << 24) as u8)
131                // TODO configure sse?
132                .sse()
133                .set_bit()
134                .ssd()
135                .bits(16)
136                .pgpsc()
137                .bits(config.clock_prescale.unwrap_or(ClockPrescaler::Hclk) as u8)
138                .mcv()
139                .bits(config.max_count_error.unwrap_or(MaxCountError::U8191) as u8)
140                .tsce()
141                .set_bit()
142        });
143        
144        let bit_pos = SPIN::OFFSET + (4 * (SPIN::GROUP - 1));
145        
146        // Schmitt trigger hysteresis on sample IOs
147        tsc.iohcr.write(|w| unsafe {
148            w.bits(1 << bit_pos)
149        });
150
151        // Set the sampling pin
152        tsc.ioscr.write(|w| unsafe { w.bits(1 << bit_pos) });
153        
154        // set the acquisitiuon groups based of the channel pins, stm32l432xx only has group 2
155        tsc.iogcsr.write(|w| { w.g2e().set_bit() });
156
157        // clear interrupt & flags
158        tsc.icr.write(|w| { 
159            w.eoaic().set_bit()
160                .mceic().set_bit()
161        });
162
163        Tsc {
164            tsc: tsc,
165            sample_pin: sample_pin,
166        }
167    }
168
169    /// Starts a charge acquisition
170    pub fn start<PIN>(&self, _input: &mut PIN) 
171        where PIN: ChannelPin<TSC>
172    {
173        // clear interrupt & flags
174        self.tsc.icr.write(|w| { 
175            w.eoaic().set_bit()
176                .mceic().set_bit()
177        });
178
179        // discharge the caps ready for a new reading
180        self.tsc.cr.modify(|_, w| {
181            w.iodef().clear_bit()
182        });
183
184        let bit_pos = PIN::OFFSET + (4 * (PIN::GROUP - 1));
185
186        // Set the channel pin
187        self.tsc.ioccr.write(|w| unsafe {
188            w.bits(1 << bit_pos)
189        });
190
191        self.tsc.cr.modify(|_, w| { w.start().set_bit() });
192    }
193
194    /// Blocks waiting for a acquisition to complete or for a Max Count Error
195    pub fn acquire<PIN>(&self, input: &mut PIN) -> Result<u16, Error>
196        where PIN: ChannelPin<TSC>
197    {
198        // start the acq
199        self.start(input);
200
201        let result = loop {
202            let isr = self.tsc.isr.read();
203            if isr.eoaf().bit_is_set() {
204                self.tsc.icr.write(|w| { w.eoaic().set_bit() });
205                break Ok(self.read_unchecked())
206            } else if isr.mcef().bit_is_set() {
207                self.tsc.icr.write(|w| { w.mceic().set_bit() });
208                break Err(Error::MaxCountError)
209            }
210        };
211
212        result
213    }
214
215    /// Reads the tsc group 2 count register
216    pub fn read<PIN>(&self, _input: &mut PIN) -> Result<u16, Error>
217        where PIN: ChannelPin<TSC>
218    {
219        let bit_pos = PIN::OFFSET + (4 * (PIN::GROUP - 1));
220        // Read the current channel config
221        let channel = self.tsc.ioccr.read().bits();
222        // if they are equal we have the right pin
223        if channel == (1 << bit_pos) {
224            Ok(self.read_unchecked())
225        } else {
226            Err(Error::InvalidPin)
227        }
228    }
229
230    /// Reads the tsc group 2 count register
231    /// WARNING, just returns the contents of the register! No validation of the correct pin 
232    pub fn read_unchecked(&self) -> u16 {
233        self.tsc.iog2cr.read().cnt().bits()
234    }
235
236    /// Enables an interrupt event
237    pub fn listen(&mut self, event: Event){
238        match event {
239            Event::EndOfAcquisition => {
240                self.tsc.ier.modify(|_, w| w.eoaie().set_bit());
241            },
242            Event::MaxCountError => {
243                self.tsc.ier.modify(|_, w| w.mceie().set_bit());
244            },
245        }
246    }
247
248    /// Disables an interrupt event
249    pub fn unlisten(&self, event: Event) {
250        match event {
251            Event::EndOfAcquisition => {
252                self.tsc.ier.modify(|_, w| w.eoaie().clear_bit());
253            },
254            Event::MaxCountError => {
255                self.tsc.ier.modify(|_, w| w.mceie().clear_bit());
256            },
257        }
258    }
259
260    /// Releases the TSC peripheral and associated pins
261    pub fn free(self) -> (TSC, SPIN) {
262        (self.tsc, self.sample_pin)
263    }
264}