MPR121 being funky? Change the baseline!
Are you working with MPR121? Does it at times start being screwy, having one channel get jammed, or another become unresponsive? Congrats, you’ve stumbled onto this IC being too smart for its own good! Here’s the deal.
MPR121 is a wonderful capacitive touch sensing IC. It can do so much for you - all of that automatically, too. One of the things it does, is ongoing baseline calibration. It can adjust to electrode capacity changing over time, so that even if you go into different environment, your touches still get registered. Well, this is the norm for any self-respecting IC, but I digress. Also, this means it can adjust to you hotplugging electrodes! Very cool and all. What if you have a stable electrode configuration (say, all of your bananas and apples are already connected with jumper wires) and it glitches in some way, as it seems to often happen with mine?
I’m not as skilled as the engineers who designed this IC. Nevertheless, it looks to me that this baseline adjustment happens way too quickly - which makes sense, but also isn’t always desired. Obviously, it also happens while you’re touching it, not just over longer periods of time accumulated. I’ve been reading baseline values out of registers while touching the pads and looking out for any screwy behaviour, and it seems to me that this is what’s responsible for false positive / negative / inverted (!) keypress registration I’ve been dealing with.
What can you do? Well, you can have the IC calibrate for a certain baseline, and then lock that baseline in - disabling baseline tracking. For this, you need to change what values get written into the ECR (0x5E) register - this register controls baseline tracking, aka whether the baseline gets adjusted on an ongoing basis.
For the MicroPython library, this is simple - change CL bits, so, write 0b01
into CL bits of the ECR reg. Look at the page 16 of the datasheet to learn more. Here’s how it looks for me:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# init as usual
mpr = mpr121.MPR121(i2c0, 0x5a)
# idk have the baseline establish itself? prolly unnecessary or too long
sleep(3)
# disabling the IC - stop mode. don't recall why but this is what works for me at the moment, won't test further.
mpr._register8(mpr121.MPR121_ELECTRODE_CONFIG, 0b00000000)
# idk why this sleep either
sleep(0.1)
# enabling the IC with baseline tracking stopped and current baseline locked in
mpr._register8(mpr121.MPR121_ELECTRODE_CONFIG, 0b01001111)
# idk why this sleep either lmao
sleep(0.1)
# sketch to read baseline and filtered values and also state:
a = [mpr.baseline_data(i) for i in range(0, 12)]
b = [mpr.filtered_data(i) for i in range(0, 12)]
print(a, b, mpr.touched())
# "while True:" as needed if you want continuous output for debugging purposes
Tested, works for me, keeps the buttons functional within half a day’s period. Maybe recalibrate it every now and then by writing the default 0b10
into the register? I don’t, and still my problems got solved with this, hopefully yours will too!
This assumes your electrodes are already attached. If you’re fiddling with electrodes, don’t disable baseline tracking, that’s what it’s there for lmao. I got an idea - if you expect to fiddle with electrodes, you can add a button to your project, that will enable baseline tracking while you press it, and disable it once you release it, a “recalibrate” kinda button. Honestly, might just add this to my code.
If you’re using a MicroPython library for MPR121, it might just preserve any changes for you. Adafruit libraries need to be hacked for this, though.
Oh also if you’re wondering about MPR121 LED driving ability, it’s there, just that you need to check appnote AN3894 to learn about it.
Now onto figuring out why IRQ doesn’t work for me, did I burn out some GPIOs yet again somehow…