Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PTC support for SAMD11 and SAMD21 #420

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
60bf956
Add PTC support for samd21e.
AuroransSolis Mar 22, 2021
3df65a6
Mapped all pins and handled X line channels.
AuroransSolis Mar 22, 2021
126a563
Hide the whole module behind SAMD21.
AuroransSolis Mar 22, 2021
76cfa1f
Couldn't stop thinking about it. Added PTC support for G and J.
AuroransSolis Mar 22, 2021
af09284
The `rustfmt.sh` script likes to remove this tag for some reason.
AuroransSolis Mar 22, 2021
1441ebb
Merge branch 'master' into master
AuroransSolis Mar 25, 2021
aadb194
Realized that for the time being, it makes more sense to put PTC stuf…
AuroransSolis Mar 26, 2021
6937385
Undid manual SVD patching and added PTC patch to the SAMD21 XSL file.
AuroransSolis Mar 26, 2021
729a92d
Merge branch 'master' into master
AuroransSolis Mar 27, 2021
9848467
Added PTC peripheral to the SAMD11 SVD file and generalized the PTC p…
AuroransSolis Apr 5, 2021
d8c9cff
Bring branch up to date with upstream.
AuroransSolis Aug 3, 2021
a5828f9
Lotsa stuff going on here, but in short, SAMD{1,2}D should have worki…
AuroransSolis Aug 3, 2021
e3fc4a7
Finally back from vacation and able to make this simple fix.
AuroransSolis Aug 13, 2021
ea256d5
Add PTC support for samd21e.
AuroransSolis Mar 22, 2021
6e4bc13
Mapped all pins and handled X line channels.
AuroransSolis Mar 22, 2021
9d537a9
Hide the whole module behind SAMD21.
AuroransSolis Mar 22, 2021
22d65af
Couldn't stop thinking about it. Added PTC support for G and J.
AuroransSolis Mar 22, 2021
3ceac4b
The `rustfmt.sh` script likes to remove this tag for some reason.
AuroransSolis Mar 22, 2021
5b46304
Realized that for the time being, it makes more sense to put PTC stuf…
AuroransSolis Mar 26, 2021
fe4c8bf
Undid manual SVD patching and added PTC patch to the SAMD21 XSL file.
AuroransSolis Mar 26, 2021
f13ea26
Added PTC peripheral to the SAMD11 SVD file and generalized the PTC p…
AuroransSolis Apr 5, 2021
91f5a1e
Lotsa stuff going on here, but in short, SAMD{1,2}D should have worki…
AuroransSolis Aug 3, 2021
db5949e
Finally back from vacation and able to make this simple fix.
AuroransSolis Aug 13, 2021
7a5613c
Merge branch 'master' of github.com:AuroransSolis/atsamd
AuroransSolis Aug 14, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hal/src/samd21/clock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ clock_generator!(
(ac_ana, AcAnaClock, AC_ANA),
(ac_dig, AcDigClock, AC_DIG),
(dac, DacClock, DAC),
(ptc, PtcClock, PTC),
(i2s0, I2S0Clock, I2S_0),
(i2s1, I2S1Clock, I2S_1),
);
Expand Down
3 changes: 3 additions & 0 deletions hal/src/samd21/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ pub mod timer;

#[cfg(feature = "usb")]
pub mod usb;

#[cfg(feature = "unproven")]
pub mod ptc;
244 changes: 244 additions & 0 deletions hal/src/samd21/ptc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
use crate::clock::GenericClockController;
use crate::gpio::v1;
use crate::gpio::v2::*;
use crate::hal::adc::{Channel, OneShot};
use crate::target_device::{
ptc::{
convctrl::ADCACCUM_A, freqctrl::SAMPLEDELAY_A, serres::RESISTOR_A, xselect::XMUX_A,
yselect::YMUX_A,
},
PM, PTC,
};

pub struct Ptc<PTC> {
ptc: PTC,
}

