MPR121 gpio and led driver

Hello folks,

I use MPR121 touch sensors and they work fine with the Arduino.
The MPR121 also has the capability to use some of the electrode pins as gpio's and to drive led's, see https://www.nxp.com/docs/en/application-note/AN3894.pdf.
I tried to use pins as output, but i did not succeed.

The register addresses needed for gpio capability are not defined in Adafruit_MPR121.h, so obviously not many people use this feature.
I wrote an h-file for this:

enum 
{
  MPR121_CTL0 = 0x73, // Control Register 0
  MPR121_CTL1 = 0x74, // Control Register 1
  MPR121_DATA = 0x75, // Data Register 1
  MPR121_DIR  = 0x76, // Direction register
  MPR121_EN   = 0x77, // Enable register
  MPR121_SET  = 0x78, // Set register
  MPR121_CLR  = 0x79, // Clear register
  MPR121_TOG  = 0x7A, // Toggle register
};

I can write to the SET and TOG registers and I can read back the DATA registers, so from the logic side it is OK.

But I do not see any voltage changes on the pins.
I am not sure how to use the CTL0 and CTL1 registers, but setting everything to 0 should work.

Here is my code:

String title1 = "MPR121 GPIO test";
String title2 = "****************";

#include <Wire.h>
#include "Adafruit_MPR121.h"
#include "mpr1221_gpio.h"

#define IPR_ADDR 0x5A
Adafruit_MPR121 cap = Adafruit_MPR121();


//-------------------------------------------------------------------------
void setup() {
  bool FoundMPR121 = false;
  byte electrodeConfiguration;
  byte count = 0;

  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(115200);
  while (!Serial) { // needed to keep leonardo/micro from starting too fast!
    delay(10);
  }

  Serial.println(title1);
  Serial.println(title2);
  Serial.println("\n");

   do
   {
      delay (200);
      Serial.print(IPR_ADDR + count);
      FoundMPR121 = cap.begin(IPR_ADDR + count);
      if (!FoundMPR121) Serial.println(" MPR121 not found, check wiring?");
      count++;
      if (count == 4)
      {
        count = 0;
      }
    } while (!FoundMPR121);
    Serial.println(" MPR121 found");
  

    cap.writeRegister (MPR121_SOFTRESET, 0x63);
    delay (100);
    cap.writeRegister (MPR121_SOFTRESET, 0x80);
    delay (100);

    //cap.setThreshholds(THRESH_TOUCH, THRESH_RELEASE);

    cap.writeRegister ( MPR121_ECR, 4);       // only x Elektrodes, the Rest is GPIO
    cap.writeRegister ( MPR121_CTL0, 0); 
    cap.writeRegister ( MPR121_CTL1, 0);      // all GPIO's as CMOS output 
    cap.writeRegister ( MPR121_DIR,  0xFF);   // all GPIO's as output
    cap.writeRegister ( MPR121_EN ,  0xFF);   // all GPIO's enabled
    
    cap.writeRegister ( MPR121_CLR,  0xFF);   // Ausgangszustand ... alle 0
    cap.writeRegister ( MPR121_SET,  0xFF);   // Ausgangszustand
    


} // setup

//---------------------------------------------------------------
void loop() {
    int dataReg;
    cap.writeRegister ( MPR121_TOG,  0xFF);   // alle GPIO's werden getogglet
    dataReg = cap.readRegister8 (MPR121_DATA);
    Serial.println (dataReg);
    delay (2000);
}

Any hints?
Thanks in advance!

What is the serial output? Does the value change there? What voltage do you measure?

I can read back the data register, so I get 0x00 and 0xFF, changing every 2 seconds.

In the meantime I tried to use the GPIO pins as input. The data register does not change when I apply 0V or 3.3V at the pins.

As I cannot find any error in the code, I ask a few further questions:

  • Do you check the correct pin(s)? the GPIOs are on pins 12 to 19 of the chip.
  • Are you sure you have an original NXP (Freescale) chip? Chinese clones may not have that functionality.
  • Did you use the circuit as described in the application note?

Thank you!

  1. yes
  2. I am not sure, and I do not know how to find out. It's a good point.
  3. I use a breakout board, and I assume that the capacitors and resistors are fitted properly.

There is one thing which I do not understand clearly:
What does CTL[0:1] mean?

Does it mean bit 0 of CTL0 and bit 0 of CTL1 correspond to GPIO0, bit 1 of CTL0 and bit 1 of CTL1 correspond to GPIO1, and so on (I assume it is so)

or does it mean bit 0 and bit 1 of CTL0 correspond to GPIO0, bit 2 and bit 3 correspond to GPIO1 and so on?

Regards and happy new year
Martin

Post schematics of that board!

Yes. At least that's my understanding. Your alternative interpretation would be very weird.

I'm also interested in this, and just managed to get this working with an dropped pull request, at least for Input and output (not tried PWM yet) and hope this will help in some way.

Blink

