Programming the interrupt output on the CST816S touchscreen controller for a Waveshare 1.28" Touch LCD

Has anyone managed to program a touchscreen with a CST816S touchscreen controller so that the interrupt pin TP_INT goes low ONLY when a gesture is detected? Currently this pin goes low whenever I touch the touchscreen regardless of whether a gesture is detected.

I’ve tried writing numerous values to the register 0xFA but this has not changed how the interrupt pin operates. This register is IrqCt1 according to the register declaration document downloaded from this website:

Some of the other registers do work (for example writing to IrqPluseWidth (0xED) does change the width of the low pulse on the interrupt pin when the screen is touched).

Unfortunately there’s discrepancies throughout the register list including for the IrqCt1 register and in general the registers are poorly explained.

The CST816S chip on my Waveshare 1.28" Touch LCD has the following details:
chip ID - 181 (from register 0xA7)
project ID - 56 (from register 0xA8)
firmware version - 1 (from register 0xA9)

Let me know if it’s helpful and I’ll post the code.

Thanks,
James

Hey @James36651, welcome to the forums!

Sending code is definitely useful, even just to have another set of eyes check over it!

I haven’t used this exact touch LCD before but the CST816S seems to be fairly commonly used for touch and gesture detection.

I found this CST816T Arduino library on Github by koendv that creates simple functions to setup the device and change modes.

Their gesture-interrupt mode is named according to the register reference doc.

I did a bit of digging in the source code for this library (src > cst816t.cpp) and the following two lines are used to write register values for the interrupt register and the motion mask register.

i2c_write(CST816T_ADDRESS, REG_IRQ_CTL, &irq_en, 1);
i2c_write(CST816T_ADDRESS, REG_MOTION_MASK, &motion_mask, 1);

where:

CST816T_ADDRESS = 0x15 # Device I2C Address
REG_IRQ_CTL = 0xFA     # IRQ Register Address
REG_MOTION_MASK = 0xEC # Motion MaskRegister Address

When the IRQ mode is set to “mode_motion”, the value within irq_en will be according to the following:

image

Where:

IRQ_EN_MOTION | IRQ_EN_LONGPRESS = 0x10 | 0x01 = 0x11 = 0b00010001
MOTION_MASK_DOUBLE_CLICK = 0b001

So the IrqCtl register will have bit4 and bit0 set and all others reset, which seems to correspond to EnMotion and OnceWLP. The MotionMask register will have bit 0 set and all others reset, though I’m unsure how necessary this change is.

I’m not sure which microcontroller you’re using, perhaps you can just use this library if you’re on Arduino. At any rate, setting these bits accordingly seems to have worked for koendv (author of the library).

Let us know how this goes!

Hi @Zach ,

thanks for the quick response and investigation, really appreciate it. I’m using an arduino uno minima. I downloaded the koendv library and attempted to use the touchme example, it compiles (as long as I change the values for TP_SDA and TP_SCL), but it wasn’t printing gestures like it’s supposed to do. I’ll look into it further in the next day or two but it looks like it’s writing to the same registers and values as I’ve attempted to.

Here’s my code, hopefully you pick up something I’ve overlooked:

#include <Wire.h>

#define CST816S_ADDR 0x15  // I2C address of the CST816S
#define GESTURE_REG 0x01   // Register for gesture data
#define FINGER_NUM 0x02 //reg for number of fingers touching screen
#define CHIP_ID 0xA7 //reg for chip id
#define X_POSH 0x03 //reg for x pos
#define X_POSL 0x04 //reg for x pos
#define BPC0H 0xB0 //
#define BPC0L 0xB1
#define BPC1H 0xB2
#define BPC1L 0xB3
#define MOTIONMASK 0xEC
#define DEBOUNCE_TIME 0xFB
#define INTERRUPT_REG 0xFA
#define INTERRUPT_PULSE 0xED
#define DEBOUNCE_T 0xFB

const byte interruptPin = 1; //interruupt 1 (pin 3 on arduino)
const byte resetPin = 4;
volatile int gestureVar=0;

void gestureCheck()
{
  gestureVar=1;
}

