Skip to content

Commit

Permalink
ran cargo fmt and cleaned up comments and unused crates
Browse files Browse the repository at this point in the history
  • Loading branch information
tstellanova committed Apr 8, 2020
1 parent 29909b5 commit 9fcd219
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 107 deletions.
17 changes: 15 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,23 @@ name = "cst816s"
version = "0.1.0"
authors = ["Todd Stellanova <[email protected]>"]
edition = "2018"

description = "CST816S touchscreen driver for embedded hal / no_std"
license = "BSD-3-Clause"
repository = "https://github.com/tstellanova/cst816s"
categories = [
"embedded",
"hardware-support",
"no-std",
]
keywords = [
"embedded-hal-driver",
"CST816S",
"touchscreen",
"PineTime"
]
readme = "README.md"

[dependencies]
arrayvec = {version = "0.5.1", default-features = false}
cortex-m = "0.6.2"
embedded-hal = {version ="0.2.3", features = ["unproven"] }

Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
## cst816s


A rust no_std driver for the
Hynan CST816S touchpad device
Hynan CST816S touchpad device.
This driver was originally developed for the PineTime smart watch.

## Status
This is work-in-progress
- [ ] Debug build runs on PineTime
- [ ] Release build runs on PineTime
- [ ] Internal I2C bus access
- [x] Blocking mode read of available touch events
- [ ] Interrupt handling of touch events
- [x] Debug build
- [x] Release build
- [x] Debug build of touchpad example runs on PineTime
- [x] Release build of touchpad example runs on PineTime
- [ ] CI
- [ ] Documentation

Expand Down
100 changes: 35 additions & 65 deletions examples/touchpad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,32 @@ extern crate panic_halt; // you can put a breakpoint on `rust_begin_unwind` to c
extern crate panic_semihosting; // logs messages to the host stderr; requires a debugger

use nrf52832_hal as p_hal;
use p_hal::gpio::{GpioExt, Level};
use p_hal::nrf52832_pac as pac;
use p_hal::{clocks::ClocksExt, gpio::{GpioExt,Level}};
use p_hal::{rng::RngExt, spim, twim, delay::Delay};
use p_hal::{delay::Delay, rng::RngExt, spim, twim};



use core::fmt;
use core::fmt::Arguments;
use cortex_m_rt as rt;
use cortex_m_semihosting::hprintln;
use cst816s::CST816S;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::{prelude::*, primitives::*, style::*};
use embedded_graphics::{
egtext, fonts::{Font12x16}, pixelcolor::Rgb565, text_style,
};
use embedded_hal::digital::v2::OutputPin;
use rt::entry;
use st7789::{Orientation, ST7789};
use cst816s::{CST816S, TouchEvent};

use embedded_hal::blocking::delay::{DelayMs,DelayUs};
use core::convert::TryInto;

use embedded_hal::blocking::delay::{DelayMs, DelayUs};

pub type HalSpimError = p_hal::spim::Error;

pub type Spim0PortType = p_hal::spim::Spim<pac::SPIM0>;
pub type DisplaySckPinType =
p_hal::gpio::p0::P0_18<p_hal::gpio::Output<p_hal::gpio::PushPull>>;
pub type DisplayMosiPinType =
p_hal::gpio::p0::P0_26<p_hal::gpio::Output<p_hal::gpio::PushPull>>;

pub type DisplaySckPinType = p_hal::gpio::p0::P0_18<p_hal::gpio::Output<p_hal::gpio::PushPull>>;
pub type DisplayMosiPinType = p_hal::gpio::p0::P0_26<p_hal::gpio::Output<p_hal::gpio::PushPull>>;

const SCREEN_WIDTH: i32 = 240;
const SCREEN_HEIGHT: i32 = 240;
const HALF_SCREEN_WIDTH: i32 = SCREEN_WIDTH / 2;
const MIN_SCREEN_DIM : i32 = SCREEN_HEIGHT;
const MIN_SCREEN_DIM: i32 = SCREEN_HEIGHT;
const SCREEN_RADIUS: u32 = (MIN_SCREEN_DIM / 2) as u32;
const FONT_HEIGHT: i32 = 20; //for Font12x16




