nucleo_l031k6_bsp/
lib.rs

1//! STM L031K6-Nucleo board support
2//!
3//! This crate provides convenience methods for working with the L031K6-Nucleo development board,
4//! and is intended to serve as a kind of example for how a board support crate might work. Under
5//! the hood, it ties pin function together with peripheral instantiation. Peripherals take as
6//! arguments, and subsequently own, the pins they're attached to. This speeds development
7//! considerably, and reduces a lot of boilerplate setup code.
8//!
9//! You can find a basic working example in [`main.rs`].
10
11#![no_std]
12#![allow(unused_imports)]
13
14pub use stm32l0x1_hal as hal;
15
16use cortex_m::peripheral::syst::SystClkSource;
17use hal::common::Constrain;
18use hal::flash::{self, *};
19use hal::gpio::{self, *};
20use hal::i2c::{self, *};
21use hal::power::{self, *};
22use hal::rcc::clocking::*;
23use hal::rcc::{self, *};
24use hal::serial::{self, *};
25use hal::time::{self, *};
26
27use stm32l0::stm32l0x1;
28use stm32l0::stm32l0x1::*;
29
30/// A configured user LED
31pub type Led = gpio::PB3<Output<PushPull, Floating>>;
32
33/// A representation of connectors CN3 and CN4
34pub struct Pins {
35    // CN3
36    /// D1 - MCO, I2C1_SCL, USART2_TX, TIM22_CH1
37    pub d1: PA9<Analog>,
38    /// D0 - I2C1_SDA, USART2_RX, TIM22_CH2
39    pub d0: PA10<Analog>,
40    /// D2 - SPI1_MOSI, EVENTOUT, USART2_RTS/ USART2_DE, COMP2_OUT
41    pub d2: PA12<Analog>,
42    /// D3 - EVENTOUT, SPI1_MISO, USART2_RTS/ USART2_DE, TIM2_CH3
43    pub d3: PB0<Analog>,
44    /// D4 - USART2_RX, I2C1_SDA, LPTIM1_IN2
45    pub d4: PB7<Analog>,
46    /// D5 - USART2_TX, I2C1_SCL, LPTIM1_ETR, TIM21_CH1
47    pub d5: PB6<Analog>,
48    /// D6 - USART2_CK, SPI1_MOSI, LPUART1_RTS/ LPUART1_DE, TIM2_CH4
49    pub d6: PB1<Analog>,
50    /// D7 - OSC32_IN
51    pub d7: PC14<Analog>,
52    /// D8 - OSC32_OUT
53    pub d8: PC15<Analog>,
54    /// D9 - MCO, LPTIM1_IN1, EVENTOUT, USART2_CK, TIM2_CH1
55    pub d9: PA8<Analog>,
56    /// D10 - MCO, LPTIM1_IN1, EVENTOUT, USART2_CK, TIM2_CH1
57    pub d10: PA11<Analog>,
58    /// D11 - SPI1_MOSI, LPTIM1_IN1, I2C1_SMBA, TIM22_CH2
59    pub d11: PB5<Analog>,
60    /// D12 - SPI1_MISO, EVENTOUT, TIM22_CH1
61    pub d12: PB4<Analog>,
62
63    // CN4
64    /// D13 - SPI1_SCK, TIM2_CH2, EVENTOUT
65    pub d13: PB3<Analog>,
66    /// A0 - LPTIM1_IN1, TIM2_CH1, USART2_CTS, TIM2_ETR, COMP1_OUT
67    pub a0: PA0<Analog>,
68    /// A1 - EVENTOUT, LPTIM1_IN2, TIM2_CH2, I2C1_SMBA, USART2_RTS/ USART2_DE, TIM21_ETR
69    pub a1: PA1<Analog>,
70    /// A2 - TIM21_CH2, TIM2_CH4, USART2_RX, LPUART1_RX
71    pub a2: PA3<Analog>,
72    /// A3 - SPI1_NSS, LPTIM1_IN1, USART2_CK, TIM22_ETR
73    pub a3: PA4<Analog>,
74    /// A4 - SPI1_SCK, LPTIM1_IN2, TIM2_ETR, TIM2_CH1
75    pub a4: PA5<Analog>,
76    /// A5 - SPI1_MISO, LPTIM1_ETR, LPUART1_CTS, TIM22_CH1, EVENTOUT, COMP1_OUT
77    pub a5: PA6<Analog>,
78    /// A6 - SPI1_MOSI, LPTIM1_OUT, USART2_CTS, TIM22_CH2, EVENTOUT, COMP2_OUT
79    pub a6: PA7<Analog>,
80    /// A7 - TIM21_CH1, TIM2_CH3, USART2_TX, LPUART1_TX, COMP2_OUT
81    pub a7: PA2<Analog>,
82}
83
84/// The L031K6-Nucleo
85pub struct Board<VDD, VCORE, RTC> {
86    /// The constrained Power peripheral
87    pub pwr: Power<VDD, VCORE, RTC>,
88    /// The constrained Flash peripheral
89    pub flash: Flash,
90    /// The constrained Rcc peripheral
91    pub rcc: Rcc,
92}
93
94/// Initialize the MCU and the board
95pub fn init<VCORE>(pwr: PWR, flash: FLASH, rcc: RCC) -> Board<VddHigh, VCORE, RtcDis>
96where
97    VCORE: Vos + FreqLimit + Latency,
98{
99    let pwr: Power<VddHigh, VCoreRange2, RtcDis> = pwr.constrain();
100    let mut pwr = pwr.into_vcore_range::<VCORE>();
101    let mut flash = flash.constrain();
102    let mut rcc = rcc.constrain();
103
104    {
105        let cfgr = rcc.cfgr.config().unwrap();
106
107        cfgr.msi.enable();
108        cfgr.msi.set_freq(clocking::MsiFreq::Hz_2_097_000);
109        cfgr.hsi16.enable();
110        cfgr.hclk_fclk = Hertz(2_097_000);
111        cfgr.pclk1 = Hertz(2_097_000);
112        cfgr.pclk2 = Hertz(2_097_000);
113        cfgr.sysclk_src = clocking::SysClkSource::MSI;
114    }
115
116    rcc.freeze(&mut flash, &mut pwr);
117
118    Board { pwr, flash, rcc }
119}
120
121impl<VDD, VCORE, RTC> Board<VDD, VCORE, RTC> {
122    /// Obtain Pins for this board in their post-reset state
123    pub fn pins(&mut self, gpioa: GPIOA, gpiob: GPIOB, gpioc: GPIOC) -> Pins {
124        let gpioa = gpio::A::new(gpioa, &mut self.rcc.iop);
125        let gpiob = gpio::B::new(gpiob, &mut self.rcc.iop);
126        let gpioc = gpio::C::new(gpioc, &mut self.rcc.iop);
127
128        Pins {
129            d1: gpioa.PA9,
130            d0: gpioa.PA10,
131            d2: gpioa.PA12,
132            d3: gpiob.PB0,
133            d4: gpiob.PB7,
134            d5: gpiob.PB6,
135            d6: gpiob.PB1,
136            d7: gpioc.PC14,
137            d8: gpioc.PC15,
138            d9: gpioa.PA8,
139            d10: gpioa.PA11,
140            d11: gpiob.PB5,
141            d12: gpiob.PB4,
142
143            d13: gpiob.PB3,
144            a0: gpioa.PA0,
145            a1: gpioa.PA1,
146            a2: gpioa.PA3,
147            a3: gpioa.PA4,
148            a4: gpioa.PA5,
149            a5: gpioa.PA6,
150            a6: gpioa.PA7,
151            a7: gpioa.PA2,
152        }
153    }
154
155    /// Set the up SysTick exception to be called every `ticks` CPU cycles
156    pub fn systick_start(&mut self, syst: &mut SYST, src: SystClkSource, ticks: u32) {
157        syst.set_clock_source(src);
158        syst.set_reload(ticks);
159        syst.clear_current();
160        syst.enable_counter();
161        syst.enable_interrupt();
162    }
163
164    /// Configure pin D13 to be used to drive the user led LD3
165    pub fn user_led<T>(&mut self, d13: PB3<T>) -> Led {
166        d13.into_output::<PushPull, Floating>()
167    }
168
169    /// Initialize the VCP UART (pass-through the STLink USB) and return Tx and Rx pins
170    pub fn vcp_usart<T>(
171        &mut self,
172        usart: USART2,
173        tx_pin_a7: PA2<T>,
174        clk_src: USARTClkSource,
175    ) -> Serial<USART2, (PA2<AF::AF4>, PA15<AF::AF4>)> {
176        // safe because we moved GPIOB when we created the Pins that gives us the PB3
177        let gpioa = gpio::A::new(
178            unsafe { stm32l0x1::Peripherals::steal() }.GPIOA,
179            &mut self.rcc.iop,
180        );
181        let rx_pin = gpioa.PA15;
182
183        let vcp_tx: PA2<AF::AF4> = tx_pin_a7
184            .into_output::<PushPull, Floating>()
185            .into_alt_fun::<AF::AF4>();
186        vcp_tx.set_pin_speed(PinSpeed::VeryHigh);
187
188        let vcp_rx: PA15<AF::AF4> = rx_pin
189            .into_output::<PushPull, Floating>()
190            .into_alt_fun::<AF::AF4>();
191        vcp_rx.set_pin_speed(PinSpeed::VeryHigh);
192
193        serial::usart2::rs232(
194            usart,
195            (vcp_tx, vcp_rx),
196            Bps(115200),
197            clk_src,
198            self.rcc.cfgr.context().unwrap(),
199            &mut self.rcc.apb1,
200            &mut self.rcc.ccipr,
201        )
202    }
203
204    /// Initialize I2C1 and return the peripheral
205    pub fn i2c1<C, A>(
206        &mut self,
207        i2c1: I2C1,
208        pins: (PB6<C>, PB7<A>),
209    ) -> I2c<I2C1, (PB6<AF::AF1>, PB7<AF::AF1>)> {
210        let i2c_sda = pins
211            .1
212            .into_output::<OpenDrain, PullUp>()
213            .into_alt_fun::<AF::AF1>();
214        i2c_sda.set_pin_speed(PinSpeed::VeryHigh);
215
216        let i2c_scl = pins
217            .0
218            .into_output::<OpenDrain, PullUp>()
219            .into_alt_fun::<AF::AF1>();
220        i2c_scl.set_pin_speed(PinSpeed::VeryHigh);
221
222        i2c::I2c::i2c1(
223            i2c1,
224            (i2c_scl, i2c_sda),
225            //Hertz(100_000),
226            i2c::I2cClkSrc::HSI16,
227            //&clk_ctx,
228            0x00303D5B, // timing
229            &mut self.rcc.apb1,
230            &mut self.rcc.ccipr,
231        )
232    }
233}