Arduino Library for SX8646 Capacitive Button Controller

 Author:   Posted on:   Updated on:  2019-04-28T10:53:01Z

The router front panel with LCD I began interfacing has a capacitive five button keypad. The panel I'm talking about was used by Sercomm SHG1500 routers and although there are multiple hardware versions of the LCD (some make use of FPGA circuits to drive the LCD, others use SPI interface), the keypad seems to be the same. Based on Semtech SX8646, it is controlled over I2C bus.

SX8646 requires 3.3 V power and is not compatible with 5 V bus. Besides I2C, it uses another pin to trigger an interrupt at host when a button is touched. The keypad PCB sits next to LCD PCB and on some hardware versions it plugs straight into it, while on others it uses a connection cable going to the router main board.

Arduino Library for SX8646 Capacitive Button Controller

SX8646 keypad PCB

The PCB in the above photo is the version that plugs into LCD PCB. Although the controller is a 3.3 V device, 5 V are also needed for the LEDs that light the keys. The pinout of this keypad is the following.

Pinout of the SX8646 keypad PCB

Pinout of the SX8646 keypad PCB

I'm not using this connector to wire it to Arduino (it has small pitch, probably 1 mm and some adapter would be required). Instead, all of these pins are available on LCD PCB connector. I've written about wiring here. I do not own the hardware version that uses a cable to connect to main board, yet the boards I have include unpopulated pads for this. It's the JP7 connector. You can find its pinout in the linked post too (it is placed next to the serial port).

I couldn't find any opensource driver for this controller, but the manufacturer has published its datasheet. With this and some logic analyzer sampling when connected to router, I was able to write a library. The configuration is identical to the one used by router. This means backlight LEDs are on all the time and turn off for a short moment when you touch a key. This behavior can be modified, but the library does not support this in this version.

SX8646 keypad schematic

SX8646 keypad schematic

SX8646 makes use of three internal memory sources, each with its name. There is the SPM (shadow parameter memory) where all parameters need to be written (copied). Whatever is set here is currently used by the controller. This is a sort of RAM memory, losing all its contents after reset and power up. Yet, at power up, SX8646 looks into NVM (non volatile memory). This is a permanent storage memory which can be programmed by user (no more than three times). If it contains valid data, its contents are copied into SPM and applied. SX8646 should be initialized and working now, without any host interaction. And there is a third memory, QSM (quick start memory), which is permanent and can't be modified. This contains factory defaults and is used as source for SPM whenever NVM is empty, invalid or written more than 3 times.

I didn't quite understand if QSM defaults SPM to a working state, but as proven by logic sampling, the interrupt pin does not trigger unless SPM is modified over I2C. Anyway, some routines for reading and writing SPM were needed. The datasheet explains the procedure and claims SPM can only be read or written in blocks of 8 bytes.

void SX8646::spmRead(uint8_t addr, uint8_t *spm) {
 writeRegister(0x0D, 0x18); // I2C in SPM: SpmCfg[5:4]=1, Read mode: SpmCfg[3]=1
 delay(30); // not specified by datasheet but used by router software
 writeRegister(0x0E, addr); // SpmBaseAddr
 readRegisters(0x00, &spm[0], 8);
 writeRegister(0x0D, 0x00); // reset SpmCfg

void SX8646::spmWrite(uint8_t addr, uint8_t *spm) {
 writeRegister(0x0D, 0x10); // I2C in SPM: SpmCfg[5:4]=1
 delay(30); // section 6.6.1, page 62 in datasheet - not quite clear
 writeRegister(0x0E, addr); // SpmBaseAddr
 delay(30); // whether all these delays are needed
 writeRegisters(0x00, &spm[0], 8);
 delay(30); // but they are used by router software
 writeRegister(0x0D, 0x00); // reset SpmCfg

To achieve low power, SX8646 is active only at 30 ms intervals. You may write to I2C, but data is processed and applied within 30 ms. Again, datasheet is not quite clear about which operations need waiting time and which don't, so I used the same timings as those detected by logic sampling when keypad was connected to router. SPM writing (writing the data block) requires 30 ms for sure, but for the others I don't know (write mode setting, address selection).

The library manages the interrupt generated by SX8646. You need to provide a callback function to handle key touches with setKeyCallback().

#include "SX8646.h"

#define KEY_INTB  PA8 // keypad interrupt pin
SX8646 keypad(KEY_INTB);

void keyTouched(const uint8_t key) {
  if (key == PANEL_NONE) Serial.println("Key: NONE");
  if (key == PANEL_OK) Serial.println("Key: OK");
  if (key == PANEL_UP) Serial.println("Key: UP");
  if (key == PANEL_DOWN) Serial.println("Key: DOWN");
  if (key == PANEL_LEFT) Serial.println("Key: LEFT");
  if (key == PANEL_RIGHT) Serial.println("Key: RIGHT");

void setup() {
  Serial.println("Semtech SX8646 Test");


This is a simple code to read key touches. But remember that every key is a bit in the byte that holds touched keys. Therefore you can handle simultaneous touches by checking a bit instead (i.e. if (key & PANEL_OK) { /* OK is touched */ }). Because of this, the above code will fail when more than one key is touched. There is nothing needed in loop() for this library.

The library is on GitHub and SX8646 datasheet is provided by Semtech. Code has only been compiled for STM32, but it should work on other Arduino platforms. Now I have a fully working front panel from Sercomm SHG1500 router, version LCDv6, which will be a great addition for my future projects.

No comments :

Post a Comment

Please read the comments policy before publishing your comment.