Adafruit_MPR121.zip (8.8 KB)
Source fork

 
/*
 * This example shows how to use MPR121 library on Arduino with hardware I2C support
 * using GPIO functions and touch buttons with debounce.
 *
 * Hardware:
 *    Use an Arduino (Nano) with I2C support and a MPR121 breakout board.
 *    If your Arduino doesn´t support hardware I2C you can use the software I2C version for ESP8266 in the other example!
 *    Connect Arduino to 5V VCC and MPR121 to 3.3V VCC output of the Arduino and GND (or use a voltage regulator such as LM117 or LF33CV).
 *    Connect SDA/SCAL lines from MPR121 board to pins 18/19 on Arduino (see note below!)
 *
 *    If your breakout board already has pullup-resistors for SDA/SCL lines no extra resistors are needed
 *    otherwise you may need to hook SDA/SCL lines with 4.7k resistors to ground for a stable communication.
 *    To show the touch control feature a LED will be used. Hook up the LED and resistors on pins as defined below.
 *
 *    - Connect a touchpad on MPR121 pin 0 (channel 0); normal cable will do
 *    - Connect MPR121 pin 8 (channel 8) with resistor to VCC
 *    - Connect a LED with resistor on MPR121 pin 11 (Channel 11) and to ground
 *
 * Note:
 *    If using an 5V compliant Arduino note that there are two different logic level in your circuit now:
 *    5V for the Arduino and 3.3V for the MPR121.
 *    This means for the SDA/SCL lines you would need a bidirectional logic-level-shifter in between the Arduino and the MPR121.
 *    I would recommend to use a LLS in between for stable communication on to prevent your MPR121 from burning.
 *    Please check your data-sheet carfully which voltage is accepted for I2C communication on MPR and Arduino!
 *    Same might be for the IRQ pin!
 *    (For me it works without a LLV on an Arduino Nano but no guarantee!)
 */

#include <Adafruit_MPR121.h>
#include <Wire.h>

//define pins used
#define IRQ_PIN 3

//touch button on MPR121 channel 0
#define PIN_MPR_SENSOR 0

//GPIO in on channel 10
#define PIN_MPR_GPIO_IN 10

//GPIO out on MPR121 Channel 11
#define PIN_MPR_GPIO_OUT 11

int ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
const long interval = 1000;           // interval at which to blink (milliseconds)

static boolean debug = true;

Adafruit_MPR121 cap = Adafruit_MPR121();


void setup() {
  //start-Serial for output
  Serial.begin(9600);
  Serial.println(F("Starting MPR121-Arduino example...."));

  //show us which SDA/SCL pins are used
  if(debug){
    Serial.print("Using I2C Pins: SDA=");
    Serial.print(SDA);
    Serial.print(", SCL=");
    Serial.println(SCL);
  }

  //init MPR121 touch sensor using default SDA/SCL pins for arduino
  if (!cap.begin(0x5A)) {
    Serial.println(F("MPR121 touch sensor not found!"));
    while (true) {
      delay(100);
      Serial.print(".");
    }
  }
  Serial.println("MPR121 found");

  //set button debounce
  cap.setDebounce(100);

  //configure MPR121 channels
  cap.setChannelType(PIN_MPR_GPIO_OUT,MPR121_GPIO_OUT); //channel 11 is GPIO out (LED)
  cap.setChannelType(PIN_MPR_GPIO_IN,MPR121_GPIO_IN); //channel 10 is GPIO in

  Serial.println(F("MPR121 touch sensor initialized..."));


  Serial.println(F("Init complete..."));
  Serial.println(F("------------------------------"));
}


void loop() {

  //check if touch button was pressed
  boolean isButtonPressed = cap.touched(PIN_MPR_SENSOR);

  if(isButtonPressed & debug){
    Serial.print("Buttons: ");
    for (uint8_t channel = 0; channel <= 11; channel++) {
      //only print if the channel is of type SENSOR
      if(cap.getChannelType(channel) != MPR121_SENSOR){
        continue;
      }
      Serial.print(channel);
      Serial.print("=");
      if(cap.touched(channel)){
        Serial.print("Y");
      }else {
        Serial.print("N");
      }
      Serial.print(" | ");
    }
    Serial.println("");
  }

    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    // digitalWrite(ledPin, ledState);
    cap.setGPIOEnabled(PIN_MPR_GPIO_OUT,ledState);
  }

  //if button is pressed -> light up LED through MPR121
  //cap.setGPIOEnabled(PIN_MPR_GPIO_OUT,isButtonPressed);

  //check if GPIO is enabled
  boolean gpioStatus = cap.getGPIOStatus(PIN_MPR_GPIO_IN);

  //if false -> error (must always be high as connected to VCC!)
  if(!gpioStatus){
    Serial.println("ERROR GPIO IS NOT HIGH! Have you added the pullup resistor?");
    delay(100);
  }

}

I can confirm that your code does indeed work, at least for blinking the LED on my board.
However it only works when using the Library version 1.0.2 or lower.

Not sure what changed in the library in the later versions, but it looks to have broken the GPIO functionality.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.