A device driver for the Freescale MPR121 capactive touch IC. Not optimized for any particular system, just a starting point to get the chip up in running in no time. Changes to registers init() method will tailor the library for end system use.

Dependents:   Seeed_Grove_I2C_Touch_Example MPR121_HelloWorld mbed_petbottle_holder_shikake test_DEV-10508 ... more

Datasheet:

http://cache.freescale.com/files/sensors/doc/data_sheet/MPR121.pdf

Information

Must add pull-ups to the I2C bus!!

Committer:
sam_grove
Date:
Fri Mar 29 21:32:38 2013 +0000
Revision:
2:4c0d4b90a3ed
Parent:
1:cee45334b36a
Child:
3:828260f21de6
Updated documentation and added LogUtil class

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sam_grove 0:42add775212a 1 /**
sam_grove 0:42add775212a 2 * @file MPR121.cpp
sam_grove 0:42add775212a 3 * @brief Device driver - MPR121 capactiive touch IC
sam_grove 0:42add775212a 4 * @author sam grove
sam_grove 0:42add775212a 5 * @version 1.0
sam_grove 0:42add775212a 6 * @see http://cache.freescale.com/files/sensors/doc/data_sheet/MPR121.pdf
sam_grove 0:42add775212a 7 *
sam_grove 0:42add775212a 8 * Copyright (c) 2013
sam_grove 0:42add775212a 9 *
sam_grove 0:42add775212a 10 * Licensed under the Apache License, Version 2.0 (the "License");
sam_grove 0:42add775212a 11 * you may not use this file except in compliance with the License.
sam_grove 0:42add775212a 12 * You may obtain a copy of the License at
sam_grove 0:42add775212a 13 *
sam_grove 0:42add775212a 14 * http://www.apache.org/licenses/LICENSE-2.0
sam_grove 0:42add775212a 15 *
sam_grove 0:42add775212a 16 * Unless required by applicable law or agreed to in writing, software
sam_grove 0:42add775212a 17 * distributed under the License is distributed on an "AS IS" BASIS,
sam_grove 0:42add775212a 18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
sam_grove 0:42add775212a 19 * See the License for the specific language governing permissions and
sam_grove 0:42add775212a 20 * limitations under the License.
sam_grove 0:42add775212a 21 */
sam_grove 0:42add775212a 22
sam_grove 0:42add775212a 23 #include "MPR121.h"
sam_grove 0:42add775212a 24
sam_grove 0:42add775212a 25 MPR121::MPR121(I2C &i2c, InterruptIn &pin, MPR121_ADDR i2c_addr)
sam_grove 0:42add775212a 26 {
sam_grove 0:42add775212a 27 _i2c = &i2c;
sam_grove 0:42add775212a 28 _irq = &pin;
sam_grove 0:42add775212a 29 _i2c_addr = (i2c_addr << 1);
sam_grove 0:42add775212a 30
sam_grove 0:42add775212a 31 return;
sam_grove 0:42add775212a 32 }
sam_grove 0:42add775212a 33
sam_grove 0:42add775212a 34 void MPR121::init(void)
sam_grove 0:42add775212a 35 {
sam_grove 0:42add775212a 36 uint8_t i = 0;
sam_grove 0:42add775212a 37 // set the i2c speed
sam_grove 0:42add775212a 38 _i2c->frequency(400000);
sam_grove 0:42add775212a 39 // irq is open-collector and active-low
sam_grove 0:42add775212a 40 _irq->mode(PullUp);
sam_grove 0:42add775212a 41
sam_grove 0:42add775212a 42 // setup and registers - start with POR values (must be in stop mode)
sam_grove 0:42add775212a 43 MPR121::writeRegister(SRST, 0x63); //REG 0x80
sam_grove 0:42add775212a 44
sam_grove 0:42add775212a 45 // baseline < filtered data = touch (set by auto-config)
sam_grove 0:42add775212a 46 // for(i=0; i<12; i++)
sam_grove 0:42add775212a 47 // {
sam_grove 0:42add775212a 48 // MPR121::writeRegister(E0BV+i, 0x10); //REG 0x1E...0x29
sam_grove 0:42add775212a 49 // }
sam_grove 0:42add775212a 50
sam_grove 0:42add775212a 51 // Baseline Filtering Control Register (changes response sensitivity)
sam_grove 0:42add775212a 52 // http://cache.freescale.com/files/sensors/doc/app_note/AN3891.pdf
sam_grove 0:42add775212a 53 MPR121::writeRegister(MHDR, 0x1); //REG 0x2B
sam_grove 0:42add775212a 54 MPR121::writeRegister(NHDR, 0x1); //REG 0x2C
sam_grove 0:42add775212a 55 MPR121::writeRegister(NCLR, 0x0); //REG 0x2D
sam_grove 0:42add775212a 56 MPR121::writeRegister(FDLR, 0x0); //REG 0x2E
sam_grove 0:42add775212a 57 MPR121::writeRegister(MHDF, 0x1); //REG 0x2F
sam_grove 0:42add775212a 58 MPR121::writeRegister(NHDF, 0x1); //REG 0x30
sam_grove 0:42add775212a 59 MPR121::writeRegister(NCLF, 0xFF); //REG 0x31
sam_grove 0:42add775212a 60 MPR121::writeRegister(FDLF, 0x2); //REG 0x32
sam_grove 0:42add775212a 61
sam_grove 0:42add775212a 62
sam_grove 0:42add775212a 63 // Touch / Release Threshold
sam_grove 0:42add775212a 64 // cache.freescale.com/files/sensors/doc/app_note/AN3892.pdf
sam_grove 0:42add775212a 65 for(i=0; i<(12*2); i+=2) // touch
sam_grove 0:42add775212a 66 {
sam_grove 0:42add775212a 67 MPR121::writeRegister(E0TTH+i, 0x20); //REG 0x41...0x58 odd
sam_grove 0:42add775212a 68 }
sam_grove 0:42add775212a 69 for(i=0; i<(12*2); i+=2) // release
sam_grove 0:42add775212a 70 {
sam_grove 0:42add775212a 71 MPR121::writeRegister(E0RTH+i, 0x10); //REG 0x41...0x58 even
sam_grove 0:42add775212a 72 }
sam_grove 0:42add775212a 73
sam_grove 0:42add775212a 74 // Debounce Register DR=b6...4, DT=b2...0
sam_grove 0:42add775212a 75 MPR121::writeRegister(DT_DR, 0x11); //REG 0x5B
sam_grove 0:42add775212a 76
sam_grove 0:42add775212a 77 // Filter and Global CDC CDT Configuration (sample time, charge current)
sam_grove 0:42add775212a 78 MPR121::writeRegister(CDC_CONFIG, 0x10); //REG 0x5C default 10
sam_grove 0:42add775212a 79 MPR121::writeRegister(CDT_CONFIG, 0x20); //REG 0x5D default 24
sam_grove 0:42add775212a 80
sam_grove 0:42add775212a 81 // Electrode Charge Current Register - uses CDC_STAT if 0
sam_grove 0:42add775212a 82 // for(i=0; i<12; i++) // current
sam_grove 0:42add775212a 83 // {
sam_grove 0:42add775212a 84 // MPR121::writeRegister(CDC0+i, 0x10); //REG 0x5F ... 0x6B
sam_grove 0:42add775212a 85 // }
sam_grove 0:42add775212a 86 // for(i=0; i<6; i++) // time
sam_grove 0:42add775212a 87 // {
sam_grove 0:42add775212a 88 // MPR121::writeRegister(CDT0_CDT1+i, 0x11); //REG 0x6C ... 0x72
sam_grove 0:42add775212a 89 // }
sam_grove 0:42add775212a 90
sam_grove 0:42add775212a 91 // Auto-Configuration Registers
sam_grove 0:42add775212a 92 // http://cache.freescale.com/files/sensors/doc/app_note/AN3889.pdf
sam_grove 0:42add775212a 93 MPR121::writeRegister(AUTO_CFG0, 0x33); // REG 0x7B
sam_grove 0:42add775212a 94 MPR121::writeRegister(AUTO_CFG1, 0x07); // REG 0x7C
sam_grove 0:42add775212a 95 MPR121::writeRegister(USL, 0xc9); // REG 0x7D((3.3-.07)/3.3) * 256
sam_grove 0:42add775212a 96 MPR121::writeRegister(LSL, 0x83); // REG 0x7E((3.3-.07)/3.3) * 256 * 0.65f
sam_grove 0:42add775212a 97 MPR121::writeRegister(TL, 0xb5); // REG 0x7F((3.3-.07)/3.3) * 256 * 0.9f
sam_grove 0:42add775212a 98 // 255 > USL > TL > LSL > 0
sam_grove 0:42add775212a 99
sam_grove 0:42add775212a 100 // MPR121::registerDump();
sam_grove 0:42add775212a 101
sam_grove 0:42add775212a 102 // Electrode Configuration Register - enable all 12 and start
sam_grove 0:42add775212a 103 MPR121::writeRegister(ECR, 0x8f);
sam_grove 0:42add775212a 104
sam_grove 0:42add775212a 105 return;
sam_grove 0:42add775212a 106 }
sam_grove 0:42add775212a 107
sam_grove 0:42add775212a 108 void MPR121::enable(void)
sam_grove 0:42add775212a 109 {
sam_grove 0:42add775212a 110 _button = 0;
sam_grove 0:42add775212a 111 _button_has_changed = 0;
sam_grove 1:cee45334b36a 112 // enable the 12 electrodes - allow disable to put device into
sam_grove 1:cee45334b36a 113 // lower current consumption mode
sam_grove 1:cee45334b36a 114 MPR121::writeRegister(ECR, 0x8f);
sam_grove 1:cee45334b36a 115 // and attach the interrupt handler
sam_grove 0:42add775212a 116 _irq->fall(this, &MPR121::handler);
sam_grove 0:42add775212a 117
sam_grove 0:42add775212a 118 return;
sam_grove 0:42add775212a 119 }
sam_grove 0:42add775212a 120
sam_grove 0:42add775212a 121 void MPR121::disable(void)
sam_grove 0:42add775212a 122 {
sam_grove 1:cee45334b36a 123 // detach the interrupt handler
sam_grove 0:42add775212a 124 _irq->fall(NULL);
sam_grove 0:42add775212a 125 _button = 0;
sam_grove 0:42add775212a 126 _button_has_changed = 0;
sam_grove 1:cee45334b36a 127 // put the device in low current consumption mode - dont re-init registers
sam_grove 1:cee45334b36a 128 MPR121::writeRegister(ECR, 0x0);
sam_grove 1:cee45334b36a 129 MPR121::writeRegister(AUTO_CFG0, 0x0); // REG 0x7B
sam_grove 1:cee45334b36a 130 MPR121::writeRegister(AUTO_CFG1, 0x0); // REG 0x7C
sam_grove 0:42add775212a 131
sam_grove 0:42add775212a 132 return;
sam_grove 0:42add775212a 133 }
sam_grove 0:42add775212a 134
sam_grove 0:42add775212a 135 uint32_t MPR121::isPressed(void)
sam_grove 0:42add775212a 136 {
sam_grove 0:42add775212a 137 return _button_has_changed;
sam_grove 0:42add775212a 138 }
sam_grove 0:42add775212a 139
sam_grove 0:42add775212a 140 uint16_t MPR121::buttonPressed(void)
sam_grove 0:42add775212a 141 {
sam_grove 0:42add775212a 142 _button_has_changed = 0;
sam_grove 0:42add775212a 143 return _button;
sam_grove 0:42add775212a 144 }
sam_grove 0:42add775212a 145
sam_grove 1:cee45334b36a 146 void MPR121::registerDump(void) const
sam_grove 0:42add775212a 147 {
sam_grove 0:42add775212a 148 uint8_t reg_val = 0;
sam_grove 0:42add775212a 149
sam_grove 0:42add775212a 150 for(int i=0; i<0x80; i++)
sam_grove 0:42add775212a 151 {
sam_grove 0:42add775212a 152 reg_val = MPR121::readRegister(i);
sam_grove 2:4c0d4b90a3ed 153 LOG("Reg 0x%02x: 0x%02x \n", i, reg_val);
sam_grove 0:42add775212a 154 }
sam_grove 0:42add775212a 155
sam_grove 0:42add775212a 156 return;
sam_grove 0:42add775212a 157 }
sam_grove 0:42add775212a 158
sam_grove 0:42add775212a 159 void MPR121::handler(void)
sam_grove 0:42add775212a 160 {
sam_grove 0:42add775212a 161 uint16_t reg_val = 0, oor_val = 0;
sam_grove 0:42add775212a 162 // read register 0 and 1
sam_grove 0:42add775212a 163 reg_val = MPR121::readRegister(ELE0_7_STAT);
sam_grove 0:42add775212a 164 reg_val |= MPR121::readRegister(ELE8_11_STAT) << 8;
sam_grove 0:42add775212a 165 // 2 and 3
sam_grove 0:42add775212a 166 oor_val = MPR121::readRegister(ELE0_7_OOR_STAT);
sam_grove 0:42add775212a 167 oor_val |= MPR121::readRegister(ELE8_11_OOR_STAT) << 8;
sam_grove 0:42add775212a 168
sam_grove 0:42add775212a 169 if(0 != oor_val)
sam_grove 0:42add775212a 170 {
sam_grove 2:4c0d4b90a3ed 171 ERROR("MPR121 OOR failure - 0x%04x\n", oor_val);
sam_grove 0:42add775212a 172 }
sam_grove 0:42add775212a 173
sam_grove 0:42add775212a 174 _button = reg_val;
sam_grove 0:42add775212a 175 _button_has_changed = 1;
sam_grove 0:42add775212a 176
sam_grove 0:42add775212a 177 return;
sam_grove 0:42add775212a 178 }
sam_grove 0:42add775212a 179
sam_grove 1:cee45334b36a 180 void MPR121::writeRegister(uint8_t const reg, uint8_t const data) const
sam_grove 0:42add775212a 181 {
sam_grove 0:42add775212a 182 char buf[2] = {reg, data};
sam_grove 0:42add775212a 183 uint8_t result = 0;
sam_grove 0:42add775212a 184
sam_grove 0:42add775212a 185 __disable_irq(); // Tickers and other timebase events can jack up the I2C bus
sam_grove 0:42add775212a 186 result = _i2c->write(_i2c_addr, buf, 2);
sam_grove 0:42add775212a 187 __enable_irq(); // Just need to block during the transaction
sam_grove 0:42add775212a 188
sam_grove 0:42add775212a 189 if(0 != result)
sam_grove 0:42add775212a 190 {
sam_grove 2:4c0d4b90a3ed 191 ERROR("I2c write failed\n");
sam_grove 0:42add775212a 192 }
sam_grove 0:42add775212a 193
sam_grove 0:42add775212a 194 return;
sam_grove 0:42add775212a 195 }
sam_grove 0:42add775212a 196
sam_grove 1:cee45334b36a 197 uint8_t MPR121::readRegister(uint8_t const reg) const
sam_grove 0:42add775212a 198 {
sam_grove 2:4c0d4b90a3ed 199 // from https://github.com/mbedmicro/mbed/blob/master/libraries/tests/peripherals/MMA8451Q/MMA8451Q.cpp
sam_grove 2:4c0d4b90a3ed 200 // char t[1] = {reg};
sam_grove 2:4c0d4b90a3ed 201 // uint8_t data;
sam_grove 2:4c0d4b90a3ed 202 // _i2c->write(_i2c_addr, t, 1, true);
sam_grove 2:4c0d4b90a3ed 203 // _i2c->read(_i2c_addr, (char *)data, 1);
sam_grove 2:4c0d4b90a3ed 204 // return data;
sam_grove 2:4c0d4b90a3ed 205
sam_grove 2:4c0d4b90a3ed 206 // modified and still wont work - need a scope
sam_grove 2:4c0d4b90a3ed 207 // char buf[1] = {reg};
sam_grove 2:4c0d4b90a3ed 208 // uint8_t w_result = 0, r_result = 0;
sam_grove 2:4c0d4b90a3ed 209 // uint8_t data;
sam_grove 2:4c0d4b90a3ed 210 //
sam_grove 2:4c0d4b90a3ed 211 // __disable_irq();
sam_grove 2:4c0d4b90a3ed 212 // w_result = _i2c->write(_i2c_addr, buf, 1, true);
sam_grove 2:4c0d4b90a3ed 213 // r_result = _i2c->read(_i2c_addr, (char *)&data, 2);
sam_grove 2:4c0d4b90a3ed 214 // __enable_irq();
sam_grove 2:4c0d4b90a3ed 215 //
sam_grove 2:4c0d4b90a3ed 216 // if((0 != w_result) || (0 != r_result))
sam_grove 2:4c0d4b90a3ed 217 // {
sam_grove 2:4c0d4b90a3ed 218 // ERROR("I2c read failed: %d, %d\n", w_result, r_result);
sam_grove 2:4c0d4b90a3ed 219 // }
sam_grove 2:4c0d4b90a3ed 220 //
sam_grove 2:4c0d4b90a3ed 221 // return (uint8_t)data;
sam_grove 2:4c0d4b90a3ed 222
sam_grove 0:42add775212a 223 uint8_t result = 1, data = 0;
sam_grove 0:42add775212a 224
sam_grove 0:42add775212a 225 __disable_irq(); // Tickers and other timebase events can jack up the I2C bus
sam_grove 0:42add775212a 226 _i2c->start();
sam_grove 0:42add775212a 227 result &= _i2c->write(_i2c_addr);
sam_grove 0:42add775212a 228 result &= _i2c->write(reg);
sam_grove 0:42add775212a 229 // issue a repeated start...
sam_grove 0:42add775212a 230 _i2c->start();
sam_grove 0:42add775212a 231 result &= _i2c->write(_i2c_addr | 0x01);
sam_grove 0:42add775212a 232 // read with nak
sam_grove 0:42add775212a 233 data = _i2c->read(0);
sam_grove 0:42add775212a 234 _i2c->stop();
sam_grove 0:42add775212a 235 __enable_irq(); // Just need to block during the transaction
sam_grove 0:42add775212a 236
sam_grove 0:42add775212a 237 if(1 != result)
sam_grove 0:42add775212a 238 {
sam_grove 2:4c0d4b90a3ed 239 ERROR("I2C read failed\n");
sam_grove 0:42add775212a 240 }
sam_grove 0:42add775212a 241
sam_grove 0:42add775212a 242 return data;
sam_grove 0:42add775212a 243 }