mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
156d6e7c9c
Signed-off-by: deadprogram <ron@hybridgroup.com>
135 lines
3.6 KiB
Go
135 lines
3.6 KiB
Go
//go:build tinygo
|
|
|
|
package tmc5160
|
|
|
|
import (
|
|
"machine"
|
|
"time"
|
|
)
|
|
|
|
// CustomError is a lightweight error type used for TinyGo compatibility.
|
|
type CustomError string
|
|
|
|
func (e CustomError) Error() string {
|
|
return string(e)
|
|
}
|
|
|
|
// SPIComm implements RegisterComm for SPI-based communication
|
|
type SPIComm struct {
|
|
spi *machine.SPI
|
|
CsPins map[uint8]machine.Pin // Map to store CS pin for each Driver by its address
|
|
}
|
|
|
|
// NewSPIComm creates a new SPIComm instance.
|
|
func NewSPIComm(spi *machine.SPI, csPins map[uint8]machine.Pin) *SPIComm {
|
|
return &SPIComm{
|
|
spi: spi,
|
|
CsPins: csPins,
|
|
}
|
|
}
|
|
|
|
// Setup initializes the SPI communication with the Driver and configures all CS pins.
|
|
func (comm *SPIComm) Setup() error {
|
|
// Check if SPI is initialized
|
|
if comm.spi == nil {
|
|
return CustomError("SPI not initialized")
|
|
}
|
|
|
|
// Configure all CS pins (make them output and set them high)
|
|
for _, csPin := range comm.CsPins {
|
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
|
csPin.High() // Set all CS pins high initially
|
|
}
|
|
|
|
// Configure the SPI interface with the desired settings
|
|
err := comm.spi.Configure(machine.SPIConfig{
|
|
LSBFirst: false,
|
|
Mode: 3,
|
|
})
|
|
if err != nil {
|
|
return CustomError("Failed to configure SPI")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// WriteRegister sends a register write command to the TMC5160.
|
|
func (comm *SPIComm) WriteRegister(register uint8, value uint32, driverAddress uint8) error {
|
|
// Assert the chip select pin (set CS low to start communication)
|
|
csPin, exists := comm.CsPins[driverAddress]
|
|
if !exists {
|
|
return CustomError("Invalid driver address")
|
|
}
|
|
csPin.Low()
|
|
|
|
// Set the register address with WRITE_ACCESS (0x80)
|
|
addressWithWriteAccess := register | 0x80
|
|
|
|
// Send the address and the data to write (split into 4 bytes)
|
|
_, err := spiTransfer40(comm.spi, addressWithWriteAccess, value)
|
|
if err != nil {
|
|
csPin.High()
|
|
return CustomError("Failed to write register")
|
|
}
|
|
|
|
// Deassert the chip select pin (set CS high to end communication)
|
|
csPin.High()
|
|
|
|
return nil
|
|
}
|
|
|
|
// ReadRegister sends a register read command to the TMC5160.
|
|
func (comm *SPIComm) ReadRegister(register uint8, driverAddress uint8) (uint32, error) {
|
|
// Assert the chip select pin (set CS low to start communication)
|
|
csPin, exists := comm.CsPins[driverAddress]
|
|
if !exists {
|
|
return 0, CustomError("Invalid driver address")
|
|
}
|
|
csPin.Low()
|
|
|
|
// Step 1: Send a dummy write operation to begin the read sequence
|
|
_, err := spiTransfer40(comm.spi, register, 0x00) // Send dummy data
|
|
if err != nil {
|
|
csPin.High()
|
|
return 0, CustomError("Failed to send dummy write")
|
|
}
|
|
csPin.High()
|
|
time.Sleep(176 * time.Nanosecond)
|
|
csPin.Low()
|
|
// Step 2: Send the register read request again to get the actual value
|
|
response, err := spiTransfer40(comm.spi, register, 0x00) // Send again to get actual register data
|
|
if err != nil {
|
|
csPin.High()
|
|
return 0, CustomError("Failed to read register")
|
|
}
|
|
|
|
// Deassert the chip select pin (set CS high to end communication)
|
|
csPin.High()
|
|
|
|
return response, nil
|
|
}
|
|
|
|
func spiTransfer40(spi *machine.SPI, register uint8, txData uint32) (uint32, error) {
|
|
// Prepare the 5-byte buffer for transmission (1 byte address + 4 bytes data)
|
|
tx := []byte{
|
|
register, // Address byte
|
|
byte(txData >> 24), // Upper 8 bits of data
|
|
byte(txData >> 16), // Middle 8 bits of data
|
|
byte(txData >> 8), // Next 8 bits of data
|
|
byte(txData), // Lower 8 bits of data
|
|
}
|
|
|
|
rx := make([]byte, 5)
|
|
|
|
// Perform the SPI transaction
|
|
err := spi.Tx(tx, rx)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// Combine the received bytes into a 32-bit response, ignore the address byte
|
|
rxData := uint32(rx[1])<<24 | uint32(rx[2])<<16 | uint32(rx[3])<<8 | uint32(rx[4])
|
|
|
|
return rxData, nil
|
|
}
|