diff --git a/Cargo.toml b/Cargo.toml index aaf850d..ab8517b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,17 @@ name = "ft6x06" version = "0.1.0" edition = "2021" authors = ["Shantanu Gaikwad"] -categories = ["embedded", "no-std"] -description = "A platform agnostic driver for the FT6x06 type touch screen driver used on STM32F413 board." +categories = ["embedded", "no-std", "hardware-support"] +description = "A platform agnostic driver for the FT6x06 type touch panel controller used on STM32F4 series board." +license = "MIT OR Apache-2.0" +repository = "https://github.com/Srg213/ft6x06" +keywords = [ + "embedded-hal-driver", + "embedded-hal", + "FT6x06", + "touchscreen", +] +readme = "README.md" [dependencies] embedded-hal = "0.2.7" @@ -42,10 +51,6 @@ name = "touch" [[example]] name = "multi_touch" -[[example]] -name = "gesture_control" -required-features = ["fsmc_lcd"] - [[example]] name = "interface" required-features = ["fsmc_lcd"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..3eee24e --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ + +# FT6x06 driver + +FT6x06 is Self-Capacitive Touch Panel Controller used on many boards manufactured by ST. +The FT6x06 Series ICs are single-chip capacitive touch panel controller ICs with a built-in 8 bit enhanced Micro-controller unit +(MCU).They adopt the self-capacitance technology, which supports single point and gesture touch. In conjunction with a +self-capacitive touch panel. This is built on top of embedded-hal and implements blocking::I2C module. The examples are built using + +The FT6x06 series ICs include FT6206 /FT6306. + +This repo also contains examples for FT6206 IC built on top of abstraction layer for STM32F4 devices-stm32f4xx-hal for the boards +STM32F412 and STM32F413 boards. Documentation of touchscreen controllers on this boards is not well written. I initially forked ft5336 +repo written in rust and modified it to fit to ft6x06. +Other parts of this driver have been reverse-engineered from the code written in C by STMicroelectronics, diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..d534cc3 --- /dev/null +++ b/build.rs @@ -0,0 +1,31 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); +} diff --git a/examples/display_touch.rs b/examples/display_touch.rs index a79bebc..b56ccfe 100644 --- a/examples/display_touch.rs +++ b/examples/display_touch.rs @@ -1,49 +1,41 @@ // #![deny(warnings)] #![no_main] #![no_std] - #![allow(unused_variables)] use cortex_m; use cortex_m_rt::entry; use rtt_target::{rprintln, rtt_init_print}; -use stm32f4xx_hal::{ - fsmc_lcd::{ FsmcLcd, LcdPins, Timing}, - pac, - prelude::*, - rcc::{ Rcc}, -}; #[cfg(feature = "stm32f412")] use stm32f4xx_hal::fsmc_lcd::ChipSelect1; #[cfg(feature = "stm32f413")] use stm32f4xx_hal::fsmc_lcd::ChipSelect3; +use stm32f4xx_hal::{ + fsmc_lcd::{FsmcLcd, LcdPins, Timing}, + pac, + prelude::*, + rcc::Rcc, +}; use embedded_graphics::{ pixelcolor::Rgb565, prelude::*, - primitives::{Circle, PrimitiveStyle}, + primitives::{Circle, PrimitiveStyle}, }; -#[cfg(feature = "stm32f412")] -use stm32f4xx_hal::i2c::I2c; #[cfg(feature = "stm32f413")] use stm32f4xx_hal::fmpi2c::FMPI2c; +#[cfg(feature = "stm32f412")] +use stm32f4xx_hal::i2c::I2c; #[allow(unused_imports)] use panic_semihosting; -use st7789::*; use ft6x06; +use st7789::*; - -/// A simple example to connect to the FT6x06 crate and access it for -/// x and y positions of touch points. There are a lot of commented-out -/// calls to items in the library, but they're a bit pointless. I couldn't -/// get the gesture stuff to work - I couldn't even get an I2C register change -/// to take place. I didn't try for the other functions like Events. -/// -/// It works for me - if you get more working, please send a PR. -/// My approach to Results is also a bit ad-hoc. +/// A simple example to connect to the FT6x06 crate and get the touch coordinates. +/// This example uses embedded-graphics to draw a small circle around the touch area. #[entry] fn main() -> ! { rtt_init_print!(); @@ -56,56 +48,54 @@ fn main() -> ! { let clocks = rcc.cfgr.sysclk(100.MHz()).freeze(); let mut delay = cp.SYST.delay(&clocks); - - let gpiob = p.GPIOB.split(); - let gpioc = p.GPIOC.split(); + + let gpiob = p.GPIOB.split(); + let gpioc = p.GPIOC.split(); let gpiod = p.GPIOD.split(); let gpioe = p.GPIOE.split(); let gpiof = p.GPIOF.split(); let gpiog = p.GPIOG.split(); - - let lcd_pins = LcdPins { - data: ( - gpiod.pd14.into_alternate(), - gpiod.pd15.into_alternate(), - gpiod.pd0.into_alternate(), - gpiod.pd1.into_alternate(), - gpioe.pe7.into_alternate(), - gpioe.pe8.into_alternate(), - gpioe.pe9.into_alternate(), - gpioe.pe10.into_alternate(), - gpioe.pe11.into_alternate(), - gpioe.pe12.into_alternate(), - gpioe.pe13.into_alternate(), - gpioe.pe14.into_alternate(), - gpioe.pe15.into_alternate(), - gpiod.pd8.into_alternate(), - gpiod.pd9.into_alternate(), - gpiod.pd10.into_alternate(), - ), - address: gpiof.pf0.into_alternate(), - read_enable: gpiod.pd4.into_alternate(), - write_enable: gpiod.pd5.into_alternate(), - #[cfg(feature = "stm32f413")] - chip_select: ChipSelect3(gpiog.pg10.into_alternate()), - #[cfg(feature = "stm32f412")] - chip_select: ChipSelect1(gpiod.pd7.into_alternate()), + + let lcd_pins = LcdPins { + data: ( + gpiod.pd14.into_alternate(), + gpiod.pd15.into_alternate(), + gpiod.pd0.into_alternate(), + gpiod.pd1.into_alternate(), + gpioe.pe7.into_alternate(), + gpioe.pe8.into_alternate(), + gpioe.pe9.into_alternate(), + gpioe.pe10.into_alternate(), + gpioe.pe11.into_alternate(), + gpioe.pe12.into_alternate(), + gpioe.pe13.into_alternate(), + gpioe.pe14.into_alternate(), + gpioe.pe15.into_alternate(), + gpiod.pd8.into_alternate(), + gpiod.pd9.into_alternate(), + gpiod.pd10.into_alternate(), + ), + address: gpiof.pf0.into_alternate(), + read_enable: gpiod.pd4.into_alternate(), + write_enable: gpiod.pd5.into_alternate(), + #[cfg(feature = "stm32f413")] + chip_select: ChipSelect3(gpiog.pg10.into_alternate()), + #[cfg(feature = "stm32f412")] + chip_select: ChipSelect1(gpiod.pd7.into_alternate()), }; - // Setup the RESET pin + // Setup the RESET pin + #[cfg(feature = "stm32f413")] + let rst = gpiob.pb13.into_push_pull_output(); + // Enable backlight #[cfg(feature = "stm32f413")] - let rst = gpiob.pb13.into_push_pull_output(); - // Enable backlight - #[cfg(feature = "stm32f413")] - let mut backlight_control = gpioe.pe5.into_push_pull_output(); - - - #[cfg(feature = "stm32f412")] - let rst = gpiod.pd11.into_push_pull_output(); - #[cfg(feature = "stm32f412")] - let mut backlight_control = gpiof.pf5.into_push_pull_output(); - - + let mut backlight_control = gpioe.pe5.into_push_pull_output(); + + #[cfg(feature = "stm32f412")] + let rst = gpiod.pd11.into_push_pull_output(); + #[cfg(feature = "stm32f412")] + let mut backlight_control = gpiof.pf5.into_push_pull_output(); + backlight_control.set_high(); // We're not using the "tearing" signal from the display let mut _te = gpiob.pb14.into_floating_input(); @@ -124,10 +114,9 @@ fn main() -> ! { disp.init(&mut delay).unwrap(); rprintln!("{}", disp.orientation() as u8); disp.clear(Rgb565::BLACK).unwrap(); - - - //Intializing the i2c bus for touchscreen - + + //Intializing the i2c bus for touchscreen + rprintln!("Connecting to I2c"); #[cfg(feature = "stm32f412")] @@ -142,7 +131,7 @@ fn main() -> ! { &clocks, ) }; - + #[cfg(feature = "stm32f413")] let mut i2c = { FMPI2c::new( @@ -154,18 +143,17 @@ fn main() -> ! { 400.kHz(), ) }; - + //ft6x06 driver - let mut touch = ft6x06::Ft6X06::new(&i2c, 0x38, &mut delay).unwrap(); - - let tsc = touch.ts_calibration(&mut i2c); - match tsc { - Err(e) => rprintln!("Error {} from ts_calibration", e), - Ok(u) => rprintln!("ts_calibration returned {}", u), - } + let mut touch = ft6x06::Ft6X06::new(&i2c, 0x38).unwrap(); + + let tsc = touch.ts_calibration(&mut i2c, &mut delay); + match tsc { + Err(e) => rprintln!("Error {} from ts_calibration", e), + Ok(u) => rprintln!("ts_calibration returned {}", u), + } rprintln!("If nothing happens - touch the screen!"); - // for _i in 0..3000 { loop { let t = touch.detect_touch(&mut i2c); let mut num: u8 = 0; @@ -181,22 +169,31 @@ fn main() -> ! { if num > 0 { let t = touch.get_touch(&mut i2c, 1); - + match t { Err(_e) => rprintln!("Error fetching touch data"), - Ok(n) => { rprintln!( - "Touch: {:>3}x{:>3} - weight: {:>3} misc: {}", - n.x, - n.y, - n.weight, - n.misc - ); - // Circle with 1 pixel wide white stroke with top-left point at (10, 20) with a diameter of 3 - Circle::new(Point::new(>::into(n.y), 240 - >::into(n.x)), 20) - .into_styled(PrimitiveStyle::with_stroke(Rgb565::RED, 1)) - .draw(&mut disp).unwrap(); - } - } - } - } + Ok(n) => { + rprintln!( + "Touch: {:>3}x{:>3} - weight: {:>3} misc: {}", + n.x, + n.y, + n.weight, + n.misc + ); + // Circle with 1 pixel wide white stroke with top-left point at (10, 20) with a diameter of 3 + Circle::new( + Point::new( + // The coordinates are flipped. + >::into(n.y), + 240 - >::into(n.x), + ), + 20, + ) + .into_styled(PrimitiveStyle::with_stroke(Rgb565::RED, 1)) + .draw(&mut disp) + .unwrap(); + } + } + } + } } diff --git a/examples/glogic.rs b/examples/glogic.rs new file mode 100644 index 0000000..484ebde --- /dev/null +++ b/examples/glogic.rs @@ -0,0 +1,79 @@ +// #![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m; +use cortex_m_rt::entry; +use rtt_target::{rprintln, rtt_init_print}; +#[cfg(feature = "stm32f413")] +use stm32f4xx_hal::fmpi2c::FMPI2c; +#[cfg(feature = "stm32f412")] +use stm32f4xx_hal::i2c::I2c; +use stm32f4xx_hal::{pac, prelude::*, rcc::Rcc}; + +use panic_semihosting as _; + +extern crate ft6x06; + +/// A simple example to connect to the FT6x06 crate and access it for +/// x and y positions of touch points. There are a lot of commented-out +/// calls to items in the library, but they're a bit pointless. I couldn't +/// get the gesture stuff to work - I couldn't even get an I2C register change +/// to take place. I didn't try for the other functions like Events. +/// +/// It works for me - if you get more working, please send a PR. +/// My approach to Results is also a bit ad-hoc. +#[entry] +fn main() -> ! { + rtt_init_print!(); + rprintln!("Started"); + + let perif = pac::Peripherals::take().unwrap(); + let cp = cortex_m::Peripherals::take().unwrap(); + + let rcc: Rcc = perif.RCC.constrain(); + + let clocks = rcc.cfgr.sysclk(100.MHz()).freeze(); + let mut delay = cp.SYST.delay(&clocks); + + rprintln!("Connecting to I2c"); + + #[cfg(feature = "stm32f412")] + let mut i2c = { + let gpiob = perif.GPIOB.split(); + I2c::new( + perif.I2C1, + ( + gpiob.pb6.into_alternate().set_open_drain(), + gpiob.pb7.into_alternate().set_open_drain(), + ), + 80.kHz(), + &clocks, + ) + }; + + #[cfg(feature = "stm32f413")] + let mut i2c = { + let gpioc = perif.GPIOC.split(); + FMPI2c::new( + perif.FMPI2C1, + ( + gpioc.pc6.into_alternate().set_open_drain(), + gpioc.pc7.into_alternate().set_open_drain(), + ), + 80.kHz(), + ) + }; + + let mut touch = ft6x06::Ft6X06::new(&i2c, 0x38).unwrap(); + + // for _i in 0..3000 { + loop { + let t = touch.gest_logic(&mut i2c); + + match t { + Err(e) => rprintln!("Error {}", e), + Ok(a) => rprintln!("{}", a as str), + } + } +} diff --git a/examples/interface.rs b/examples/interface.rs index fd86f51..e94f2d7 100644 --- a/examples/interface.rs +++ b/examples/interface.rs @@ -1,51 +1,44 @@ -// #![deny(warnings)] #![no_main] #![no_std] - #![allow(unused_variables)] +// #![deny(warnings)] +/// A simple example to connect to the FT6x06 crate on stm32f412/3 board and get the touch data to evaluate +/// which option is clicked by the user. This can be considered as interface +/// for user to give an input. use cortex_m; use cortex_m_rt::entry; use rtt_target::{rprintln, rtt_init_print}; -use stm32f4xx_hal::{ - fsmc_lcd::{FsmcLcd, LcdPins, Timing}, - pac, - prelude::*, - rcc::{ Rcc}, -}; #[cfg(feature = "stm32f412")] use stm32f4xx_hal::fsmc_lcd::ChipSelect1; #[cfg(feature = "stm32f413")] use stm32f4xx_hal::fsmc_lcd::ChipSelect3; +use stm32f4xx_hal::{ + fsmc_lcd::{FsmcLcd, LcdPins, Timing}, + pac, + prelude::*, + rcc::Rcc, +}; use embedded_graphics::{ - mono_font::{ascii::FONT_6X10, MonoTextStyle}, + mono_font::{ascii::FONT_6X10, MonoTextStyle}, pixelcolor::Rgb565, prelude::*, + primitives::{PrimitiveStyleBuilder, Rectangle}, text::Text, - primitives::{Rectangle, PrimitiveStyleBuilder}, }; -#[cfg(feature = "stm32f412")] -use stm32f4xx_hal::i2c::I2c; #[cfg(feature = "stm32f413")] use stm32f4xx_hal::fmpi2c::FMPI2c; +#[cfg(feature = "stm32f412")] +use stm32f4xx_hal::i2c::I2c; #[allow(unused_imports)] use panic_semihosting; -use st7789::*; use ft6x06; +use st7789::*; - -/// A simple example to connect to the FT6x06 crate and access it for -/// x and y positions of touch points. There are a lot of commented-out -/// calls to items in the library, but they're a bit pointless. I couldn't -/// get the gesture stuff to work - I couldn't even get an I2C register change -/// to take place. I didn't try for the other functions like Events. -/// -/// It works for me - if you get more working, please send a PR. -/// My approach to Results is also a bit ad-hoc. #[entry] fn main() -> ! { rtt_init_print!(); @@ -58,56 +51,54 @@ fn main() -> ! { let clocks = rcc.cfgr.sysclk(100.MHz()).freeze(); let mut delay = cp.SYST.delay(&clocks); - - let gpiob = p.GPIOB.split(); - let gpioc = p.GPIOC.split(); + + let gpiob = p.GPIOB.split(); + let gpioc = p.GPIOC.split(); let gpiod = p.GPIOD.split(); let gpioe = p.GPIOE.split(); let gpiof = p.GPIOF.split(); let gpiog = p.GPIOG.split(); - - let lcd_pins = LcdPins { - data: ( - gpiod.pd14.into_alternate(), - gpiod.pd15.into_alternate(), - gpiod.pd0.into_alternate(), - gpiod.pd1.into_alternate(), - gpioe.pe7.into_alternate(), - gpioe.pe8.into_alternate(), - gpioe.pe9.into_alternate(), - gpioe.pe10.into_alternate(), - gpioe.pe11.into_alternate(), - gpioe.pe12.into_alternate(), - gpioe.pe13.into_alternate(), - gpioe.pe14.into_alternate(), - gpioe.pe15.into_alternate(), - gpiod.pd8.into_alternate(), - gpiod.pd9.into_alternate(), - gpiod.pd10.into_alternate(), - ), - address: gpiof.pf0.into_alternate(), - read_enable: gpiod.pd4.into_alternate(), - write_enable: gpiod.pd5.into_alternate(), - #[cfg(feature = "stm32f413")] - chip_select: ChipSelect3(gpiog.pg10.into_alternate()), - #[cfg(feature = "stm32f412")] - chip_select: ChipSelect1(gpiod.pd7.into_alternate()), + + let lcd_pins = LcdPins { + data: ( + gpiod.pd14.into_alternate(), + gpiod.pd15.into_alternate(), + gpiod.pd0.into_alternate(), + gpiod.pd1.into_alternate(), + gpioe.pe7.into_alternate(), + gpioe.pe8.into_alternate(), + gpioe.pe9.into_alternate(), + gpioe.pe10.into_alternate(), + gpioe.pe11.into_alternate(), + gpioe.pe12.into_alternate(), + gpioe.pe13.into_alternate(), + gpioe.pe14.into_alternate(), + gpioe.pe15.into_alternate(), + gpiod.pd8.into_alternate(), + gpiod.pd9.into_alternate(), + gpiod.pd10.into_alternate(), + ), + address: gpiof.pf0.into_alternate(), + read_enable: gpiod.pd4.into_alternate(), + write_enable: gpiod.pd5.into_alternate(), + #[cfg(feature = "stm32f413")] + chip_select: ChipSelect3(gpiog.pg10.into_alternate()), + #[cfg(feature = "stm32f412")] + chip_select: ChipSelect1(gpiod.pd7.into_alternate()), }; - // Setup the RESET pin + // Setup the RESET pin #[cfg(feature = "stm32f413")] - let rst = gpiob.pb13.into_push_pull_output(); - // Enable backlight - #[cfg(feature = "stm32f413")] - let mut backlight_control = gpioe.pe5.into_push_pull_output(); - - - #[cfg(feature = "stm32f412")] - let rst = gpiod.pd11.into_push_pull_output(); - #[cfg(feature = "stm32f412")] - let mut backlight_control = gpiof.pf5.into_push_pull_output(); - - + let rst = gpiob.pb13.into_push_pull_output(); + // Enable backlight + #[cfg(feature = "stm32f413")] + let mut backlight_control = gpioe.pe5.into_push_pull_output(); + + #[cfg(feature = "stm32f412")] + let rst = gpiod.pd11.into_push_pull_output(); + #[cfg(feature = "stm32f412")] + let mut backlight_control = gpiof.pf5.into_push_pull_output(); + backlight_control.set_high(); // We're not using the "tearing" signal from the display let mut _te = gpiob.pb14.into_floating_input(); @@ -126,29 +117,33 @@ fn main() -> ! { disp.init(&mut delay).unwrap(); rprintln!("{}", disp.orientation() as u8); disp.clear(Rgb565::BLACK).unwrap(); - - + let style = PrimitiveStyleBuilder::new() - .stroke_color(Rgb565::RED) - .stroke_width(3) - .fill_color(Rgb565::BLACK) - .build(); - - Rectangle::new(Point::new(140, 80), Size::new(80, 80)) - .into_styled(style) - .draw(&mut disp).unwrap(); - - Rectangle::new(Point::new(20,80), Size::new(80, 80)) - .into_styled(style) - .draw(&mut disp).unwrap(); - - - // Create a new character style - let text_style = MonoTextStyle::new(&FONT_6X10, Rgb565::WHITE); - - Text::new("No", Point::new(180,120), text_style).draw(&mut disp).unwrap(); - Text::new("Yes", Point::new(60, 120), text_style).draw(&mut disp).unwrap(); - + .stroke_color(Rgb565::RED) + .stroke_width(3) + .fill_color(Rgb565::BLACK) + .build(); + + Rectangle::new(Point::new(140, 80), Size::new(80, 80)) + .into_styled(style) + .draw(&mut disp) + .unwrap(); + + Rectangle::new(Point::new(20, 80), Size::new(80, 80)) + .into_styled(style) + .draw(&mut disp) + .unwrap(); + + // Create a new character style + let text_style = MonoTextStyle::new(&FONT_6X10, Rgb565::WHITE); + + Text::new("No", Point::new(180, 120), text_style) + .draw(&mut disp) + .unwrap(); + Text::new("Yes", Point::new(60, 120), text_style) + .draw(&mut disp) + .unwrap(); + rprintln!("Connecting to I2c"); #[cfg(feature = "stm32f412")] @@ -163,7 +158,7 @@ fn main() -> ! { &clocks, ) }; - + #[cfg(feature = "stm32f413")] let mut i2c = { FMPI2c::new( @@ -175,17 +170,16 @@ fn main() -> ! { 10.kHz(), ) }; - - let mut touch = ft6x06::Ft6X06::new(&i2c, 0x38, &mut delay).unwrap(); - - let tsc = touch.ts_calibration(&mut i2c); - match tsc { - Err(e) => rprintln!("Error {} from ts_calibration", e), - Ok(u) => rprintln!("ts_calibration returned {}", u), - } + + let mut touch = ft6x06::Ft6X06::new(&i2c, 0x38).unwrap(); + + let tsc = touch.ts_calibration(&mut i2c, &mut delay); + match tsc { + Err(e) => rprintln!("Error {} from ts_calibration", e), + Ok(u) => rprintln!("ts_calibration returned {}", u), + } rprintln!("If nothing happens - touch the screen!"); - - // for _i in 0..3000 { + loop { let t = touch.detect_touch(&mut i2c); let mut num: u8 = 0; @@ -201,26 +195,23 @@ fn main() -> ! { if num > 0 { let t = touch.get_touch(&mut i2c, 1); - + match t { Err(_e) => rprintln!("Error fetching touch data"), - Ok(n) => { - - if n.x > 80 && n.x < 160{ - if n.y < 100 && n.y > 20 { - rprintln!("You pressed Yes"); - } - if n.y < 200 && n.y > 120 { - rprintln!("You pressed No"); - } - else{ - rprintln!("Press a key"); - } - }else{ - rprintln!("Press a key"); - } - } - } - } -} + Ok(n) => { + if n.x > 80 && n.x < 160 { + if n.y < 100 && n.y > 20 { + rprintln!("You pressed Yes"); + } else if n.y < 200 && n.y > 120 { + rprintln!("You pressed No"); + } else { + rprintln!("Press a key"); + } + } else { + rprintln!("Press a key"); + } + } + } + } + } } diff --git a/examples/multi_touch.rs b/examples/multi_touch.rs new file mode 100644 index 0000000..356290b --- /dev/null +++ b/examples/multi_touch.rs @@ -0,0 +1,108 @@ + +#![no_main] +#![no_std] + +/// An example to use access Ft6x06 driver and get coordinates for +/// multiple touch points. + +use cortex_m; +use cortex_m_rt::entry; +use rtt_target::{rprintln, rtt_init_print}; +#[cfg(feature = "stm32f413")] +use stm32f4xx_hal::fmpi2c::FMPI2c; +#[cfg(feature = "stm32f412")] +use stm32f4xx_hal::i2c::I2c; +use stm32f4xx_hal::{pac, prelude::*, rcc::Rcc}; + +#[allow(unused_imports)] +use panic_semihosting; + +extern crate ft6x06; + +fn main() -> ! { + rtt_init_print!(); + rprintln!("Started"); + + let perif = pac::Peripherals::take().unwrap(); + let cp = cortex_m::Peripherals::take().unwrap(); + + let rcc: Rcc = perif.RCC.constrain(); + + let clocks = rcc.cfgr.sysclk(100.MHz()).freeze(); + let mut delay = cp.SYST.delay(&clocks); + + rprintln!("Connecting to I2c"); + + #[cfg(feature = "stm32f412")] + let mut i2c = { + let gpiob = perif.GPIOB.split(); + I2c::new( + perif.I2C1, + ( + gpiob.pb6.into_alternate().set_open_drain(), + gpiob.pb7.into_alternate().set_open_drain(), + ), + 400.kHz(), + &clocks, + ) + }; + + #[cfg(feature = "stm32f413")] + let mut i2c = { + let gpioc = perif.GPIOC.split(); + FMPI2c::new( + perif.FMPI2C1, + ( + gpioc.pc6.into_alternate().set_open_drain(), + gpioc.pc7.into_alternate().set_open_drain(), + ), + 400.kHz(), + ) + }; + + let mut touch = ft6x06::Ft6X06::new(&i2c, 0x38).unwrap(); + + let tsc = touch.ts_calibration(&mut i2c, &mut delay); + match tsc { + Err(e) => rprintln!("Error {} from ts_calibration", e), + Ok(u) => rprintln!("ts_calibration returned {}", u), + } + rprintln!("If nothing happens - touch the screen!"); + // for _i in 0..3000 { + loop { + let t = touch.detect_touch(&mut i2c); + let mut num: u8 = 0; + match t { + Err(e) => rprintln!("Error {} from fetching number of touches", e), + Ok(n) => { + num = n; + if num != 0 { + rprintln!("Number of touches: {}", num) + }; + } + } + + if num > 0 { + let t = touch.get_multi_touch(&mut i2c, 1); + match t { + Err(_e) => rprintln!("Error fetching touch data"), + Ok(n) => { + rprintln!( + "Touch: {:>3}x{:>3} - weight: {:>3} misc: {}", + n.touch_x[0], + n.touch_y[0], + n.touch_weight[0], + n.touch_area[0], + ); + rprintln!( + "Touch: {:>3}x{:>3} - weight: {:>3} misc: {}", + n.touch_x[0], + n.touch_y[1], + n.touch_weight[1], + n.touch_area[1], + ) + } + } + } + } +} diff --git a/examples/touch.rs b/examples/touch.rs index 71b628e..48eef70 100644 --- a/examples/touch.rs +++ b/examples/touch.rs @@ -1,33 +1,22 @@ -// #![deny(warnings)] #![no_main] #![no_std] +/// A basic example to show the use of ft6x06 crate using STM32F412/3 board +/// This example shows how to get touch coordinates. use cortex_m; use cortex_m_rt::entry; use rtt_target::{rprintln, rtt_init_print}; -use stm32f4xx_hal::{ - pac, - prelude::*, - rcc::{ Rcc}, -}; -#[cfg(feature = "stm32f412")] -use stm32f4xx_hal::i2c::I2c; #[cfg(feature = "stm32f413")] use stm32f4xx_hal::fmpi2c::FMPI2c; +#[cfg(feature = "stm32f412")] +use stm32f4xx_hal::i2c::I2c; +use stm32f4xx_hal::{pac, prelude::*, rcc::Rcc}; #[allow(unused_imports)] use panic_semihosting; extern crate ft6x06; -/// A simple example to connect to the FT6x06 crate and access it for -/// x and y positions of touch points. There are a lot of commented-out -/// calls to items in the library, but they're a bit pointless. I couldn't -/// get the gesture stuff to work - I couldn't even get an I2C register change -/// to take place. I didn't try for the other functions like Events. -/// -/// It works for me - if you get more working, please send a PR. -/// My approach to Results is also a bit ad-hoc. #[entry] fn main() -> ! { rtt_init_print!(); @@ -42,9 +31,8 @@ fn main() -> ! { let mut delay = cp.SYST.delay(&clocks); rprintln!("Connecting to I2c"); - - - ///STM32F412 touchscreen controller uses I2C1 module from embedded-hal. + + // STM32F412 touchscreen controller uses I2C1 module from embedded-hal. #[cfg(feature = "stm32f412")] let mut i2c = { let gpiob = perif.GPIOB.split(); @@ -58,9 +46,8 @@ fn main() -> ! { &clocks, ) }; - - - ///STM32F413 shares the same I2C bus for both audio driver and touchscreen controller. FMPI2C module from embedded-hal is used. + + // STM32F413 shares the same I2C bus for both audio driver and touchscreen controller. FMPI2C module from embedded-hal is used. #[cfg(feature = "stm32f413")] let mut i2c = { let gpioc = perif.GPIOC.split(); @@ -73,14 +60,14 @@ fn main() -> ! { 5.kHz(), ) }; - - let mut touch = ft6x06::Ft6X06::new(&i2c, 0x38, &mut delay).unwrap(); - - let tsc = touch.ts_calibration(&mut i2c); - match tsc { - Err(e) => rprintln!("Error {} from ts_calibration", e), - Ok(u) => rprintln!("ts_calibration returned {}", u), - } + + let mut touch = ft6x06::Ft6X06::new(&i2c, 0x38).unwrap(); + + let tsc = touch.ts_calibration(&mut i2c, &mut delay); + match tsc { + Err(e) => rprintln!("Error {} from ts_calibration", e), + Ok(u) => rprintln!("ts_calibration returned {}", u), + } rprintln!("If nothing happens - touch the screen!"); loop { @@ -112,191 +99,3 @@ fn main() -> ! { } } - -// touch.test(&mut i2c); -// rprintln!("Returned from test"); - -// rprintln!("{:?}", touch.get_capabilities()); - -// let dm = touch.dev_mode_r(&mut i2c); -// match dm { -// Err(_e) => rprintln!("Error {} returned from i2c"), -// Ok(u) => rprintln!("dev_mode_r returned {}", u), -// } - -// let dmw = touch.dev_mode_w(&mut i2c, FT6x06_DEV_MODE_FACTORY); -// match dmw { -// Err(_e) => rprintln!("Error {} returned from writing dev mode"), -// Ok(u) => rprintln!("dev_mode_w returned {}", u), -// } - -// let tds = touch.td_status(&mut i2c); -// match tds { -// Err(_e) => rprintln!("Error returned when querying status"), -// Ok(u) => rprintln!("td_status returned {}", u), -// } - - -// let cid = touch.chip_id(&mut i2c); -// match cid { -// Err(e) => rprintln!("Error {} from chip_id", e), -// Ok(u) => rprintln!("Chip ID is: 0x{:02x}", u), -// } - -// let fid = touch.firmware_id(&mut i2c); -// match fid { -// Err(e) => rprintln!("Error {} from chip_id", e), -// Ok(u) => rprintln!("Firmware ID is: 0x{:02x}", u), -// } - -// match touch.gesture_radian_read(&mut i2c) { -// Err(e) => rprintln!("Error {} from gesture_radian_read", e), -// Ok(u) => rprintln!("*Gesture_radian_read ID is: 0x{:02x}", u), -// } - -// match touch.gesture_radian_write(&mut i2c, 0x20) { -// Err(_e) => rprintln!("Error from gesture_radian_write"), -// Ok(u) => rprintln!("*Okay writing radians, result = {}", u), -// } -// match touch.gesture_radian_read(&mut i2c) { -// Err(e) => rprintln!("Error {} from gesture_radian_read", e), -// Ok(u) => rprintln!("*Gesture_radian_read ID is: 0x{:02x}", u), -// } -// let mut gesture_init = ft6x06::GestureInit::new(0x38); - -// let gesture_entries: [u8; 6] = [0x20, 0x20, 0x20, 0x80, 0x80, 0x80]; -// rprintln!( -// "Gesture write result: {}", -// gesture_init -// .write( -// &mut i2c, -// gesture_entries[0], -// gesture_entries[1], -// gesture_entries[2], -// gesture_entries[3], -// gesture_entries[4], -// gesture_entries[5], -// ) -// .unwrap() -// ); - -// gesture_init.read(&mut i2c).ok(); -// rprintln!( -// "Gestures as initialized -// Radians: {} -// Offset left/right: {} -// Offset up/down: {} -// Distance left/right: {} -// Distance up/down: {} -// Distance zoom: {}", -// gesture_init.radian, -// gesture_init.offset_left_right, -// gesture_init.offset_up_down, -// gesture_init.distance_left_right, -// gesture_init.distance_up_down, -// gesture_init.distance_zoom -// ); -// let g = touch.get_gesture(&mut i2c); -// if let Err(_e) = g { -// rprintln!("Error in getting gesture"); -// } else if let Ok(a) = g { -// rprintln!("Returned from get_gesture: {}", print_gesturekind(a)); -// } - -// match touch.gesture_radian_read(&mut i2c) { -// Err(a) => rprintln!("Error {} reading radians", a), -// Ok(b) => rprintln!("Value read from radians: {}", b), -// } - -// touch.delay_ms(10); - -// match touch.gesture_radian_write(&mut i2c, 0x20) { -// Err(_a) => rprintln!("Error writing radians"), -// Ok(_b) => rprintln!("Value written to radians okay"), -// } - -// touch.delay_ms(10); - -// match touch.gesture_radian_read(&mut i2c) { -// Err(a) => rprintln!("Error {} reading radians", a), -// Ok(b) => rprintln!("Value read from radians: {}", b), -// } -// touch.delay_ms(100); -// } - -// let g = touch.get_gesture(&mut i2c); -// if let Err(e) = g { -// rprintln!("Error in getting gesture"); -// } else if let Ok(a) = g { -// // loop { -// // match a { -// // ft6x06::GestureKind::Fault => break, -// // _ => { -// // rprintln!("Trying write and read GestureInit"); - -// // let mut gesture_entries: [u8; 6] = [0x20, 0x20, 0x20, 0x80, 0x80, 0x80]; -// // rprintln!( -// // "Gesture write result: {}", -// // gesture_init -// // .write( -// // &mut i2c, -// // gesture_entries[0], -// // gesture_entries[1], -// // gesture_entries[2], -// // gesture_entries[3], -// // gesture_entries[4], -// // gesture_entries[5], -// // ) -// // .unwrap() -// // ); - -// // gesture_init.read(&mut i2c); -// // rprintln!( -// // "Gestures as initialized -// // Radians: {} -// // Offset left/right: {} -// // Offset up/down: {} -// // Distance left/right: {} -// // Distance up/down: {} -// // Distance zoom: {}", -// // gesture_init.radian, -// // gesture_init.offset_left_right, -// // gesture_init.offset_up_down, -// // gesture_init.distance_left_right, -// // gesture_init.distance_up_down, -// // gesture_init.distance_zoom -// // ); -// // } -// // } -// // rprintln!( -// // " Gesture: {}", -// // match a { -// // ft6x06::GestureKind::None => "None", -// // ft6x06::GestureKind::Up => "Up", -// // ft6x06::GestureKind::Right => "Right", -// // ft6x06::GestureKind::Down => "Down", -// // ft6x06::GestureKind::Left => "Left", -// // ft6x06::GestureKind::ZoomIn => "ZoomIn", -// // ft6x06::GestureKind::ZoomOut => "ZoomOut", -// // ft6x06::GestureKind::Fault => "Fault", -// // } -// // ); -// // } -// } -// } - -// loop {} -// } - -// fn print_gesturekind(g: ft6x06::GestureKind) -> &'static str { -// match g { -// ft6x06::GestureKind::None => "None", -// ft6x06::GestureKind::Up => "Up", -// ft6x06::GestureKind::Right => "Right", -// ft6x06::GestureKind::Down => "Down", -// ft6x06::GestureKind::Left => "Left", -// ft6x06::GestureKind::ZoomIn => "ZoomIn", -// ft6x06::GestureKind::ZoomOut => "ZoomOut", -// ft6x06::GestureKind::Fault => "Fault", -// } -// } diff --git a/src/constant.rs b/src/constant.rs index 271c898..0f8596b 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -1,194 +1,193 @@ - - /// Maximum border values of the touchscreen pad/// -pub const FT_6X06_MAX_WIDTH :u16 = 800; /// Touchscreen pad max width /// -pub const FT_6X06_MAX_HEIGHT :u16 = 480; /// Touchscreen pad max height /// +pub const FT_6X06_MAX_WIDTH: u16 = 800; +/// Touchscreen pad max width /// +pub const FT_6X06_MAX_HEIGHT: u16 = 480; +/// Touchscreen pad max height /// /// Touchscreen pad max width and height values for FT6x36 Touch -pub const FT_6X06_MAX_WIDTH_HEIGHT :u8 = 240; +pub const FT_6X06_MAX_WIDTH_HEIGHT: u8 = 240; /// Possible values of driver functions return status/// -pub const FT6X06_STATUS_OK :u8 = 0; -pub const FT6X06_STATUS_NOT_OK :u8 = 1; +pub const FT6X06_STATUS_OK: u8 = 0; +pub const FT6X06_STATUS_NOT_OK: u8 = 1; /// Possible values of global variable 'TS_I2C_Initialized'/// -pub const FT6X06_I2C_NOT_INITIALIZED :u8 = 0; -pub const FT6X06_I2C_INITIALIZED :u8 = 1; +pub const FT6X06_I2C_NOT_INITIALIZED: u8 = 0; +pub const FT6X06_I2C_INITIALIZED: u8 = 1; /// Max detectable simultaneous touches/// -pub const FT6X06_MAX_DETECTABLE_TOUCH :u8 = 2; +pub const FT6X06_MAX_DETECTABLE_TOUCH: u8 = 2; ///// - /// @brief : Definitions for FT6X06 I2C register addresses on 8 bit - ////// +/// @brief : Definitions for FT6X06 I2C register addresses on 8 bit +////// /// Current mode register of the FT6X06 (R/W)/// -pub const FT6X06_DEV_MODE_REG : u8 = 0x00; +pub const FT6X06_DEV_MODE_REG: u8 = 0x00; /// Possible values of FT6X06_DEV_MODE_REG/// -pub const FT6X06_DEV_MODE_WORKING : u8 = 0x00; -pub const FT6X06_DEV_MODE_FACTORY : u8 = 0x04; +pub const FT6X06_DEV_MODE_WORKING: u8 = 0x00; +pub const FT6X06_DEV_MODE_FACTORY: u8 = 0x04; -pub const FT6X06_DEV_MODE_MASK : u8 = 0x7; -pub const FT6X06_DEV_MODE_SHIFT :u8 = 4; +pub const FT6X06_DEV_MODE_MASK: u8 = 0x7; +pub const FT6X06_DEV_MODE_SHIFT: u8 = 4; /// Gesture ID register/// -pub const FT6X06_GEST_ID_REG : u8 = 0x01; +pub const FT6X06_GEST_ID_REG: u8 = 0x01; /// Possible values of FT6X06_GEST_ID_REG/// -pub const FT6X06_GEST_ID_NO_GESTURE : u8 = 0x00; -pub const FT6X06_GEST_ID_MOVE_UP : u8 = 0x10; -pub const FT6X06_GEST_ID_MOVE_RIGHT : u8 = 0x14; -pub const FT6X06_GEST_ID_MOVE_DOWN : u8 = 0x18; -pub const FT6X06_GEST_ID_MOVE_LEFT : u8 = 0x1C; -pub const FT6X06_GEST_ID_ZOOM_IN : u8 = 0x48; -pub const FT6X06_GEST_ID_ZOOM_OUT : u8 = 0x49; +pub const FT6X06_GEST_ID_NO_GESTURE: u8 = 0x00; +pub const FT6X06_GEST_ID_MOVE_UP: u8 = 0x10; +pub const FT6X06_GEST_ID_MOVE_RIGHT: u8 = 0x14; +pub const FT6X06_GEST_ID_MOVE_DOWN: u8 = 0x18; +pub const FT6X06_GEST_ID_MOVE_LEFT: u8 = 0x1C; +pub const FT6X06_GEST_ID_ZOOM_IN: u8 = 0x48; +pub const FT6X06_GEST_ID_ZOOM_OUT: u8 = 0x49; /// Touch Data Status register : gives number of active touch points (0..2)/// -pub const FT6X06_TD_STAT_REG : u8 = 0x02; +pub const FT6X06_TD_STAT_REG: u8 = 0x02; /// Values related to FT6X06_TD_STAT_REG/// -pub const FT6X06_TD_STAT_MASK : u8 = 0x0F; -pub const FT6X06_TD_STAT_SHIFT : u8 = 0x00; +pub const FT6X06_TD_STAT_MASK: u8 = 0x0F; +pub const FT6X06_TD_STAT_SHIFT: u8 = 0x00; /// Values Pn_XH and Pn_YH related/// -pub const FT6X06_TOUCH_EVT_FLAG_PRESS_DOWN : u8 = 0x00; -pub const FT6X06_TOUCH_EVT_FLAG_LIFT_UP : u8 = 0x01; -pub const FT6X06_TOUCH_EVT_FLAG_CONTACT : u8 = 0x02; -pub const FT6X06_TOUCH_EVT_FLAG_NO_EVENT : u8 = 0x03; +pub const FT6X06_TOUCH_EVT_FLAG_PRESS_DOWN: u8 = 0x00; +pub const FT6X06_TOUCH_EVT_FLAG_LIFT_UP: u8 = 0x01; +pub const FT6X06_TOUCH_EVT_FLAG_CONTACT: u8 = 0x02; +pub const FT6X06_TOUCH_EVT_FLAG_NO_EVENT: u8 = 0x03; -pub const FT6X06_TOUCH_EVT_FLAG_SHIFT :u8 = 6; -pub const FT6X06_TOUCH_EVT_FLAG_MASK :u8 = 3 << FT6X06_TOUCH_EVT_FLAG_SHIFT; +pub const FT6X06_TOUCH_EVT_FLAG_SHIFT: u8 = 6; +pub const FT6X06_TOUCH_EVT_FLAG_MASK: u8 = 3 << FT6X06_TOUCH_EVT_FLAG_SHIFT; -pub const FT6X06_MSB_MASK : u8 = 0x0F; -pub const FT6X06_MSB_SHIFT :u8 = 0; +pub const FT6X06_MSB_MASK: u8 = 0x0F; +pub const FT6X06_MSB_SHIFT: u8 = 0; /// Values Pn_XL and Pn_YL related/// -pub const FT6X06_LSB_MASK : u8 = 0xFF; -pub const FT6X06_LSB_SHIFT :u8 = 0; +pub const FT6X06_LSB_MASK: u8 = 0xFF; +pub const FT6X06_LSB_SHIFT: u8 = 0; -pub const FT6X06_P1_XH_REG : u8 = 0x03; -pub const FT6X06_P1_XL_REG : u8 = 0x04; -pub const FT6X06_P1_YH_REG : u8 = 0x05; -pub const FT6X06_P1_YL_REG : u8 = 0x06; +pub const FT6X06_P1_XH_REG: u8 = 0x03; +pub const FT6X06_P1_XL_REG: u8 = 0x04; +pub const FT6X06_P1_YH_REG: u8 = 0x05; +pub const FT6X06_P1_YL_REG: u8 = 0x06; /// Touch Pressure register value (R)/// -pub const FT6X06_P1_WEIGHT_REG : u8 = 0x07; +pub const FT6X06_P1_WEIGHT_REG: u8 = 0x07; /// Values Pn_WEIGHT related /// -pub const FT6X06_TOUCH_WEIGHT_MASK : u8 = 0xFF; -pub const FT6X06_TOUCH_WEIGHT_SHIFT : u8 = 0; +pub const FT6X06_TOUCH_WEIGHT_MASK: u8 = 0xFF; +pub const FT6X06_TOUCH_WEIGHT_SHIFT: u8 = 0; /// Touch area register/// -pub const FT6X06_P1_MISC_REG : u8 = 0x08; +pub const FT6X06_P1_MISC_REG: u8 = 0x08; /// Values related to FT6X06_Pn_MISC_REG/// -pub const FT6X06_TOUCH_AREA_MASK : u8 = 0x04 << 4; -pub const FT6X06_TOUCH_AREA_SHIFT : u8 = 0x04; +pub const FT6X06_TOUCH_AREA_MASK: u8 = 0x04 << 4; +pub const FT6X06_TOUCH_AREA_SHIFT: u8 = 0x04; -pub const FT6X06_P2_XH_REG : u8 = 0x09; -pub const FT6X06_P2_XL_REG : u8 = 0x0A; -pub const FT6X06_P2_YH_REG : u8 = 0x0B; -pub const FT6X06_P2_YL_REG : u8 = 0x0C; -pub const FT6X06_P2_WEIGHT_REG : u8 = 0x0D; -pub const FT6X06_P2_MISC_REG : u8 = 0x0E; +pub const FT6X06_P2_XH_REG: u8 = 0x09; +pub const FT6X06_P2_XL_REG: u8 = 0x0A; +pub const FT6X06_P2_YH_REG: u8 = 0x0B; +pub const FT6X06_P2_YL_REG: u8 = 0x0C; +pub const FT6X06_P2_WEIGHT_REG: u8 = 0x0D; +pub const FT6X06_P2_MISC_REG: u8 = 0x0E; /// Threshold for touch detection/// -pub const FT6X06_TH_GROUP_REG : u8 = 0x80; +pub const FT6X06_TH_GROUP_REG: u8 = 0x80; /// Values FT6X06_TH_GROUP_REG : threshold related /// -pub const FT6X06_THRESHOLD_MASK : u8 = 0xFF; -pub const FT6X06_THRESHOLD_SHIFT :u8 = 0; +pub const FT6X06_THRESHOLD_MASK: u8 = 0xFF; +pub const FT6X06_THRESHOLD_SHIFT: u8 = 0; /// Filter function coefficients/// -pub const FT6X06_TH_DIFF_REG : u8 = 0x85; +pub const FT6X06_TH_DIFF_REG: u8 = 0x85; /// Control register/// -pub const FT6X06_CTRL_REG : u8 = 0x86; +pub const FT6X06_CTRL_REG: u8 = 0x86; /// Values related to FT6X06_CTRL_REG/// /// Will keep the Active mode when there is no touching/// -pub const FT6X06_CTRL_KEEP_ACTIVE_MODE : u8 = 0x00; +pub const FT6X06_CTRL_KEEP_ACTIVE_MODE: u8 = 0x00; /// Switching from Active mode to Monitor mode automatically when there is no touching/// -pub const FT6X06_CTRL_KEEP_AUTO_SWITCH_MONITOR_MODE : u8 = 0x01; +pub const FT6X06_CTRL_KEEP_AUTO_SWITCH_MONITOR_MODE: u8 = 0x01; /// The time period of switching from Active mode to Monitor mode when there is no touching/// -pub const FT6X06_TIMEENTERMONITOR_REG : u8 = 0x87; +pub const FT6X06_TIMEENTERMONITOR_REG: u8 = 0x87; /// Report rate in Active mode/// -pub const FT6X06_PERIODACTIVE_REG : u8 = 0x88; +pub const FT6X06_PERIODACTIVE_REG: u8 = 0x88; /// Report rate in Monitor mode/// -pub const FT6X06_PERIODMONITOR_REG : u8 = 0x89; +pub const FT6X06_PERIODMONITOR_REG: u8 = 0x89; /// The value of the minimum allowed angle while Rotating gesture mode/// -pub const FT6X06_RADIAN_VALUE_REG : u8 = 0x91; +pub const FT6X06_RADIAN_VALUE_REG: u8 = 0x91; /// Maximum offset while Moving Left and Moving Right gesture/// -pub const FT6X06_OFFSET_LEFT_RIGHT_REG : u8 = 0x92; +pub const FT6X06_OFFSET_LEFT_RIGHT_REG: u8 = 0x92; /// Maximum offset while Moving Up and Moving Down gesture/// -pub const FT6X06_OFFSET_UP_DOWN_REG : u8 = 0x93; +pub const FT6X06_OFFSET_UP_DOWN_REG: u8 = 0x93; /// Minimum distance while Moving Left and Moving Right gesture/// -pub const FT6X06_DISTANCE_LEFT_RIGHT_REG : u8 = 0x94; +pub const FT6X06_DISTANCE_LEFT_RIGHT_REG: u8 = 0x94; /// Minimum distance while Moving Up and Moving Down gesture/// -pub const FT6X06_DISTANCE_UP_DOWN_REG : u8 = 0x95; +pub const FT6X06_DISTANCE_UP_DOWN_REG: u8 = 0x95; /// Maximum distance while Zoom In and Zoom Out gesture/// -pub const FT6X06_DISTANCE_ZOOM_REG : u8 = 0x96; +pub const FT6X06_DISTANCE_ZOOM_REG: u8 = 0x96; /// High 8-bit of LIB Version info/// -pub const FT6X06_LIB_VER_H_REG : u8 = 0xA1; +pub const FT6X06_LIB_VER_H_REG: u8 = 0xA1; /// Low 8-bit of LIB Version info/// -pub const FT6X06_LIB_VER_L_REG : u8 = 0xA2; +pub const FT6X06_LIB_VER_L_REG: u8 = 0xA2; /// Chip Selecting/// -pub const FT6X06_CIPHER_REG : u8 = 0xA3; +pub const FT6X06_CIPHER_REG: u8 = 0xA3; /// Interrupt mode register (used when in interrupt mode)/// -pub const FT6X06_GMODE_REG : u8 = 0xA4; +pub const FT6X06_GMODE_REG: u8 = 0xA4; -pub const FT6X06_G_MODE_INTERRUPT_MASK : u8 = 0x03; -pub const FT6X06_G_MODE_INTERRUPT_SHIFT : u8 = 0x00; +pub const FT6X06_G_MODE_INTERRUPT_MASK: u8 = 0x03; +pub const FT6X06_G_MODE_INTERRUPT_SHIFT: u8 = 0x00; /// Possible values of FT6X06_GMODE_REG/// -pub const FT6X06_G_MODE_INTERRUPT_POLLING : u8 = 0x00; -pub const FT6X06_G_MODE_INTERRUPT_TRIGGER : u8 = 0x01; +pub const FT6X06_G_MODE_INTERRUPT_POLLING: u8 = 0x00; +pub const FT6X06_G_MODE_INTERRUPT_TRIGGER: u8 = 0x01; /// Current power mode the FT6X06 system is in (R)/// -pub const FT6X06_PWR_MODE_REG : u8 = 0xA5; +pub const FT6X06_PWR_MODE_REG: u8 = 0xA5; /// FT6X06 firmware version/// -pub const FT6X06_FIRMID_REG : u8 = 0xA6; +pub const FT6X06_FIRMID_REG: u8 = 0xA6; /// FT6X06 Chip identification register/// -pub const FT6X06_CHIP_ID_REG : u8 = 0xA8; +pub const FT6X06_CHIP_ID_REG: u8 = 0xA8; /// Possible values of FT6X06_CHIP_ID_REG/// -pub const FT6X06_ID_VALUE : u8 = 0x11; -pub const FT6X36_ID_VALUE : u8 = 0xCD; +pub const FT6X06_ID_VALUE: u8 = 0x11; +pub const FT6X36_ID_VALUE: u8 = 0xCD; /// Release code version/// -pub const FT6X06_RELEASE_CODE_ID_REG : u8 = 0xAF; +pub const FT6X06_RELEASE_CODE_ID_REG: u8 = 0xAF; /// Current operating mode the FT6X06 system is in (R)/// -pub const FT6X06_STATE_REG : u8 = 0xBC; +pub const FT6X06_STATE_REG: u8 = 0xBC; -pub const FT6X06_OK : u8 = 0; -pub const FT6X06_ERROR : i8 = -1; +pub const FT6X06_OK: u8 = 0; +pub const FT6X06_ERROR: i8 = -1; -/// Max detectable simultaneous touches -pub const FT6X06_MAX_NB_TOUCH : usize = 2; - -/// Touch FT6XX6 IDs -pub const FT6X06_ID : u8 = 0x11; -pub const FT6X36_ID : u8 = 0xCD; +/// Max detectable simultaneous touches +pub const FT6X06_MAX_NB_TOUCH: usize = 2; +/// Touch FT6XX6 IDs +pub const FT6X06_ID: u8 = 0x11; +pub const FT6X36_ID: u8 = 0xCD; pub const FT6X06_MAX_X_LENGTH: u16 = 800_u16; pub const FT6X06_MAX_Y_LENGTH: u16 = 480_u16; diff --git a/src/lib.rs b/src/lib.rs index f5ece48..4803c46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,20 +1,47 @@ -//! -//! A platform agnostic driver for FT6X06 touchscreen . -//! -//! Built using 'embedded-hal' traits. -//! -//! The Touchscreen driver for FT6X06 -//! -//! +//! +//! A platform agnostic driver for FT6X06 touchscreen . Built using 'embedded-hal' traits. +//! +//! The Touchscreen driver for FT6X06 series touch panel controller +//! +//! +//! +//! +//! ### Example +//! +//! ##### Initializing the Ft6x06 driver struct +//! let mut touch = ft6x06::Ft6X06::new(&i2c, ).unwrap(); +//! +//! To detect single touch, use the following snippet, +//! +//! let t = touch.detect_touch(&mut i2c); +//! let mut num: u8 = 0; +//! match t { +//! Err(e) => rprintln!("Error {} from fetching number of touches", e), +//! Ok(n) => { +//! num = n; +//! if num != 0 { +//! rprintln!("Number of touches: {}", num) +//! }; +//! } +//! } +//! +//! if num > 0 { +//! let t = touch.get_touch(&mut i2c, 1); +//! match t { +//! Err(_e) => rprintln!("Error fetching touch data"), +//! Ok(n) => rprintln!( +//! "Touch: {:>3}x{:>3} - weight: {:>3} misc: {}", +//! n.x, +//! n.y, +//! n.weight, +//! n.misc +//! ), +//! } +//! } +//! +//! //! //! -//! ##Example -//! -//! ### Initializing the Ft6x06 driver struct -//! let mut touch = ft6x06::Ft6X06::new(&i2c, 0x38, &mut delay).unwrap(); -//! -//! - #![no_std] #![no_main] @@ -24,12 +51,11 @@ pub mod constant; #[cfg(feature = "gesture")] use heapless::Vec; +use crate::constant::*; +use core::marker::PhantomData; use embedded_hal as hal; use hal::blocking::{delay::DelayMs, i2c}; -use rtt_target::{rprintln, rtt_init_print}; -use core::marker::PhantomData; -use crate::constant::*; - +use rtt_target::rprintln; #[derive(Copy, Clone, Debug)] pub struct Ft6x06Capabilities { @@ -50,23 +76,14 @@ const FALSE: bool = false; const FT6X06_CAPABILITIES: Ft6x06Capabilities = Ft6x06Capabilities { multi_touch: TRUE, + // Gesture is not set as per given in ft6x06 crate by STMicroelectronics gesture: FALSE, max_touch: FT6X06_MAX_NB_TOUCH as u8, max_x_length: FT6X06_MAX_X_LENGTH, may_y_length: FT6X06_MAX_Y_LENGTH, }; - - -/// Touch structure - derived from the available I2C registers -/// There are ten available touch registers on the chip, but also -/// a defined maximum of 2 in FT6X06_MAX_NB_TOUCH above. -/// The touch registers occur in banks of 6, for each of the ten -/// potential touches, defined as follows, and the registers are -/// contiguous. That means that a single read can get all of the -/// data for one touch, or all of the data for all the touches. -/// In the absence of documentation on the MISC register, it is being -/// ignored. +/// Touch structure - derived from the available I2C registers. // #define FT6X06_P1_XH_REG 0x03U // #define FT6X06_P1_XL_REG 0x04U // #define FT6X06_P1_YH_REG 0x05U @@ -90,11 +107,9 @@ pub struct TouchState { pub misc: u8, } - - /// For storing multi-touch data -pub struct MultiTouch{ - pub detected: bool, +pub struct MultiTouch { + pub detected: bool, /// X postion pub touch_x: [u16; 2], /// Y position @@ -102,12 +117,11 @@ pub struct MultiTouch{ /// Weight of touch pub touch_weight: [u16; 2], /// Misc (contents not known) - pub touch_area: [u16; 2] + pub touch_area: [u16; 2], } - #[derive(Debug)] -/// When a gesture is polled it could be one of these: +/// Possible choices of gesture pub enum GestureKind { /// No gesture detected None, @@ -127,18 +141,25 @@ pub enum GestureKind { Fault, } - - -/// Structure that holds the values for a gesture -/// The name is what's in the c code. -/// The register definitions are: -/// pub const FT6X06_RADIAN_VALUE_REG: u8 = 0x91; -/// pub const FT6X06_OFFSET_LR_REG: u8 = 0x92; -/// pub const FT6X06_OFFSET_UD_REG: u8 = 0x93; -/// pub const FT6X06_DISTANCE_LR_REG: u8 = 0x94; -/// pub const FT6X06_DISTANCE_UD_REG: u8 = 0x95; -/// pub const FT6X06_DISTANCE_ZOOM_REG: u8 = 0x96; - +// Gestures don't seem to work using values of control registers and reading radian_value_reg. +// I tried working with the GestureInit struct and i2c bus to read gestures but failed. +// I removed its impl but kept the struct to give idea of how it is implementated in C. +// This code for gestures is taken from ft5336 repo by bobgates, +// but it seems control register values are not read in buffer of i2c bus. +// So I created a algoritmic to detect gesture. The following struct just shows how +// the gestures registers are to set. + +// Structure that holds the values for a gesture +// The name is what's in the c code. +// The register definitions are: +// pub const FT6X06_RADIAN_VALUE_REG: u8 = 0x91; +// pub const FT6X06_OFFSET_LR_REG: u8 = 0x92; +// pub const FT6X06_OFFSET_UD_REG: u8 = 0x93; +// pub const FT6X06_DISTANCE_LR_REG: u8 = 0x94; +// pub const FT6X06_DISTANCE_UD_REG: u8 = 0x95; +// pub const FT6X06_DISTANCE_ZOOM_REG: u8 = 0x96; + +#[allow(dead_code)] pub struct GestureInit { addr: u8, i2c: PhantomData, @@ -157,117 +178,8 @@ pub struct GestureInit { pub distance_zoom: u8, } - - -/// I wasn't able to get gestures to work. I suspect something is required in -/// the control register, but I don't know what. Also, this STM page (for nominally the same device): -/// -/// has a different set of gestures available to the list above. -impl<'b, I2C, E> GestureInit -where - I2C: i2c::WriteRead + i2c::Write + i2c::Read, -{ - /// Initialise. Takes the I2C address just to avoid transferring it all the time. - /// It turns out the gesture init registers are contiguous, see comment above - /// or definitions of FT6X06_RADIAN_VALUE_REG and what follow, so they're also - /// in the initialiser. - /// - /// This code didn't work in the STM32F7 Discovery - It wouldn't read parameters set. - pub fn new(addr: u8) -> GestureInit { - GestureInit { - i2c: PhantomData, - addr, - radian: 0, - offset_left_right: 0, - offset_up_down: 0, - distance_left_right: 0, - distance_up_down: 0, - distance_zoom: 0, - } - } - - /// Fill the gesture struct with the values held for it on the - /// touchscreen - pub fn read(&mut self, i2c: &mut I2C) -> Result<&str, &str> { - let mut buf: [u8; 6] = [4; 6]; - - let result = i2c.write_read(self.addr, &[FT6X06_RADIAN_VALUE_REG], &mut buf); - - rprintln!( - "Gesture read buf values: {} {} {} {} {} {} ", - buf[0], - buf[1], - buf[2], - buf[3], - buf[4], - buf[5], - ); - - - match result { - Err(_e) => Err("Error reading gesture init registers"), - Ok(_d) => { - self.radian = buf[0]; - self.offset_left_right = buf[1]; - self.offset_up_down = buf[2]; - self.distance_left_right = buf[3]; - self.distance_up_down = buf[4]; - self.distance_zoom = buf[5]; - Ok("Success reading gesture init") - } - } - } - - /// Write the six parameters of the gesture_init type into the FT6206 - pub fn write( - &mut self, - i2c: &mut I2C, - radian: u8, - offset_lr: u8, - offset_ud: u8, - dist_lr: u8, - dist_up: u8, - zoom: u8, - ) -> Result<&str, &str> { - let mut entries: [u8; 6] = [radian, offset_lr, offset_ud, dist_lr, dist_up, zoom]; - - rprintln!( - "Gesture write entries values before: {} {} {} {} {} {} ", - entries[0], - entries[1], - entries[2], - entries[3], - entries[4], - entries[5], - ); - - - let result = i2c.write_read(self.addr, &mut [FT6X06_RADIAN_VALUE_REG], &mut entries); - - rprintln!( - "Gesture write entries values: {} {} {} {} {} {} ", - entries[0], - entries[1], - entries[2], - entries[3], - entries[4], - entries[5], - ); - - - if let Err(_g) = result { - Err("Error setting address in GestureInit") - } else { - // let result = i2c.write(self.addr, &mut entries); - // match result { - // Err(_e) => Err("Error writing GestureInit"), - Ok("Okay writing GestureInit") - // } - } - } -} - -/// FT6x06 driver +/// FT6x06 driver object. +/// I2C bus type and its address are set. pub struct Ft6X06 { i2c: PhantomData, addr: u8, @@ -299,10 +211,6 @@ where // Ok(*self) } - //pub fn DisableIT(&self, i2c: &mut I2C) -> Result {} - /// Future test code - pub fn test(&self, _i2c: &mut I2C) {} - ///As the ft6X06 library owns the delay, the simplest way to /// deliver it to the callign code seems to be to return a function call. pub fn delay_ms(&mut self, delay_source: &mut impl DelayMs, delay: u32) { @@ -345,7 +253,11 @@ where } /// Run an internal calibration on the FT6X06 - pub fn ts_calibration(&mut self, i2c: &mut I2C, delay_source: &mut impl DelayMs) -> Result { + pub fn ts_calibration( + &mut self, + i2c: &mut I2C, + delay_source: &mut impl DelayMs, + ) -> Result { //} -> Result { let mut _ret = FT6X06_OK; let mut _nbr_attempt: u32; @@ -452,25 +364,25 @@ where misc: buf[5], }) } - + /// Fetch the touch data specified by touch_i /// touch_i should go from 1 to FT6X06_MAX_NB_TOUCH pub fn get_multi_touch(&mut self, i2c: &mut I2C, touch_i: u8) -> Result { let mut buf: [u8; 12] = [0; 12]; i2c.write_read(self.addr, &[FT6X06_P1_XH_REG + 6 * (touch_i - 1)], &mut buf)?; - + let mut x: [u16; FT6X06_MAX_NB_TOUCH] = [0; FT6X06_MAX_NB_TOUCH]; let mut y: [u16; FT6X06_MAX_NB_TOUCH] = [0; FT6X06_MAX_NB_TOUCH]; let mut weight: [u16; FT6X06_MAX_NB_TOUCH] = [0; FT6X06_MAX_NB_TOUCH]; let mut misc: [u16; FT6X06_MAX_NB_TOUCH] = [0; FT6X06_MAX_NB_TOUCH]; - + let mut it: usize = 0; - for i in 0..FT6X06_MAX_NB_TOUCH{ - x[i] = (FT6X06_P1_XH_TP_BIT_MASK & buf[0 + it]) as u16 * 256 + buf[1 + it] as u16; - y[i] = (FT6X06_P1_YH_TP_BIT_MASK & buf[2 + it]) as u16 * 256 + buf[3 + it] as u16; - weight[i] = buf[4 + it] as u16; - misc[i] = buf[5 + it] as u16; - it = it + 6; + for i in 0..FT6X06_MAX_NB_TOUCH { + x[i] = (FT6X06_P1_XH_TP_BIT_MASK & buf[0 + it]) as u16 * 256 + buf[1 + it] as u16; + y[i] = (FT6X06_P1_YH_TP_BIT_MASK & buf[2 + it]) as u16 * 256 + buf[3 + it] as u16; + weight[i] = buf[4 + it] as u16; + misc[i] = buf[5 + it] as u16; + it = it + 6; } Ok(MultiTouch { @@ -500,90 +412,84 @@ where Ok(g) } + pub fn get_coordinates(&mut self, i2c: &mut I2C) -> Result<(u16, u16), &str> { + let mut t = self.detect_touch(i2c); + while t.unwrap() == 0 || t == Err("Error getting touch data") { + t = self.detect_touch(i2c); + } + + let num: u8; + match t { + Err(_e) => return Err("Error {} from fetching number of touches"), + Ok(n) => { + num = n; + if num != 0 { + rprintln!("Number of touches in get_coordinates: {}", num); + }; + if num > 0 { + let t = self.get_touch(i2c, 1); + return match t { + Err(_e) => Err("Error fetching touch data"), + Ok(n) => Ok((n.x, n.y)), + }; + } else { + return Err("no"); + } + } + } + } - pub fn get_coordinates(&mut self, i2c: &mut I2C) -> Result<(u16,u16), &str> - { - let mut t = self.detect_touch(i2c); - while t.unwrap() == 0 || t == Err("Error getting touch data") { - t = self.detect_touch(i2c); - } - - let mut num: u8 = 0; - match t { - Err(_e) => return Err("Error {} from fetching number of touches"), - Ok(n) => { - num = n; - if num != 0 { - rprintln!("Number of touches in get_coordinates: {}", num); - }; - if num > 0 { - let t = self.get_touch(i2c, 1); - return match t { - Err(_e) => Err("Error fetching touch data"), - Ok(n) => Ok((n.x,n.y)), - } - } - else{ - return Err("no"); - } - } - } - } - - #[cfg(feature="gesture")] - pub fn gest_logic(&mut self, i2c:&mut I2C, sec: u16) -> Result{ - - let mut vec1: Vec = Vec::new(); - let mut vec2: Vec = Vec::new(); - - for _i in 1..20{ - let a = self.get_coordinates(i2c); - - match a{ - Err(_e) => { - rprintln!("err"); - continue; - } - Ok((x,y)) => { - vec1.push(x).expect("errrrrr"); - vec2.push(y).expect("errrrr"); - }, - }; - } - let itr1 = vec1.iter(); - let itr2 = vec2.iter(); - - let maxX: u16 = *itr1.max().expect("errrrrr"); - let maxY: u16 = *itr2.max().expect("errrrrr"); - - let itr1 = vec1.iter(); - let itr2 = vec2.iter(); - - let minX: u16 = *itr1.min().expect("errrrrr"); - let minY: u16 = *itr2.min().expect("errrrrr"); - - let startX: u16 = vec1[0]; - let startY: u16 = vec2[0]; - - let endX: u16 = vec1[19]; - let endY: u16 = vec2[19]; - - let diffX = endX-startX; - let diffY = endY-startY; - - if diffX > 100 || diffY > 100 { - return Err("wrong gestures.") - } - else if diffX > diffY{ - if diffX > 0 { return Ok(GestureKind::Right)} - else { return Ok(GestureKind::Left)} - } - else if diffX < diffY{ - if diffY > 0 { return Ok(GestureKind::Up)} - else { return Ok(GestureKind::Left)} - } - else{ - return Err("error gesture") - } - } +// /// Logic for getting the gesture. +// #[cfg(feature = "gesture")] +// pub fn gest_logic(&mut self, i2c: &mut I2C) -> Result { +// let mut vec1: Vec = Vec::new(); +// let mut vec2: Vec = Vec::new(); +// +// for _i in 1..20 { +// let a = self.get_coordinates(i2c); +// +// match a { +// Err(_e) => { +// rprintln!("err"); +// continue; +// } +// Ok((x, y)) => { +// vec1.push(x).expect("err"); +// vec2.push(y).expect("err"); +// } +// }; +// } +// let itr1 = vec1.iter(); +// let itr2 = vec2.iter(); +// +// let max_x: u16 = *itr1.max().expect("err"); +// let max_y: u16 = *itr2.max().expect("err"); +// +// let start_x: u16 = vec1[0]; +// let start_y: u16 = vec2[0]; +// +// let end_x: u16 = vec1[19]; +// let end_y: u16 = vec2[19]; +// +// let diff_x = end_x - start_x; +// let diff_y = end_y - start_y; +// +// if diff_x > 100 || diff_y > 100 { +// return Err("wrong gestures."); +// } else if diff_x > diff_y { +// if diff_x > 0 { +// return Ok(GestureKind::Right); +// } else { +// return Ok(GestureKind::Left); +// } +// } else if diff_x < diff_y { +// if diff_y > 0 { +// return Ok(GestureKind::Up); +// } else { +// return Ok(GestureKind::Left); +// } +// } else { +// return Err("error gesture"); +// } +// } }