diff --git a/tm4c-hal/src/gpio.rs b/tm4c-hal/src/gpio.rs index 45990ed..3887aa5 100644 --- a/tm4c-hal/src/gpio.rs +++ b/tm4c-hal/src/gpio.rs @@ -11,6 +11,9 @@ pub trait InputMode {} /// All output modes implement this pub trait OutputMode {} +/// All analog modes implement this +pub trait AnalogMode {} + /// OpenDrain modes implement this pub trait OpenDrainMode { /// Is pull-up enabled @@ -55,6 +58,11 @@ impl OpenDrainMode for PullUp { true } } +/// Sub-mode of Input: Analog input (type state) +pub struct AnalogInput; +impl AnalogMode for AnalogInput {} +impl InputMode for AnalogInput {} +impl IsUnlocked for AnalogInput {} /// Tri-state pub struct Tristate; @@ -73,17 +81,11 @@ impl IsUnlocked for Output where MODE: OutputMode {} pub struct AlternateFunction where AF: AlternateFunctionChoice, - MODE: OutputMode, { _func: PhantomData, _mode: PhantomData, } -impl IsUnlocked for AlternateFunction -where - AF: AlternateFunctionChoice, - MODE: OutputMode, -{ -} +impl IsUnlocked for AlternateFunction where AF: AlternateFunctionChoice {} /// Sub-mode of Output/AlternateFunction: Push pull output (type state for /// Output) diff --git a/tm4c-hal/src/lib.rs b/tm4c-hal/src/lib.rs index 790e1a5..4df6935 100644 --- a/tm4c-hal/src/lib.rs +++ b/tm4c-hal/src/lib.rs @@ -191,7 +191,29 @@ macro_rules! gpio_macro { _mode: PhantomData, } + impl $PXi { + fn number(&self) -> u8 { + $i + } + } + impl $PXi where MODE: IsUnlocked { + /// Configures the pin to analog input. + pub fn into_ain( + self, + _gpio_control: &mut GpioControl, + ) -> $PXi> { + let p = unsafe { &*$GPIOX::ptr() }; + unsafe { bb::change_bit(&p.afsel, $i, true); } + unsafe { bb::change_bit(&p.dir, $i, false); } + unsafe { bb::change_bit(&p.odr, $i, false); } + unsafe { bb::change_bit(&p.pur, $i, false); } + unsafe { bb::change_bit(&p.pdr, $i, false); } + unsafe { bb::change_bit(&p.den, $i, false); } + unsafe { bb::change_bit(&p.amsel, $i, false); } + $PXi { _mode: PhantomData } + } + /// Configures the pin to serve as alternate function 1 through 15. /// Disables open-drain to make the output a push-pull. pub fn into_af_push_pull( diff --git a/tm4c123x-hal/src/adc.rs b/tm4c123x-hal/src/adc.rs new file mode 100644 index 0000000..eed637e --- /dev/null +++ b/tm4c123x-hal/src/adc.rs @@ -0,0 +1,143 @@ +//! Analog-to-Digital Converter +use core::marker::PhantomData; + +use crate::{ + bb, + gpio::gpiob::{PB4, PB5}, + gpio::gpiod::{PD0, PD1, PD2, PD3}, + gpio::gpioe::{PE0, PE1, PE2, PE3, PE4, PE5}, + hal::adc, + ss_ctl, ss_fifo, ss_mux, sysctl, +}; + +pub use crate::sample_seq::{SS0, SS1, SS2, SS3}; + +use tm4c123x::{ADC0, ADC1}; +use tm4c_hal::gpio::{AnalogInput, Input}; + +/// Example ADC +pub struct Adc { + /// adc peripheral + adc: ADC, + + // input pin + #[allow(dead_code)] + pin: PIN, + + // SampleSequencer being used + _ss: PhantomData, +} + +macro_rules! pin_hal { + ($ ($PXN:ident: ($num:expr), )+) => { + $( + impl adc::Channel for $PXN> { + type ID = u8; + + fn channel() -> u8 { + $num + } + } + + impl adc::Channel for $PXN> { + type ID = u8; + + fn channel() -> u8 { + $num + } + } + )+ + } +} + +macro_rules! init_hal { + ($($ADCX:ident: ($powerDomain:ident, $adcX:ident, $SSX:ident),)+) => { + $( + + impl Adc<$SSX, $ADCX, PIN> + where + PIN: adc::Channel<$ADCX>, + PIN::ID: Into + { + /// Configures the ADC peripheral to operate in full duplex master mode + pub fn new( + adc: $ADCX, + pin: PIN, + pc: &sysctl::PowerControl, + ) -> Self + { + // power up + sysctl::control_power( + pc, sysctl::Domain::$powerDomain, + sysctl::RunMode::Run, sysctl::PowerState::On); + sysctl::reset(pc, sysctl::Domain::$powerDomain); + + unsafe { // disable for config + bb::change_bit(&adc.actss, $SSX::num(), false); + } + adc.emux.modify(|r, w| unsafe { w.bits(r.bits() & !(0xF000)) }); // software trigger + + ss_mux!(adc, $SSX).write(|w| unsafe { w.bits(PIN::channel().into()) }); + + unsafe { + bb::change_bit(&ss_ctl!(adc, $SSX), 1, true); + bb::change_bit(&ss_ctl!(adc, $SSX), 2, true); + bb::change_bit(&adc.actss, $SSX::num(), true); + } + + Adc { _ss: PhantomData, pin, adc } + } + + /// Releases the peripheral and pin + pub fn free(self) -> ($ADCX, PIN) { + (self.adc,self.pin) + } + + /// Configured channel + pub fn channel(&self) -> PIN::ID { + PIN::channel() + } + + /// Blocking read + pub fn read_blocking(&self) -> u16 { + unsafe { + bb::change_bit(&self.adc.pssi, $SSX::num(), true); // Enable SS3 conversion or start sampling data from AN0 + } + while (&self.adc.ris.read().bits() & 8) == 0 { + // cortex_m::asm::nop(); + } + let ref _adc = self.adc; + let adc_value = ss_fifo!(_adc, $SSX).read().data().bits(); //clear conversion clear flag bit + self.adc.isc.write(|w| unsafe { w.bits(8) }); + adc_value + } + } + )+ + } +} + +init_hal! { + ADC0: (Adc0, adc0, SS0), + ADC0: (Adc0, adc0, SS1), + ADC0: (Adc0, adc0, SS2), + ADC0: (Adc0, adc0, SS3), + ADC1: (Adc1, adc1, SS0), + ADC1: (Adc1, adc1, SS1), + ADC1: (Adc1, adc1, SS2), + ADC1: (Adc1, adc1, SS3), +} + +pin_hal! { + PE3: (0), + PE2: (1), + PE1: (2), + PE0: (3), + PD3: (4), + PD2: (5), + PD1: (6), + PD0: (7), + PE5: (8), + PE4: (9), + PB4: (10), + PB5: (11), +} diff --git a/tm4c123x-hal/src/lib.rs b/tm4c123x-hal/src/lib.rs index 12137ba..62111d3 100644 --- a/tm4c123x-hal/src/lib.rs +++ b/tm4c123x-hal/src/lib.rs @@ -32,11 +32,13 @@ pub use crate::tm4c123x::interrupt; use embedded_hal as hal; +pub mod adc; pub mod gpio; pub mod hib; pub mod i2c; pub mod prelude; pub mod pwm; +pub mod sample_seq; pub mod serial; pub mod spi; pub mod sysctl; diff --git a/tm4c123x-hal/src/sample_seq.rs b/tm4c123x-hal/src/sample_seq.rs new file mode 100644 index 0000000..a87e5fb --- /dev/null +++ b/tm4c123x-hal/src/sample_seq.rs @@ -0,0 +1,86 @@ +#![macro_use] +//! Sample sequencers for ADC + +/// 8 Samples 8 FIFO depth +pub struct SS0; +impl SS0 { + /// Sample sequencer number + pub fn num() -> u8 { + return 0; + } +} +/// 4 Samples 4 FIFO depth +pub struct SS1; +impl SS1 { + /// Sample sequencer number + pub fn num() -> u8 { + return 1; + } +} +/// 4 Samples 4 FIFO depth +pub struct SS2; +impl SS2 { + /// Sample sequencer number + pub fn num() -> u8 { + return 2; + } +} +/// 1 Samples 1 FIFO depth +pub struct SS3; +impl SS3 { + /// Sample sequencer number + pub fn num() -> u8 { + return 3; + } +} + +#[macro_export] +/// ssctl field accessor +macro_rules! ss_ctl { + ($adc:ident, SS0) => { + $adc.ssctl0 + }; + ($adc:ident, SS1) => { + $adc.ssctl1 + }; + ($adc:ident, SS2) => { + $adc.ssctl2 + }; + ($adc:ident, SS3) => { + $adc.ssctl3 + }; +} + +#[macro_export] +/// ssmux field accessor +macro_rules! ss_mux { + ($adc:ident, SS0) => { + $adc.ssmux0 + }; + ($adc:ident, SS1) => { + $adc.ssmux1 + }; + ($adc:ident, SS2) => { + $adc.ssmux2 + }; + ($adc:ident, SS3) => { + $adc.ssmux3 + }; +} + +#[macro_export] +/// ssfifo field accessor +macro_rules! ss_fifo { + ($adc:ident, SS0) => { + $adc.ssfifo0 + }; + ($adc:ident, SS1) => { + $adc.ssfifo1 + }; + ($adc:ident, SS2) => { + $adc.ssfifo2 + }; + ($adc:ident, SS3) => { + $adc.ssfifo3 + }; +}