impl Ptc<PTC> {
pub fn ptc(ptc: PTC, pm: &mut PM, clocks: &mut GenericClockController) -> Self {
// Enable PTC in the APBC mask
pm.apbcmask.modify(|_, w| w.ptc_().set_bit());
let gclk1 = clocks.gclk1();
// Enable the PTC clock
clocks.ptc(&gclk1).expect("ptc clock setup failed");
while ptc.ctrlb.read().syncflag().bit_is_set() {}

// Reset the PTC module
ptc.ctrla.modify(|_, w| w.swrst().set_bit());
while ptc.ctrlb.read().syncflag().bit_is_set() {}

// Magic writes? Honestly dunno what these are for.
// f7 => 11110111
// fb => 11111011
// fc => 11111100
ptc.unk4c04.write(|w| unsafe { w.bits(0xf7) });
ptc.unk4c04.write(|w| unsafe { w.bits(0xfb) });
ptc.unk4c04.write(|w| unsafe { w.bits(0xfc) });
while ptc.ctrlb.read().syncflag().bit_is_set() {}

// Next in the init sequence in the FreeTouch repo, writes of the following two
// values are made to FREQCTRL:
// 9f => 10011111
// ---baaaa
// ef => 11101111
// ---baaaa
// The upper three bits are unused, so I'm unsure what the point of this is
// beyond setting all of the SAMPLEDELAY field to 1 and toggling
// FREQSPREADEN. Furthermore, the next thing done is setting SAMPLEDELAY
// to 0, thus ending up with (in theory): 11101111
// & 11110000
// ----------
// 11100000
// So honestly, I'm just going to set them to 0 in one step.
ptc.freqctrl.write(|w| {
w.freqspreaden().clear_bit();
w.sampledelay().variant(SAMPLEDELAY_A::FREQHOP1)
});
while ptc.ctrlb.read().syncflag().bit_is_set() {}

// Software init
ptc.ctrlc.write(|w| w.init().set_bit());
// Set to run in standby
ptc.ctrla.write(|w| w.runstdby().set_bit());
while ptc.ctrlb.read().syncflag().bit_is_set() {}

// Set interrupt enables
ptc.intenclr.write(|w| {
w.wco().set_bit();
w.eoc().set_bit()
});
while ptc.ctrlb.read().syncflag().bit_is_set() {}

Self { ptc }
}

pub fn compcap(&mut self, compcap: u16) {
self.ptc
.compcap
.write(|w| unsafe { w.value().bits(compcap) });
while self.ptc.ctrlb.read().syncflag().bit_is_set() {}
}

pub fn intcap(&mut self, intcap: u8) {
self.ptc.intcap.write(|w| unsafe { w.value().bits(intcap) });
while self.ptc.ctrlb.read().syncflag().bit_is_set() {}
}

pub fn oversample(&mut self, oversample: ADCACCUM_A) {
self.ptc
.convctrl
.write(|w| w.adcaccum().variant(oversample));
while self.ptc.ctrlb.read().syncflag().bit_is_set() {}
}

pub fn sample_delay(&mut self, sampledelay: SAMPLEDELAY_A) {
match sampledelay {
SAMPLEDELAY_A::FREQHOP1 => self.ptc.freqctrl.write(|w| w.freqspreaden().clear_bit()),
_ => self.ptc.freqctrl.write(|w| w.freqspreaden().set_bit()),
}
self.ptc
.freqctrl
.write(|w| w.sampledelay().variant(sampledelay));
while self.ptc.ctrlb.read().syncflag().bit_is_set() {}
}

pub fn series_resistance(&mut self, serres: RESISTOR_A) {
self.ptc.serres.write(|w| w.resistor().variant(serres));
while self.ptc.ctrlb.read().syncflag().bit_is_set() {}
}

pub fn xselect(&mut self, xselect: XMUX_A) {
self.ptc.xselect.write(|w| w.xmux().variant(xselect));
}

pub fn yselect(&mut self, yselect: YMUX_A) {
self.ptc.yselect.write(|w| w.ymux().variant(yselect));
}

fn power_up(&mut self) {
while self.ptc.ctrlb.read().syncflag().bit_is_set() {}
self.ptc.ctrla.modify(|_, w| w.enable().set_bit());
while self.ptc.ctrlb.read().syncflag().bit_is_set() {}
}

fn power_down(&mut self) {
while self.ptc.ctrlb.read().syncflag().bit_is_set() {}
self.ptc.ctrla.modify(|_, w| w.enable().clear_bit());
while self.ptc.ctrlb.read().syncflag().bit_is_set() {}
}

fn convert(&mut self) -> u16 {
self.ptc
.burstmode
.write(|w| unsafe { w.burstmode().bits(0xa4) });
while self.ptc.ctrlb.read().syncflag().bit_is_set() {}

self.ptc.convctrl.write(|w| w.convert().set_bit());
while self.ptc.ctrlb.read().syncflag().bit_is_set() {}

self.ptc.result.read().result().bits()
}
}

