stm32_rust_template/mcu/stm32f407/
spi.rs

1// SPI peripheral definitions
2// Generated from STM32F407 SVD file
3
4use super::{PeripheralAccess, SPI1_BASEADDR, SPI2_BASEADDR, SPI3_BASEADDR};
5
6// SPI Register Block
7#[repr(C)]
8pub struct RegisterBlock {
9    pub cr1: u32,     // RW: control register 1
10    pub cr2: u32,     // RW: control register 2
11    pub sr: u32,      // RW: status register
12    pub dr: u32,      // RW: data register
13    pub crcpr: u32,   // RW: CRC polynomial register
14    pub rxcrcr: u32,  // RO: RX CRC register
15    pub txcrcr: u32,  // RO: TX CRC register
16    pub i2scfgr: u32, // RW: I2S configuration register
17    pub i2spr: u32,   // RW: I2S prescaler register
18}
19
20// SPI peripheral instances
21pub struct SPI1;
22pub struct SPI2;
23pub struct SPI3;
24
25impl PeripheralAccess for SPI1 {
26    const BASE_ADDRESS: u32 = SPI1_BASEADDR;
27    type RegisterBlock = RegisterBlock;
28}
29
30impl PeripheralAccess for SPI2 {
31    const BASE_ADDRESS: u32 = SPI2_BASEADDR;
32    type RegisterBlock = RegisterBlock;
33}
34
35impl PeripheralAccess for SPI3 {
36    const BASE_ADDRESS: u32 = SPI3_BASEADDR;
37    type RegisterBlock = RegisterBlock;
38}
39
40// SPI Register Field Definitions
41
42// CR1 register fields
43pub const CR1_BIDIMODE_POS: u32 = 15;
44pub const CR1_BIDIMODE_WIDTH: u32 = 1;
45pub const CR1_BIDIMODE_MASK: u32 = 0x1 << 15;
46// BIDIMODE enumerated values
47pub const CR1_BIDIMODE_UNIDIRECTIONAL: u32 = 0 << 15;
48pub const CR1_BIDIMODE_BIDIRECTIONAL: u32 = 1 << 15;
49
50pub const CR1_BIDIOE_POS: u32 = 14;
51pub const CR1_BIDIOE_WIDTH: u32 = 1;
52pub const CR1_BIDIOE_MASK: u32 = 0x1 << 14;
53// BIDIOE enumerated values
54pub const CR1_BIDIOE_OUTPUTDISABLED: u32 = 0 << 14;
55pub const CR1_BIDIOE_OUTPUTENABLED: u32 = 1 << 14;
56
57pub const CR1_CRCEN_POS: u32 = 13;
58pub const CR1_CRCEN_WIDTH: u32 = 1;
59pub const CR1_CRCEN_MASK: u32 = 0x1 << 13;
60// CRCEN enumerated values
61pub const CR1_CRCEN_DISABLED: u32 = 0 << 13;
62pub const CR1_CRCEN_ENABLED: u32 = 1 << 13;
63
64pub const CR1_CRCNEXT_POS: u32 = 12;
65pub const CR1_CRCNEXT_WIDTH: u32 = 1;
66pub const CR1_CRCNEXT_MASK: u32 = 0x1 << 12;
67// CRCNEXT enumerated values
68pub const CR1_CRCNEXT_TXBUFFER: u32 = 0 << 12;
69pub const CR1_CRCNEXT_CRC: u32 = 1 << 12;
70
71pub const CR1_DFF_POS: u32 = 11;
72pub const CR1_DFF_WIDTH: u32 = 1;
73pub const CR1_DFF_MASK: u32 = 0x1 << 11;
74// DFF enumerated values
75pub const CR1_DFF_EIGHTBIT: u32 = 0 << 11;
76pub const CR1_DFF_SIXTEENBIT: u32 = 1 << 11;
77
78pub const CR1_RXONLY_POS: u32 = 10;
79pub const CR1_RXONLY_WIDTH: u32 = 1;
80pub const CR1_RXONLY_MASK: u32 = 0x1 << 10;
81// RXONLY enumerated values
82pub const CR1_RXONLY_FULLDUPLEX: u32 = 0 << 10;
83pub const CR1_RXONLY_OUTPUTDISABLED: u32 = 1 << 10;
84
85pub const CR1_SSM_POS: u32 = 9;
86pub const CR1_SSM_WIDTH: u32 = 1;
87pub const CR1_SSM_MASK: u32 = 0x1 << 9;
88// SSM enumerated values
89pub const CR1_SSM_DISABLED: u32 = 0 << 9;
90pub const CR1_SSM_ENABLED: u32 = 1 << 9;
91
92pub const CR1_SSI_POS: u32 = 8;
93pub const CR1_SSI_WIDTH: u32 = 1;
94pub const CR1_SSI_MASK: u32 = 0x1 << 8;
95// SSI enumerated values
96pub const CR1_SSI_SLAVESELECTED: u32 = 0 << 8;
97pub const CR1_SSI_SLAVENOTSELECTED: u32 = 1 << 8;
98
99pub const CR1_LSBFIRST_POS: u32 = 7;
100pub const CR1_LSBFIRST_WIDTH: u32 = 1;
101pub const CR1_LSBFIRST_MASK: u32 = 0x1 << 7;
102// LSBFIRST enumerated values
103pub const CR1_LSBFIRST_MSBFIRST: u32 = 0 << 7;
104pub const CR1_LSBFIRST_LSBFIRST: u32 = 1 << 7;
105
106pub const CR1_SPE_POS: u32 = 6;
107pub const CR1_SPE_WIDTH: u32 = 1;
108pub const CR1_SPE_MASK: u32 = 0x1 << 6;
109// SPE enumerated values
110pub const CR1_SPE_DISABLED: u32 = 0 << 6;
111pub const CR1_SPE_ENABLED: u32 = 1 << 6;
112
113pub const CR1_BR_POS: u32 = 3;
114pub const CR1_BR_WIDTH: u32 = 3;
115pub const CR1_BR_MASK: u32 = 0x7 << 3;
116// BR enumerated values
117pub const CR1_BR_DIV2: u32 = 0 << 3;
118pub const CR1_BR_DIV4: u32 = 1 << 3;
119pub const CR1_BR_DIV8: u32 = 2 << 3;
120pub const CR1_BR_DIV16: u32 = 3 << 3;
121pub const CR1_BR_DIV32: u32 = 4 << 3;
122pub const CR1_BR_DIV64: u32 = 5 << 3;
123pub const CR1_BR_DIV128: u32 = 6 << 3;
124pub const CR1_BR_DIV256: u32 = 7 << 3;
125
126pub const CR1_MSTR_POS: u32 = 2;
127pub const CR1_MSTR_WIDTH: u32 = 1;
128pub const CR1_MSTR_MASK: u32 = 0x1 << 2;
129// MSTR enumerated values
130pub const CR1_MSTR_SLAVE: u32 = 0 << 2;
131pub const CR1_MSTR_MASTER: u32 = 1 << 2;
132
133pub const CR1_CPOL_POS: u32 = 1;
134pub const CR1_CPOL_WIDTH: u32 = 1;
135pub const CR1_CPOL_MASK: u32 = 0x1 << 1;
136// CPOL enumerated values
137pub const CR1_CPOL_IDLELOW: u32 = 0 << 1;
138pub const CR1_CPOL_IDLEHIGH: u32 = 1 << 1;
139
140pub const CR1_CPHA_POS: u32 = 0;
141pub const CR1_CPHA_WIDTH: u32 = 1;
142pub const CR1_CPHA_MASK: u32 = 0x1 << 0;
143// CPHA enumerated values
144pub const CR1_CPHA_FIRSTEDGE: u32 = 0 << 0;
145pub const CR1_CPHA_SECONDEDGE: u32 = 1 << 0;
146
147// CR2 register fields
148pub const CR2_TXEIE_POS: u32 = 7;
149pub const CR2_TXEIE_WIDTH: u32 = 1;
150pub const CR2_TXEIE_MASK: u32 = 0x1 << 7;
151// TXEIE enumerated values
152pub const CR2_TXEIE_MASKED: u32 = 0 << 7;
153pub const CR2_TXEIE_NOTMASKED: u32 = 1 << 7;
154
155pub const CR2_RXNEIE_POS: u32 = 6;
156pub const CR2_RXNEIE_WIDTH: u32 = 1;
157pub const CR2_RXNEIE_MASK: u32 = 0x1 << 6;
158// RXNEIE enumerated values
159pub const CR2_RXNEIE_MASKED: u32 = 0 << 6;
160pub const CR2_RXNEIE_NOTMASKED: u32 = 1 << 6;
161
162pub const CR2_ERRIE_POS: u32 = 5;
163pub const CR2_ERRIE_WIDTH: u32 = 1;
164pub const CR2_ERRIE_MASK: u32 = 0x1 << 5;
165// ERRIE enumerated values
166pub const CR2_ERRIE_MASKED: u32 = 0 << 5;
167pub const CR2_ERRIE_NOTMASKED: u32 = 1 << 5;
168
169pub const CR2_FRF_POS: u32 = 4;
170pub const CR2_FRF_WIDTH: u32 = 1;
171pub const CR2_FRF_MASK: u32 = 0x1 << 4;
172// FRF enumerated values
173pub const CR2_FRF_MOTOROLA: u32 = 0 << 4;
174pub const CR2_FRF_TI: u32 = 1 << 4;
175
176pub const CR2_SSOE_POS: u32 = 2;
177pub const CR2_SSOE_WIDTH: u32 = 1;
178pub const CR2_SSOE_MASK: u32 = 0x1 << 2;
179// SSOE enumerated values
180pub const CR2_SSOE_DISABLED: u32 = 0 << 2;
181pub const CR2_SSOE_ENABLED: u32 = 1 << 2;
182
183pub const CR2_TXDMAEN_POS: u32 = 1;
184pub const CR2_TXDMAEN_WIDTH: u32 = 1;
185pub const CR2_TXDMAEN_MASK: u32 = 0x1 << 1;
186// TXDMAEN enumerated values
187pub const CR2_TXDMAEN_DISABLED: u32 = 0 << 1;
188pub const CR2_TXDMAEN_ENABLED: u32 = 1 << 1;
189
190pub const CR2_RXDMAEN_POS: u32 = 0;
191pub const CR2_RXDMAEN_WIDTH: u32 = 1;
192pub const CR2_RXDMAEN_MASK: u32 = 0x1 << 0;
193// RXDMAEN enumerated values
194pub const CR2_RXDMAEN_DISABLED: u32 = 0 << 0;
195pub const CR2_RXDMAEN_ENABLED: u32 = 1 << 0;
196
197// SR register fields
198pub const SR_FRE_POS: u32 = 8;
199pub const SR_FRE_WIDTH: u32 = 1;
200pub const SR_FRE_MASK: u32 = 0x1 << 8;
201// FRE enumerated values
202pub const SR_FRE_NOERROR: u32 = 0 << 8;
203pub const SR_FRE_ERROR: u32 = 1 << 8;
204
205pub const SR_BSY_POS: u32 = 7;
206pub const SR_BSY_WIDTH: u32 = 1;
207pub const SR_BSY_MASK: u32 = 0x1 << 7;
208// BSY enumerated values
209pub const SR_BSY_NOTBUSY: u32 = 0 << 7;
210pub const SR_BSY_BUSY: u32 = 1 << 7;
211
212pub const SR_OVR_POS: u32 = 6;
213pub const SR_OVR_WIDTH: u32 = 1;
214pub const SR_OVR_MASK: u32 = 0x1 << 6;
215// OVR enumerated values
216pub const SR_OVR_NOOVERRUN: u32 = 0 << 6;
217pub const SR_OVR_OVERRUN: u32 = 1 << 6;
218
219pub const SR_MODF_POS: u32 = 5;
220pub const SR_MODF_WIDTH: u32 = 1;
221pub const SR_MODF_MASK: u32 = 0x1 << 5;
222// MODF enumerated values
223pub const SR_MODF_NOFAULT: u32 = 0 << 5;
224pub const SR_MODF_FAULT: u32 = 1 << 5;
225
226pub const SR_CRCERR_POS: u32 = 4;
227pub const SR_CRCERR_WIDTH: u32 = 1;
228pub const SR_CRCERR_MASK: u32 = 0x1 << 4;
229// CRCERR enumerated values
230pub const SR_CRCERR_MATCH: u32 = 0 << 4;
231pub const SR_CRCERR_NOMATCH: u32 = 1 << 4;
232
233pub const SR_UDR_POS: u32 = 3;
234pub const SR_UDR_WIDTH: u32 = 1;
235pub const SR_UDR_MASK: u32 = 0x1 << 3;
236// UDR enumerated values
237pub const SR_UDR_NOUNDERRUN: u32 = 0 << 3;
238pub const SR_UDR_UNDERRUN: u32 = 1 << 3;
239
240pub const SR_CHSIDE_POS: u32 = 2;
241pub const SR_CHSIDE_WIDTH: u32 = 1;
242pub const SR_CHSIDE_MASK: u32 = 0x1 << 2;
243// CHSIDE enumerated values
244pub const SR_CHSIDE_LEFT: u32 = 0 << 2;
245pub const SR_CHSIDE_RIGHT: u32 = 1 << 2;
246
247pub const SR_TXE_POS: u32 = 1;
248pub const SR_TXE_WIDTH: u32 = 1;
249pub const SR_TXE_MASK: u32 = 0x1 << 1;
250// TXE enumerated values
251pub const SR_TXE_NOTEMPTY: u32 = 0 << 1;
252pub const SR_TXE_EMPTY: u32 = 1 << 1;
253
254pub const SR_RXNE_POS: u32 = 0;
255pub const SR_RXNE_WIDTH: u32 = 1;
256pub const SR_RXNE_MASK: u32 = 0x1 << 0;
257// RXNE enumerated values
258pub const SR_RXNE_EMPTY: u32 = 0 << 0;
259pub const SR_RXNE_NOTEMPTY: u32 = 1 << 0;
260
261// DR register fields
262pub const DR_DR_POS: u32 = 0;
263pub const DR_DR_WIDTH: u32 = 16;
264pub const DR_DR_MASK: u32 = 0xFFFF << 0;
265
266// CRCPR register fields
267pub const CRCPR_CRCPOLY_POS: u32 = 0;
268pub const CRCPR_CRCPOLY_WIDTH: u32 = 16;
269pub const CRCPR_CRCPOLY_MASK: u32 = 0xFFFF << 0;
270
271// RXCRCR register fields
272pub const RXCRCR_RXCRC_POS: u32 = 0;
273pub const RXCRCR_RXCRC_WIDTH: u32 = 16;
274pub const RXCRCR_RXCRC_MASK: u32 = 0xFFFF << 0;
275
276// TXCRCR register fields
277pub const TXCRCR_TXCRC_POS: u32 = 0;
278pub const TXCRCR_TXCRC_WIDTH: u32 = 16;
279pub const TXCRCR_TXCRC_MASK: u32 = 0xFFFF << 0;
280
281// I2SCFGR register fields
282pub const I2SCFGR_I2SMOD_POS: u32 = 11;
283pub const I2SCFGR_I2SMOD_WIDTH: u32 = 1;
284pub const I2SCFGR_I2SMOD_MASK: u32 = 0x1 << 11;
285// I2SMOD enumerated values
286pub const I2SCFGR_I2SMOD_SPIMODE: u32 = 0 << 11;
287pub const I2SCFGR_I2SMOD_I2SMODE: u32 = 1 << 11;
288
289pub const I2SCFGR_I2SE_POS: u32 = 10;
290pub const I2SCFGR_I2SE_WIDTH: u32 = 1;
291pub const I2SCFGR_I2SE_MASK: u32 = 0x1 << 10;
292// I2SE enumerated values
293pub const I2SCFGR_I2SE_DISABLED: u32 = 0 << 10;
294pub const I2SCFGR_I2SE_ENABLED: u32 = 1 << 10;
295
296pub const I2SCFGR_I2SCFG_POS: u32 = 8;
297pub const I2SCFGR_I2SCFG_WIDTH: u32 = 2;
298pub const I2SCFGR_I2SCFG_MASK: u32 = 0x3 << 8;
299// I2SCFG enumerated values
300pub const I2SCFGR_I2SCFG_SLAVETX: u32 = 0 << 8;
301pub const I2SCFGR_I2SCFG_SLAVERX: u32 = 1 << 8;
302pub const I2SCFGR_I2SCFG_MASTERTX: u32 = 2 << 8;
303pub const I2SCFGR_I2SCFG_MASTERRX: u32 = 3 << 8;
304
305pub const I2SCFGR_PCMSYNC_POS: u32 = 7;
306pub const I2SCFGR_PCMSYNC_WIDTH: u32 = 1;
307pub const I2SCFGR_PCMSYNC_MASK: u32 = 0x1 << 7;
308// PCMSYNC enumerated values
309pub const I2SCFGR_PCMSYNC_SHORT: u32 = 0 << 7;
310pub const I2SCFGR_PCMSYNC_LONG: u32 = 1 << 7;
311
312pub const I2SCFGR_I2SSTD_POS: u32 = 4;
313pub const I2SCFGR_I2SSTD_WIDTH: u32 = 2;
314pub const I2SCFGR_I2SSTD_MASK: u32 = 0x3 << 4;
315// I2SSTD enumerated values
316pub const I2SCFGR_I2SSTD_PHILIPS: u32 = 0 << 4;
317pub const I2SCFGR_I2SSTD_MSB: u32 = 1 << 4;
318pub const I2SCFGR_I2SSTD_LSB: u32 = 2 << 4;
319pub const I2SCFGR_I2SSTD_PCM: u32 = 3 << 4;
320
321pub const I2SCFGR_CKPOL_POS: u32 = 3;
322pub const I2SCFGR_CKPOL_WIDTH: u32 = 1;
323pub const I2SCFGR_CKPOL_MASK: u32 = 0x1 << 3;
324// CKPOL enumerated values
325pub const I2SCFGR_CKPOL_IDLELOW: u32 = 0 << 3;
326pub const I2SCFGR_CKPOL_IDLEHIGH: u32 = 1 << 3;
327
328pub const I2SCFGR_DATLEN_POS: u32 = 1;
329pub const I2SCFGR_DATLEN_WIDTH: u32 = 2;
330pub const I2SCFGR_DATLEN_MASK: u32 = 0x3 << 1;
331// DATLEN enumerated values
332pub const I2SCFGR_DATLEN_SIXTEENBIT: u32 = 0 << 1;
333pub const I2SCFGR_DATLEN_TWENTYFOURBIT: u32 = 1 << 1;
334pub const I2SCFGR_DATLEN_THIRTYTWOBIT: u32 = 2 << 1;
335
336pub const I2SCFGR_CHLEN_POS: u32 = 0;
337pub const I2SCFGR_CHLEN_WIDTH: u32 = 1;
338pub const I2SCFGR_CHLEN_MASK: u32 = 0x1 << 0;
339// CHLEN enumerated values
340pub const I2SCFGR_CHLEN_SIXTEENBIT: u32 = 0 << 0;
341pub const I2SCFGR_CHLEN_THIRTYTWOBIT: u32 = 1 << 0;
342
343// I2SPR register fields
344pub const I2SPR_MCKOE_POS: u32 = 9;
345pub const I2SPR_MCKOE_WIDTH: u32 = 1;
346pub const I2SPR_MCKOE_MASK: u32 = 0x1 << 9;
347// MCKOE enumerated values
348pub const I2SPR_MCKOE_DISABLED: u32 = 0 << 9;
349pub const I2SPR_MCKOE_ENABLED: u32 = 1 << 9;
350
351pub const I2SPR_ODD_POS: u32 = 8;
352pub const I2SPR_ODD_WIDTH: u32 = 1;
353pub const I2SPR_ODD_MASK: u32 = 0x1 << 8;
354// ODD enumerated values
355pub const I2SPR_ODD_EVEN: u32 = 0 << 8;
356pub const I2SPR_ODD_ODD: u32 = 1 << 8;
357
358pub const I2SPR_I2SDIV_POS: u32 = 0;
359pub const I2SPR_I2SDIV_WIDTH: u32 = 8;
360pub const I2SPR_I2SDIV_MASK: u32 = 0xFF << 0;
361
362// SPI Mode enumeration
363#[derive(Copy, Clone, Debug, PartialEq)]
364pub enum SpiMode {
365    Mode0 = 0, // CPOL=0, CPHA=0
366    Mode1 = 1, // CPOL=0, CPHA=1
367    Mode2 = 2, // CPOL=1, CPHA=0
368    Mode3 = 3, // CPOL=1, CPHA=1
369}
370
371// SPI Baudrate prescaler enumeration
372#[derive(Copy, Clone, Debug, PartialEq)]
373pub enum SpiBaudRate {
374    Div2 = 0,
375    Div4 = 1,
376    Div8 = 2,
377    Div16 = 3,
378    Div32 = 4,
379    Div64 = 5,
380    Div128 = 6,
381    Div256 = 7,
382}
383
384// Helper functions for SPI
385impl RegisterBlock {
386    /// Enable SPI
387    pub fn enable(&mut self) {
388        self.cr1 |= CR1_SPE_MASK;
389    }
390
391    /// Disable SPI
392    pub fn disable(&mut self) {
393        self.cr1 &= !CR1_SPE_MASK;
394    }
395
396    /// Set SPI mode (CPOL/CPHA)
397    pub fn set_mode(&mut self, mode: SpiMode) {
398        self.cr1 =
399            (self.cr1 & !(CR1_CPOL_MASK | CR1_CPHA_MASK)) | (((mode as u32) & 0x3) << CR1_CPHA_POS);
400    }
401
402    /// Set master mode
403    pub fn set_master(&mut self) {
404        self.cr1 |= CR1_MSTR_MASK;
405    }
406
407    /// Set slave mode
408    pub fn set_slave(&mut self) {
409        self.cr1 &= !CR1_MSTR_MASK;
410    }
411
412    /// Set baud rate prescaler
413    pub fn set_baud_rate(&mut self, baudrate: SpiBaudRate) {
414        self.cr1 = (self.cr1 & !CR1_BR_MASK) | ((baudrate as u32) << CR1_BR_POS);
415    }
416
417    /// Check if transmit buffer is empty
418    pub fn is_tx_empty(&self) -> bool {
419        (self.sr & SR_TXE_MASK) != 0
420    }
421
422    /// Check if receive buffer is not empty
423    pub fn is_rx_not_empty(&self) -> bool {
424        (self.sr & SR_RXNE_MASK) != 0
425    }
426
427    /// Check if SPI is busy
428    pub fn is_busy(&self) -> bool {
429        (self.sr & SR_BSY_MASK) != 0
430    }
431
432    /// Write data
433    pub fn write_data(&mut self, data: u16) {
434        self.dr = data as u32;
435    }
436
437    /// Read data
438    pub fn read_data(&self) -> u16 {
439        self.dr as u16
440    }
441
442    /// Transfer a single byte (blocking)
443    pub fn transfer_byte(&mut self, data: u8) -> u8 {
444        // Wait for TXE
445        while !self.is_tx_empty() {}
446
447        // Send data
448        self.write_data(data as u16);
449
450        // Wait for RXNE
451        while !self.is_rx_not_empty() {}
452
453        // Read received data
454        self.read_data() as u8
455    }
456}