Skip to main content

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