use super::{hal, pac};
use hal::prelude::*;
use embedded_hal_bus::spi as bspi;
use hal::clock::GenericClockController;
use hal::gpio::PA01;
use hal::pwm;
use hal::qspi;
use hal::sercom::uart::{self, BaudMode, Oversampling};
use hal::sercom::{i2c, spi, Sercom1, Sercom4};
use hal::time::Hertz;
use hal::typelevel::NoneT;
use st7735_lcd::{Orientation, ST7735};
#[cfg(feature = "usb")]
use hal::usb::usb_device::bus::UsbBusAllocator;
#[cfg(feature = "usb")]
pub use hal::usb::UsbBus;
#[cfg(feature = "usb")]
use pac::gclk::{genctrl::Srcselect, pchctrl::Genselect};
hal::bsp_peripherals!(
Sercom2 { I2cSercom }
Sercom5 { UartSercom }
);
pub use crate::buttons::ButtonReader;
pub use crate::buttons::Keys;
use hal::pwm::Pwm2;
pub use aliases::*;
pub mod aliases {
use super::hal::bsp_pins;
bsp_pins!(
PA02 {
name: speaker
aliases: {
Reset: SpeakerReset
}
},
PA27 {
name: speaker_enable
aliases: {
Reset: SpeakerEnableReset
}
},
PA05 {
name: a1
aliases: {
Reset: A1Reset
}
},
PB08 {
name: a2
aliases: {
Reset: A2Reset
}
},
PB09 {
name: a3
aliases: {
Reset: A3Reset
}
},
PA04 {
name: a4
aliases: {
Reset: A4Reset
}
},
PA06 {
name: a5
aliases: {
Reset: A5Reset
}
},
PB01 {
name: battery
aliases: {
AlternateB: BatteryPin,
Reset: BatteryReset
}
},
PB04 {
name: light
aliases: {
Reset: LightReset,
AlternateB: LightSensor
}
},
PB03 {
name: d2
aliases: {
Reset: D2Reset
}
},
PB02 {
name: d3
aliases: {
Reset: D3Reset
}
},
PA16 {
name: d5
aliases: {
Reset: D5Reset,
AlternateM: GclkOut
}
},
PA18 {
name: d6
aliases: {
Reset: D6Reset
}
},
PB14 {
name: accel_irq
aliases: {
Reset: AccelIrqReset
}
},
PA15 {
name: neopixel
aliases: {
PushPullOutput: NeopixelPin,
Reset: NeopixelReset,
AlternateC: NeopixelPinSpi,
}
},
PA19 {
name: d9
aliases: {
Reset: D9Reset
}
},
PA20 {
name: d10
aliases: {
Reset: D10Reset
}
},
PA21 {
name: d11
aliases: {
Reset: D11Reset
}
},
PA22 {
name: d12
aliases: {
Reset: D12Reset
}
},
PA23 {
name: d13
aliases: {
PushPullOutput: RedLed,
Reset: D13Reset,
AlternateE: Tc4Pwm,
AlternateG: RedLedTcc0
}
},
PB15 {
name: tft_mosi,
aliases: {
AlternateC: TftMosi,
Reset: TftMosiReset
}
},
PB13 {
name: tft_sclk
aliases: {
AlternateC: TftSclk,
Reset: TftSclkReset
}
},
PA00 {
name: tft_reset
aliases: {
PushPullOutput: TftReset,
Reset: TftResetReset
}
},
PB05 {
name: tft_dc
aliases: {
PushPullOutput: TftDc,
Reset: TftDcReset
}
},
PB12 {
name: tft_cs
aliases: {
PushPullOutput: TftCs,
Reset: TftCsReset
}
},
PA01 {
name: tft_backlight
aliases: {
AlternateE: TftBacklight,
Reset: TftBacklightReset
}
},
PB16 {
name: tx
aliases: {
AlternateC: UartTx,
Reset: UartTxReset
}
},
PB17 {
name: rx
aliases: {
AlternateC: UartRx,
Reset: UartRxReset
}
},
PB22 {
name: miso
aliases: {
AlternateC: SpiMiso,
Reset: SpiMisoReset
}
},
PB23 {
name: mosi
aliases: {
AlternateC: SpiMosi,
Reset: SpiMosiReset
}
},
PA17 {
name: sclk
aliases: {
AlternateC: SpiSclk,
Reset: SpiSclkReset
}
},
PA12 {
name: sda
aliases: {
AlternateC: Sda,
Reset: SdaReset
}
},
PA13 {
name: scl
aliases: {
AlternateC: Scl,
Reset: SclReset
}
},
PA24 {
name: usb_dm
aliases: {
AlternateH: UsbDm,
Reset: UsbDmReset
}
},
PA25 {
name: usb_dp
aliases: {
AlternateH: UsbDp,
Reset: UsbDpReset
}
},
PA14 {
name: sd_cs
aliases: {
Reset: SdCsReset
}
},
PB07 {
name: joy_x
aliases: {
AlternateB: JoyX,
Reset: JoyXReset
}
},
PB06 {
name: joy_y
aliases: {
AlternateB: JoyY,
Reset: JoyYReset
}
},
PB00 {
name: button_latch
aliases: {
PushPullOutput: ButtonLatch,
Reset: ButtonLatchReset
}
},
PB30 {
name: button_out
aliases: {
FloatingInput: ButtonOut,
Reset: ButtonOutReset
}
},
PB31 {
name: button_clock
aliases: {
PushPullOutput: ButtonClock,
Reset: ButtonClockReset
}
},
PB10 {
name: flash_sclk
aliases: {
AlternateH: QspiSclk,
Reset: QspiSclkReset
}
},
PB11 {
name: flash_cs
aliases: {
AlternateH: QspiCs,
Reset: QspiCsReset
}
},
PA08 {
name: flash_d0
aliases: {
AlternateH: QspiD0,
Reset: QspiD0Reset
}
},
PA09 {
name: flash_d1
aliases: {
AlternateH: QspiD1,
Reset: QspiD1Reset
}
},
PA10 {
name: flash_d2
aliases: {
AlternateH: QspiD2,
Reset: QspiD2Reset
}
},
PA11 {
name: flash_d3
aliases: {
AlternateH: QspiD3,
Reset: QspiD3Reset
}
},
);
}
impl Pins {
pub fn split(self) -> Sets {
let speaker = Speaker {
speaker: self.speaker,
enable: self.speaker_enable,
};
let display = Display {
tft_mosi: self.tft_mosi,
tft_sclk: self.tft_sclk,
tft_reset: self.tft_reset,
tft_cs: self.tft_cs,
tft_dc: self.tft_dc,
tft_backlight: self.tft_backlight,
};
let analog = Analog {
a1: self.a1,
a2: self.a2,
a3: self.a3,
a4: self.a4,
a5: self.a5,
};
let digital = Digital {
d2: self.d2,
d3: self.d3,
d5: self.d5,
d6: self.d6,
d9: self.d9,
d10: self.d10,
d11: self.d11,
d12: self.d12,
};
let flash = QSPIFlash {
sclk: self.flash_sclk,
cs: self.flash_cs,
data0: self.flash_d0,
data1: self.flash_d1,
data2: self.flash_d2,
data3: self.flash_d3,
};
let spi = SPI {
sclk: self.sclk,
mosi: self.mosi,
miso: self.miso,
};
let i2c = I2C {
sda: self.sda,
scl: self.scl,
};
let neopixel = Neopixel {
neopixel: self.neopixel,
};
let battery = Battery {
battery: self.battery,
};
let usb = USB {
dm: self.usb_dm,
dp: self.usb_dp,
};
let uart = UART {
rx: self.rx,
tx: self.tx,
};
let buttons = Buttons {
latch: self.button_latch,
data_in: self.button_out,
clock: self.button_clock,
};
let joystick = Joystick {
joy_x: self.joy_x,
joy_y: self.joy_y,
};
Sets {
display,
led_pin: self.d13,
neopixel,
battery,
light_pin: self.light,
i2c,
sd_cs_pin: self.sd_cs,
analog,
digital,
speaker,
spi,
flash,
usb,
uart,
buttons,
joystick,
}
}
}
pub struct Sets {
pub display: Display,
pub led_pin: D13Reset,
pub neopixel: Neopixel,
pub light_pin: LightReset,
pub i2c: I2C,
pub sd_cs_pin: SdCsReset,
pub battery: Battery,
pub speaker: Speaker,
pub spi: SPI,
pub usb: USB,
pub uart: UART,
pub analog: Analog,
pub digital: Digital,
pub flash: QSPIFlash,
pub buttons: Buttons,
pub joystick: Joystick,
}
pub struct Display {
pub tft_mosi: TftMosiReset,
pub tft_sclk: TftSclkReset,
pub tft_reset: TftResetReset,
pub tft_cs: TftCsReset,
pub tft_dc: TftDcReset,
pub tft_backlight: TftBacklightReset,
}
#[derive(Debug)]
pub enum DisplayError {
SercomClock,
Spi,
Driver,
Tc2Tc3Clock,
}
impl From<()> for DisplayError {
#[inline]
fn from(_value: ()) -> Self {
Self::Driver
}
}
pub type TftPads = spi::Pads<Sercom4, NoneT, TftMosi, TftSclk>;
pub type TftSpi = bspi::ExclusiveDevice<
spi::PanicOnRead<spi::Spi<spi::Config<TftPads>, spi::Tx>>,
TftCs,
bspi::NoDelay,
>;
pub type DisplayDriver = ST7735<TftSpi, TftDc, TftReset>;
impl Display {
pub fn init(
self,
clocks: &mut GenericClockController,
sercom4: pac::Sercom4,
mclk: &mut pac::Mclk,
timer2: pac::Tc2,
delay: &mut hal::delay::Delay,
) -> Result<(DisplayDriver, Pwm2<PA01>), DisplayError> {
let gclk0 = clocks.gclk0();
let clock = &clocks
.sercom4_core(&gclk0)
.ok_or(DisplayError::SercomClock)?;
let pads = spi::Pads::default()
.sclk(self.tft_sclk)
.data_out(self.tft_mosi);
let mut tft_cs: TftCs = self.tft_cs.into();
tft_cs.set_low().ok();
let tft_spi = bspi::ExclusiveDevice::new_no_delay(
spi::Config::new(mclk, sercom4, pads, clock.freq())
.spi_mode(spi::MODE_0)
.baud(16.MHz())
.enable()
.into_panic_on_read(),
tft_cs,
)
.map_err(|_| DisplayError::Spi)?;
let mut display = st7735_lcd::ST7735::new(
tft_spi,
self.tft_dc.into(),
self.tft_reset.into(),
true,
false,
160,
128,
);
display.init(delay)?;
display.set_orientation(&Orientation::LandscapeSwapped)?;
let pwm_clock = &clocks.tc2_tc3(&gclk0).ok_or(())?;
let pwm_pinout = pwm::TC2Pinout::Pa1(self.tft_backlight);
let mut pwm2 = Pwm2::new(pwm_clock, 1.kHz(), timer2, pwm_pinout, mclk);
pwm2.set_duty(pwm2.get_max_duty());
Ok((display, pwm2))
}
}
pub struct Neopixel {
pub neopixel: NeopixelReset,
}
#[cfg(feature = "neopixel-spi")]
pub type NeopixelSpiPads = spi::Pads<hal::sercom::Sercom2, NoneT, NeopixelPinSpi, Scl>;
#[cfg(feature = "neopixel-spi")]
pub type NeopixelSpi = spi::PanicOnRead<spi::Spi<spi::Config<NeopixelSpiPads>, spi::Tx>>;
#[cfg(feature = "neopixel-spi")]
impl Neopixel {
pub fn init_spi(
self,
clocks: &mut GenericClockController,
scl: impl hal::gpio::AnyPin<Id = hal::gpio::PA13>,
sercom2: pac::Sercom2,
mclk: &mut pac::Mclk,
) -> ws2812_spi::Ws2812<NeopixelSpi> {
use hal::fugit::RateExtU32;
let gclk0 = clocks.gclk0();
let clock = &clocks.sercom2_core(&gclk0).unwrap();
let pads = spi::Pads::default()
.data_out(self.neopixel)
.sclk(scl.into());
let spi = spi::Config::new(mclk, sercom2, pads, clock.freq())
.spi_mode(spi::MODE_0)
.baud(3.MHz())
.enable()
.into_panic_on_read();
ws2812_spi::Ws2812::new(spi)
}
}
pub struct SPI {
pub mosi: SpiMosiReset,
pub miso: SpiMisoReset,
pub sclk: SpiSclkReset,
}
pub type SpiPads = spi::Pads<Sercom1, SpiMiso, SpiMosi, SpiSclk>;
pub type Spi = spi::Spi<spi::Config<SpiPads>, spi::Duplex>;
impl SPI {
pub fn init(
self,
clocks: &mut GenericClockController,
baud: impl Into<Hertz>,
sercom1: pac::Sercom1,
mclk: &mut pac::Mclk,
) -> Spi {
let gclk0 = clocks.gclk0();
let clock = &clocks.sercom1_core(&gclk0).unwrap();
let pads = spi::Pads::default()
.data_in(self.miso)
.data_out(self.mosi)
.sclk(self.sclk);
spi::Config::new(mclk, sercom1, pads, clock.freq())
.spi_mode(spi::MODE_0)
.baud(baud.into())
.enable()
}
}
pub struct I2C {
pub sda: SdaReset,
pub scl: SclReset,
}
pub type I2cPads = i2c::Pads<I2cSercom, Sda, Scl>;
pub type I2c = i2c::I2c<i2c::Config<I2cPads>>;
pub fn i2c_master(
clocks: &mut GenericClockController,
baud: impl Into<Hertz>,
sercom: I2cSercom,
mclk: &mut pac::Mclk,
sda: impl Into<Sda>,
scl: impl Into<Scl>,
) -> I2c {
let gclk0 = clocks.gclk0();
let clock = &clocks.sercom2_core(&gclk0).unwrap();
let freq = clock.freq();
let baud = baud.into();
let pads = i2c::Pads::new(sda.into(), scl.into());
i2c::Config::new(mclk, sercom, pads, freq)
.baud(baud)
.enable()
}
pub struct Speaker {
pub speaker: SpeakerReset,
pub enable: SpeakerEnableReset,
}
pub struct USB {
pub dm: UsbDmReset,
pub dp: UsbDpReset,
}
impl USB {
#[cfg(feature = "usb")]
pub fn init(
self,
usb: pac::Usb,
clocks: &mut GenericClockController,
mclk: &mut pac::Mclk,
) -> UsbBusAllocator<UsbBus> {
clocks.configure_gclk_divider_and_source(Genselect::Gclk2, 1, Srcselect::Dfll, false);
let usb_gclk = clocks.get_gclk(Genselect::Gclk2).unwrap();
let usb_clock = &clocks.usb(&usb_gclk).unwrap();
let (dm, dp): (UsbDm, UsbDp) = (self.dm.into(), self.dp.into());
UsbBusAllocator::new(UsbBus::new(usb_clock, mclk, dm, dp, usb))
}
}
pub struct UART {
pub tx: UartTxReset,
pub rx: UartRxReset,
}
pub type UartPads = uart::Pads<UartSercom, UartRx, UartTx>;
pub type Uart = uart::Uart<uart::Config<UartPads>, uart::Duplex>;
impl UART {
pub fn init(
self,
clocks: &mut GenericClockController,
baud: impl Into<Hertz>,
sercom: UartSercom,
mclk: &mut pac::Mclk,
) -> Uart {
let gclk0 = clocks.gclk0();
let clock = &clocks.sercom5_core(&gclk0).unwrap();
let baud = baud.into();
let rx: UartRx = self.rx.into();
let tx: UartTx = self.tx.into();
let pads = uart::Pads::default().rx(rx).tx(tx);
uart::Config::new(mclk, sercom, pads, clock.freq())
.baud(baud, BaudMode::Fractional(Oversampling::Bits16))
.enable()
}
}
pub struct Analog {
pub a1: A1Reset,
pub a2: A2Reset,
pub a3: A3Reset,
pub a4: A4Reset,
pub a5: A5Reset,
}
pub struct Digital {
pub d2: D2Reset,
pub d3: D3Reset,
pub d5: D5Reset,
pub d6: D6Reset,
pub d9: D9Reset,
pub d10: D10Reset,
pub d11: D11Reset,
pub d12: D12Reset,
}
pub struct QSPIFlash {
pub sclk: QspiSclkReset,
pub cs: QspiCsReset,
pub data0: QspiD0Reset,
pub data1: QspiD1Reset,
pub data2: QspiD2Reset,
pub data3: QspiD3Reset,
}
impl QSPIFlash {
pub fn init(self, mclk: &mut pac::Mclk, qspi: pac::Qspi) -> qspi::Qspi<qspi::OneShot> {
qspi::Qspi::new(
mclk, qspi, self.sclk, self.cs, self.data0, self.data1, self.data2, self.data3,
)
}
}
pub struct Buttons {
pub latch: ButtonLatchReset,
pub data_in: ButtonOutReset,
pub clock: ButtonClockReset,
}
impl Buttons {
pub fn init(self) -> ButtonReader {
let mut latch: ButtonLatch = self.latch.into();
latch.set_high().ok();
let mut clock: ButtonClock = self.clock.into();
clock.set_high().ok();
ButtonReader {
latch,
data_in: self.data_in.into(),
clock,
last: 0,
}
}
}
pub struct JoystickReader {
pub joy_x: JoyX,
pub joy_y: JoyY,
}
impl JoystickReader {
pub fn read(&mut self, adc: &mut hal::adc::Adc<hal::adc::Adc1>) -> (u16, u16) {
let y_data: u16 = adc.read(&mut self.joy_y);
let x_data: u16 = adc.read(&mut self.joy_x);
(x_data, y_data)
}
}
pub struct Joystick {
pub joy_x: JoyXReset,
pub joy_y: JoyYReset,
}
impl Joystick {
pub fn init(self) -> JoystickReader {
JoystickReader {
joy_x: self.joy_x.into(),
joy_y: self.joy_y.into(),
}
}
}
pub struct BatteryReader {
pub battery: BatteryPin,
}
impl BatteryReader {
pub fn read(&mut self, adc: &mut hal::adc::Adc<hal::adc::Adc0>) -> f32 {
let data: u16 = adc.read(&mut self.battery);
let result: f32 = (data as f32 / 4095.0) * 2.0 * 3.3;
result
}
}
pub struct Battery {
pub battery: BatteryReset,
}
impl Battery {
pub fn init(self) -> BatteryReader {
BatteryReader {
battery: self.battery.into(),
}
}
}