From ddc223e194336f655716454df9862d22fa44a4db Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 17 Aug 2018 01:04:18 +0000 Subject: [PATCH 1/9] Updated docs for module. Started Tsc impl --- src/datetime.rs | 2 +- src/dma.rs | 2 ++ src/lib.rs | 6 ++-- src/pwr.rs | 2 ++ src/rtc.rs | 2 +- src/tsc.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 src/tsc.rs diff --git a/src/datetime.rs b/src/datetime.rs index 93949159..766f0f0b 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -1,4 +1,4 @@ -/// Date and timer units & helper functions +//! Date and timer units & helper functions /// Seconds #[derive(Clone, Copy, Debug)] diff --git a/src/dma.rs b/src/dma.rs index 475f0403..6fa75679 100644 --- a/src/dma.rs +++ b/src/dma.rs @@ -1,3 +1,5 @@ +//! Direct Memory Access Engine + #![allow(dead_code)] use core::marker::PhantomData; diff --git a/src/lib.rs b/src/lib.rs index 5320d5c4..57d60c9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,9 @@ +//! STM32l432xx Hardware abstraction layer + #![no_std] -// currently these are the only 2 unstable features, never_typoe can replaced with void, nto sure what unsize can be repalced with +// TODO, remove this feature (currently required in dma.rs) #![feature(unsize)] -#![feature(never_type)] extern crate cortex_m; extern crate cast; @@ -25,6 +26,7 @@ pub mod spi; pub mod rtc; pub mod pwr; pub mod datetime; +pub mod tsc; #[cfg(test)] diff --git a/src/pwr.rs b/src/pwr.rs index 3c7c99dd..8b04a3e3 100644 --- a/src/pwr.rs +++ b/src/pwr.rs @@ -1,3 +1,5 @@ +//! Power management + use rcc::{APB1R1}; use stm32l4::stm32l4x2::{pwr, PWR}; diff --git a/src/rtc.rs b/src/rtc.rs index 7bff6495..302fbe58 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -1,4 +1,4 @@ -/// RTC peripheral abstraction +//! RTC peripheral abstraction use datetime::*; use rcc::{BDCR, APB1R1}; diff --git a/src/tsc.rs b/src/tsc.rs new file mode 100644 index 00000000..684ad94e --- /dev/null +++ b/src/tsc.rs @@ -0,0 +1,77 @@ +//! Touch sense controller + +use rcc::AHB1; +use stm32l4::stm32l4x2::{TSC}; + +pub enum Event { + /// Max count error + MaxCountError, + /// End of acquisition + EndOfAcquisition +} + +pub trait Pins { + const REMAP: u8; +} + +pub struct Tsc { + pins: PINS, + tsc: TSC +} + +impl Tsc { + pub fn tsc(tsc: TSC, pins: PINS, ahb: &mut AHB1) -> Self + where PINS: Pins + { + /* Enable the peripheral clock */ + ahb.enr().modify(|_, w| w.tscen().set_bit()); + ahb.rstr().modify(|_, w| w.tscrst().set_bit()); + ahb.rstr().modify(|_, w| w.tscrst().clear_bit()); + + + + Tsc { + tsc, + pins + } + } + + /// Starts a charge acquisition + pub fn start(&self) { + + } + + /// Blocks waiting for a acquisition to complete + pub fn wait(&self) -> Result<(), ()> { + Ok(()) + } + + /// Enables an interrupt event + pub fn listen(&mut self, event: Event){ + match event { + Event::EndOfAcquisition => { + self.tsc.ier.modify(|_, w| w.eoaie().set_bit()); + }, + Event::MaxCountError => { + self.tsc.ier.modify(|_, w| w.mceie().set_bit()); + }, + } + } + + /// Disables an interrupt event + pub fn unlisten(&self, event: Event) { + match event { + Event::EndOfAcquisition => { + self.tsc.ier.modify(|_, w| w.eoaie().clear_bit()); + }, + Event::MaxCountError => { + self.tsc.ier.modify(|_, w| w.mceie().clear_bit()); + }, + } + } + + /// Releases the TSC peripheral and associated pins + pub fn free(self) -> (TSC, PINS) { + (self.tsc, self.pins) + } +} \ No newline at end of file From a1fe2aaf394c41ddc5fcdcc140a7f8172435ef13 Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 17 Aug 2018 20:00:48 +0000 Subject: [PATCH 2/9] Continued structure, configured tsc cr. impl pin definitions for the tsc, currently requires all three pins are required (plus the sample pin) even if a a user only wants to use one channel. Added into af8 and af9 for gpio --- examples/touch.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++++ src/gpio.rs | 50 +++++++++++++++++++++++++++++++++++++- src/tsc.rs | 46 ++++++++++++++++++++++++++++++++--- 3 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 examples/touch.rs diff --git a/examples/touch.rs b/examples/touch.rs new file mode 100644 index 00000000..34d172d5 --- /dev/null +++ b/examples/touch.rs @@ -0,0 +1,62 @@ +//! Test the serial interface +//! +//! This example requires you to short (connect) the TX and RX pins. +#![deny(unsafe_code)] +// #![deny(warnings)] +#![no_main] +#![no_std] + +extern crate cortex_m; +#[macro_use(entry, exception)] +extern crate cortex_m_rt as rt; +extern crate panic_semihosting; + +extern crate stm32l432xx_hal as hal; + + +use cortex_m::asm; +use hal::prelude::*; +use hal::stm32l4::stm32l4x2; +use hal::tsc::Tsc; +use rt::ExceptionFrame; + +entry!(main); + +fn main() -> ! { + let p = stm32l4x2::Peripherals::take().unwrap(); + + let mut flash = p.FLASH.constrain(); + let mut rcc = p.RCC.constrain(); + // let mut gpioa = p.GPIOA.split(&mut rcc.ahb2); + let mut gpiob = p.GPIOB.split(&mut rcc.ahb2); + + // clock configuration using the default settings (all clocks run at 8 MHz) + let clocks = rcc.cfgr.freeze(&mut flash.acr); + // TRY this alternate clock configuration (clocks run at nearly the maximum frequency) + // let clocks = rcc.cfgr.sysclk(64.mhz()).pclk1(32.mhz()).freeze(&mut flash.acr); + + + let sample_pin = gpiob.pb4.into_af9(&mut gpiob.moder, &mut gpiob.afrl); + let c1 = gpiob.pb5.into_af9(&mut gpiob.moder, &mut gpiob.afrl); + let c2 = gpiob.pb6.into_af9(&mut gpiob.moder, &mut gpiob.afrl); + let c3 = gpiob.pb7.into_af9(&mut gpiob.moder, &mut gpiob.afrl); + + let tsc = Tsc::tsc(p.TSC, (sample_pin, c1, c2, c3) , &mut rcc.ahb1); + + // if all goes well you should reach this breakpoint + asm::bkpt(); + + loop {} +} + +exception!(HardFault, hard_fault); + +fn hard_fault(ef: &ExceptionFrame) -> ! { + panic!("{:#?}", ef); +} + +exception!(*, default_handler); + +fn default_handler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); +} diff --git a/src/gpio.rs b/src/gpio.rs index 54e4b808..f650e350 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -99,7 +99,7 @@ macro_rules! gpio { use rcc::AHB2; use super::{ - AF4, AF5, AF6, AF7, Floating, GpioExt, Input, OpenDrain, Output, + AF4, AF5, AF6, AF7, AF8, AF9, Floating, GpioExt, Input, OpenDrain, Output, PullDown, PullUp, PushPull, }; @@ -317,6 +317,54 @@ macro_rules! gpio { $PXi { _mode: PhantomData } } + /// Configures the pin to serve as alternate function 8 (AF8) + pub fn into_af8( + self, + moder: &mut MODER, + afr: &mut $AFR, + ) -> $PXi { + let offset = 2 * $i; + + // alternate function mode + let mode = 0b10; + moder.moder().modify(|r, w| unsafe { + w.bits((r.bits() & !(0b11 << offset)) | (mode << offset)) + }); + + let af = 8; + let offset = 4 * ($i % 8); + + afr.afr().modify(|r, w| unsafe { + w.bits((r.bits() & !(0b1111 << offset)) | (af << offset)) + }); + + $PXi { _mode: PhantomData } + } + + /// Configures the pin to serve as alternate function 9 (AF9) + pub fn into_af9( + self, + moder: &mut MODER, + afr: &mut $AFR, + ) -> $PXi { + let offset = 2 * $i; + + // alternate function mode + let mode = 0b10; + moder.moder().modify(|r, w| unsafe { + w.bits((r.bits() & !(0b11 << offset)) | (mode << offset)) + }); + + let af = 9; + let offset = 4 * ($i % 8); + + afr.afr().modify(|r, w| unsafe { + w.bits((r.bits() & !(0b1111 << offset)) | (af << offset)) + }); + + $PXi { _mode: PhantomData } + } + /// Configures the pin to operate as a floating input pin pub fn into_floating_input( self, diff --git a/src/tsc.rs b/src/tsc.rs index 684ad94e..f50f62bb 100644 --- a/src/tsc.rs +++ b/src/tsc.rs @@ -2,6 +2,8 @@ use rcc::AHB1; use stm32l4::stm32l4x2::{TSC}; +use gpio::gpiob::{PB4, PB5, PB6, PB7}; +use gpio::{AF9}; pub enum Event { /// Max count error @@ -10,12 +12,19 @@ pub enum Event { EndOfAcquisition } +// TODO currently requires all the pins even if a user wants one channel, fix pub trait Pins { - const REMAP: u8; + const REMAP: bool; +} + +impl Pins for (PB4, PB5, PB6, PB7) { + const REMAP: bool = false; // TODO REMAP } pub struct Tsc { pins: PINS, + // num_channels: usize, + // channel_pins: [PINS; 3], // upto 3 channels on the stm32l432xx tsc: TSC } @@ -28,11 +37,42 @@ impl Tsc { ahb.rstr().modify(|_, w| w.tscrst().set_bit()); ahb.rstr().modify(|_, w| w.tscrst().clear_bit()); + tsc.cr.write(|w| unsafe { + w.ctph() + .bits(1 << 28) + .ctpl() + .bits(1 << 24) + .sse() + .clear_bit() + .pgpsc() + .bits(2 << 12) + .mcv() + // 000: 255 + // 001: 511 + // 010: 1023 + // 011: 2047 + // 100: 4095 + // 101: 8191 + // 110: 16383 + .bits(0b101) // TODO make this value configurable + }); + + // TODO this may require the pin index, maybe make into_touch_pin in gpio.rs + + // Set the sampling pin + tsc.ioscr.write(|w| { w }); + // Set the channel pin(s) + tsc.ioccr.write(|w| { w }); + + // set the acquisitiuon groups based of the channel pins + tsc.iogcsr.write(|w| { w }); Tsc { - tsc, - pins + tsc: tsc, + pins: pins, + // num_channels: 0, + // channel_pins: [PINS; 3] } } From c355f9f0afdc1efc33c71abb2cd18ac86f3b3c50 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 19 Aug 2018 12:03:58 +0000 Subject: [PATCH 3/9] More startup code for tsc, need to refactor gpio for af with different modes at the same time --- src/tsc.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/tsc.rs b/src/tsc.rs index f50f62bb..cee3bcb8 100644 --- a/src/tsc.rs +++ b/src/tsc.rs @@ -59,14 +59,19 @@ impl Tsc { // TODO this may require the pin index, maybe make into_touch_pin in gpio.rs + // TODO allow configuration // Set the sampling pin - tsc.ioscr.write(|w| { w }); + tsc.ioscr.write(|w| { w.g2_io1().set_bit() }); // Set the channel pin(s) - tsc.ioccr.write(|w| { w }); + tsc.ioccr.write(|w| { + w.g2_io2().set_bit() + .g2_io3().set_bit() + .g2_io4().set_bit() + }); - // set the acquisitiuon groups based of the channel pins - tsc.iogcsr.write(|w| { w }); + // set the acquisitiuon groups based of the channel pins, stm32l432xx only has group 2 + tsc.iogcsr.write(|w| { w.g2e().set_bit() }); Tsc { tsc: tsc, From 76482d982a0f80a193766013e87dbef466c5a9a2 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 19 Aug 2018 23:44:25 +0000 Subject: [PATCH 4/9] GPIO changes: AF * Added `Alternate` pin state struct that holds the AF mode and the pin mode, e.g Alternate> . * tested that serial still works, therfore I assume spi will too. * Added `into_touch_channel` & `into_touch_sample` to gpio, which helps get the pin in the write state in one command, still need to disable smit trigger hysteris` on those pins. --- .vscode/launch.json | 2 +- examples/touch.rs | 10 +++++----- src/gpio.rs | 43 ++++++++++++++++++++++++++++++++++++------- src/serial.rs | 8 ++++---- src/spi.rs | 8 ++++---- src/tsc.rs | 38 ++++++++++++++++++++------------------ 6 files changed, 70 insertions(+), 39 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 4586cf8f..009369fb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,7 +13,7 @@ "debugger_args": [ "-nx" // dont use the .gdbinit file ], - "executable": "./target/thumbv7em-none-eabi/debug/examples/rtc", + "executable": "./target/thumbv7em-none-eabi/debug/examples/serial", "remote": true, "target": ":3333", "cwd": "${workspaceRoot}", diff --git a/examples/touch.rs b/examples/touch.rs index 34d172d5..1c0323cd 100644 --- a/examples/touch.rs +++ b/examples/touch.rs @@ -36,12 +36,12 @@ fn main() -> ! { // let clocks = rcc.cfgr.sysclk(64.mhz()).pclk1(32.mhz()).freeze(&mut flash.acr); - let sample_pin = gpiob.pb4.into_af9(&mut gpiob.moder, &mut gpiob.afrl); - let c1 = gpiob.pb5.into_af9(&mut gpiob.moder, &mut gpiob.afrl); - let c2 = gpiob.pb6.into_af9(&mut gpiob.moder, &mut gpiob.afrl); - let c3 = gpiob.pb7.into_af9(&mut gpiob.moder, &mut gpiob.afrl); + let sample_pin = gpiob.pb4.into_touch_sample(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); + let c1 = gpiob.pb5.into_touch_channel(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); + let c2 = gpiob.pb6.into_touch_channel(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); + let c3 = gpiob.pb7.into_touch_channel(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); - let tsc = Tsc::tsc(p.TSC, (sample_pin, c1, c2, c3) , &mut rcc.ahb1); + let tsc = Tsc::tsc(p.TSC, sample_pin, (c1, c2, c3) , &mut rcc.ahb1); // if all goes well you should reach this breakpoint asm::bkpt(); diff --git a/src/gpio.rs b/src/gpio.rs index f650e350..e69ffebb 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -38,6 +38,13 @@ pub struct PushPull; /// Open drain output (type state) pub struct OpenDrain; +/// Alternate mode (type state) +pub struct Alternate +{ + _af: PhantomData, + _mode: PhantomData, +} + /// Alternate function 0 (type state) pub struct AF0; @@ -99,7 +106,7 @@ macro_rules! gpio { use rcc::AHB2; use super::{ - AF4, AF5, AF6, AF7, AF8, AF9, Floating, GpioExt, Input, OpenDrain, Output, + Alternate, AF4, AF5, AF6, AF7, AF8, AF9, Floating, GpioExt, Input, OpenDrain, Output, PullDown, PullUp, PushPull, }; @@ -229,7 +236,7 @@ macro_rules! gpio { self, moder: &mut MODER, afr: &mut $AFR, - ) -> $PXi { + ) -> $PXi> { let offset = 2 * $i; // alternate function mode @@ -252,7 +259,7 @@ macro_rules! gpio { self, moder: &mut MODER, afr: &mut $AFR, - ) -> $PXi { + ) -> $PXi> { let offset = 2 * $i; // alternate function mode @@ -275,7 +282,7 @@ macro_rules! gpio { self, moder: &mut MODER, afr: &mut $AFR, - ) -> $PXi { + ) -> $PXi> { let offset = 2 * $i; // alternate function mode @@ -298,7 +305,7 @@ macro_rules! gpio { self, moder: &mut MODER, afr: &mut $AFR, - ) -> $PXi { + ) -> $PXi> { let offset = 2 * $i; // alternate function mode @@ -322,7 +329,7 @@ macro_rules! gpio { self, moder: &mut MODER, afr: &mut $AFR, - ) -> $PXi { + ) -> $PXi> { let offset = 2 * $i; // alternate function mode @@ -346,7 +353,7 @@ macro_rules! gpio { self, moder: &mut MODER, afr: &mut $AFR, - ) -> $PXi { + ) -> $PXi> { let offset = 2 * $i; // alternate function mode @@ -471,6 +478,28 @@ macro_rules! gpio { $PXi { _mode: PhantomData } } + + /// Configures the pin to operate as an touch sample + pub fn into_touch_sample( + self, + moder: &mut MODER, + otyper: &mut OTYPER, + afr: &mut $AFR, + ) -> $PXi>> { + let od = self.into_open_drain_output(moder, otyper); + od.into_af9(moder, afr) + } + + /// Configures the pin to operate as an touch channel + pub fn into_touch_channel( + self, + moder: &mut MODER, + otyper: &mut OTYPER, + afr: &mut $AFR, + ) -> $PXi>> { + let od = self.into_push_pull_output(moder, otyper); + od.into_af9(moder, afr) + } } impl $PXi> { diff --git a/src/serial.rs b/src/serial.rs index 33c28d3a..314d8341 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -11,7 +11,7 @@ use void::Void; use gpio::gpioa::{PA10, PA2, PA3, PA9}; use gpio::gpiob::{PB6, PB7}; -use gpio::AF7; +use gpio::{AF7, Alternate, Input, Floating}; use rcc::{APB1R1, APB2, Clocks}; use time::Bps; use dma::{dma1, CircBuffer}; @@ -45,15 +45,15 @@ pub trait Pins { const REMAP: u8; } -impl Pins for (PA9, PA10) { +impl Pins for (PA9>>, PA10>>) { const REMAP: u8 = 0; } -impl Pins for (PB6, PB7) { +impl Pins for (PB6>>, PB7>>) { const REMAP: u8 = 1; } -impl Pins for (PA2, PA3) { +impl Pins for (PA2>>, PA3>>) { const REMAP: u8 = 0; } diff --git a/src/spi.rs b/src/spi.rs index bcd32116..c2f9d584 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -7,7 +7,7 @@ use nb; use stm32l4::stm32l4x2::{SPI1, /* TODO SPI2, */ SPI3}; use gpio::gpioa::{PA5, PA6, PA7}; -use gpio::{AF5}; +use gpio::{AF5, Input, Floating, Alternate}; use rcc::{APB1R1, APB2, Clocks}; use time::Hertz; @@ -30,9 +30,9 @@ pub trait Pins { impl Pins for ( - PA5, - PA6, - PA7, + PA5>>, + PA6>>, + PA7>>, ) { const REMAP: bool = false; // TODO REMAP diff --git a/src/tsc.rs b/src/tsc.rs index cee3bcb8..95359d39 100644 --- a/src/tsc.rs +++ b/src/tsc.rs @@ -3,7 +3,7 @@ use rcc::AHB1; use stm32l4::stm32l4x2::{TSC}; use gpio::gpiob::{PB4, PB5, PB6, PB7}; -use gpio::{AF9}; +use gpio::{AF9, Alternate, Output, OpenDrain, PushPull}; pub enum Event { /// Max count error @@ -12,25 +12,28 @@ pub enum Event { EndOfAcquisition } -// TODO currently requires all the pins even if a user wants one channel, fix -pub trait Pins { - const REMAP: bool; -} +// TODO macro to impl all possible channel/sample pin combinations +pub trait SamplePin {} +impl SamplePin for PB4>> {} -impl Pins for (PB4, PB5, PB6, PB7) { - const REMAP: bool = false; // TODO REMAP -} +pub trait ChannelPins {} +impl ChannelPins for ( + PB5>>, + PB6>>, + PB7>>) +{} -pub struct Tsc { +// TODO currently requires all the pins even if a user wants one channel, fix +pub struct Tsc { + sample_pin: SPIN, pins: PINS, - // num_channels: usize, - // channel_pins: [PINS; 3], // upto 3 channels on the stm32l432xx tsc: TSC } -impl Tsc { - pub fn tsc(tsc: TSC, pins: PINS, ahb: &mut AHB1) -> Self - where PINS: Pins +impl Tsc { + pub fn tsc(tsc: TSC, sample_pin: SPIN, pins: PINS, ahb: &mut AHB1) -> Self + where PINS: ChannelPins, + SPIN: SamplePin { /* Enable the peripheral clock */ ahb.enr().modify(|_, w| w.tscen().set_bit()); @@ -75,9 +78,8 @@ impl Tsc { Tsc { tsc: tsc, + sample_pin: sample_pin, pins: pins, - // num_channels: 0, - // channel_pins: [PINS; 3] } } @@ -116,7 +118,7 @@ impl Tsc { } /// Releases the TSC peripheral and associated pins - pub fn free(self) -> (TSC, PINS) { - (self.tsc, self.pins) + pub fn free(self) -> (TSC, SPIN, PINS) { + (self.tsc, self.sample_pin, self.pins) } } \ No newline at end of file From df197a0fcf3cc8394a023670a41bd1f63866c843 Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 20 Aug 2018 00:26:09 +0000 Subject: [PATCH 5/9] Functioning axample, it seems the flag gets set instantly, could be a noise issue, could be that the smapling cap is too small. --- .vscode/launch.json | 2 +- examples/touch.rs | 4 ++++ src/tsc.rs | 45 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 009369fb..4872b815 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,7 +13,7 @@ "debugger_args": [ "-nx" // dont use the .gdbinit file ], - "executable": "./target/thumbv7em-none-eabi/debug/examples/serial", + "executable": "./target/thumbv7em-none-eabi/debug/examples/touch", "remote": true, "target": ":3333", "cwd": "${workspaceRoot}", diff --git a/examples/touch.rs b/examples/touch.rs index 1c0323cd..6fa97e9b 100644 --- a/examples/touch.rs +++ b/examples/touch.rs @@ -43,6 +43,10 @@ fn main() -> ! { let tsc = Tsc::tsc(p.TSC, sample_pin, (c1, c2, c3) , &mut rcc.ahb1); + tsc.start(); + + tsc.wait().unwrap(); + // if all goes well you should reach this breakpoint asm::bkpt(); diff --git a/src/tsc.rs b/src/tsc.rs index 95359d39..7c420044 100644 --- a/src/tsc.rs +++ b/src/tsc.rs @@ -5,6 +5,7 @@ use stm32l4::stm32l4x2::{TSC}; use gpio::gpiob::{PB4, PB5, PB6, PB7}; use gpio::{AF9, Alternate, Output, OpenDrain, PushPull}; +#[derive(Debug)] pub enum Event { /// Max count error MaxCountError, @@ -42,13 +43,13 @@ impl Tsc { tsc.cr.write(|w| unsafe { w.ctph() - .bits(1 << 28) + .bits((1 << 28) as u8) .ctpl() - .bits(1 << 24) + .bits((1 << 24) as u8) .sse() .clear_bit() .pgpsc() - .bits(2 << 12) + .bits((2 << 12) as u8) .mcv() // 000: 255 // 001: 511 @@ -58,11 +59,20 @@ impl Tsc { // 101: 8191 // 110: 16383 .bits(0b101) // TODO make this value configurable + .tsce() + .set_bit() }); - // TODO this may require the pin index, maybe make into_touch_pin in gpio.rs - // TODO allow configuration + + // Schmitt trigger hysteresis on all used TSC IOs + tsc.iohcr.write(|w| { + w.g2_io1().set_bit() + .g2_io2().set_bit() + .g2_io3().set_bit() + .g2_io4().set_bit() + }); + // Set the sampling pin tsc.ioscr.write(|w| { w.g2_io1().set_bit() }); @@ -76,6 +86,12 @@ impl Tsc { // set the acquisitiuon groups based of the channel pins, stm32l432xx only has group 2 tsc.iogcsr.write(|w| { w.g2e().set_bit() }); + // clear interrupt flags + tsc.icr.write(|w| { + w.eoaic().clear_bit() + .mceic().clear_bit() + }); + Tsc { tsc: tsc, sample_pin: sample_pin, @@ -85,12 +101,25 @@ impl Tsc { /// Starts a charge acquisition pub fn start(&self) { + // clear interrupt flags + self.tsc.icr.write(|w| { + w.eoaic().clear_bit() + .mceic().clear_bit() + }); + self.tsc.cr.modify(|_, w| { w.start().set_bit() }); } - /// Blocks waiting for a acquisition to complete - pub fn wait(&self) -> Result<(), ()> { - Ok(()) + /// Blocks waiting for a acquisition to complete or for a Max Count Error + pub fn wait(&self) -> Result { + loop { + let isr = self.tsc.isr.read(); + if isr.eoaf().bit_is_set() { + break Ok(Event::EndOfAcquisition); + } else if isr.mcef().bit_is_set() { + break Err(Event::MaxCountError); + } + } } /// Enables an interrupt event From 17dd09c4504aa0ac50e7ff34fc411c420498238e Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 20 Aug 2018 12:47:16 +0000 Subject: [PATCH 6/9] Tsc working! wait() returns the number of charge cycles on ALL channel pins in a group, so if we need to read them individually we have to do 3 reads (TODO). THe peripheral is now setup we now need to bottom out an api to choose pins for reading etc - future work could include linear motions (see stm32 touch library) --- examples/touch.rs | 13 +++++++------ src/tsc.rs | 21 +++++++++++++-------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/examples/touch.rs b/examples/touch.rs index 6fa97e9b..ddf9da2d 100644 --- a/examples/touch.rs +++ b/examples/touch.rs @@ -14,16 +14,17 @@ extern crate panic_semihosting; extern crate stm32l432xx_hal as hal; -use cortex_m::asm; use hal::prelude::*; use hal::stm32l4::stm32l4x2; use hal::tsc::Tsc; use rt::ExceptionFrame; +use hal::delay::Delay; entry!(main); fn main() -> ! { let p = stm32l4x2::Peripherals::take().unwrap(); + let cp = cortex_m::Peripherals::take().unwrap(); let mut flash = p.FLASH.constrain(); let mut rcc = p.RCC.constrain(); @@ -35,7 +36,8 @@ fn main() -> ! { // TRY this alternate clock configuration (clocks run at nearly the maximum frequency) // let clocks = rcc.cfgr.sysclk(64.mhz()).pclk1(32.mhz()).freeze(&mut flash.acr); - + // let mut delay = Delay::new(cp.SYST, clocks); + let sample_pin = gpiob.pb4.into_touch_sample(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); let c1 = gpiob.pb5.into_touch_channel(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); let c2 = gpiob.pb6.into_touch_channel(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); @@ -44,11 +46,10 @@ fn main() -> ! { let tsc = Tsc::tsc(p.TSC, sample_pin, (c1, c2, c3) , &mut rcc.ahb1); tsc.start(); + let baseline = tsc.wait().unwrap(); - tsc.wait().unwrap(); - - // if all goes well you should reach this breakpoint - asm::bkpt(); + tsc.start(); + let touched = tsc.wait().unwrap(); loop {} } diff --git a/src/tsc.rs b/src/tsc.rs index 7c420044..2789d19e 100644 --- a/src/tsc.rs +++ b/src/tsc.rs @@ -86,10 +86,10 @@ impl Tsc { // set the acquisitiuon groups based of the channel pins, stm32l432xx only has group 2 tsc.iogcsr.write(|w| { w.g2e().set_bit() }); - // clear interrupt flags + // clear interrupt & flags tsc.icr.write(|w| { - w.eoaic().clear_bit() - .mceic().clear_bit() + w.eoaic().set_bit() + .mceic().set_bit() }); Tsc { @@ -101,21 +101,26 @@ impl Tsc { /// Starts a charge acquisition pub fn start(&self) { - // clear interrupt flags + // clear interrupt & flags self.tsc.icr.write(|w| { - w.eoaic().clear_bit() - .mceic().clear_bit() + w.eoaic().set_bit() + .mceic().set_bit() + }); + + // discharge the caps ready for a new reading + self.tsc.cr.modify(|_, w| { + w.iodef().clear_bit() }); self.tsc.cr.modify(|_, w| { w.start().set_bit() }); } /// Blocks waiting for a acquisition to complete or for a Max Count Error - pub fn wait(&self) -> Result { + pub fn wait(&self) -> Result { loop { let isr = self.tsc.isr.read(); if isr.eoaf().bit_is_set() { - break Ok(Event::EndOfAcquisition); + break Ok(self.tsc.iog2cr.read().cnt().bits()); } else if isr.mcef().bit_is_set() { break Err(Event::MaxCountError); } From 773902acb7cbebbf717e5cdf31a3f2f757e8a7d4 Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 21 Aug 2018 00:28:58 +0000 Subject: [PATCH 7/9] Found an implementation for pins that allows us to specify the tsc group information in the type. can now read from two seperate pins (3 touch keys) --- examples/touch.rs | 34 +++++++++++++++++++------------ src/tsc.rs | 52 ++++++++++++++++++++++++++--------------------- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/examples/touch.rs b/examples/touch.rs index ddf9da2d..fb3ef5b3 100644 --- a/examples/touch.rs +++ b/examples/touch.rs @@ -18,13 +18,12 @@ use hal::prelude::*; use hal::stm32l4::stm32l4x2; use hal::tsc::Tsc; use rt::ExceptionFrame; -use hal::delay::Delay; entry!(main); fn main() -> ! { let p = stm32l4x2::Peripherals::take().unwrap(); - let cp = cortex_m::Peripherals::take().unwrap(); + // let cp = cortex_m::Peripherals::take().unwrap(); let mut flash = p.FLASH.constrain(); let mut rcc = p.RCC.constrain(); @@ -32,26 +31,35 @@ fn main() -> ! { let mut gpiob = p.GPIOB.split(&mut rcc.ahb2); // clock configuration using the default settings (all clocks run at 8 MHz) - let clocks = rcc.cfgr.freeze(&mut flash.acr); + let _clocks = rcc.cfgr.freeze(&mut flash.acr); // TRY this alternate clock configuration (clocks run at nearly the maximum frequency) // let clocks = rcc.cfgr.sysclk(64.mhz()).pclk1(32.mhz()).freeze(&mut flash.acr); // let mut delay = Delay::new(cp.SYST, clocks); + let mut led = gpiob.pb3.into_push_pull_output(&mut gpiob.moder, &mut gpiob.otyper); let sample_pin = gpiob.pb4.into_touch_sample(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); - let c1 = gpiob.pb5.into_touch_channel(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); - let c2 = gpiob.pb6.into_touch_channel(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); - let c3 = gpiob.pb7.into_touch_channel(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); + let mut c1 = gpiob.pb5.into_touch_channel(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); + let mut c2 = gpiob.pb6.into_touch_channel(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); + // let mut c3 = gpiob.pb7.into_touch_channel(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); - let tsc = Tsc::tsc(p.TSC, sample_pin, (c1, c2, c3) , &mut rcc.ahb1); + // , (c1, c2, c3) + let tsc = Tsc::tsc(p.TSC, sample_pin, &mut rcc.ahb1); - tsc.start(); + tsc.start(&mut c1); let baseline = tsc.wait().unwrap(); - - tsc.start(); - let touched = tsc.wait().unwrap(); - - loop {} + let threshold = (baseline / 100) * 60; + loop { + tsc.start(&mut c1); + let touched = tsc.wait().unwrap(); + tsc.start(&mut c2); + let _touched_c2 = tsc.wait().unwrap(); + if touched < threshold { + led.set_high(); + } else { + led.set_low(); + } + } } exception!(HardFault, hard_fault); diff --git a/src/tsc.rs b/src/tsc.rs index 2789d19e..921b3769 100644 --- a/src/tsc.rs +++ b/src/tsc.rs @@ -17,24 +17,30 @@ pub enum Event { pub trait SamplePin {} impl SamplePin for PB4>> {} -pub trait ChannelPins {} -impl ChannelPins for ( - PB5>>, - PB6>>, - PB7>>) -{} +pub trait ChannelPin { + const OFFSET: u32; +} +impl ChannelPin for PB5>> { + const OFFSET: u32 = 1 << 1 + (1 * 4); +} +impl ChannelPin for PB6>> { + const OFFSET: u32 = 1 << 2 + (1 * 4); +} +impl ChannelPin for PB7>> { + const OFFSET: u32 = 1 << 3 + (1 * 4); +} + // TODO currently requires all the pins even if a user wants one channel, fix -pub struct Tsc { +pub struct Tsc { sample_pin: SPIN, - pins: PINS, + // pins: PINS, tsc: TSC } -impl Tsc { - pub fn tsc(tsc: TSC, sample_pin: SPIN, pins: PINS, ahb: &mut AHB1) -> Self - where PINS: ChannelPins, - SPIN: SamplePin +impl Tsc { + pub fn tsc(tsc: TSC, sample_pin: SPIN, ahb: &mut AHB1) -> Self + where SPIN: SamplePin // PINS: ChannelPins, { /* Enable the peripheral clock */ ahb.enr().modify(|_, w| w.tscen().set_bit()); @@ -75,13 +81,6 @@ impl Tsc { // Set the sampling pin tsc.ioscr.write(|w| { w.g2_io1().set_bit() }); - - // Set the channel pin(s) - tsc.ioccr.write(|w| { - w.g2_io2().set_bit() - .g2_io3().set_bit() - .g2_io4().set_bit() - }); // set the acquisitiuon groups based of the channel pins, stm32l432xx only has group 2 tsc.iogcsr.write(|w| { w.g2e().set_bit() }); @@ -95,12 +94,14 @@ impl Tsc { Tsc { tsc: tsc, sample_pin: sample_pin, - pins: pins, + // pins: pins, } } /// Starts a charge acquisition - pub fn start(&self) { + pub fn start(&self, _input: &mut PIN) + where PIN: ChannelPin + { // clear interrupt & flags self.tsc.icr.write(|w| { w.eoaic().set_bit() @@ -112,6 +113,11 @@ impl Tsc { w.iodef().clear_bit() }); + // Set the channel pin + self.tsc.ioccr.write(|w| unsafe { + w.bits(PIN::OFFSET) + }); + self.tsc.cr.modify(|_, w| { w.start().set_bit() }); } @@ -152,7 +158,7 @@ impl Tsc { } /// Releases the TSC peripheral and associated pins - pub fn free(self) -> (TSC, SPIN, PINS) { - (self.tsc, self.sample_pin, self.pins) + pub fn free(self) -> (TSC, SPIN) { + (self.tsc, self.sample_pin) } } \ No newline at end of file From 67df935ac8becbfbc2fa98c9f25906950a1fe535 Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 21 Aug 2018 00:35:56 +0000 Subject: [PATCH 8/9] Impl sample and channel for all pins, atm this means you can use a sample pin as a channel pin - not sure how to stop atm --- src/tsc.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/tsc.rs b/src/tsc.rs index 921b3769..d051e7bc 100644 --- a/src/tsc.rs +++ b/src/tsc.rs @@ -14,12 +14,28 @@ pub enum Event { } // TODO macro to impl all possible channel/sample pin combinations -pub trait SamplePin {} -impl SamplePin for PB4>> {} +pub trait SamplePin { + const OFFSET: u32; +} +impl SamplePin for PB4>> { + const OFFSET: u32 = 1 << 0 + (1 * 4); +} +impl SamplePin for PB5>> { + const OFFSET: u32 = 1 << 1 + (1 * 4); +} +impl SamplePin for PB6>> { + const OFFSET: u32 = 1 << 2 + (1 * 4); +} +impl SamplePin for PB7>> { + const OFFSET: u32 = 1 << 3 + (1 * 4); +} pub trait ChannelPin { const OFFSET: u32; } +impl ChannelPin for PB4>> { + const OFFSET: u32 = 1 << 0 + (1 * 4); +} impl ChannelPin for PB5>> { const OFFSET: u32 = 1 << 1 + (1 * 4); } @@ -40,7 +56,7 @@ pub struct Tsc { impl Tsc { pub fn tsc(tsc: TSC, sample_pin: SPIN, ahb: &mut AHB1) -> Self - where SPIN: SamplePin // PINS: ChannelPins, + where SPIN: SamplePin { /* Enable the peripheral clock */ ahb.enr().modify(|_, w| w.tscen().set_bit()); From 96d63d1a57bc1012f7494436a25eaa04094ef0ab Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 21 Aug 2018 21:03:17 +0000 Subject: [PATCH 9/9] Converted start into acquire which starts the tsc acquisition and blocks until it is complete --- examples/touch.rs | 10 +++---- src/tsc.rs | 72 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/examples/touch.rs b/examples/touch.rs index fb3ef5b3..093f959f 100644 --- a/examples/touch.rs +++ b/examples/touch.rs @@ -46,14 +46,12 @@ fn main() -> ! { // , (c1, c2, c3) let tsc = Tsc::tsc(p.TSC, sample_pin, &mut rcc.ahb1); - tsc.start(&mut c1); - let baseline = tsc.wait().unwrap(); + let baseline = tsc.acquire(&mut c1).unwrap(); let threshold = (baseline / 100) * 60; + loop { - tsc.start(&mut c1); - let touched = tsc.wait().unwrap(); - tsc.start(&mut c2); - let _touched_c2 = tsc.wait().unwrap(); + let touched = tsc.acquire(&mut c1).unwrap(); + let _touched_c2 = tsc.acquire(&mut c2).unwrap(); if touched < threshold { led.set_high(); } else { diff --git a/src/tsc.rs b/src/tsc.rs index d051e7bc..d7b3d65b 100644 --- a/src/tsc.rs +++ b/src/tsc.rs @@ -15,35 +15,45 @@ pub enum Event { // TODO macro to impl all possible channel/sample pin combinations pub trait SamplePin { + const GROUP: u32; const OFFSET: u32; } impl SamplePin for PB4>> { - const OFFSET: u32 = 1 << 0 + (1 * 4); + const GROUP: u32 = 2; + const OFFSET: u32 = 0; } impl SamplePin for PB5>> { - const OFFSET: u32 = 1 << 1 + (1 * 4); + const GROUP: u32 = 2; + const OFFSET: u32 = 1; } impl SamplePin for PB6>> { - const OFFSET: u32 = 1 << 2 + (1 * 4); + const GROUP: u32 = 2; + const OFFSET: u32 = 2; } impl SamplePin for PB7>> { - const OFFSET: u32 = 1 << 3 + (1 * 4); + const GROUP: u32 = 2; + const OFFSET: u32 = 3; } pub trait ChannelPin { + const GROUP: u32; const OFFSET: u32; } impl ChannelPin for PB4>> { - const OFFSET: u32 = 1 << 0 + (1 * 4); + const GROUP: u32 = 2; + const OFFSET: u32 = 0; } impl ChannelPin for PB5>> { - const OFFSET: u32 = 1 << 1 + (1 * 4); + const GROUP: u32 = 2; + const OFFSET: u32 = 1; } impl ChannelPin for PB6>> { - const OFFSET: u32 = 1 << 2 + (1 * 4); + const GROUP: u32 = 2; + const OFFSET: u32 = 2; } impl ChannelPin for PB7>> { - const OFFSET: u32 = 1 << 3 + (1 * 4); + const GROUP: u32 = 2; + const OFFSET: u32 = 3; } @@ -87,16 +97,15 @@ impl Tsc { // TODO allow configuration - // Schmitt trigger hysteresis on all used TSC IOs - tsc.iohcr.write(|w| { - w.g2_io1().set_bit() - .g2_io2().set_bit() - .g2_io3().set_bit() - .g2_io4().set_bit() + let bit_pos = SPIN::OFFSET + (4 * (SPIN::GROUP - 1)); + + // Schmitt trigger hysteresis on sample IOs + tsc.iohcr.write(|w| unsafe { + w.bits(1 << bit_pos) }); // Set the sampling pin - tsc.ioscr.write(|w| { w.g2_io1().set_bit() }); + tsc.ioscr.write(|w| unsafe { w.bits(1 << bit_pos) }); // set the acquisitiuon groups based of the channel pins, stm32l432xx only has group 2 tsc.iogcsr.write(|w| { w.g2e().set_bit() }); @@ -110,7 +119,6 @@ impl Tsc { Tsc { tsc: tsc, sample_pin: sample_pin, - // pins: pins, } } @@ -129,24 +137,44 @@ impl Tsc { w.iodef().clear_bit() }); + let bit_pos = PIN::OFFSET + (4 * (PIN::GROUP - 1)); + // Set the channel pin self.tsc.ioccr.write(|w| unsafe { - w.bits(PIN::OFFSET) + w.bits(1 << bit_pos) }); self.tsc.cr.modify(|_, w| { w.start().set_bit() }); } /// Blocks waiting for a acquisition to complete or for a Max Count Error - pub fn wait(&self) -> Result { - loop { + pub fn acquire(&self, input: &mut PIN) -> Result + where PIN: ChannelPin + { + let bit_pos = PIN::OFFSET + (4 * (PIN::GROUP - 1)); + + // disable Schmitt trigger hysteresis + self.tsc.iohcr.write(|w| unsafe { + w.bits(1 << bit_pos) + }); + + self.start(input); + + let result = loop { let isr = self.tsc.isr.read(); if isr.eoaf().bit_is_set() { - break Ok(self.tsc.iog2cr.read().cnt().bits()); + break Ok(self.tsc.iog2cr.read().cnt().bits()) } else if isr.mcef().bit_is_set() { - break Err(Event::MaxCountError); + break Err(Event::MaxCountError) } - } + }; + + // re-enable Schmitt trigger hysteresis + self.tsc.iohcr.write(|w| unsafe { + w.bits(0 << bit_pos) + }); + + result } /// Enables an interrupt event