qt_py_m0/
lib.rs

1#![no_std]
2#![deny(nonstandard_style)]
3#![deny(rust_2018_idioms)]
4
5//! # Adafruit QT Py Board Support Package
6//!
7//! This crate provides a board support package for the Adafruit QT Py board.
8//! This device is a small form-factor breadboard-compatible SAMD21E-based
9//! device with an on-board WS2812 LED ("neopixel"), [STEMMA I2C][stemma]
10//! ([Qwiic][qwiic]-compatible) connector, and USB-C running USB
11//! 2.0 connectivity.
12//!
13//! # Useful External Links
14//! - [Adafruit QT Py Product Page][qtpy]
15//! - [QT Py schematics][schematics]
16//!
17//! [qtpy]: https://learn.adafruit.com/adafruit-qt-py
18//! [stemma]: https://www.adafruit.com/category/1005
19//! [qwiic]: https://www.sparkfun.com/qwiic
20//! [schematics]: https://cdn-learn.adafruit.com/assets/assets/000/095/390/original/adafruit_products_QTPy_sch.png
21
22pub use atsamd_hal as hal;
23pub use hal::pac;
24
25use hal::bsp_pins;
26use hal::clock::GenericClockController;
27use hal::sercom::v2::spi;
28use hal::sercom::v2::uart::{self, BaudMode, Oversampling};
29use hal::sercom::v2::{Sercom0, Sercom2};
30use hal::sercom::I2CMaster1;
31use hal::time::Hertz;
32
33#[cfg(feature = "rt")]
34pub use cortex_m_rt::entry;
35
36#[cfg(feature = "usb")]
37use hal::usb::UsbBus;
38#[cfg(feature = "usb")]
39use usb_device::bus::UsbBusAllocator;
40
41bsp_pins! {
42    // General purpose pins.
43    PA02 {
44        name: a0
45        aliases: {
46            Reset: A0Reset
47        }
48    }
49    PA03 {
50        name: a1
51        aliases: {
52            Reset: A1Reset
53        }
54    }
55    PA04 {
56        name: a2
57        aliases: {
58            Reset: A2Reset
59        }
60    }
61    PA05 {
62        name: a3
63        aliases: {
64            Reset: A3Reset
65        }
66    }
67
68    // UART port pins.
69    PA06 {
70        name: tx
71        aliases: {
72            AlternateD: UartTx,
73            Reset: UartTxReset
74        }
75    },
76    PA07 {
77        name: rx
78        aliases: {
79            AlternateD: UartRx,
80            Reset: UartRxReset
81        }
82    }
83
84    // SPI port pins.
85    PA09 {
86        name: miso
87        aliases: {
88            AlternateD: SpiMiso,
89            Reset: MisoReset
90        }
91    }
92    PA10 {
93        name: mosi
94        aliases: {
95            AlternateD: SpiMosi,
96            Reset: MosiReset
97        }
98    }
99    PA11 {
100        name: sclk
101        aliases: {
102            AlternateD: SpiSck,
103            Reset: SckReset
104        }
105    }
106
107    // I2C port pins.
108    PA16 {
109        name: sda
110        aliases: {
111            AlternateC: I2cSda,
112            Reset: I2cSdaReset
113        }
114    }
115    PA17 {
116        name: scl
117        aliases: {
118            AlternateC: I2cScl,
119            Reset: I2cSclReset
120        }
121    }
122
123    // Neopixel power and data pins.
124    PA15 {
125        name: neopixel_power
126        aliases: {
127            PushPullOutput: NeopixelPower,
128            Reset: NeopixelPowerReset
129        }
130    }
131    PA18 {
132        name: neopixel_data
133        aliases: {
134            PushPullOutput: NeopixelData,
135            Reset: NeopixelDataReset
136        }
137    }
138
139    // USB pins.
140    PA24 {
141        name: usb_dm,
142        aliases: {
143            AlternateG: UsbDm,
144            Reset: UsbDmReset
145        }
146    }
147    PA25 {
148        name: usb_dp,
149        aliases: {
150            AlternateG: UsbDp,
151            Reset: UsbDpReset
152        }
153    }
154
155    // Factory non-populated flash part on flip side of board.
156    PA08 {
157        name: flash_cs
158        aliases: {
159            PushPullOutput: FlashCs,
160            Reset: FlashCsReset
161        }
162    }
163    PA19 {
164        name: flash_miso
165        aliases: {
166            AlternateD: FlashMiso,
167            Reset: FlashMisoReset
168        }
169    }
170    PA22 {
171        name: flash_mosi
172        aliases: {
173            AlternateC: FlashMosi,
174            Reset: FlashMosiReset
175        }
176    }
177    PA23 {
178        name: flash_sclk
179        aliases: {
180            AlternateC: FlashSck,
181            Reset: FlashSckReset
182        }
183    }
184}
185
186impl Pins {
187    /// Splits this `Pins` into categorized sets of pins.
188    pub fn split(self) -> Sets {
189        let analog = Analog {
190            a0: self.a0,
191            a1: self.a1,
192            a2: self.a2,
193            a3: self.a3,
194        };
195        let uart = Uart {
196            tx: self.tx,
197            rx: self.rx,
198        };
199        let spi = Spi {
200            miso: self.miso,
201            mosi: self.mosi,
202            sclk: self.sclk,
203        };
204        let i2c = I2c {
205            sda: self.sda,
206            scl: self.scl,
207        };
208        let neopixel = Neopixel {
209            power: self.neopixel_power,
210            data: self.neopixel_data,
211        };
212        let usb = Usb {
213            dm: self.usb_dm,
214            dp: self.usb_dp,
215        };
216        Sets {
217            analog,
218            uart,
219            spi,
220            i2c,
221            neopixel,
222            usb,
223        }
224    }
225}
226
227/// Pins grouped by category.
228pub struct Sets {
229    /// A0-A3 pins.
230    pub analog: Analog,
231    /// TX/RX pins.
232    pub uart: Uart,
233    /// SPI pins.
234    pub spi: Spi,
235    /// I2C/QWIIC pins.
236    pub i2c: I2c,
237    /// On-board Neopixel pins.
238    pub neopixel: Neopixel,
239    /// USB pins.
240    pub usb: Usb,
241}
242
243/// 'Analog' GPIO pins. Marked A0-A3 on the board. Can also be used as normal
244/// digital GPIO.
245pub struct Analog {
246    /// A0 pin.
247    pub a0: A0Reset,
248    /// A1 pin.
249    pub a1: A1Reset,
250    /// A2 pin.
251    pub a2: A2Reset,
252    /// A3 pin.
253    pub a3: A3Reset,
254}
255
256/// UART mapped to the TX/RX pins on the board.
257pub struct Uart {
258    /// TX pin.
259    pub tx: UartTxReset,
260    /// RX pin.
261    pub rx: UartRxReset,
262}
263
264/// UART pads for the labelled RX & TX pins
265pub type UartPads = uart::Pads<Sercom0, UartRx, UartTx>;
266
267/// UART device for the labelled RX & TX pins
268pub type UartConfig = uart::Uart<uart::Config<UartPads>, uart::Duplex>;
269
270impl Uart {
271    /// Convenience function for creating a UART on the TX/RX pins.
272    pub fn init(
273        self,
274        clocks: &mut GenericClockController,
275        freq: impl Into<Hertz>,
276        sercom0: pac::SERCOM0,
277        pm: &mut pac::PM,
278    ) -> UartConfig {
279        let gclk0 = clocks.gclk0();
280        let clock = &clocks.sercom0_core(&gclk0).unwrap();
281        let rx: UartRx = self.rx.into();
282        let tx: UartTx = self.tx.into();
283        let pads = uart::Pads::default().rx(rx).tx(tx);
284        uart::Config::new(pm, sercom0, pads, clock.freq())
285            .baud(freq.into(), BaudMode::Fractional(Oversampling::Bits16))
286            .enable()
287    }
288}
289
290/// SPI pins.
291pub struct Spi {
292    /// SPI MISO pin.
293    pub miso: MisoReset,
294    /// SPI MOSI pin.
295    pub mosi: MosiReset,
296    /// SPI SCK pin.
297    pub sclk: SckReset,
298}
299
300type SpiPads = spi::Pads<Sercom2, SpiMiso, SpiMosi, SpiSck>;
301
302/// The SPI type for the labeled SPI bus.
303pub type SpiConfig = spi::Spi<spi::Config<SpiPads>, spi::Duplex>;
304
305impl Spi {
306    /// Convenience function for creating a mode 0 SPI interface on the SPI
307    /// pins.
308    pub fn init(
309        self,
310        clocks: &mut GenericClockController,
311        baud: impl Into<Hertz>,
312        sercom2: pac::SERCOM2,
313        pm: &mut pac::PM,
314    ) -> SpiConfig {
315        let gclk0 = clocks.gclk0();
316        let clock = clocks.sercom2_core(&gclk0).unwrap();
317        let pads = spi::Pads::default()
318            .data_in(self.miso)
319            .data_out(self.mosi)
320            .sclk(self.sclk);
321        spi::Config::new(pm, sercom2, pads, clock.freq())
322            .spi_mode(spi::MODE_0)
323            .baud(baud)
324            .enable()
325    }
326}
327
328/// I2C pins.
329pub struct I2c {
330    /// I2C SDA pin.
331    pub sda: I2cSdaReset,
332    /// I2C SCL pin.
333    pub scl: I2cSclReset,
334}
335
336impl I2c {
337    /// Convenience function for creating an I2C host on the I2C pins.
338    pub fn init(
339        self,
340        clocks: &mut GenericClockController,
341        freq: impl Into<Hertz>,
342        sercom1: pac::SERCOM1,
343        pm: &mut pac::PM,
344    ) -> I2CMaster1<I2cSda, I2cScl> {
345        let gclk0 = clocks.gclk0();
346        let clock = &clocks.sercom1_core(&gclk0).unwrap();
347        I2CMaster1::new(
348            clock,
349            freq.into(),
350            sercom1,
351            pm,
352            self.sda.into(),
353            self.scl.into(),
354        )
355    }
356}
357
358/// Neopixel pins.
359pub struct Neopixel {
360    /// Neopixel power pin. Must be driven high to provide power to the on-board
361    /// neopixel.
362    pub power: NeopixelPowerReset,
363    /// Neopixel data pin.
364    pub data: NeopixelDataReset,
365}
366
367/// USB pins. These are connected to the on-board USB-C connector.
368pub struct Usb {
369    /// USB DM pin.
370    pub dm: UsbDmReset,
371    /// USB DP pin.
372    pub dp: UsbDpReset,
373}
374
375impl Usb {
376    /// Convenience function for creating a USB device attached to the USB pins.
377    #[cfg(feature = "usb")]
378    pub fn init(
379        self,
380        usb: pac::USB,
381        clocks: &mut GenericClockController,
382        pm: &mut pac::PM,
383    ) -> UsbBusAllocator<UsbBus> {
384        let gclk0 = clocks.gclk0();
385        let usb_clock = &clocks.usb(&gclk0).unwrap();
386        let (dm, dp): (UsbDm, UsbDp) = (self.dm.into(), self.dp.into());
387        UsbBusAllocator::new(UsbBus::new(usb_clock, pm, dm, dp, usb))
388    }
389}