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!!

Files at this revision

API Documentation at this revision

Comitter:
sam_grove
Date:
Thu Mar 07 19:25:08 2013 +0000
Child:
1:cee45334b36a
Commit message:
Working baseline example

Changed in this revision

MPR121.cpp Show annotated file Show diff for this revision Revisions of this file
MPR121.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPR121.cpp	Thu Mar 07 19:25:08 2013 +0000
@@ -0,0 +1,210 @@
+/**
+ * @file    MPR121.cpp
+ * @brief   Device driver - MPR121 capactiive touch IC
+ * @author  sam grove
+ * @version 1.0
+ * @see     http://cache.freescale.com/files/sensors/doc/data_sheet/MPR121.pdf
+ *
+ * Copyright (c) 2013
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MPR121.h"
+    
+MPR121::MPR121(I2C &i2c, InterruptIn &pin, MPR121_ADDR i2c_addr)
+{
+    _i2c = &i2c;
+    _irq = &pin;
+    _i2c_addr = (i2c_addr << 1);
+    
+    return;
+}
+
+void MPR121::init(void)
+{
+    uint8_t i = 0;
+    // set the i2c speed
+    _i2c->frequency(400000);
+    // irq is open-collector and active-low
+    _irq->mode(PullUp);
+    
+    // setup and registers - start with POR values (must be in stop mode)
+    MPR121::writeRegister(SRST, 0x63); //REG 0x80
+    
+    // baseline < filtered data = touch (set by auto-config)
+//    for(i=0; i<12; i++)
+//    {
+//        MPR121::writeRegister(E0BV+i, 0x10); //REG 0x1E...0x29
+//    }
+    
+    // Baseline Filtering Control Register (changes response sensitivity)
+    // http://cache.freescale.com/files/sensors/doc/app_note/AN3891.pdf
+    MPR121::writeRegister(MHDR, 0x1);  //REG 0x2B
+    MPR121::writeRegister(NHDR, 0x1);  //REG 0x2C
+    MPR121::writeRegister(NCLR, 0x0);  //REG 0x2D
+    MPR121::writeRegister(FDLR, 0x0);  //REG 0x2E
+    MPR121::writeRegister(MHDF, 0x1);  //REG 0x2F
+    MPR121::writeRegister(NHDF, 0x1);  //REG 0x30
+    MPR121::writeRegister(NCLF, 0xFF); //REG 0x31
+    MPR121::writeRegister(FDLF, 0x2);  //REG 0x32
+    
+    
+    // Touch / Release Threshold
+    // cache.freescale.com/files/sensors/doc/app_note/AN3892.pdf
+    for(i=0; i<(12*2); i+=2) // touch
+    {
+        MPR121::writeRegister(E0TTH+i, 0x20); //REG 0x41...0x58 odd
+    }
+    for(i=0; i<(12*2); i+=2) // release
+    {
+        MPR121::writeRegister(E0RTH+i, 0x10); //REG 0x41...0x58 even
+    }
+    
+    // Debounce Register DR=b6...4, DT=b2...0
+    MPR121::writeRegister(DT_DR, 0x11); //REG 0x5B
+    
+    // Filter and Global CDC CDT Configuration (sample time, charge current)
+    MPR121::writeRegister(CDC_CONFIG, 0x10); //REG 0x5C default 10
+    MPR121::writeRegister(CDT_CONFIG, 0x20); //REG 0x5D default 24
+    
+    // Electrode Charge Current Register - uses CDC_STAT if 0
+//    for(i=0; i<12; i++) // current
+//    {
+//        MPR121::writeRegister(CDC0+i, 0x10); //REG 0x5F ... 0x6B
+//    }
+//    for(i=0; i<6; i++) // time
+//    {
+//        MPR121::writeRegister(CDT0_CDT1+i, 0x11); //REG 0x6C ... 0x72
+//    }
+    
+    // Auto-Configuration Registers
+    // http://cache.freescale.com/files/sensors/doc/app_note/AN3889.pdf
+    MPR121::writeRegister(AUTO_CFG0, 0x33); // REG 0x7B
+    MPR121::writeRegister(AUTO_CFG1, 0x07); // REG 0x7C
+    MPR121::writeRegister(USL, 0xc9);       // REG 0x7D((3.3-.07)/3.3) * 256
+    MPR121::writeRegister(LSL, 0x83);       // REG 0x7E((3.3-.07)/3.3) * 256 * 0.65f
+    MPR121::writeRegister(TL,  0xb5);       // REG 0x7F((3.3-.07)/3.3) * 256 * 0.9f
+    // 255 > USL > TL > LSL > 0
+    
+//    MPR121::registerDump();
+    
+    // Electrode Configuration Register - enable all 12 and start
+    MPR121::writeRegister(ECR, 0x8f);
+    
+    return;
+}
+
+void MPR121::enable(void)
+{
+    _button = 0;
+    _button_has_changed = 0;
+    _irq->fall(this, &MPR121::handler);
+    
+    return;
+}
+
+void MPR121::disable(void)
+{
+    _irq->fall(NULL);
+    _button = 0;
+    _button_has_changed = 0;
+    
+    return;
+}
+
+uint32_t MPR121::isPressed(void)
+{
+    return _button_has_changed;
+}
+
+uint16_t MPR121::buttonPressed(void)
+{
+    _button_has_changed = 0;
+    return _button;
+}
+
+void MPR121::registerDump(void)
+{
+    uint8_t reg_val = 0;
+    
+    for(int i=0; i<0x80; i++)
+    {
+        reg_val = MPR121::readRegister(i);
+        printf("Reg 0x%02x: 0x%02x \n", i, reg_val);
+    }
+    
+    return;
+}
+
+void MPR121::handler(void)
+{
+    uint16_t reg_val = 0, oor_val = 0;
+    // read register 0 and 1
+    reg_val  = MPR121::readRegister(ELE0_7_STAT);
+    reg_val |= MPR121::readRegister(ELE8_11_STAT) << 8;
+    // 2 and 3
+    oor_val  = MPR121::readRegister(ELE0_7_OOR_STAT);
+    oor_val |= MPR121::readRegister(ELE8_11_OOR_STAT) << 8;
+    
+    if(0 != oor_val)
+    {
+        error("%s %d: MPR121 OOR failure - 0x%04x\n", __FILE__, __LINE__, oor_val);
+    }
+   
+    _button = reg_val;
+    _button_has_changed = 1;
+    
+    return;
+}
+
+void MPR121::writeRegister(uint8_t reg, uint8_t data)
+{
+    char buf[2] = {reg, data};
+    uint8_t result = 0;
+    
+    __disable_irq(); // Tickers and other timebase events can jack up the I2C bus
+    result = _i2c->write(_i2c_addr, buf, 2);
+    __enable_irq();  // Just need to block during the transaction
+    
+    if(0 != result)
+    {
+        error("%s %d: I2c write failed\n", __FILE__, __LINE__);
+    }
+    
+    return;
+}
+
+uint8_t MPR121::readRegister(uint8_t reg)
+{
+    uint8_t result = 1, data = 0;
+    
+    __disable_irq(); // Tickers and other timebase events can jack up the I2C bus
+    _i2c->start();
+    result &= _i2c->write(_i2c_addr);
+    result &= _i2c->write(reg);
+    // issue a repeated start...
+    _i2c->start();
+    result &= _i2c->write(_i2c_addr | 0x01);
+    // read with nak
+    data = _i2c->read(0);
+    _i2c->stop();
+    __enable_irq();  // Just need to block during the transaction
+    
+    if(1 != result)
+    {
+        error("%s %d: I2C read failed\n", __FILE__, __LINE__);
+    }
+    
+    return data;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPR121.h	Thu Mar 07 19:25:08 2013 +0000
@@ -0,0 +1,189 @@
+/**
+ * @file    MPR121.h
+ * @brief   Device driver - MPR121 capactiive touch IC
+ * @author  sam grove
+ * @version 1.0
+ * @see     http://cache.freescale.com/files/sensors/doc/data_sheet/MPR121.pdf
+ *
+ * Copyright (c) 2013
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#ifndef MPR121_H
+#define MPR121_H
+
+#include "mbed.h"
+
+/** Using the Sparkfun SEN-10250
+ *
+ * Example:
+ * @code
+ *  #include "mbed.h"
+ *  #include "MPR121.h"
+ *
+ *  DigitalOut myled(LED1);
+ *  Serial pc(USBTX, USBRX);
+ * 
+ *  I2C i2c(p28, p27);
+ *  InterruptIn irq(p26);
+ *  MPR121 touch_pad(i2c, irq, MPR121::ADDR_VSS);
+ * 
+ *  int main() 
+ *  {
+ *      pc.baud(921600);    // boost the communication speed
+ *      printf("\033[2J");  // clear the terminal
+ *      printf("\033[1;1H");// and set the cursor to home
+ *      wait(0.1f);
+ *      printf("*******************************************************\n");
+ *         
+ *      touch_pad.init();
+ *      touch_pad.enable();
+ *    
+ *      while(1)
+ *      {
+ *          if(touch_pad.isPressed())
+ *          {
+ *              uint16_t button_val = touch_pad.buttonPressed();
+ *              printf("button = 0x%04x\n", button_val);
+ *              myled = (button_val>0) ? 1 : 0;
+ *          }    
+ *      }
+ *  }
+ * @endcode
+ */
+
+/**
+ *  @class MPR121
+ *  @brief API abstraction for the MPR121 capacitive touch IC
+ */ 
+class MPR121
+{
+private:
+    
+    I2C         *_i2c;
+    InterruptIn *_irq;
+    uint8_t      _i2c_addr;
+    volatile uint16_t _button;
+    volatile uint32_t _button_has_changed;
+    
+    /** The interrupt handler for the IRQ pin
+     */
+    void handler(void);
+
+public:
+    
+    /**
+     *  @enum MPR121_ADDR
+     *  @brief Possible terminations for the ADDR pin
+     */ 
+    enum MPR121_ADDR
+    { 
+        ADDR_VSS = 0x5A, /*!< ADDR connected to VSS */
+        ADDR_VDD,    /*!< ADDR connected to VDD */
+        ADDR_SCL,    /*!< ADDR connected to SDA */
+        ADDR_SDA     /*!< ADDR connected to SCL */
+    };
+    
+    /**
+     *  @enum MPR121_REGISTER
+     *  @brief The device register map
+     */
+    enum MPR121_REGISTER
+    {
+        ELE0_7_STAT = 0x00,
+        ELE8_11_STAT, ELE0_7_OOR_STAT, ELE8_11_OOR_STAT, EFD0LB, EFD0HB, 
+        EFD1LB, EFD1HB, EFD2LB, EFD2HB, EFD3LB, EFD3HB, EFD4LB, EFD4HB, EFD5LB, EFD5HB,
+        
+        EFD6LB = 0x10,
+        EFD6HB, EFD7LB, EFD7HB, EFD8LB, EFD8HB, EFD9LB, EFD9HB, EFD10LB,
+        EFD10HB, EFD11LB, EFD11HB, EFDPROXLB, EFDPROXHB, E0BV, E1BV,
+        
+        E2BV = 0x20,
+        E3BV, E4BV, E5BV, E6BV, E7BV, E8BV, E9BV, E10BV, E11BV, EPROXBV,
+        MHDR, NHDR, NCLR, FDLR, MHDF, 
+        
+        NHDF = 0x30,
+        NCLF, FDLF, NHDT, NCLT, FDLT, MHDPROXR, NHDPROXR, NCLPROXR,
+        FDLPROXR, MHDPROXF, NHDPROXF, NCLPROXF, FDLPROXF, NHDPROXT, NCLPROXT,
+        
+        FDLPROXT = 0x40,
+        E0TTH, E0RTH, E1TTH, E1RTH, E2TTH, E2RTH, E3TTH, E3RTH,
+        E4TTH, E4RTH, E5TTH, E5RTH, E6TTH, E6RTH, E7TTH,
+        
+        E7RTH = 0x50,
+        E8TTH, E8RTH, E9TTH, E9RTH, E10TTH, E10RTH, E11TTH, E11RTH,
+        EPROXTTH, EPROXRTH, DT_DR, CDC_CONFIG, CDT_CONFIG, ECR, CDC0,
+        
+        CDC1 = 0x60,
+        CDC2, CDC3, CDC4, CDC5, CDC6, CDC7, CDC8, CDC9, CDC10, CDC11, CDCPROX, CDT0_CDT1,
+        CDT2_CDT3, CDT4_CDT5, CDT6_CDT7, 
+        
+        CDT8_CDT9 = 0x70,
+        CDT10_CDT11, CDTPROX, GPIO_CTRL0, GPIO_CTRL1, GPIO_DATA, GPIO_DIR, GPIO_EN, GPIO_SET,
+        GPIO_CLR, GPIO_TOGGLE, AUTO_CFG0, AUTO_CFG1, USL, LSL, TL,
+        
+        SRST = 0x80
+    };
+    
+    /** Create the MPR121 object
+     *  @param i2c A defined I2C object
+     *  @param pin A defined InterruptIn object
+     *  @param i2c_addr Connection of the address line
+     */    
+    MPR121(I2C &i2c, InterruptIn &pin, MPR121_ADDR i2c_addr);
+    
+    /** Clear state vars and initilize the dependant objects
+     */
+    void init(void);
+    
+    /** Allow the IC to run and collect user input
+     */
+    void enable(void);
+    
+    /** Stop the IC and put into low power mode
+     */
+    void disable(void);
+    
+    /** Determine if a new button press event occured
+     *  Upon calling the state is cleared until another press is detected
+     *  @return 1 if a press has been detected since the last call, 0 otherwise
+     */
+    uint32_t isPressed(void);
+    
+    /** Get the electrode status (ELE12 ... ELE0 -> b15 xxx b11 ... b0
+     *  The buttons are bit mapped. ELE0 = b0 ... ELE11 = b11 b12 ... b15 undefined
+     *  @return The state of all buttons
+     */
+    uint16_t buttonPressed(void);
+    
+    /** print the register map and values to the console
+     */
+    void registerDump(void);
+    
+    /** Write to a register (exposed for debugging reasons)
+     *  Note: most writes are only valid in stop mode
+     *  @param reg The register to be written
+     *  @param data The data to be written
+     */
+    void writeRegister(uint8_t reg, uint8_t data);
+    
+    /** Read from a register (exposed for debugging reasons)
+     *  @param reg The register to read from
+     *  @return The register contents
+     */
+    uint8_t readRegister(uint8_t reg);
+    
+};
+
+#endif