impl<WORD, PIN> OneShot<PTC, WORD, PIN> for Ptc<PTC>
where
WORD: From<u16>,
PIN: Channel<PTC, ID = u8>,
{
type Error = ();

fn read(&mut self, _pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
let channel = PIN::channel();
while self.ptc.ctrlb.read().syncflag().bit_is_set() {}

// Select and enable specified channel
if channel > 15 {
let channel = channel - 16;
self.ptc
.xselect
.write(|w| unsafe { w.xmux().bits(1 << channel) });
self.ptc
.xselecten
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << channel)) });
} else {
self.ptc
.yselect
.write(|w| unsafe { w.ymux().bits(1 << channel) });
self.ptc
.yselecten
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << channel)) });
};
self.power_up();
let result = self.convert();
self.power_down();

Ok(result.into())
}
}

macro_rules! ptc_pins {
($($PinId:ident: $Chan:literal),+) => {
$(
impl Channel<PTC> for Pin<$PinId, AlternateB> {
type ID = u8;
fn channel() -> u8 { $Chan }
}
)+
}
}

/// Implement ['Channel`] for [`v1::Pin`]s based on the implementations for
/// `v2` [`Pin`]s
impl<I> Channel<PTC> for v1::Pin<I, v1::PfB>
where
I: PinId,
Pin<I, AlternateB>: Channel<PTC, ID = u8>,
{
type ID = u8;
fn channel() -> u8 {
Pin::<I, AlternateB>::channel()
}
}

ptc_pins! {
PA02: 0,
PA03: 1,
PA04: 2,
PA05: 3,
PA06: 4,
PA07: 5,
PA08: 16,
PA09: 17,
PA10: 18,
PA11: 19,
PA16: 20,
PA17: 21,
PA18: 22,
PA19: 23,
PA22: 26,
PA23: 27
}

#[cfg(any(feature = "samd21g", feature = "samd21j"))]
ptc_pins! {
PB02: 8,
PB03: 9,
PB08: 14,
PB09: 15,
PA20: 24,
PA21: 25
}

#[cfg(feature = "samd21j")]
ptc_pins! {
PB00: 6,
PB01: 7,
PB04: 10,
PB05: 11,
PB06: 12,
PB07: 13,
PB12: 28,
PB13: 29,
PB14: 30,
PB15: 31
}
1 change: 1 addition & 0 deletions pac/atsamd21e/device.x
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ PROVIDE(TC5 = DefaultHandler);
PROVIDE(ADC = DefaultHandler);
PROVIDE(AC = DefaultHandler);
PROVIDE(DAC = DefaultHandler);
PROVIDE(PTC = DefaultHandler);
PROVIDE(I2S = DefaultHandler);