type DisplayType<'a> = st7789::ST7789<
shared_bus::proxy::BusProxy<
Expand Down Expand Up @@ -80,7 +65,6 @@ fn main() -> ! {
// random number generator peripheral
let mut rng = dp.RNG.constrain();


// internal i2c0 bus devices: BMA421 (accel), HRS3300 (hrs), CST816S (TouchPad)
// BMA421-INT: P0.08
// TP-INT: P0.28
Expand All @@ -100,13 +84,7 @@ fn main() -> ! {
};

// create SPIM0 interface, 8 Mbps, use 122 as "over read character"
let spim0 = spim::Spim::new(
dp.SPIM0,
spim0_pins,
spim::Frequency::M8,
spim::MODE_3,
122,
);
let spim0 = spim::Spim::new(dp.SPIM0, spim0_pins, spim::Frequency::M8, spim::MODE_3, 122);
let spi_bus0 = shared_bus::CortexMBusManager::new(spim0);

// backlight control pin for display: always on
Expand All @@ -131,76 +109,68 @@ fn main() -> ! {
draw_background(&mut display, &mut display_csn);

// setup touchpad external interrupt pin: P0.28/AIN4 (TP_INT)
let touch_int = port0.p0_28.into_pullup_input().degrade();
let touch_int = port0.p0_28.into_pullup_input().degrade();
// setup touchpad reset pin: P0.10/NFC2 (TP_RESET)
let touch_rst = port0.p0_10.into_push_pull_output(Level::High).degrade();
let touch_rst = port0.p0_10.into_push_pull_output(Level::High).degrade();

let mut touchpad = CST816S::new(
i2c_port,
touch_int,
touch_rst);
let mut touchpad = CST816S::new(i2c_port, touch_int, touch_rst);
touchpad.setup(&mut delay_source).unwrap();
hprintln!("setup done").unwrap();

loop {
let rand_val = rng.random_u16();
let rand_color = Rgb565::new((rand_val >> 11) as u8, (rand_val >> 5) as u8 & 0x3F, (rand_val & 0x1F) as u8);
let rand_color = Rgb565::new(
(rand_val >> 11) as u8,
(rand_val >> 5) as u8 & 0x3F,
(rand_val & 0x1F) as u8,
);

if let Some(evt) = touchpad.read_one_touch_event() {
draw_target(&mut display, &mut display_csn, evt.x, evt.y,rand_color);
//hprintln!("{:?}", evt).unwrap();
}
else {
draw_target(&mut display, &mut display_csn, evt.x, evt.y, rand_color);
} else {
delay_source.delay_us(1000u32);
}

}
}


fn configure_display(display: &mut DisplayType, display_csn: &mut impl OutputPin, delay_source: &mut (impl DelayMs<u8> + DelayUs<u32>)) {
fn configure_display(
display: &mut DisplayType,
display_csn: &mut impl OutputPin,
delay_source: &mut (impl DelayMs<u8> + DelayUs<u32>),
) {
let _ = display_csn.set_low();
display.init(delay_source).unwrap();
display.set_orientation(&Orientation::Portrait).unwrap();
let _ = display_csn.set_high();
}

fn draw_background(display: &mut DisplayType, display_csn: &mut impl OutputPin) {
fn draw_background(display: &mut DisplayType, display_csn: &mut impl OutputPin) {
if let Ok(_) = display_csn.set_low() {
let clear_bg = Rectangle::new(
Point::new(0, 0),
Point::new(SCREEN_WIDTH, SCREEN_HEIGHT),
)
let clear_bg = Rectangle::new(Point::new(0, 0), Point::new(SCREEN_WIDTH, SCREEN_HEIGHT))
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK));
clear_bg.draw(display).unwrap();

let center_circle = Circle::new(
Point::new(HALF_SCREEN_WIDTH, SCREEN_HEIGHT / 2),
SCREEN_RADIUS,
)
.into_styled(PrimitiveStyle::with_stroke(Rgb565::YELLOW, 4));
.into_styled(PrimitiveStyle::with_stroke(Rgb565::YELLOW, 4));
center_circle.draw(display).unwrap();
}
let _ = display_csn.set_high();
}

fn draw_target(display: &mut DisplayType,
display_csn: &mut impl OutputPin,
x_pos: i32,
y_pos: i32,
stroke_color: Rgb565,
fn draw_target(
display: &mut DisplayType,
display_csn: &mut impl OutputPin,
x_pos: i32,
y_pos: i32,
stroke_color: Rgb565,
) {
if let Ok(_) = display_csn.set_low() {

let targ_circle = Circle::new(
Point::new(x_pos, y_pos),
10,
).into_styled(PrimitiveStyle::with_stroke(stroke_color, 4));
let targ_circle = Circle::new(Point::new(x_pos, y_pos), 10)
.into_styled(PrimitiveStyle::with_stroke(stroke_color, 4));
targ_circle.draw(display).unwrap();
}
let _ = display_csn.set_high();
}




64 changes: 29 additions & 35 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
#![no_std]


use core::fmt::Debug;

use embedded_hal as hal;
use hal::blocking::delay::{DelayUs};

use hal::blocking::delay::DelayUs;

/// Errors in this crate
#[derive(Debug)]
Expand All @@ -14,13 +12,12 @@ pub enum Error<CommE, PinE> {
Pin(PinE),

GenericError,

}

pub struct CST816S<I2C, PINT, RST> {
i2c: I2C,
pin_int: PINT,
pin_rst: RST,
pin_rst: RST,
blob_buf: [u8; BLOB_BUF_LEN],
}

Expand All @@ -43,12 +40,11 @@ pub struct TouchEvent {
impl<I2C, PINT, RST, CommE, PinE> CST816S<I2C, PINT, RST>
where
I2C: hal::blocking::i2c::Write<Error = CommE>
+ hal::blocking::i2c::Read<Error = CommE>
+ hal::blocking::i2c::WriteRead<Error = CommE>,
+ hal::blocking::i2c::Read<Error = CommE>
+ hal::blocking::i2c::WriteRead<Error = CommE>,
PINT: hal::digital::v2::InputPin,
RST: hal::digital::v2::StatefulOutputPin<Error = PinE>,
{

pub fn new(port: I2C, interrupt_pin: PINT, reset_pin: RST) -> Self {
Self {
i2c: port,
Expand All @@ -59,9 +55,10 @@ where
}

/// setup the driver to communicate with the device
pub fn setup(&mut self, delay_source: &mut impl DelayUs<u32>)
-> Result<(), Error<CommE, PinE>>
{
pub fn setup(
&mut self,
delay_source: &mut impl DelayUs<u32>,
) -> Result<(), Error<CommE, PinE>> {
// reset the chip
self.pin_rst.set_low().map_err(Error::Pin)?;
delay_source.delay_us(20_000);
Expand All @@ -74,17 +71,17 @@ where
}

/// Read enough registers to fill our read buf
pub fn read_registers(&mut self)
-> Result<(), Error<CommE, PinE>> {

self.i2c.write_read(Self::DEFAULT_I2C_ADDRESS,
&[Self::REG_FIRST],
self.blob_buf.as_mut()).map_err(Error::Comm)?;
pub fn read_registers(&mut self) -> Result<(), Error<CommE, PinE>> {
self.i2c
.write_read(
Self::DEFAULT_I2C_ADDRESS,
&[Self::REG_FIRST],
self.blob_buf.as_mut(),
)
.map_err(Error::Comm)?;
Ok(())
}



///
/// Translate raw register data into touch events
///
Expand All @@ -96,7 +93,7 @@ where
action: 0,
finger_id: 0,
pressure: 0,
area: 0
area: 0,
};

// two of the registers mix 4 bits of position with other values
Expand All @@ -111,19 +108,18 @@ where

// action of touch (0 = down, 1 = up, 2 = contact)
touch.action = (touch_x_h_and_action >> 6) as u8;
touch.finger_id = (touch_y_h_and_finger >> 4) as u8;
touch.finger_id = (touch_y_h_and_finger >> 4) as u8;

// Compute touch pressure and area
touch.pressure = buf[Self::TOUCH_PRESURE_OFF ];
touch.area = buf[Self::TOUCH_AREA_OFF ] >> 4;
touch.pressure = buf[Self::TOUCH_PRESURE_OFF];
touch.area = buf[Self::TOUCH_AREA_OFF] >> 4;

Some(touch)
}

/// The main method for getting the current set of touch events
/// Reads events into the event buffer provided
pub fn read_one_touch_event(&mut self, ) -> Option<TouchEvent> {

pub fn read_one_touch_event(&mut self) -> Option<TouchEvent> {
// the interrupt pin should be low if there is data available;
// otherwise, attempting to read i2c will cause a stall
if let Ok(data_available) = self.pin_int.is_low() {
Expand All @@ -132,20 +128,22 @@ where
let gesture_id = self.blob_buf[Self::GESTURE_ID_OFF];
let num_points = (self.blob_buf[Self::NUM_POINTS_OFF] & 0x0F) as usize;
for i in 0..num_points {
let evt_start: usize = (i * Self::RAW_TOUCH_EVENT_LEN) + Self::GESTURE_HEADER_LEN;
let evt_start: usize =
(i * Self::RAW_TOUCH_EVENT_LEN) + Self::GESTURE_HEADER_LEN;
if let Some(mut evt) = Self::touch_event_from_data(
self.blob_buf[evt_start..evt_start + Self::RAW_TOUCH_EVENT_LEN].as_ref())
{
self.blob_buf[evt_start..evt_start + Self::RAW_TOUCH_EVENT_LEN]
.as_ref(),
) {
evt.gesture = gesture_id;
//TODO we only ever appear to get one event on the PineTime: handle more?
return Some(evt)
return Some(evt);
}
}
}
}
}

None
None
}

const DEFAULT_I2C_ADDRESS: u8 = 0x15;
Expand All @@ -158,7 +156,7 @@ where
pub const MAX_TOUCH_CHANNELS: usize = 10;

/// The first register on the device
const REG_FIRST:u8 = 0x00;
const REG_FIRST: u8 = 0x00;

/// Header bytes (first three of every register block read)
// const RESERVED_0_OFF: usize = 0;
Expand All @@ -176,14 +174,10 @@ where
const TOUCH_Y_L_OFF: usize = 3;
const TOUCH_PRESURE_OFF: usize = 4;
const TOUCH_AREA_OFF: usize = 5;

}


const BLOB_BUF_LEN: usize = 63; // (MAX_TOUCH_CHANNELS + RAW_TOUCH_EVENT_LEN) + GESTURE_HEADER_LEN;



#[cfg(test)]
mod tests {
#[test]
Expand Down

0 comments on commit 9fcd219

Please sign in to comment.