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:
Tue Aug 27 21:39:33 2013 +0000
Parent:
2:4c0d4b90a3ed
Child:
4:c1bc00c5e8e5
Child:
5:3934358ec2b7
Child:
7:eb4012317732
Commit message:
Removed LogUtil and used mbed_debug.h, updated I2C read transactions, new example, tested with LPC1768, KL25Z and LPC11U24 using mbed library rev66

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
--- a/MPR121.cpp	Fri Mar 29 21:32:38 2013 +0000
+++ b/MPR121.cpp	Tue Aug 27 21:39:33 2013 +0000
@@ -21,6 +21,9 @@
  */
 
 #include "MPR121.h"
+#include "mbed_debug.h"
+
+#define DEBUG 1
     
 MPR121::MPR121(I2C &i2c, InterruptIn &pin, MPR121_ADDR i2c_addr)
 {
@@ -33,7 +36,6 @@
 
 void MPR121::init(void)
 {
-    uint8_t i = 0;
     // set the i2c speed
     _i2c->frequency(400000);
     // irq is open-collector and active-low
@@ -42,12 +44,6 @@
     // 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
@@ -59,16 +55,15 @@
     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
+    for(int i=0; i<(12*2); i+=2) // touch
     {
-        MPR121::writeRegister(E0TTH+i, 0x20); //REG 0x41...0x58 odd
+        MPR121::writeRegister(static_cast<MPR121_REGISTER>(E0TTH+i), 0x20); //REG 0x41...0x58 odd
     }
-    for(i=0; i<(12*2); i+=2) // release
+    for(int i=0; i<(12*2); i+=2) // release
     {
-        MPR121::writeRegister(E0RTH+i, 0x10); //REG 0x41...0x58 even
+        MPR121::writeRegister(static_cast<MPR121_REGISTER>(E0RTH+i), 0x10); //REG 0x41...0x58 even
     }
     
     // Debounce Register DR=b6...4, DT=b2...0
@@ -78,16 +73,6 @@
     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
@@ -97,8 +82,6 @@
     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);
     
@@ -143,14 +126,14 @@
     return _button;
 }
 
-void MPR121::registerDump(void) const
+void MPR121::registerDump(Serial &obj) const
 {
     uint8_t reg_val = 0;
     
     for(int i=0; i<0x80; i++)
     {
-        reg_val = MPR121::readRegister(i);
-        LOG("Reg 0x%02x: 0x%02x \n", i, reg_val);
+        reg_val = MPR121::readRegister(static_cast<MPR121_REGISTER>(i));
+        obj.printf("Reg 0x%02x: 0x%02x \n", i, reg_val);
     }
     
     return;
@@ -166,9 +149,13 @@
     oor_val  = MPR121::readRegister(ELE0_7_OOR_STAT);
     oor_val |= MPR121::readRegister(ELE8_11_OOR_STAT) << 8;
     
-    if(0 != oor_val)
+    // debugging stuff and errors - if OOR fails someone was touching the pad during auto-config
+    //  Just reboot until they're not doing this
+    if((0 != oor_val) && DEBUG)
     {
-        ERROR("MPR121 OOR failure - 0x%04x\n", oor_val);
+        debug("MPR121 OOR failure - 0x%04x\n", oor_val);
+        wait(0.1f);
+        NVIC_SystemReset();
     }
    
     _button = reg_val;
@@ -177,66 +164,32 @@
     return;
 }
 
-void MPR121::writeRegister(uint8_t const reg, uint8_t const data) const
+void MPR121::writeRegister(MPR121_REGISTER const reg, uint8_t const data) const
 {
     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)
+    if(result && DEBUG)
     {
-        ERROR("I2c write failed\n");
+        debug("I2c write failed\n");
     }
     
     return;
 }
 