void setup() {
    pinMode(resetPin, OUTPUT);
    Serial.begin(115200);
    while(!Serial)
    {}
    Serial.println("aTEST"); //put in as a test
   
   //---------unreset so screen is in active mode
    digitalWrite(resetPin, LOW);
    delay(50);
    digitalWrite(resetPin,HIGH);//setting this pin is preventing/delaying from being able to communicate with i2c...
    delay(50);
    //pinMode(resetPin, INPUT); //TP works better when this pin is left as input for some reason
    Wire.begin();
  //-----------

    Wire.beginTransmission(CST816S_ADDR);
    Wire.write(INTERRUPT_REG); //register
//    Wire.write(INTERRUPT_PULSE); //register
//    Wire.write(DEBOUNCE_T); //register
    Wire.write(0b00010001); //interrupt condition <---------- try modifying this
    Serial.print(Wire.endTransmission());
    Serial.println(" - irq reg");

    Wire.beginTransmission(CST816S_ADDR);
    Wire.write(INTERRUPT_PULSE); //register    
    Wire.write(0b00000001); //interrupt condition <---------- try modifying this
    Serial.print(Wire.endTransmission());
    Serial.println(" - pulse width");

    Wire.beginTransmission(CST816S_ADDR);
    //delay(500); 
    Wire.write(MOTIONMASK); //register
    Wire.write(0x01); //enable double click
    Serial.print(Wire.endTransmission());
    Serial.println(" - Motion mask");

    Wire.beginTransmission(CST816S_ADDR);
    Wire.write(MOTIONMASK); //register    
    Wire.endTransmission();
    Wire.requestFrom(CST816S_ADDR, 1);
    if(Wire.available())
    {
      uint8_t motionMask2 = Wire.read();
      Serial.print("motionM2 confirm: ");
      Serial.println(motionMask2);
    }

    Wire.beginTransmission(CST816S_ADDR);
    Wire.write(INTERRUPT_REG); //register    
    Wire.endTransmission();
    Wire.requestFrom(CST816S_ADDR, 1);
    if(Wire.available())
    {
      uint8_t interruptReg = Wire.read();
      Serial.print("intReg confirm: ");
      Serial.println(interruptReg);
    }

//    attachInterrupt(0, gestureCheck, FALLING); 

}

void loop() {

  if(digitalRead(A2)==0)
    {
    Wire.beginTransmission(CST816S_ADDR);
    Wire.write(GESTURE_REG);
    Wire.endTransmission();
    Wire.requestFrom(CST816S_ADDR, 1);
    
    if (Wire.available()) {
        uint8_t gesture = Wire.read();
        switch (gesture) {
            //case 0x00:
                //Serial.print("no gesture - ");
                //Serial.println(millis());
            case 0x01:
                Serial.print("swipe up - ");
                Serial.println(millis());
                break;
            case 0x02:
                Serial.print("swipe down - ");
                Serial.println(millis());
                break;
            case 0x03:
                Serial.print("swipe left - ");
                Serial.println(millis());
                break;
            case 0x04:
                Serial.print("swipe right - ");
                Serial.println(millis());
                break;
            case 0x0B:
                Serial.print("double click - ");
                Serial.println(millis());
                break;
        }
    digitalWrite(13,1);
    delay(10);
    digitalWrite(13,0);
    }

    //gestureVar=0;
    }
      
}
1 Like

Hey @James36651,

let us know if you end up figuring this out, seems like a complicated one.

Having a look through your code I can’t see anything obviously incorrect although it may help to address the registers in order. The datasheet, while vague, does seem to indicate that modifying 0xFA before 0xFB for example may prove more successful.

Best of luck with this!

After looking into this further I found that the touch driver used on my Waveshare 1.28inch Touch LCD is actually the CST816T, not the CST816S as the Waveshare Wiki stated (has since been updated to say CST816S/T). According to Waveshare support these chips should have identical registers, so not sure what the difference between the chips actually is.

I since ordered another 1.28" capacitive touch screen from Alibaba (same as this one: 1.28 inch 240x240 IPS TFT LCD Round Circle Capacitive Touch Screen), and it has a CST816D chip. Funny thing is this display works exactly as described on the register, if I write bit 4 to register IrqCt1 it gives a single low pulse only when a gesture is detected and similarly writing to the other bits for IrqCt1 work as described. Code I used to test these two was identical.

If anyone else has a Waveshare touch LCD I’d be really interested to know what the driver chip PN is and whether the interrupt output behaves as described in the datasheet, or if it fires continuously whenever the screen is touched like mine does. I’m wondering whether there actually is a difference between the CST816S/CST816D and CST816T chips, or if mine is just faulty for some reason.



You can request a firmware upgrade or clarification from Waveshare or the actual IC vendor. Some developers have succeeded in getting better documentation this way.

Thanks @ahsrab292840 for the reply, I’ve been in touch with Waveshare but they weren’t super knowledgeable about these chips and just told me it was working correctly which is obviously wrong considering what the CST816S datasheet says and how the CST816D I have works. I’ll try the chip manufacturer if I can figure out who it actually is and if they have a support contact… I’m not holding my breath that they will.

What I’d really like to know is if anyone has one of these devices 1) what chip does it use and 2) does their interrupt signal perform as per the datasheet, or does it pulse continuously whenever a touch is detected regardless of how the interrupt register is set.