From 7fc5095b6b768a6e441752223724b27adaf2f014 Mon Sep 17 00:00:00 2001 From: ardnew Date: Tue, 1 Sep 2020 21:47:50 -0500 Subject: [PATCH 1/7] reordered SPI initialization and transfer operations for stm32 --- src/machine/machine_stm32_spi.go | 135 ++++++++++++++++++++++++++----- 1 file changed, 113 insertions(+), 22 deletions(-) diff --git a/src/machine/machine_stm32_spi.go b/src/machine/machine_stm32_spi.go index 2e14a46184..f90f96da5a 100644 --- a/src/machine/machine_stm32_spi.go +++ b/src/machine/machine_stm32_spi.go @@ -19,6 +19,37 @@ type SPIConfig struct { Mode uint8 } +// const ( +// modeSlave = 0 +// modeMaster = stm32.SPI_CR1_MSTR | stm32.SPI_CR1_SSI +// +// direction2Lines = 0 +// direction2LinesRx = stm32.SPI_CR1_RXONLY +// direction1Line = stm32.SPI_CR1_BIDIMODE +// +// dataSize8Bit = 0 +// dataSize16Bit = stm32.SPI_CR1_DFF +// +// clkPolarityLow = 0 +// clkPolarityHigh = stm32.SPI_CR1_CPOL +// +// clkPhase1Edge = 0 +// clkPhase2Edge = stm32.SPI_CR1_CPHA +// +// slaveSelectSoft = stm32.SPI_CR1_SSM +// slaveSelectHardInput = 0 +// slaveSelectHardOutput = stm32.SPI_CR2_SSOE << 16 +// +// firstBitMSB = 0 +// firstBitLSB = stm32.SPI_CR1_LSBFIRST +// +// tiModeDisable = 0 +// tiModeEnable = stm32.SPI_CR2_FRF +// +// crcDisable = 0 +// crcEnable = stm32.SPI_CR1_CRCEN +// ) + // Configure is intended to setup the STM32 SPI1 interface. // Features still TODO: // - support SPI2 and SPI3 @@ -26,9 +57,41 @@ type SPIConfig struct { // - allow setting direction in HW for additional optimization? // - hardware SS pin? func (spi SPI) Configure(config SPIConfig) { + + // -- CONFIGURING THE SPI IN MASTER MODE -- + // + // 1. Select the BR[2:0] bits to define the serial clock baud rate (see + // SPI_CR1 register). + // 2. Select the CPOL and CPHA bits to define one of the four relationships + // between the data transfer and the serial clock (see Figure 248). This + // step is not required when the TI mode is selected. + // 3. Set the DFF bit to define 8- or 16-bit data frame format + // 4. Configure the LSBFIRST bit in the SPI_CR1 register to define the frame + // format. This step is not required when the TI mode is selected. + // 5. If the NSS pin is required in input mode, in hardware mode, connect the + // NSS pin to a high-level signal during the complete byte transmit + // sequence. In NSS software mode, set the SSM and SSI bits in the SPI_CR1 + // register. If the NSS pin is required in output mode, the SSOE bit only + // should be set. This step is not required when the TI mode is selected. + // 6. Set the FRF bit in SPI_CR2 to select the TI protocol for serial + // communications. + // 7. The MSTR and SPE bits must be set (they remain set only if the NSS pin + // is connected to a high-level signal). + + // disable SPI interface before any configuration changes + spi.Bus.CR1.ClearBits(stm32.SPI_CR1_SPE) + // enable clock for SPI enableAltFuncClock(unsafe.Pointer(spi.Bus)) + // init pins + if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 { + config.SCK = SPI0_SCK_PIN + config.SDO = SPI0_SDO_PIN + config.SDI = SPI0_SDI_PIN + } + spi.configurePins(config) + // Get SPI baud rate based on the bus speed it's attached to var conf uint32 = spi.getBaudRate(config) @@ -56,44 +119,72 @@ func (spi SPI) Configure(config SPIConfig) { conf &^= (1 << stm32.SPI_CR1_CPHA_Pos) } - // set to SPI controller - conf |= stm32.SPI_CR1_MSTR + // configure as SPI master + conf |= stm32.SPI_CR1_MSTR | stm32.SPI_CR1_SSI + + // use software-controlled GPIO for slave select + conf |= stm32.SPI_CR1_SSM - // disable MCU acting as SPI peripheral - conf |= stm32.SPI_CR1_SSM | stm32.SPI_CR1_SSI + // enable the SPI interface + conf |= stm32.SPI_CR1_SPE // now set the configuration spi.Bus.CR1.Set(conf) - - // init pins - if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 { - config.SCK = SPI0_SCK_PIN - config.SDO = SPI0_SDO_PIN - config.SDI = SPI0_SDI_PIN - } - spi.configurePins(config) - - // enable SPI interface - spi.Bus.CR1.SetBits(stm32.SPI_CR1_SPE) } // Transfer writes/reads a single byte using the SPI interface. func (spi SPI) Transfer(w byte) (byte, error) { - // Write data to be transmitted to the SPI data register - spi.Bus.DR.Set(uint32(w)) - // Wait until transmit complete - for !spi.Bus.SR.HasBits(stm32.SPI_SR_TXE) { + // 1. Enable the SPI by setting the SPE bit to 1. + // 2. Write the first data item to be transmitted into the SPI_DR register + // (this clears the TXE flag). + // 3. Wait until TXE=1 and write the second data item to be transmitted. Then + // wait until RXNE=1 and read the SPI_DR to get the first received data + // item (this clears the RXNE bit). Repeat this operation for each data + // item to be transmitted/received until the n–1 received data. + // 4. Wait until RXNE=1 and read the last received data. + // 5. Wait until TXE=1 and then wait until BSY=0 before disabling the SPI. + + // lazy enabling of SPI interface, in case it has been disabled due to error + // or intent. + if !spi.Bus.CR1.HasBits(stm32.SPI_CR1_SPE) { + spi.Bus.CR1.SetBits(stm32.SPI_CR1_SPE) } - // Wait until receive complete + // put output word (8-bit) in data register (DR), which is parallel-loaded + // into shift register, and shifted out on MOSI. + spi.Bus.DR.Set(uint32(w)) + + // wait for SPI bus receive buffer not empty bit (RXNE) to be set. + // warning: blocks forever until this condition is met. for !spi.Bus.SR.HasBits(stm32.SPI_SR_RXNE) { } - // Wait until SPI is not busy + // copy input word (8-bit) in data register (DR), which was shifted in on MISO + // and parallel-loaded into register. + data := byte(spi.Bus.DR.Get()) + + // wait for SPI bus transmit buffer empty bit (TXE) to be set. + // warning: blocks forever until this condition is met. + for !spi.Bus.SR.HasBits(stm32.SPI_SR_TXE) { + } + + // wait for SPI bus busy bit (BSY) to be clear to indicate synchronous + // transfer complete. this will effectively prevent this Transfer() function + // from being capable of maintaining high-bandwidth communication throughput, + // but it will help guarantee stability on the bus. for spi.Bus.SR.HasBits(stm32.SPI_SR_BSY) { } + // clear the overrun flag. + // note: this assumes 2-lines directionality (the default and only supported + // direction at the moment). + // otherwise, it is not appropriate to clear this flag. + _ = spi.Bus.SR.Get() + + // disable the SPI interface + spi.Bus.CR1.ClearBits(stm32.SPI_CR1_SPE) + // Return received data from SPI data register - return byte(spi.Bus.DR.Get()), nil + return data, nil } From a10c08e872a4bb1f5a1c15b0b35348d8b1b84f5f Mon Sep 17 00:00:00 2001 From: ardnew Date: Thu, 3 Sep 2020 22:50:20 -0500 Subject: [PATCH 2/7] fix SPI baudrate calculation --- src/machine/machine_stm32f405.go | 42 ++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_stm32f405.go b/src/machine/machine_stm32f405.go index e59941716c..aa94361a78 100644 --- a/src/machine/machine_stm32f405.go +++ b/src/machine/machine_stm32f405.go @@ -6,6 +6,7 @@ package machine import ( "device/stm32" + "math/bits" "runtime/interrupt" ) @@ -46,8 +47,45 @@ type SPI struct { AltFuncSelector stm32.AltFunc } -func (spi SPI) configurePins(config SPIConfig) {} -func (spi SPI) getBaudRate(config SPIConfig) uint32 { return 0 } +func (spi SPI) configurePins(config SPIConfig) { + config.SCK.ConfigureAltFunc(PinConfig{Mode: PinModeSPICLK}, spi.AltFuncSelector) + config.SDO.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDO}, spi.AltFuncSelector) + config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector) +} + +func (spi SPI) getBaudRate(config SPIConfig) uint32 { + var clock uint32 + switch spi.Bus { + case stm32.SPI1: + clock = CPUFrequency() / 2 + case stm32.SPI2, stm32.SPI3: + clock = CPUFrequency() / 4 + } + + // limit requested frequency to bus frequency + freq := config.Frequency + if freq > clock { + freq = clock + } + + // calculate the exact clock divisor (freq=clock/div -> div=clock/freq). + // truncation is fine, since it produces a less-than-or-equal divisor, and + // thus a greater-than-or-equal frequency. + // divisors only come in consecutive powers of 2, so we can use log2 (or, + // equivalently, bits.Len - 1) to convert to respective enum value. + div := bits.Len32(clock/freq) - 1 + + // but DIV1 (2^0) is not permitted, as the least divisor is DIV2 (2^1), so + // subtract 1 from the log2 value, keeping a lower bound of 0 + if div < 0 { + div = 0 + } else if div > 0 { + div-- + } + + // finally, shift the enumerated value into position for SPI CR1 + return uint32(div) << stm32.SPI_CR1_BR_Pos +} // -- I2C ---------------------------------------------------------------------- From 1076b32ff51ac87bb5882570a7c1e2797ad8da65 Mon Sep 17 00:00:00 2001 From: ardnew Date: Fri, 4 Sep 2020 16:43:48 -0500 Subject: [PATCH 3/7] add SPI config options for CS mode selection (hw/sw), data size (8/16-bit), and direction (duplex/simplex) --- src/machine/board_feather-stm32f405.go | 16 +++++ src/machine/machine_stm32_spi.go | 94 +++++++++++++++++++++----- 2 files changed, 92 insertions(+), 18 deletions(-) diff --git a/src/machine/board_feather-stm32f405.go b/src/machine/board_feather-stm32f405.go index 14c7d063f9..3566591f90 100644 --- a/src/machine/board_feather-stm32f405.go +++ b/src/machine/board_feather-stm32f405.go @@ -178,6 +178,22 @@ const ( SPI_SDO_PIN = SPI0_SDO_PIN // ) +var ( + SPI1 = SPI{ + Bus: stm32.SPI2, + AltFuncSelector: stm32.AF5_SPI1_SPI2, + } + SPI2 = SPI{ + Bus: stm32.SPI3, + AltFuncSelector: stm32.AF6_SPI3, + } + SPI3 = SPI{ + Bus: stm32.SPI1, + AltFuncSelector: stm32.AF5_SPI1_SPI2, + } + SPI0 = SPI1 +) + func initSPI() {} // -- I2C ---------------------------------------------------------------------- diff --git a/src/machine/machine_stm32_spi.go b/src/machine/machine_stm32_spi.go index f90f96da5a..6bf911bcfa 100644 --- a/src/machine/machine_stm32_spi.go +++ b/src/machine/machine_stm32_spi.go @@ -9,6 +9,28 @@ import ( "unsafe" ) +// SPI directionality +const ( + DirFullDuplex = 0 + DirSimplexRx = 1 + DirHalfDuplexRx = 2 + DirHalfDuplexTx = 3 +) + +// SPI data frame format/size +const ( + DataWidth8Bit = 0 + DataWidth16Bit = 1 +) + +// SPI chip/slave select mode. Use any GPIO pin in software mode, otherwise use +// one of the pins with NSS alternate function in hardware mode. +const ( + CSSoft = 0 + CSHardIn = 1 + CSHardOut = 2 +) + // SPIConfig is used to store config info for SPI. type SPIConfig struct { Frequency uint32 @@ -17,6 +39,9 @@ type SPIConfig struct { SDI Pin LSBFirst bool Mode uint8 + Direction uint8 + DataSize uint8 + CSMode uint8 } // const ( @@ -51,11 +76,6 @@ type SPIConfig struct { // ) // Configure is intended to setup the STM32 SPI1 interface. -// Features still TODO: -// - support SPI2 and SPI3 -// - allow setting data size to 16 bits? -// - allow setting direction in HW for additional optimization? -// - hardware SS pin? func (spi SPI) Configure(config SPIConfig) { // -- CONFIGURING THE SPI IN MASTER MODE -- @@ -98,38 +118,76 @@ func (spi SPI) Configure(config SPIConfig) { // set bit transfer order if config.LSBFirst { conf |= stm32.SPI_CR1_LSBFIRST + } else { + conf &^= stm32.SPI_CR1_LSBFIRST } // set polarity and phase on the SPI interface switch config.Mode { case Mode0: - conf &^= (1 << stm32.SPI_CR1_CPOL_Pos) - conf &^= (1 << stm32.SPI_CR1_CPHA_Pos) + conf &^= stm32.SPI_CR1_CPOL + conf &^= stm32.SPI_CR1_CPHA case Mode1: - conf &^= (1 << stm32.SPI_CR1_CPOL_Pos) - conf |= (1 << stm32.SPI_CR1_CPHA_Pos) + conf &^= stm32.SPI_CR1_CPOL + conf |= stm32.SPI_CR1_CPHA case Mode2: - conf |= (1 << stm32.SPI_CR1_CPOL_Pos) - conf &^= (1 << stm32.SPI_CR1_CPHA_Pos) + conf |= stm32.SPI_CR1_CPOL + conf &^= stm32.SPI_CR1_CPHA case Mode3: - conf |= (1 << stm32.SPI_CR1_CPOL_Pos) - conf |= (1 << stm32.SPI_CR1_CPHA_Pos) + conf |= stm32.SPI_CR1_CPOL + conf |= stm32.SPI_CR1_CPHA default: // to mode 0 - conf &^= (1 << stm32.SPI_CR1_CPOL_Pos) - conf &^= (1 << stm32.SPI_CR1_CPHA_Pos) + conf &^= stm32.SPI_CR1_CPOL + conf &^= stm32.SPI_CR1_CPHA + } + + // configure the direction of SPI data + switch config.Direction { + case DirFullDuplex: + conf &^= (stm32.SPI_CR1_RXONLY | stm32.SPI_CR1_BIDIMODE | stm32.SPI_CR1_BIDIOE) + case DirSimplexRx: + conf &^= (stm32.SPI_CR1_BIDIMODE | stm32.SPI_CR1_BIDIOE) + conf |= stm32.SPI_CR1_RXONLY + case DirHalfDuplexRx: + conf &^= (stm32.SPI_CR1_RXONLY | stm32.SPI_CR1_BIDIOE) + conf |= stm32.SPI_CR1_BIDIMODE + case DirHalfDuplexTx: + conf &^= stm32.SPI_CR1_RXONLY + conf |= (stm32.SPI_CR1_BIDIMODE | stm32.SPI_CR1_BIDIOE) + } + + // set data frame format/size + switch config.DataSize { + case DataWidth8Bit: + conf &^= stm32.SPI_CR1_DFF + case DataWidth16Bit: + conf |= stm32.SPI_CR1_DFF + } + + // configure chip select mode: hardware vs software + var nss uint32 + switch config.CSMode { + case CSSoft: + conf &^= (stm32.SPI_CR2_SSOE << 16) + nss |= stm32.SPI_CR1_SSM + conf |= nss + case CSHardIn: + conf &^= stm32.SPI_CR1_SSM | (stm32.SPI_CR2_SSOE << 16) + case CSHardOut: + conf &^= stm32.SPI_CR1_SSM + nss |= (stm32.SPI_CR2_SSOE << 16) + conf |= nss } // configure as SPI master conf |= stm32.SPI_CR1_MSTR | stm32.SPI_CR1_SSI - // use software-controlled GPIO for slave select - conf |= stm32.SPI_CR1_SSM - // enable the SPI interface conf |= stm32.SPI_CR1_SPE // now set the configuration spi.Bus.CR1.Set(conf) + spi.Bus.CR2.SetBits(nss >> 16) } // Transfer writes/reads a single byte using the SPI interface. From e6d7ba834e69d2cc2ccac8c47331d5bc5908d8be Mon Sep 17 00:00:00 2001 From: ardnew Date: Sat, 12 Sep 2020 19:30:02 -0500 Subject: [PATCH 4/7] clear overrun only in full duplex mode --- src/machine/machine_stm32_spi.go | 40 ++++---------------------------- 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/src/machine/machine_stm32_spi.go b/src/machine/machine_stm32_spi.go index 6bf911bcfa..bc9de44699 100644 --- a/src/machine/machine_stm32_spi.go +++ b/src/machine/machine_stm32_spi.go @@ -44,37 +44,6 @@ type SPIConfig struct { CSMode uint8 } -// const ( -// modeSlave = 0 -// modeMaster = stm32.SPI_CR1_MSTR | stm32.SPI_CR1_SSI -// -// direction2Lines = 0 -// direction2LinesRx = stm32.SPI_CR1_RXONLY -// direction1Line = stm32.SPI_CR1_BIDIMODE -// -// dataSize8Bit = 0 -// dataSize16Bit = stm32.SPI_CR1_DFF -// -// clkPolarityLow = 0 -// clkPolarityHigh = stm32.SPI_CR1_CPOL -// -// clkPhase1Edge = 0 -// clkPhase2Edge = stm32.SPI_CR1_CPHA -// -// slaveSelectSoft = stm32.SPI_CR1_SSM -// slaveSelectHardInput = 0 -// slaveSelectHardOutput = stm32.SPI_CR2_SSOE << 16 -// -// firstBitMSB = 0 -// firstBitLSB = stm32.SPI_CR1_LSBFIRST -// -// tiModeDisable = 0 -// tiModeEnable = stm32.SPI_CR2_FRF -// -// crcDisable = 0 -// crcEnable = stm32.SPI_CR1_CRCEN -// ) - // Configure is intended to setup the STM32 SPI1 interface. func (spi SPI) Configure(config SPIConfig) { @@ -234,11 +203,10 @@ func (spi SPI) Transfer(w byte) (byte, error) { for spi.Bus.SR.HasBits(stm32.SPI_SR_BSY) { } - // clear the overrun flag. - // note: this assumes 2-lines directionality (the default and only supported - // direction at the moment). - // otherwise, it is not appropriate to clear this flag. - _ = spi.Bus.SR.Get() + // clear the overrun flag (only in full-duplex mode) + if !spi.Bus.CR1.HasBits(stm32.SPI_CR1_RXONLY | stm32.SPI_CR1_BIDIMODE | stm32.SPI_CR1_BIDIOE) { + spi.Bus.SR.Get() + } // disable the SPI interface spi.Bus.CR1.ClearBits(stm32.SPI_CR1_SPE) From cd1e52128d36684e46b894581962081063433243 Mon Sep 17 00:00:00 2001 From: ardnew Date: Thu, 17 Sep 2020 16:08:16 -0500 Subject: [PATCH 5/7] remove unique features from STM32 SPI --- src/machine/machine_stm32_spi.go | 74 -------------------------------- src/machine/machine_stm32f405.go | 6 ++- 2 files changed, 4 insertions(+), 76 deletions(-) diff --git a/src/machine/machine_stm32_spi.go b/src/machine/machine_stm32_spi.go index bc9de44699..10a0dac91d 100644 --- a/src/machine/machine_stm32_spi.go +++ b/src/machine/machine_stm32_spi.go @@ -9,28 +9,6 @@ import ( "unsafe" ) -// SPI directionality -const ( - DirFullDuplex = 0 - DirSimplexRx = 1 - DirHalfDuplexRx = 2 - DirHalfDuplexTx = 3 -) - -// SPI data frame format/size -const ( - DataWidth8Bit = 0 - DataWidth16Bit = 1 -) - -// SPI chip/slave select mode. Use any GPIO pin in software mode, otherwise use -// one of the pins with NSS alternate function in hardware mode. -const ( - CSSoft = 0 - CSHardIn = 1 - CSHardOut = 2 -) - // SPIConfig is used to store config info for SPI. type SPIConfig struct { Frequency uint32 @@ -39,9 +17,6 @@ type SPIConfig struct { SDI Pin LSBFirst bool Mode uint8 - Direction uint8 - DataSize uint8 - CSMode uint8 } // Configure is intended to setup the STM32 SPI1 interface. @@ -87,65 +62,17 @@ func (spi SPI) Configure(config SPIConfig) { // set bit transfer order if config.LSBFirst { conf |= stm32.SPI_CR1_LSBFIRST - } else { - conf &^= stm32.SPI_CR1_LSBFIRST } // set polarity and phase on the SPI interface switch config.Mode { - case Mode0: - conf &^= stm32.SPI_CR1_CPOL - conf &^= stm32.SPI_CR1_CPHA case Mode1: - conf &^= stm32.SPI_CR1_CPOL conf |= stm32.SPI_CR1_CPHA case Mode2: conf |= stm32.SPI_CR1_CPOL - conf &^= stm32.SPI_CR1_CPHA case Mode3: conf |= stm32.SPI_CR1_CPOL conf |= stm32.SPI_CR1_CPHA - default: // to mode 0 - conf &^= stm32.SPI_CR1_CPOL - conf &^= stm32.SPI_CR1_CPHA - } - - // configure the direction of SPI data - switch config.Direction { - case DirFullDuplex: - conf &^= (stm32.SPI_CR1_RXONLY | stm32.SPI_CR1_BIDIMODE | stm32.SPI_CR1_BIDIOE) - case DirSimplexRx: - conf &^= (stm32.SPI_CR1_BIDIMODE | stm32.SPI_CR1_BIDIOE) - conf |= stm32.SPI_CR1_RXONLY - case DirHalfDuplexRx: - conf &^= (stm32.SPI_CR1_RXONLY | stm32.SPI_CR1_BIDIOE) - conf |= stm32.SPI_CR1_BIDIMODE - case DirHalfDuplexTx: - conf &^= stm32.SPI_CR1_RXONLY - conf |= (stm32.SPI_CR1_BIDIMODE | stm32.SPI_CR1_BIDIOE) - } - - // set data frame format/size - switch config.DataSize { - case DataWidth8Bit: - conf &^= stm32.SPI_CR1_DFF - case DataWidth16Bit: - conf |= stm32.SPI_CR1_DFF - } - - // configure chip select mode: hardware vs software - var nss uint32 - switch config.CSMode { - case CSSoft: - conf &^= (stm32.SPI_CR2_SSOE << 16) - nss |= stm32.SPI_CR1_SSM - conf |= nss - case CSHardIn: - conf &^= stm32.SPI_CR1_SSM | (stm32.SPI_CR2_SSOE << 16) - case CSHardOut: - conf &^= stm32.SPI_CR1_SSM - nss |= (stm32.SPI_CR2_SSOE << 16) - conf |= nss } // configure as SPI master @@ -156,7 +83,6 @@ func (spi SPI) Configure(config SPIConfig) { // now set the configuration spi.Bus.CR1.Set(conf) - spi.Bus.CR2.SetBits(nss >> 16) } // Transfer writes/reads a single byte using the SPI interface. diff --git a/src/machine/machine_stm32f405.go b/src/machine/machine_stm32f405.go index aa94361a78..4709fa2c5c 100644 --- a/src/machine/machine_stm32f405.go +++ b/src/machine/machine_stm32f405.go @@ -62,9 +62,11 @@ func (spi SPI) getBaudRate(config SPIConfig) uint32 { clock = CPUFrequency() / 4 } - // limit requested frequency to bus frequency + // limit requested frequency to bus frequency and min frequency (DIV256) freq := config.Frequency - if freq > clock { + if min := clock / 256; freq < min { + freq = min + } else if freq > clock { freq = clock } From 9e3c4bc463d02d860d70f2457b5ba9fc962f5385 Mon Sep 17 00:00:00 2001 From: ardnew Date: Thu, 17 Sep 2020 20:18:57 -0500 Subject: [PATCH 6/7] use software CS by default --- src/machine/machine_stm32_spi.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/machine/machine_stm32_spi.go b/src/machine/machine_stm32_spi.go index 10a0dac91d..11f02bb906 100644 --- a/src/machine/machine_stm32_spi.go +++ b/src/machine/machine_stm32_spi.go @@ -81,8 +81,12 @@ func (spi SPI) Configure(config SPIConfig) { // enable the SPI interface conf |= stm32.SPI_CR1_SPE + // use software CS (GPIO) by default + conf |= stm32.SPI_CR1_SSM + // now set the configuration spi.Bus.CR1.Set(conf) + spi.Bus.CR2.SetBits((conf & stm32.SPI_CR1_SSM_Msk) >> 16) } // Transfer writes/reads a single byte using the SPI interface. From 5f0d697257afa9c98ffca213db6e1465b249fe36 Mon Sep 17 00:00:00 2001 From: ardnew Date: Fri, 2 Oct 2020 08:54:10 -0500 Subject: [PATCH 7/7] stm32f405: do not enable/disable SPI interface for every transfer --- src/machine/machine_stm32_spi.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/machine/machine_stm32_spi.go b/src/machine/machine_stm32_spi.go index 11f02bb906..dd69137f83 100644 --- a/src/machine/machine_stm32_spi.go +++ b/src/machine/machine_stm32_spi.go @@ -102,12 +102,6 @@ func (spi SPI) Transfer(w byte) (byte, error) { // 4. Wait until RXNE=1 and read the last received data. // 5. Wait until TXE=1 and then wait until BSY=0 before disabling the SPI. - // lazy enabling of SPI interface, in case it has been disabled due to error - // or intent. - if !spi.Bus.CR1.HasBits(stm32.SPI_CR1_SPE) { - spi.Bus.CR1.SetBits(stm32.SPI_CR1_SPE) - } - // put output word (8-bit) in data register (DR), which is parallel-loaded // into shift register, and shifted out on MOSI. spi.Bus.DR.Set(uint32(w)) @@ -138,9 +132,6 @@ func (spi SPI) Transfer(w byte) (byte, error) { spi.Bus.SR.Get() } - // disable the SPI interface - spi.Bus.CR1.ClearBits(stm32.SPI_CR1_SPE) - // Return received data from SPI data register return data, nil }