stm32_rust_template/driver/spi/
stm32f407.rs

1#[cfg(feature = "stm32f407")]
2extern crate alloc;
3
4use super::{BitOrder, Config, Event, FrameFormat, Mode, Result, SlaveSelectMode, Spi, Status};
5use crate::mcu::stm32f407::{self, spi::*};
6use crate::utils;
7use alloc::boxed::Box;
8use core::ops::FnMut;
9use core::ptr;
10
11/// Default APB bus clock frequencies in Hz.
12/// Update these to match your clock configuration.
13const PCLK1_HZ: u32 = 16_000_000; // APB1 (SPI2/3)
14const PCLK2_HZ: u32 = 16_000_000; // APB2 (SPI1)
15
16/// A polling-based SPI driver for STM32F407.
17pub struct SpiDriver<'a> {
18    regs: *mut RegisterBlock,
19    _callback: Option<Box<dyn FnMut(Event) + 'a>>,
20    config: Config,
21    data_count: u32,
22}
23
24impl<'a> SpiDriver<'a> {
25    pub fn new(spi_base_addr: u32, config: Config) -> Self {
26        Self {
27            regs: spi_base_addr as *mut RegisterBlock,
28            _callback: None,
29            config,
30            data_count: 0,
31        }
32    }
33
34    /// Create a new SPI1 driver instance (APB2 clock)
35    pub fn new_spi1(config: Config) -> Self {
36        Self::new(stm32f407::SPI1_BASEADDR, config)
37    }
38
39    /// Create a new SPI2 driver instance (APB1 clock)
40    pub fn new_spi2(config: Config) -> Self {
41        Self::new(stm32f407::SPI2_BASEADDR, config)
42    }
43
44    /// Create a new SPI3 driver instance (APB1 clock)
45    pub fn new_spi3(config: Config) -> Self {
46        Self::new(stm32f407::SPI3_BASEADDR, config)
47    }
48
49    fn regs(&self) -> &mut RegisterBlock {
50        unsafe { &mut *self.regs }
51    }
52
53    fn is_on_apb2(&self) -> bool {
54        let base = self.regs as u32;
55        base == stm32f407::SPI1_BASEADDR
56    }
57
58    fn get_flag_status(&self, flag_bit: u32) -> bool {
59        let sr = unsafe { ptr::read_volatile(&self.regs().sr) };
60        utils::read_bit(sr, flag_bit)
61    }
62
63    fn wait_txe(&self) {
64        while !self.get_flag_status(SR_TXE_POS) {}
65    }
66
67    fn wait_rxne(&self) {
68        while !self.get_flag_status(SR_RXNE_POS) {}
69    }
70
71    fn wait_not_busy(&self) {
72        while self.get_flag_status(SR_BSY_POS) {}
73    }
74
75    fn clear_ovr_flag(&mut self) {
76        // Read DR and SR to clear OVR flag
77        let _ = unsafe { ptr::read_volatile(&self.regs().dr) };
78        let _ = unsafe { ptr::read_volatile(&self.regs().sr) };
79    }
80
81    fn configure_cr1(&mut self) -> u32 {
82        let mut cr1 = 0;
83
84        // 1. Configure device mode
85        match self.config.mode {
86            Mode::Master => {
87                cr1 = utils::set_bit(cr1, CR1_MSTR_POS, true);
88            }
89            Mode::Slave => {
90                cr1 = utils::set_bit(cr1, CR1_MSTR_POS, false);
91            }
92            Mode::Inactive => {
93                // Keep peripheral disabled
94                return cr1;
95            }
96        }
97
98        // 2. Configure bus configuration (bidirectional mode)
99        match self.config.slave_select_mode {
100            SlaveSelectMode::MasterHwInput => {
101                // Half-duplex mode (BIDIMODE=1, BIDIOE=0)
102                cr1 = utils::set_bit(cr1, CR1_BIDIMODE_POS, true);
103                cr1 = utils::set_bit(cr1, CR1_BIDIOE_POS, false);
104            }
105            SlaveSelectMode::MasterHwOutput => {
106                // Full-duplex mode (BIDIMODE=0)
107                cr1 = utils::set_bit(cr1, CR1_BIDIMODE_POS, false);
108            }
109            SlaveSelectMode::MasterSoftware => {
110                // Full-duplex mode with software SS control
111                cr1 = utils::set_bit(cr1, CR1_BIDIMODE_POS, false);
112                cr1 = utils::set_bit(cr1, CR1_SSM_POS, true);
113                cr1 = utils::set_bit(cr1, CR1_SSI_POS, true);
114            }
115            SlaveSelectMode::MasterUnused => {
116                // Full-duplex mode
117                cr1 = utils::set_bit(cr1, CR1_BIDIMODE_POS, false);
118            }
119            SlaveSelectMode::SlaveHardware => {
120                // Slave mode with hardware SS
121                cr1 = utils::set_bit(cr1, CR1_SSM_POS, false);
122            }
123            SlaveSelectMode::SlaveSoftware => {
124                // Slave mode with software SS
125                cr1 = utils::set_bit(cr1, CR1_SSM_POS, true);
126            }
127        }
128
129        // 3. Configure serial clock speed (baud rate)
130        let pclk = if self.is_on_apb2() {
131            PCLK2_HZ
132        } else {
133            PCLK1_HZ
134        };
135        let br_div = match self.config.bus_speed_hz {
136            speed if speed >= pclk / 2 => CR1_BR_DIV2,
137            speed if speed >= pclk / 4 => CR1_BR_DIV4,
138            speed if speed >= pclk / 8 => CR1_BR_DIV8,
139            speed if speed >= pclk / 16 => CR1_BR_DIV16,
140            speed if speed >= pclk / 32 => CR1_BR_DIV32,
141            speed if speed >= pclk / 64 => CR1_BR_DIV64,
142            speed if speed >= pclk / 128 => CR1_BR_DIV128,
143            _ => CR1_BR_DIV256,
144        };
145        cr1 = utils::set_bits(cr1, br_div, CR1_BR_POS, CR1_BR_WIDTH);
146
147        // 4. Configure data frame format
148        match self.config.data_bits {
149            8 => {
150                cr1 = utils::set_bit(cr1, CR1_DFF_POS, false);
151            }
152            16 => {
153                cr1 = utils::set_bit(cr1, CR1_DFF_POS, true);
154            }
155            _ => {
156                // Unsupported data bits
157                return 0;
158            }
159        }
160
161        // 5. Configure CPOL and CPHA
162        match self.config.frame_format {
163            FrameFormat::CPOL0_CPHA0 => {
164                cr1 = utils::set_bit(cr1, CR1_CPOL_POS, false);
165                cr1 = utils::set_bit(cr1, CR1_CPHA_POS, false);
166            }
167            FrameFormat::CPOL0_CPHA1 => {
168                cr1 = utils::set_bit(cr1, CR1_CPOL_POS, false);
169                cr1 = utils::set_bit(cr1, CR1_CPHA_POS, true);
170            }
171            FrameFormat::CPOL1_CPHA0 => {
172                cr1 = utils::set_bit(cr1, CR1_CPOL_POS, true);
173                cr1 = utils::set_bit(cr1, CR1_CPHA_POS, false);
174            }
175            FrameFormat::CPOL1_CPHA1 => {
176                cr1 = utils::set_bit(cr1, CR1_CPOL_POS, true);
177                cr1 = utils::set_bit(cr1, CR1_CPHA_POS, true);
178            }
179            FrameFormat::TI_SSI => {
180                // TI frame format
181                cr1 = utils::set_bit(cr1, CR1_CPOL_POS, false);
182                cr1 = utils::set_bit(cr1, CR1_CPHA_POS, false);
183            }
184            FrameFormat::Microwire => {
185                // Microwire frame format
186                cr1 = utils::set_bit(cr1, CR1_CPOL_POS, false);
187                cr1 = utils::set_bit(cr1, CR1_CPHA_POS, false);
188            }
189        }
190
191        // 6. Configure bit order
192        match self.config.bit_order {
193            BitOrder::LSB_MSB => {
194                cr1 = utils::set_bit(cr1, CR1_LSBFIRST_POS, true);
195            }
196            BitOrder::MSB_LSB => {
197                cr1 = utils::set_bit(cr1, CR1_LSBFIRST_POS, false);
198            }
199        }
200
201        cr1
202    }
203
204    fn configure_cr2(&mut self) -> u32 {
205        let mut cr2 = 0;
206
207        // Configure SSOE for hardware slave select output
208        if matches!(
209            self.config.slave_select_mode,
210            SlaveSelectMode::MasterHwOutput
211        ) {
212            cr2 = utils::set_bit(cr2, CR2_SSOE_POS, true);
213        }
214
215        // Configure frame format
216        match self.config.frame_format {
217            FrameFormat::TI_SSI => {
218                cr2 = utils::set_bit(cr2, CR2_FRF_POS, true);
219            }
220            _ => {
221                cr2 = utils::set_bit(cr2, CR2_FRF_POS, false);
222            }
223        }
224
225        cr2
226    }
227}
228
229impl<'a> Spi<'a> for SpiDriver<'a> {
230    fn initialize(&mut self, callback: impl FnMut(Event) + 'a) -> Result<()> {
231        self._callback = Some(Box::new(callback));
232
233        // Note: The peripheral clock must be enabled before calling this function.
234
235        // Disable peripheral for configuration
236        let mut cr1 = unsafe { ptr::read_volatile(&self.regs().cr1) };
237        cr1 = utils::set_bit(cr1, CR1_SPE_POS, false);
238        unsafe { ptr::write_volatile(&mut self.regs().cr1, cr1) };
239
240        // Configure CR1 register
241        let cr1_config = self.configure_cr1();
242        if cr1_config == 0 {
243            return Err(-1); // Invalid configuration
244        }
245        unsafe { ptr::write_volatile(&mut self.regs().cr1, cr1_config) };
246
247        // Configure CR2 register
248        let cr2_config = self.configure_cr2();
249        unsafe { ptr::write_volatile(&mut self.regs().cr2, cr2_config) };
250
251        // Enable the peripheral
252        let mut cr1 = unsafe { ptr::read_volatile(&self.regs().cr1) };
253        cr1 = utils::set_bit(cr1, CR1_SPE_POS, true);
254        unsafe { ptr::write_volatile(&mut self.regs().cr1, cr1) };
255
256        Ok(())
257    }
258
259    fn uninitialize(&mut self) -> Result<()> {
260        let mut cr1 = unsafe { ptr::read_volatile(&self.regs().cr1) };
261        cr1 = utils::set_bit(cr1, CR1_SPE_POS, false);
262        unsafe { ptr::write_volatile(&mut self.regs().cr1, cr1) };
263        self._callback = None;
264        Ok(())
265    }
266
267    fn configure(&mut self, config: &Config) -> Result<()> {
268        self.config = config.clone();
269
270        // Re-initialize with new configuration
271        if let Some(callback) = self._callback.take() {
272            self.initialize(callback)?;
273        }
274
275        Ok(())
276    }
277
278    fn send(&mut self, data: &[u8]) -> Result<()> {
279        self.data_count = 0;
280
281        for &byte in data {
282            self.wait_txe();
283            unsafe { ptr::write_volatile(&mut self.regs().dr, byte as u32) };
284            self.data_count += 1;
285        }
286
287        // Wait for transmission to complete
288        self.wait_not_busy();
289
290        if let Some(cb) = &mut self._callback {
291            cb(Event::TRANSFER_COMPLETE);
292        }
293
294        Ok(())
295    }
296
297    fn receive(&mut self, data: &mut [u8]) -> Result<()> {
298        self.data_count = 0;
299
300        // For receive-only mode, we need to send dummy data
301        for b in data.iter_mut() {
302            self.wait_txe();
303            unsafe { ptr::write_volatile(&mut self.regs().dr, 0xFF) }; // Send dummy data
304
305            self.wait_rxne();
306            *b = unsafe { ptr::read_volatile(&self.regs().dr) as u8 };
307            self.data_count += 1;
308        }
309
310        if let Some(cb) = &mut self._callback {
311            cb(Event::TRANSFER_COMPLETE);
312        }
313
314        Ok(())
315    }
316
317    fn transfer(&mut self, data_out: &[u8], data_in: &mut [u8]) -> Result<()> {
318        if data_in.len() != data_out.len() {
319            return Err(-1);
320        }
321
322        self.data_count = 0;
323
324        for (i, &byte) in data_out.iter().enumerate() {
325            self.wait_txe();
326            unsafe { ptr::write_volatile(&mut self.regs().dr, byte as u32) };
327
328            self.wait_rxne();
329            data_in[i] = unsafe { ptr::read_volatile(&self.regs().dr) as u8 };
330            self.data_count += 1;
331        }
332
333        // Wait for transmission to complete
334        self.wait_not_busy();
335
336        if let Some(cb) = &mut self._callback {
337            cb(Event::TRANSFER_COMPLETE);
338        }
339
340        Ok(())
341    }
342
343    fn get_data_count(&self) -> u32 {
344        self.data_count
345    }
346
347    fn get_status(&self) -> Status {
348        let sr = unsafe { ptr::read_volatile(&self.regs().sr) };
349
350        Status {
351            busy: utils::read_bit(sr, SR_BSY_POS),
352            data_lost: utils::read_bit(sr, SR_OVR_POS),
353            mode_fault: utils::read_bit(sr, SR_MODF_POS),
354        }
355    }
356
357    fn control_slave_select(&mut self, active: bool) -> Result<()> {
358        // Only applicable for software slave select mode
359        if matches!(
360            self.config.slave_select_mode,
361            SlaveSelectMode::MasterSoftware
362        ) {
363            let mut cr1 = unsafe { ptr::read_volatile(&self.regs().cr1) };
364            cr1 = utils::set_bit(cr1, CR1_SSI_POS, active);
365            unsafe { ptr::write_volatile(&mut self.regs().cr1, cr1) };
366            Ok(())
367        } else {
368            Err(-2) // Not supported in current mode
369        }
370    }
371}