mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-06 20:13:40 +00:00
2333ef2454
Add SPIv2 driver for STM32U5 using TXDR/RXDR and CFG1/CFG2 registers, which differ from the classic SPI peripheral on older STM32 families. Implements Configure() and single-byte Transfer(). Add SPI1 peripheral and pin definitions to arduino-uno-q board. Exclude stm32u5 from the shared classic SPI build tag.
120 lines
2.5 KiB
Go
120 lines
2.5 KiB
Go
//go:build stm32u5
|
|
|
|
package machine
|
|
|
|
// SPI on STM32U5 uses the new SPIv2 peripheral with separate TXDR/RXDR registers.
|
|
|
|
import (
|
|
"unsafe"
|
|
)
|
|
|
|
// SPIConfig is used to store config info for SPI.
|
|
type SPIConfig struct {
|
|
Frequency uint32
|
|
SCK Pin
|
|
SDO Pin
|
|
SDI Pin
|
|
LSBFirst bool
|
|
Mode uint8
|
|
}
|
|
|
|
// Configure is intended to setup the STM32U5 SPI peripheral.
|
|
func (spi *SPI) Configure(config SPIConfig) error {
|
|
// Disable SPI interface before any configuration changes
|
|
spi.Bus.CR1.ClearBits(1) // Clear SPE (bit 0)
|
|
|
|
// Enable clock for SPI
|
|
enableAltFuncClock(unsafe.Pointer(spi.Bus))
|
|
|
|
// Init pins - use defaults if not specified
|
|
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)
|
|
|
|
// Configure CFG1: baud rate and data size
|
|
var cfg1 uint32
|
|
|
|
// Set baud rate (MBR bits [30:28])
|
|
cfg1 |= spi.getBaudRate(config)
|
|
|
|
// Set data size to 8 bits (DSIZE[4:0] = 7 = 8-1)
|
|
cfg1 |= 7
|
|
|
|
spi.Bus.CFG1.Set(cfg1)
|
|
|
|
// Configure CFG2: master mode, SS output, polarity, phase
|
|
var cfg2 uint32
|
|
const (
|
|
cfg2_MASTER = 1 << 22 // MASTER bit
|
|
cfg2_SSM = 1 << 26 // Software SS management
|
|
cfg2_SSOE = 1 << 29 // SS output enable
|
|
cfg2_AFCNTR = 1 << 31 // Alternate function GPIO control always active
|
|
cfg2_CPOL = 1 << 25
|
|
cfg2_CPHA = 1 << 24
|
|
cfg2_LSBFRST = 1 << 23
|
|
)
|
|
|
|
cfg2 |= cfg2_MASTER | cfg2_SSM | cfg2_AFCNTR
|
|
|
|
// Set polarity and phase
|
|
switch config.Mode {
|
|
case Mode1:
|
|
cfg2 |= cfg2_CPHA
|
|
case Mode2:
|
|
cfg2 |= cfg2_CPOL
|
|
case Mode3:
|
|
cfg2 |= cfg2_CPOL | cfg2_CPHA
|
|
}
|
|
|
|
// Set bit transfer order
|
|
if config.LSBFirst {
|
|
cfg2 |= cfg2_LSBFRST
|
|
}
|
|
|
|
spi.Bus.CFG2.Set(cfg2)
|
|
|
|
// Enable SPI
|
|
spi.Bus.CR1.SetBits(1) // Set SPE (bit 0)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Transfer writes/reads a single byte using the SPI interface.
|
|
func (spi *SPI) Transfer(w byte) (byte, error) {
|
|
// Set transfer size to 1 frame
|
|
spi.Bus.CR2.Set(1)
|
|
|
|
// Start the transfer
|
|
spi.Bus.CR1.SetBits(1 << 9) // CSTART bit
|
|
|
|
// Wait until TX FIFO is ready (TXP bit in SR)
|
|
const sr_TXP = 1 << 1
|
|
const sr_RXP = 1 << 0
|
|
const sr_EOT = 1 << 3
|
|
|
|
for !spi.Bus.SR.HasBits(sr_TXP) {
|
|
}
|
|
|
|
// Write byte to TXDR
|
|
spi.Bus.TXDR.Set(uint32(w))
|
|
|
|
// Wait for RX data available (RXP bit in SR)
|
|
for !spi.Bus.SR.HasBits(sr_RXP) {
|
|
}
|
|
|
|
// Read received byte
|
|
data := byte(spi.Bus.RXDR.Get())
|
|
|
|
// Wait for end of transfer
|
|
for !spi.Bus.SR.HasBits(sr_EOT) {
|
|
}
|
|
|
|
// Clear EOT flag
|
|
spi.Bus.IFCR.Set(sr_EOT)
|
|
|
|
return data, nil
|
|
}
|