From 45c68ef0fc565309928bbbd405534ee91eebb5a2 Mon Sep 17 00:00:00 2001 From: sago35 Date: Tue, 14 Dec 2021 22:29:33 +0900 Subject: [PATCH] ft6336: add support for ft6336 --- Makefile | 7 +- README.md | 3 +- examples/ft6336/basic/m5stack_core2.go | 24 +++ examples/ft6336/basic/main.go | 16 ++ examples/ft6336/touchpaint/m5stack_core2.go | 55 +++++++ examples/ft6336/touchpaint/main.go | 163 ++++++++++++++++++++ ft6336/ft6336.go | 107 +++++++++++++ ft6336/registers.go | 49 ++++++ 8 files changed, 422 insertions(+), 2 deletions(-) create mode 100644 examples/ft6336/basic/m5stack_core2.go create mode 100644 examples/ft6336/basic/main.go create mode 100644 examples/ft6336/touchpaint/m5stack_core2.go create mode 100644 examples/ft6336/touchpaint/main.go create mode 100644 ft6336/ft6336.go create mode 100644 ft6336/registers.go diff --git a/Makefile b/Makefile index e87d2db..9543508 100644 --- a/Makefile +++ b/Makefile @@ -219,12 +219,17 @@ endif @md5sum ./build/test.hex tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/xpt2046/main.go @md5sum ./build/test.uf2 + tinygo build -size short -o ./build/test.elf -target=m5stack-core2 ./examples/ft6336/basic/ + @md5sum ./build/test.elf + tinygo build -size short -o ./build/test.elf -target=m5stack-core2 ./examples/ft6336/touchpaint/ + @md5sum ./build/test.elf DRIVERS = $(wildcard */) NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \ hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \ hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 \ - pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 axp192 xpt2046 + pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 axp192 xpt2046 \ + ft6336 TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS)) unit-test: diff --git a/README.md b/README.md index d665595..a2b699a 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ func main() { ## Currently supported devices -The following 77 devices are supported. +The following 78 devices are supported. | Device Name | Interface Type | |----------|-------------| @@ -78,6 +78,7 @@ The following 77 devices are supported. | [DS3231 real time clock](https://datasheets.maximintegrated.com/en/ds/DS3231.pdf) | I2C | | [ESP32 as WiFi Coprocessor with Arduino nina-fw](https://github.com/arduino/nina-fw) | SPI | | [ESP8266/ESP32 AT Command set for WiFi/TCP/UDP](https://github.com/espressif/esp32-at) | UART | +| [FT6336 touch controller](https://focuslcds.com/content/FT6236.pdf) | I2C | | [GPS module](https://www.u-blox.com/en/product/neo-6-series) | I2C/UART | | [HC-SR04 Ultrasonic distance sensor](https://cdn.sparkfun.com/datasheets/Sensors/Proximity/HCSR04.pdf) | GPIO | | [HD44780 LCD controller](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | GPIO/I2C | diff --git a/examples/ft6336/basic/m5stack_core2.go b/examples/ft6336/basic/m5stack_core2.go new file mode 100644 index 0000000..ff475bd --- /dev/null +++ b/examples/ft6336/basic/m5stack_core2.go @@ -0,0 +1,24 @@ +//go:build m5stack_core2 +// +build m5stack_core2 + +package main + +import ( + "machine" + + "tinygo.org/x/drivers/ft6336" + "tinygo.org/x/drivers/i2csoft" + "tinygo.org/x/drivers/touch" +) + +// InitDisplay initializes the display of each board. +func initDevices() (touch.Pointer, error) { + i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN) + i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3}) + + resistiveTouch := ft6336.New(i2c, machine.Pin(39)) + resistiveTouch.Configure(ft6336.Config{}) + resistiveTouch.SetPeriodActive(0x00) + + return resistiveTouch, nil +} diff --git a/examples/ft6336/basic/main.go b/examples/ft6336/basic/main.go new file mode 100644 index 0000000..a421ec7 --- /dev/null +++ b/examples/ft6336/basic/main.go @@ -0,0 +1,16 @@ +package main + +func main() { + touchScreen, _ := initDevices() + + for { + touch := touchScreen.ReadTouchPoint() + if touch.Z > 0 { + //X and Y are 16 bit with 12 bit resolution and need to be scaled for the display size + //Z is 24 bit and is typically > 2000 for a touch + println("touch:", touch.X, touch.Y, touch.Z) + //Example of scaling for m5stack-core2's 320x240 display with 320x270 touch area + println("screen:", (touch.X*320)>>16, (touch.Y*270)>>16) + } + } +} diff --git a/examples/ft6336/touchpaint/m5stack_core2.go b/examples/ft6336/touchpaint/m5stack_core2.go new file mode 100644 index 0000000..b4f91c0 --- /dev/null +++ b/examples/ft6336/touchpaint/m5stack_core2.go @@ -0,0 +1,55 @@ +//go:build m5stack_core2 +// +build m5stack_core2 + +package main + +import ( + "image/color" + "machine" + + axp192 "tinygo.org/x/drivers/axp192/m5stack-core2-axp192" + "tinygo.org/x/drivers/ft6336" + "tinygo.org/x/drivers/i2csoft" + "tinygo.org/x/drivers/ili9341" + "tinygo.org/x/drivers/touch" +) + +// InitDisplay initializes the display of each board. +func initDevices() (touchPaintDisplay, touch.Pointer, error) { + machine.SPI2.Configure(machine.SPIConfig{ + SCK: machine.LCD_SCK_PIN, + SDO: machine.LCD_SDO_PIN, + SDI: machine.LCD_SDI_PIN, + Frequency: 40e6, + }) + + i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN) + i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3}) + + axp := axp192.New(i2c) + led := axp.LED + led.Low() + + display := ili9341.NewSPI( + machine.SPI2, + machine.LCD_DC_PIN, + machine.LCD_SS_PIN, + machine.NoPin, + ) + + // configure display + display.Configure(ili9341.Config{ + Width: 320, + Height: 240, + DisplayInversion: true, + }) + display.FillScreen(color.RGBA{255, 255, 255, 255}) + + display.SetRotation(ili9341.Rotation0Mirror) + + resistiveTouch := ft6336.New(i2c, machine.Pin(39)) + resistiveTouch.Configure(ft6336.Config{}) + resistiveTouch.SetPeriodActive(0x00) + + return display, resistiveTouch, nil +} diff --git a/examples/ft6336/touchpaint/main.go b/examples/ft6336/touchpaint/main.go new file mode 100644 index 0000000..35dfe59 --- /dev/null +++ b/examples/ft6336/touchpaint/main.go @@ -0,0 +1,163 @@ +package main + +import ( + "image/color" + "math" + + "tinygo.org/x/drivers" + "tinygo.org/x/drivers/touch" +) + +type touchPaintDisplay interface { + drivers.Displayer + FillRectangle(x, y, width, height int16, c color.RGBA) error + DrawRectangle(x, y, w, h int16, c color.RGBA) error +} + +var ( + white = color.RGBA{255, 255, 255, 255} + black = color.RGBA{0, 0, 0, 255} + red = color.RGBA{255, 0, 0, 255} + green = color.RGBA{0, 255, 0, 255} + blue = color.RGBA{0, 0, 255, 255} + magenta = color.RGBA{255, 0, 255, 255} + yellow = color.RGBA{255, 255, 0, 255} + cyan = color.RGBA{0, 255, 255, 255} + + oldColor color.RGBA + currentColor color.RGBA +) + +const ( + penRadius = 3 + boxSize = 30 + + Xmin = 0 + Xmax = 0xFFFF + Ymin = 0 + Ymax = 0xFFFF +) + +func main() { + display, resistiveTouch, _ := initDevices() + + // fill the background and activate the backlight + width, height := display.Size() + display.FillRectangle(0, 0, width, height, black) + + // make color selection boxes + display.FillRectangle(0, 0, boxSize, boxSize, red) + display.FillRectangle(boxSize, 0, boxSize, boxSize, yellow) + display.FillRectangle(boxSize*2, 0, boxSize, boxSize, green) + display.FillRectangle(boxSize*3, 0, boxSize, boxSize, cyan) + display.FillRectangle(boxSize*4, 0, boxSize, boxSize, blue) + display.FillRectangle(boxSize*5, 0, boxSize, boxSize, magenta) + display.FillRectangle(boxSize*6, 0, boxSize, boxSize, black) + display.FillRectangle(boxSize*7, 0, boxSize, boxSize, white) + + // set the initial color to red and draw a box to highlight it + oldColor = red + currentColor = red + display.DrawRectangle(0, 0, boxSize, boxSize, white) + + last := touch.Point{} + + // loop and poll for touches, including performing debouncing + debounce := 0 + for { + + point := resistiveTouch.ReadTouchPoint() + touch := touch.Point{} + if point.Z>>6 > 100 { + rawX := mapval(point.X, Xmin, Xmax, 0, int(width)) + rawY := mapval(point.Y, Ymin, Ymax, 0, int(height)) + touch.X = rawX + touch.Y = rawY + touch.Z = 1 + } else { + touch.X = 0 + touch.Y = 0 + touch.Z = 0 + } + + if last.Z != touch.Z { + debounce = 0 + last = touch + } else if math.Abs(float64(touch.X-last.X)) > 4 || + math.Abs(float64(touch.Y-last.Y)) > 4 { + debounce = 0 + last = touch + } else if debounce > 1 { + debounce = 0 + HandleTouch(display, last) + } else if touch.Z > 0 { + debounce++ + } else { + last = touch + debounce = 0 + } + + } +} + +// based on Arduino's "map" function +func mapval(x int, inMin int, inMax int, outMin int, outMax int) int { + return (x-inMin)*(outMax-outMin)/(inMax-inMin) + outMin +} + +func HandleTouch(display touchPaintDisplay, touch touch.Point) { + + if int16(touch.Y) < boxSize { + oldColor = currentColor + x := int16(touch.X) + switch { + case x < boxSize: + currentColor = red + case x < boxSize*2: + currentColor = yellow + case x < boxSize*3: + currentColor = green + case x < boxSize*4: + currentColor = cyan + case x < boxSize*5: + currentColor = blue + case x < boxSize*6: + currentColor = magenta + case x < boxSize*7: + currentColor = black + case x < boxSize*8: + currentColor = white + } + + if oldColor == currentColor { + return + } + + display.DrawRectangle((x/boxSize)*boxSize, 0, boxSize, boxSize, white) + switch oldColor { + case red: + x = 0 + case yellow: + x = boxSize + case green: + x = boxSize * 2 + case cyan: + x = boxSize * 3 + case blue: + x = boxSize * 4 + case magenta: + x = boxSize * 5 + case black: + x = boxSize * 6 + case white: + x = boxSize * 7 + } + display.FillRectangle(int16(x), 0, boxSize, boxSize, oldColor) + + } + + if (int16(touch.Y) - penRadius) > boxSize { + display.FillRectangle( + int16(touch.X), int16(touch.Y), penRadius*2, penRadius*2, currentColor) + } +} diff --git a/ft6336/ft6336.go b/ft6336/ft6336.go new file mode 100644 index 0000000..a0662a8 --- /dev/null +++ b/ft6336/ft6336.go @@ -0,0 +1,107 @@ +// Package ft6336 provides a driver for the FT6336 I2C Self-Capacitive touch +// panel controller. +// +// Datasheet: https://focuslcds.com/content/FT6236.pdf +// +package ft6336 + +import ( + "machine" + + "tinygo.org/x/drivers" + "tinygo.org/x/drivers/touch" +) + +// Device wraps FT6336 I2C Self-Capacitive touch +type Device struct { + bus drivers.I2C + buf []byte + Address uint8 + intPin machine.Pin +} + +// New returns FT6336 device for the provided I2C bus using default address. +func New(i2c drivers.I2C, intPin machine.Pin) *Device { + return &Device{ + bus: i2c, + buf: make([]byte, 11), + Address: Address, + intPin: intPin, + } +} + +// Config contains settings for FT6636. +type Config struct { +} + +// Configure the FT6336 device. +func (d *Device) Configure(config Config) error { + d.write1Byte(0xA4, 0x00) + d.intPin.Configure(machine.PinConfig{Mode: machine.PinInputPulldown}) + return nil +} + +// SetGMode sets interrupt mode. +// 0x00 : Interrupt Polling mode +// 0x01 : Interrupt Trigger mode (default) +func (d *Device) SetGMode(v uint8) { + d.write1Byte(RegGMode, v) +} + +// GetGMode gets interrupt mode. +func (d *Device) GetGMode() uint8 { + return d.read8bit(RegGMode) +} + +// SetPeriodActive sets report rate in Active mode. +func (d *Device) SetPeriodActive(v uint8) { + d.write1Byte(RegPeriodActive, v) +} + +// GetPeriodActive gets report rate in Active mode. +func (d *Device) GetPeriodActive() uint8 { + return d.read8bit(RegPeriodActive) +} + +// GetFirmwareID gets firmware version. +func (d *Device) GetFirmwareID() uint8 { + return d.read8bit(RegFirmid) +} + +// Read reads the registers. +func (d *Device) Read() []byte { + d.bus.Tx(uint16(d.Address), []byte{0x02}, d.buf[:]) + return d.buf[:] +} + +// ReadTouchPoint reads a single touch.Point from the device. The maximum value +// for each touch.Point is 0xFFFF. +func (d *Device) ReadTouchPoint() touch.Point { + d.Read() + z := 0xFFFFF + if d.buf[0] == 0 { + z = 0 + } + + //Scale X&Y to 16 bit for consistency across touch drivers + return touch.Point{ + X: (int(d.buf[1]&0x0F)<<8 + int(d.buf[2])) * ((1 << 16) / 320), + Y: (int(d.buf[3]&0x0F)<<8 + int(d.buf[4])) * ((1 << 16) / 270), + Z: z, + } +} + +// Touched returns if touched or not. +func (d *Device) Touched() bool { + p := d.ReadTouchPoint() + return p.Z > 0 +} + +func (d *Device) write1Byte(reg, data uint8) { + d.bus.WriteRegister(d.Address, reg, []byte{data}) +} + +func (d *Device) read8bit(reg uint8) uint8 { + d.bus.ReadRegister(d.Address, reg, d.buf[:1]) + return d.buf[0] +} diff --git a/ft6336/registers.go b/ft6336/registers.go new file mode 100644 index 0000000..a5eb453 --- /dev/null +++ b/ft6336/registers.go @@ -0,0 +1,49 @@ +package ft6336 + +// 0x00 DEV_MODE +// 0x01 GEST_ID +// 0x02 TD_STATUS +// 0x03 P1_XH +// 0x04 P1_XL +// 0x05 P1_YH +// 0x06 P1_YL +// 0x07 P1_WEIGHT +// 0x08 P1_MISC +// 0x09 P2_XH +// 0x0A P2_XL +// 0x0B P2_YH +// 0x0C P2_YL +// 0x0D P2_WEIGHT +// 0x0E P2_MISC +// 0x80 TH_GROUP +// 0x85 TH_DIFF +// 0x86 CTRL +// 0x87 TIMEENTERMONITOR +// 0x88 PERIODACTIVE +// 0x89 PERIODMONITOR +// 0x91 RADIAN_VALUE +// 0x92 OFFSET_LEFT_RIGHT +// 0x93 OFFSET_UP_D +// 0x94 DISTANCE_LE +// 0x95 DISTANCE_UP +// 0x96 DISTANCE_ZO +// ... +// 0xA1 LIB_VER_H +// 0xA2 LIB_VER_L +// 0xA3 CIPHER +// 0xA4 G_MODE +// 0xA5 PWR_MODE +// 0xA6 FIRMID +// 0xA8 FOCALTECH_ID +// ... +// 0xAF RELEASE_CODE_ID +// ... +// 0xBC STATE + +const ( + Address = 0x38 + + RegPeriodActive = 0x88 + RegGMode = 0xA4 + RegFirmid = 0xA6 +)