@@ -20,15 +20,42 @@ type SPIConfig struct {
2020}
2121
2222// Configure is intended to setup the STM32 SPI1 interface.
23- // Features still TODO:
24- // - support SPI2 and SPI3
25- // - allow setting data size to 16 bits?
26- // - allow setting direction in HW for additional optimization?
27- // - hardware SS pin?
2823func (spi SPI ) Configure (config SPIConfig ) {
24+
25+ // -- CONFIGURING THE SPI IN MASTER MODE --
26+ //
27+ // 1. Select the BR[2:0] bits to define the serial clock baud rate (see
28+ // SPI_CR1 register).
29+ // 2. Select the CPOL and CPHA bits to define one of the four relationships
30+ // between the data transfer and the serial clock (see Figure 248). This
31+ // step is not required when the TI mode is selected.
32+ // 3. Set the DFF bit to define 8- or 16-bit data frame format
33+ // 4. Configure the LSBFIRST bit in the SPI_CR1 register to define the frame
34+ // format. This step is not required when the TI mode is selected.
35+ // 5. If the NSS pin is required in input mode, in hardware mode, connect the
36+ // NSS pin to a high-level signal during the complete byte transmit
37+ // sequence. In NSS software mode, set the SSM and SSI bits in the SPI_CR1
38+ // register. If the NSS pin is required in output mode, the SSOE bit only
39+ // should be set. This step is not required when the TI mode is selected.
40+ // 6. Set the FRF bit in SPI_CR2 to select the TI protocol for serial
41+ // communications.
42+ // 7. The MSTR and SPE bits must be set (they remain set only if the NSS pin
43+ // is connected to a high-level signal).
44+
45+ // disable SPI interface before any configuration changes
46+ spi .Bus .CR1 .ClearBits (stm32 .SPI_CR1_SPE )
47+
2948 // enable clock for SPI
3049 enableAltFuncClock (unsafe .Pointer (spi .Bus ))
3150
51+ // init pins
52+ if config .SCK == 0 && config .SDO == 0 && config .SDI == 0 {
53+ config .SCK = SPI0_SCK_PIN
54+ config .SDO = SPI0_SDO_PIN
55+ config .SDI = SPI0_SDI_PIN
56+ }
57+ spi .configurePins (config )
58+
3259 // Get SPI baud rate based on the bus speed it's attached to
3360 var conf uint32 = spi .getBaudRate (config )
3461
@@ -39,61 +66,72 @@ func (spi SPI) Configure(config SPIConfig) {
3966
4067 // set polarity and phase on the SPI interface
4168 switch config .Mode {
42- case Mode0 :
43- conf &^= (1 << stm32 .SPI_CR1_CPOL_Pos )
44- conf &^= (1 << stm32 .SPI_CR1_CPHA_Pos )
4569 case Mode1 :
46- conf &^= (1 << stm32 .SPI_CR1_CPOL_Pos )
47- conf |= (1 << stm32 .SPI_CR1_CPHA_Pos )
70+ conf |= stm32 .SPI_CR1_CPHA
4871 case Mode2 :
49- conf |= (1 << stm32 .SPI_CR1_CPOL_Pos )
50- conf &^= (1 << stm32 .SPI_CR1_CPHA_Pos )
72+ conf |= stm32 .SPI_CR1_CPOL
5173 case Mode3 :
52- conf |= (1 << stm32 .SPI_CR1_CPOL_Pos )
53- conf |= (1 << stm32 .SPI_CR1_CPHA_Pos )
54- default : // to mode 0
55- conf &^= (1 << stm32 .SPI_CR1_CPOL_Pos )
56- conf &^= (1 << stm32 .SPI_CR1_CPHA_Pos )
74+ conf |= stm32 .SPI_CR1_CPOL
75+ conf |= stm32 .SPI_CR1_CPHA
5776 }
5877
59- // set to SPI controller
60- conf |= stm32 .SPI_CR1_MSTR
78+ // configure as SPI master
79+ conf |= stm32 .SPI_CR1_MSTR | stm32 .SPI_CR1_SSI
80+
81+ // enable the SPI interface
82+ conf |= stm32 .SPI_CR1_SPE
6183
62- // disable MCU acting as SPI peripheral
63- conf |= stm32 .SPI_CR1_SSM | stm32 . SPI_CR1_SSI
84+ // use software CS (GPIO) by default
85+ conf |= stm32 .SPI_CR1_SSM
6486
6587 // now set the configuration
6688 spi .Bus .CR1 .Set (conf )
67-
68- // init pins
69- if config .SCK == 0 && config .SDO == 0 && config .SDI == 0 {
70- config .SCK = SPI0_SCK_PIN
71- config .SDO = SPI0_SDO_PIN
72- config .SDI = SPI0_SDI_PIN
73- }
74- spi .configurePins (config )
75-
76- // enable SPI interface
77- spi .Bus .CR1 .SetBits (stm32 .SPI_CR1_SPE )
89+ spi .Bus .CR2 .SetBits ((conf & stm32 .SPI_CR1_SSM_Msk ) >> 16 )
7890}
7991
8092// Transfer writes/reads a single byte using the SPI interface.
8193func (spi SPI ) Transfer (w byte ) (byte , error ) {
82- // Write data to be transmitted to the SPI data register
94+
95+ // 1. Enable the SPI by setting the SPE bit to 1.
96+ // 2. Write the first data item to be transmitted into the SPI_DR register
97+ // (this clears the TXE flag).
98+ // 3. Wait until TXE=1 and write the second data item to be transmitted. Then
99+ // wait until RXNE=1 and read the SPI_DR to get the first received data
100+ // item (this clears the RXNE bit). Repeat this operation for each data
101+ // item to be transmitted/received until the n–1 received data.
102+ // 4. Wait until RXNE=1 and read the last received data.
103+ // 5. Wait until TXE=1 and then wait until BSY=0 before disabling the SPI.
104+
105+ // put output word (8-bit) in data register (DR), which is parallel-loaded
106+ // into shift register, and shifted out on MOSI.
83107 spi .Bus .DR .Set (uint32 (w ))
84108
85- // Wait until transmit complete
86- for ! spi .Bus .SR .HasBits (stm32 .SPI_SR_TXE ) {
109+ // wait for SPI bus receive buffer not empty bit (RXNE) to be set.
110+ // warning: blocks forever until this condition is met.
111+ for ! spi .Bus .SR .HasBits (stm32 .SPI_SR_RXNE ) {
87112 }
88113
89- // Wait until receive complete
90- for ! spi .Bus .SR .HasBits (stm32 .SPI_SR_RXNE ) {
114+ // copy input word (8-bit) in data register (DR), which was shifted in on MISO
115+ // and parallel-loaded into register.
116+ data := byte (spi .Bus .DR .Get ())
117+
118+ // wait for SPI bus transmit buffer empty bit (TXE) to be set.
119+ // warning: blocks forever until this condition is met.
120+ for ! spi .Bus .SR .HasBits (stm32 .SPI_SR_TXE ) {
91121 }
92122
93- // Wait until SPI is not busy
123+ // wait for SPI bus busy bit (BSY) to be clear to indicate synchronous
124+ // transfer complete. this will effectively prevent this Transfer() function
125+ // from being capable of maintaining high-bandwidth communication throughput,
126+ // but it will help guarantee stability on the bus.
94127 for spi .Bus .SR .HasBits (stm32 .SPI_SR_BSY ) {
95128 }
96129
130+ // clear the overrun flag (only in full-duplex mode)
131+ if ! spi .Bus .CR1 .HasBits (stm32 .SPI_CR1_RXONLY | stm32 .SPI_CR1_BIDIMODE | stm32 .SPI_CR1_BIDIOE ) {
132+ spi .Bus .SR .Get ()
133+ }
134+
97135 // Return received data from SPI data register
98- return byte ( spi . Bus . DR . Get ()) , nil
136+ return data , nil
99137}
0 commit comments