Skip to content

Instantly share code, notes, and snippets.

@drashna
Created October 31, 2025 18:55
Show Gist options
  • Select an option

  • Save drashna/2071ef449fc51acb1d3e313b3600bb36 to your computer and use it in GitHub Desktop.

Select an option

Save drashna/2071ef449fc51acb1d3e313b3600bb36 to your computer and use it in GitHub Desktop.
ft6x36 driver (not working?)
// Copyright 2025 Christopher Courtney, aka Drashna Jael're (@drashna) <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "ft6x36.h"
#include "i2c_master.h"
#include "print.h"
#include "timer.h"
#include "gpio.h"
#include "wait.h"
// FT6X36 touch controller datasheet:
// https://www.buydisplay.com/download/ic/FT6236-FT6336-FT6436L-FT6436_Datasheet.pdf
#ifndef FT6X36_I2C_ADDRRESS
# define FT6X36_I2C_ADDRRESS 0x38
#endif // FT6X36_I2C_ADDRRESS
#ifndef FT6X36_I2C_TIMEOUT
# define FT6X36_I2C_TIMEOUT 100
#endif // FT6X36_I2C_TIMEOUT
// #ifndef FT6X36_RESET_PIN
// # error "FT6X36_RESET_PIN is not defined and is required for proper operation"
// #endif // FT6X36_RESET_PIN
static const uint8_t threshold = FT6X36_DEFAULT_THRESHOLD;
bool ft6x36_init(void) {
i2c_init();
uint8_t data = 0;
#ifdef FT6X36_INTERRUPT_PIN
gpio_set_pin_input_low(FT6X36_INTERRUPT_PIN);
gpio_set_pin_output_open_drain(FT6X36_RESET_PIN);
#endif
#ifndef FT6X36_RESET_PIN
gpio_write_pin_high(FT6X36_RESET_PIN);
#endif
if (i2c_read_register(FT6X36_I2C_ADDRRESS << 1, FT6X36_REG_PANEL_ID, &data, 1, FT6X36_I2C_TIMEOUT) !=
I2C_STATUS_SUCCESS) {
xprintf("Failed to read panel ID\n");
return false;
}
if (data != FT6X36_VENDID) {
xprintf("Invalid vendor ID: %02X\n", data);
return false;
}
i2c_read_register(FT6X36_I2C_ADDRRESS << 1, FT6X36_REG_CHIPID, &data, sizeof(data), FT6X36_I2C_TIMEOUT);
if (data == FT6206_CHIPID) {
xprintf("Detected FT6206\n");
} else if (data == FT6236_CHIPID) {
xprintf("Detected FT6236\n");
} else if (data == FT6336_CHIPID) {
xprintf("Detected FT6336\n");
} else {
xprintf("Invalid chip ID: %02X\n", data);
return false;
}
// set device mode to "working mode"
i2c_write_register(FT6X36_I2C_ADDRRESS << 1, FT6X36_REG_DEVICE_MODE, 0, 1, FT6X36_I2C_TIMEOUT);
// set threshold for touch detection
i2c_write_register(FT6X36_I2C_ADDRRESS << 1, FT6X36_REG_THRESHOLD, &threshold, 1, FT6X36_I2C_TIMEOUT);
// set report rate in active mode
i2c_write_register(FT6X36_I2C_ADDRRESS << 1, FT6X36_REG_TOUCHRATE_ACTIVE, (const uint8_t *)0x0E, 1,
FT6X36_I2C_TIMEOUT);
// // set to polling mode
i2c_write_register(FT6X36_I2C_ADDRRESS << 1, FT6X36_REG_INTERRUPT_MODE, (const uint8_t *)1, 1, FT6X36_I2C_TIMEOUT);
return true;
}
void ft6x36_read_data(void) {
uint8_t data[16];
i2c_write_register(FT6X36_I2C_ADDRRESS << 1, FT6X36_REG_DEVICE_MODE, 0, 1, FT6X36_I2C_TIMEOUT);
i2c_status_t status = i2c_read_register(FT6X36_I2C_ADDRRESS << 1, 0, data, ARRAY_SIZE(data), FT6X36_I2C_TIMEOUT);
if (status != I2C_STATUS_SUCCESS) {
xprintf("Failed to read data\n");
return;
}
xprintf("Data 1: %02X %02X %02X %02X %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3], data[4], data[5],
data[6], data[7]);
xprintf("Data 2: %02X %02X %02X %02X %02X %02X %02X %02X\n", data[8], data[9], data[10], data[11], data[12],
data[13], data[14], data[15]);
}
void ft6x36_task(void) {
static uint16_t interval = 0;
if (timer_elapsed(interval) > 1000) {
interval = timer_read();
// bool state = gpio_read_pin(FT6X36_INTERRUPT_PIN);
// xprintf("INT: %d\n", state);
// ft6x36_read_data();
}
}
// Copyright 2025 Christopher Courtney, aka Drashna Jael're (@drashna) <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <stdint.h>
#include <stdbool.h>
enum ft6x36_registers {
FT6X36_REG_DEVICE_MODE = 0x00,
FT6X36_REG_GESTURE_ID = 0x01,
FT6X36_REG_NUM_TOUCHES = 0x02,
FT6X36_REG_P1_XH = 0x03,
FT6X36_REG_P1_XL = 0x04,
FT6X36_REG_P1_YH = 0x05,
FT6X36_REG_P1_YL = 0x06,
FT6X36_REG_P1_WEIGHT = 0x07,
FT6X36_REG_P1_MISC = 0x08,
FT6X36_REG_P2_XH = 0x09,
FT6X36_REG_P2_XL = 0x0A,
FT6X36_REG_P2_YH = 0x0B,
FT6X36_REG_P2_YL = 0x0C,
FT6X36_REG_P2_WEIGHT = 0x0D,
FT6X36_REG_P2_MISC = 0x0E,
FT6X36_REG_THRESHOLD = 0x80,
FT6X36_REG_FILTER_COEF = 0x85,
FT6X36_REG_CTRL = 0x86,
FT6X36_REG_TIME_ENTER_MONITOR = 0x87,
FT6X36_REG_TOUCHRATE_ACTIVE = 0x88,
FT6X36_REG_TOUCHRATE_MONITOR = 0x89, // value in ms
FT6X36_REG_RADIAN_VALUE = 0x91,
FT6X36_REG_OFFSET_LEFT_RIGHT = 0x92,
FT6X36_REG_OFFSET_UP_DOWN = 0x93,
FT6X36_REG_DISTANCE_LEFT_RIGHT = 0x94,
FT6X36_REG_DISTANCE_UP_DOWN = 0x95,
FT6X36_REG_DISTANCE_ZOOM = 0x96,
FT6X36_REG_LIB_VERSION_H = 0xA1,
FT6X36_REG_LIB_VERSION_L = 0xA2,
FT6X36_REG_CHIPID = 0xA3,
FT6X36_REG_INTERRUPT_MODE = 0xA4,
FT6X36_REG_POWER_MODE = 0xA5,
FT6X36_REG_FIRMWARE_VERSION = 0xA6,
FT6X36_REG_PANEL_ID = 0xA8,
FT6X36_REG_STATE = 0xBC,
};
enum ft6x36_power_mode {
FT6X36_PMODE_ACTIVE = 0x00,
FT6X36_PMODE_MONITOR = 0x01,
FT6X36_PMODE_STANDBY = 0x02,
FT6X36_PMODE_HIBERNATE = 0x03,
};
#define FT6X36_VENDID 0x11
#define FT6206_CHIPID 0x06
#define FT6236_CHIPID 0x36
#define FT6336_CHIPID 0x64
#ifndef FT6X36_DEFAULT_THRESHOLD
# define FT6X36_DEFAULT_THRESHOLD 22
#endif
enum ft6x36_raw_touch_event {
PressDown,
LiftUp,
Contact,
NoEvent,
};
enum ft6x36_touch_event {
None,
TouchStart,
TouchMove,
TouchEnd,
Tap,
DragStart,
DragMove,
DragEnd,
};
enum ft6x36_gesture_event {
NoGesture = 0x00,
SwipeUp = 0x10,
SwipeRight = 0x14,
SwipeDown = 0x18,
SwipeLeft = 0x1C,
ZoomIn = 0x48,
ZoomOut = 0x49,
};
typedef struct {
uint8_t device_mode;
uint8_t gesture_id;
uint8_t num_touches;
union {
struct {
uint8_t msb_x : 4;
uint8_t reserved : 2;
uint8_t event : 2;
} b;
uint8_t w;
} x_high;
uint8_t x_low;
union {
struct {
uint8_t msb_y : 4;
uint8_t touch_id : 4;
} b;
uint8_t w;
} y_high;
uint8_t y_low;
uint8_t weight;
uint8_t misc;
} ft6x36_data_t;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment