1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
#[cfg(feature = "sync")]
mod hal_imports {
pub use embedded_hal::delay::DelayNs;
pub use embedded_hal::i2c::I2c;
}
#[cfg(feature = "async")]
mod hal_imports {
pub use embedded_hal_async::delay::DelayNs;
pub use embedded_hal_async::i2c::I2c;
}
use crate::{registers::*, Channel, DebounceNumber};
use crate::{Mpr121Address, Mpr121Error};
use hal_imports::*;
/// This is the sensor itself and takes in an I2C Device or bus.
/// See the examples folder for more details.
/// The driver can work in either Async or Sync mode by specifying the the feature "async" or "sync".
pub struct Mpr121<I2C: I2c> {
pub(crate) i2c: I2C,
pub(crate) addr: Mpr121Address,
}
impl<I2C: I2c> Mpr121<I2C> {
/// Default Threshold
pub const DEFAULT_TOUCH_THRESHOLD: u8 = 12;
/// Default Release
pub const DEFAULT_RELEASE_THRESOLD: u8 = 6;
/// The value to be written to soft reset register, to trigger a reset
pub(crate) const SOFT_RESET_VALUE: u8 = 0x63;
///Creates the driver for the given I²C ports. Assumes that the I²C port is configured as master.
///
/// If `use_auto_config` is set, the controller will use its auto configuration routine to setup
/// charging parameters whenever it is transitioned from STOP to START mode.
///
/// Note that we use the same default values as the Adafruit implementation, except for threshold values.
/// Use [set_thresholds](Self::set_thresholds) to define those.
///
/// In the event of an error, returns [Mpr121Error]
#[maybe_async::maybe_async]
pub async fn new(
i2c: I2C,
addr: Mpr121Address,
delay: &mut impl DelayNs,
use_auto_config: bool,
) -> Result<Self, Mpr121Error> {
let mut dev = Mpr121 { i2c, addr };
dev.reset_verify(delay).await?;
// Check for overcurrent
if dev.is_over_current_set().await? {
return Err(Mpr121Error::OverCurrent);
}
// Put Device in Stop Mode
dev.write_register(Register::Ecr, 0x0).await?;
//Initialise the device to the similar settings as Adafruit
dev.set_thresholds(
Self::DEFAULT_TOUCH_THRESHOLD,
Self::DEFAULT_RELEASE_THRESOLD,
)
.await?;
dev.initialise_registers(use_auto_config).await?;
Ok(dev)
}
#[maybe_async::maybe_async]
async fn initialise_registers(&mut self, use_auto_config: bool) -> Result<(), Mpr121Error> {
//Setup Filters MHD==MaximumHalfDelta, NHD=NoiseHalfDelta
// Have a look at 5.5 in the data sheet for more information.
self.write_register(Register::MaximumHalfDeltaRising, 0x01)
.await?;
self.write_register(Register::NoiseCountLimitRising, 0x01)
.await?;
self.write_register(Register::NoiseCountLimitRising, 0x0e)
.await?;
self.write_register(Register::FilterDelayCountLimitRising, 0x00)
.await?;
self.write_register(Register::MaximmHalfDeltaFalling, 0x01)
.await?;
self.write_register(Register::NoiseHalfDeltaFalling, 0x05)
.await?;
self.write_register(Register::NoiseCountLimitFalling, 0x01)
.await?;
self.write_register(Register::FilterDelayCountFalling, 0x00)
.await?;
self.write_register(Register::NoiseHalfDeltaTouched, 0x00)
.await?;
self.write_register(Register::NoiseCountLimitTouched, 0x00)
.await?;
self.write_register(Register::FilterDelayCountLimitTouched, 0x00)
.await?;
self.write_register(Register::Debounce, DebounceNumber::Zero.into())
.await?;
self.write_register(
Register::GlobalChargeDischargeCurrentConfig,
Register::GlobalChargeDischargeCurrentConfig.get_initial_value(),
)
.await?;
self.write_register(Register::GlobalChargeDischargeTimeConfig, 0x20)
.await?;
if use_auto_config {
self.write_register(Register::AutoConfig0, 0x0b).await?;
self.write_register(Register::UpSideLimit, limits::UP_SIDE)
.await?;
self.write_register(Register::TargetLevel, limits::TARGET_LEVEL)
.await?;
self.write_register(Register::LowSideLimit, limits::LOW_SIDE)
.await?;
}
//enable electrodes and return to start mode // See Datasheet 5.11
let calibration_lock_bit = 0b1 << 7;
let ecr_setting = calibration_lock_bit + Channel::NUM_CHANNELS;
self.write_register(Register::Ecr, ecr_setting).await?;
Ok(())
}
/// This method will reset and verify that the correct device is on the bus, if there is a failed read/write in the process or
/// if the device registers do not match what is expected. It is likely that the device is not connected. Due to the nature of this function
/// it should only really be called once as it will reset any prexisting configurations applied
#[maybe_async::maybe_async]
async fn reset_verify(&mut self, delay: &mut impl DelayNs) -> Result<(), Mpr121Error> {
self.reset().await?;
delay.delay_us(100).await;
// Verify that the default registers match up
let register_1 = Register::GlobalChargeDischargeCurrentConfig;
let read_register_1_config = self.read_reg8(register_1).await?;
if read_register_1_config != register_1.get_initial_value() {
return Err(Mpr121Error::WrongDevice {
mismatched_register: register_1,
expected: register_1.get_initial_value(),
actual: read_register_1_config,
});
}
let register_2 = Register::GlobalChargeDischargeTimeConfig;
let read_register_2_config = self.read_reg8(register_2).await?;
if read_register_2_config != register_2.get_initial_value() {
return Err(Mpr121Error::WrongDevice {
mismatched_register: register_2,
expected: register_2.get_initial_value(),
actual: read_register_2_config,
});
}
Ok(())
}
/// Performs a software reset on the device, resetting the MPR121 Touch sensor back to default configuration
#[maybe_async::maybe_async]
pub async fn reset(&mut self) -> Result<(), Mpr121Error> {
let result = self
.write_register(Register::SoftReset, Self::SOFT_RESET_VALUE)
.await;
// Map any read/write errors to a failed reset error
result.err().map(|err| match err {
Mpr121Error::ReadError(reg) => Mpr121Error::ResetFailed {
was_read: true,
reg,
},
Mpr121Error::WriteError(reg) => Mpr121Error::ResetFailed {
was_read: false,
reg,
},
_ => {
unreachable!("There should only be a read or write error at this stage, perhaps a lower level API has changed?")
}
});
Ok(())
}
/// Initializes the driver assuming the sensors address is the default one (0x5a).
/// If this fails, consider searching for the driver.
/// Or following the documentation on setting a driver address, and use [new](Self::new) to specify the address.
///
/// Have a look at [new](Self::new) for further documentation.
#[maybe_async::maybe_async]
pub async fn new_default(i2c: I2C, delay: &mut impl DelayNs) -> Result<Self, Mpr121Error> {
let result = Self::new(i2c, Mpr121Address::Default, delay, true).await?;
Ok(result)
}
/// Returns true if over-current is detected by the device.
/// In that case you probably have to check your circuit
///
/// In the event of an error [Mpr121Error] is returned
#[maybe_async::maybe_async]
pub async fn is_over_current_set(&mut self) -> Result<bool, Mpr121Error> {
const OVER_CURRENT_PROTECTION_FLAG_MASK: u8 = 0b1 << 7;
let read = self.read_reg8(Register::TouchStatus8_11).await?;
//If bit D7 is set, we have OVCF
Ok((read & (OVER_CURRENT_PROTECTION_FLAG_MASK)) > 0)
}
/// Set the touch and release threshold for all channels. Usually the touch threshold is a little bigger than the release
/// threshold. This creates some debounce characteristics. The correct thresholds depend on the application.
///
/// Have a look at [note AN3892](https://www.nxp.com/docs/en/application-note/AN3892.pdf) of the mpr121 guidelines.
/// In the event of an error [Mpr121Error] is returned
#[maybe_async::maybe_async]
pub async fn set_thresholds(&mut self, touch: u8, release: u8) -> Result<(), Mpr121Error> {
for i in 0..Channel::NUM_CHANNELS {
//Note ignoring false set thresholds
self.write_register(
Register::get_threshold_register(
Channel::try_from(i).expect("Channel Iteration Should not fail"),
),
touch,
)
.await?;
self.write_register(
Register::get_release_register(
Channel::try_from(i).expect("Channel Iteration should not fail"),
),
release,
)
.await?;
}
Ok(())
}
/// Sets the count for both touch and release. See 5.7 of the [Mpr121 Data Sheet](https://www.nxp.com/docs/en/data-sheet/MPR121.pdf).
///
/// In the event of an error [Mpr121Error] is returned
#[maybe_async::maybe_async]
pub async fn set_debounce(
&mut self,
trigger_debounce: DebounceNumber,
release_debounce: DebounceNumber,
) -> Result<(), Mpr121Error> {
let bits = (u8::from(release_debounce) << 4) | (u8::from(trigger_debounce));
self.write_register(Register::Debounce, bits).await?;
Ok(())
}
/// Reads the filtered data from touch channels. Noise gets filtered out by the
/// chip. See 5.3 in the data sheet.
///
/// Note that the resulting value is only 10bit wide.
///
/// Otherwise [Mpr121Error] is returned
#[maybe_async::maybe_async]
pub async fn get_filtered(&mut self, channel: Channel) -> Result<u16, Mpr121Error> {
let register = Register::get_filtered_data_msb(channel);
let result = self.read_reg16(register).await?;
Ok(result)
}
/// Reads the baseline data for the channel. Note that this has only a resolution of 8bit.
///
/// Otherwise [Mpr121Error] is returned
#[maybe_async::maybe_async]
pub async fn get_baseline(&mut self, channel: Channel) -> Result<u8, Mpr121Error> {
//NOTE: the original reads a 8bit value and left shifts 2bit.
// While the shift is correct the data sheet mentions:
//
// Although internally the baseline value is 10-bit,
// users can only access the 8 MSB of the 10-bit baseline value through the
// baseline value registers. The read out from the baseline register must
// be left shift two bits before comparing it with the 10-bit
// electrode data.
//
// reading only 8bit and shifting 2bit effectively reduces the resolution to
// 6bit, since we loose the 2MSB.
//
// Therefore we read 16bit, mask out the top 6, and then shift
let register = Register::get_baseline(channel);
let mut value = self.read_reg16(register).await?;
value &= 0b00000011_11111100;
let cast = (value << 2)
.try_into() // If this fails to convert into u8
.map_err(|_| Mpr121Error::DataConversionError(register))?;
Ok(cast)
}
/// Reads the *touched* state of all channels. Returns a u16 where each bit 0..12 indicates whether the
/// pin is touched or not. Use bit shifting / masking to generate a mask, or, if only one sensor's value is
/// needed, use [get_touch_state](Self::get_sensor_touch).
///
/// Otherwise [Mpr121Error] is returned
#[maybe_async::maybe_async]
pub async fn get_touched(&mut self) -> Result<u16, Mpr121Error> {
//mask upper four bits returns the rest
let unmasked = self.read_reg16(Register::TouchStatus0_7).await?;
Ok(unmasked & 0x0fff)
}
///Returns the touch state of the given sensor.
///
/// Otherwise [Mpr121Error] is returned
#[maybe_async::maybe_async]
pub async fn get_sensor_touch(&mut self, channel: Channel) -> Result<bool, Mpr121Error> {
let result = self.get_touched().await?;
Ok(result & channel.get_bit_mask() > 0)
}
}