-uint8_t MPR121::readRegister(uint8_t const reg) const
+uint8_t MPR121::readRegister(MPR121_REGISTER const reg) const
 {
-    // from https://github.com/mbedmicro/mbed/blob/master/libraries/tests/peripherals/MMA8451Q/MMA8451Q.cpp
-//    char t[1] = {reg};
-//    uint8_t data;
-//    _i2c->write(_i2c_addr, t, 1, true);
-//    _i2c->read(_i2c_addr, (char *)data, 1);
-//    return data;
-
-    // modified and still wont work - need a scope
-//    char buf[1] = {reg};
-//    uint8_t w_result = 0, r_result = 0;
-//    uint8_t data;
-//    
-//    __disable_irq();
-//    w_result = _i2c->write(_i2c_addr, buf, 1, true);
-//    r_result = _i2c->read(_i2c_addr, (char *)&data, 2);
-//    __enable_irq();
-//    
-//    if((0 != w_result) || (0 != r_result))
-//    {
-//        ERROR("I2c read failed: %d, %d\n", w_result, r_result);
-//    }
-//    
-//    return (uint8_t)data;
+    char buf[1] = {reg}, data = 0;
+    uint8_t result = 1;
     
-    uint8_t result = 1, data = 0;
+    result &= _i2c->write(_i2c_addr, buf, 1, true);
+    result &= _i2c->read(_i2c_addr, &data, 1); 
     
-    __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)
+    if(result && DEBUG)
     {
-        ERROR("I2C read failed\n");
+        debug("I2c read failed\n");
     }
     
     return data;
--- a/MPR121.h	Fri Mar 29 21:32:38 2013 +0000
+++ b/MPR121.h	Tue Aug 27 21:39:33 2013 +0000
@@ -24,58 +24,52 @@
 #define MPR121_H
 
 #include "mbed.h"
-#include "LogUtil.h"
 
-/** Using the Sparkfun SEN-10250
+/** Using the Sparkfun SEN-10250 BoB
  *
  * Example:
  * @code
- * #include "mbed.h"
- * #include "MPR121.h"
- * 
- * // TODO: put IC in low power mode when disabled
- * 
- * DigitalOut myled(LED1);
- * DigitalOut off(LED4);
- * Timer t;
- * 
- * LogUtil logger;
- * 
- * I2C i2c(p28, p27);
- * InterruptIn irq(p26);
- * MPR121 touch_pad(i2c, irq, MPR121::ADDR_VSS);
- * 
- * int main() 
- * {       
- *     touch_pad.init();
- *     touch_pad.enable();
- *     t.start();
- *     while(1)
- *     {
- *         if(touch_pad.isPressed())
- *         {
- *             uint16_t button_val = touch_pad.buttonPressed();
- *             LOG("button = 0x%04x\n", button_val);
- *             myled = (button_val>0) ? 1 : 0;
- *         }
- *         if(t.read_ms() > 5000)
- *         {
- *             touch_pad.disable();
- *             off = 1;
- *             wait(5.0f);
- *             off = 0;
- *             touch_pad.enable();
- *             t.reset();
- *         }
- *             
- *     }
- * }
+ *  #include "mbed.h"
+ *  #include "MPR121.h"
+ *  
+ *  Serial pc(USBTX, USBRX);
+ *  DigitalOut myled(LED1);
+ *  
+ *  #if defined TARGET_LPC1768 || TARGET_LPC11U24
+ *    I2C i2c(p28, p27);
+ *    InterruptIn irq(p26);
+ *    MPR121 touch_pad(i2c, irq, MPR121::ADDR_VSS);
+ *  
+ *  #elif defined TARGET_KL25Z
+ *    I2C i2c(PTC9, PTC8);
+ *    InterruptIn irq(PTA5);
+ *    MPR121 touch_pad(i2c, irq, MPR121::ADDR_VSS);
+ *  
+ *  #else
+ *    #error TARGET NOT TESTED
+ *  #endif
+ *  
+ *  int main()  
+ *  {       
+ *      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
+ *  @brief API for the MPR121 capacitive touch IC
  */ 
 class MPR121
 {
@@ -153,7 +147,7 @@
      */    
     MPR121(I2C &i2c, InterruptIn &pin, MPR121_ADDR i2c_addr);
     
-    /** Clear state vars and initilize the dependant objects
+    /** Clear state variables and initilize the dependant objects
      */
     void init(void);
     
@@ -178,21 +172,22 @@
     uint16_t buttonPressed(void);
     
     /** print the register map and values to the console
+     *  @param obj - a Serial object that prints to a console
      */
-    void registerDump(void) const;
+    void registerDump(Serial &obj) const;
     
     /** 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 const reg, uint8_t const data) const;
+    void writeRegister(MPR121_REGISTER const reg, uint8_t const data) const;
     
     /** Read from a register (exposed for debugging reasons)
      *  @param reg - The register to read from
      *  @return The register contents
      */
-    uint8_t readRegister(uint8_t const reg) const;
+    uint8_t readRegister(MPR121_REGISTER const reg) const;
     
 };