13 changes: 13 additions & 0 deletions pac/atsamd21e/src/gclk/clkctrl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ pub enum ID_A {
AC_ANA = 32,
#[doc = "33: DAC"]
DAC = 33,
#[doc = "34: PTCReserved"]
PTC = 34,
#[doc = "35: I2S_0"]
I2S_0 = 35,
#[doc = "36: I2S_1"]
Expand Down Expand Up @@ -135,6 +137,7 @@ impl ID_R {
31 => Val(ID_A::AC_DIG),
32 => Val(ID_A::AC_ANA),
33 => Val(ID_A::DAC),
34 => Val(ID_A::PTC),
35 => Val(ID_A::I2S_0),
36 => Val(ID_A::I2S_1),
i => Res(i),
Expand Down Expand Up @@ -310,6 +313,11 @@ impl ID_R {
pub fn is_dac(&self) -> bool {
*self == ID_A::DAC
}
#[doc = "Checks if the value of the field is `PTC`"]
#[inline(always)]
pub fn is_ptc(&self) -> bool {
*self == ID_A::PTC
}
#[doc = "Checks if the value of the field is `I2S_0`"]
#[inline(always)]
pub fn is_i2s_0(&self) -> bool {
Expand Down Expand Up @@ -501,6 +509,11 @@ impl<'a> ID_W<'a> {
pub fn dac(self) -> &'a mut W {
self.variant(ID_A::DAC)
}
#[doc = "PTCReserved"]
#[inline(always)]
pub fn ptc(self) -> &'a mut W {
self.variant(ID_A::PTC)
}
#[doc = "I2S_0"]
#[inline(always)]
pub fn i2s_0(self) -> &'a mut W {
Expand Down
31 changes: 30 additions & 1 deletion pac/atsamd21e/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ extern "C" {
fn ADC();
fn AC();
fn DAC();
fn PTC();
fn I2S();
}
#[doc(hidden)]
Expand Down Expand Up @@ -90,7 +91,7 @@ pub static __INTERRUPTS: [Vector; 28] = [
Vector { _handler: ADC },
Vector { _handler: AC },
Vector { _handler: DAC },
Vector { _reserved: 0 },
Vector { _handler: PTC },
Vector { _handler: I2S },
];
#[doc = r"Enumeration of all the interrupts"]
Expand Down Expand Up @@ -141,6 +142,8 @@ pub enum Interrupt {
AC = 24,
#[doc = "25 - DAC"]
DAC = 25,
#[doc = "26 - PTC"]
PTC = 26,
#[doc = "27 - I2S"]
I2S = 27,
}
Expand Down Expand Up @@ -513,6 +516,27 @@ impl Deref for PORT {
}
#[doc = "Port Module"]
pub mod port;
#[doc = "Peripheral Touch Controller"]
pub struct PTC {
_marker: PhantomData<*const ()>,
}
unsafe impl Send for PTC {}
impl PTC {
#[doc = r"Returns a pointer to the register block"]
#[inline(always)]
pub const fn ptr() -> *const ptc::RegisterBlock {
0x4200_4c00 as *const _
}
}
impl Deref for PTC {
type Target = ptc::RegisterBlock;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { &*PTC::ptr() }
}
}
#[doc = "Peripheral Touch Controller"]
pub mod ptc;
#[doc = "Port Module (IOBUS)"]
pub struct PORT_IOBUS {
_marker: PhantomData<*const ()>,
Expand Down Expand Up @@ -851,6 +875,8 @@ pub struct Peripherals {
pub PM: PM,
#[doc = "PORT"]
pub PORT: PORT,
#[doc = "PTC"]
pub PTC: PTC,
#[doc = "PORT_IOBUS"]
pub PORT_IOBUS: PORT_IOBUS,
#[doc = "RTC"]
Expand Down Expand Up @@ -950,6 +976,9 @@ impl Peripherals {
PORT: PORT {
_marker: PhantomData,
},
PTC: PTC {
_marker: PhantomData,
},
PORT_IOBUS: PORT_IOBUS {
_marker: PhantomData,
},
Expand Down
Loading