mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
@@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/tmc2209"
|
||||
)
|
||||
|
||||
func main() {
|
||||
uart := machine.UART0
|
||||
comm := tmc2209.NewUARTComm(*uart, 0)
|
||||
// Create an instance of the TMC2209 with UART communication
|
||||
tmc := tmc2209.NewTMC2209(comm, 0x00) // Replace 0x00 with the appropriate address
|
||||
|
||||
// Set up the TMC2209 driver
|
||||
err := tmc.Setup()
|
||||
if err != nil {
|
||||
println("Failed to set up TMC2209: ", err)
|
||||
}
|
||||
|
||||
// Write to a register (example: setting a register value)
|
||||
err = tmc.WriteRegister(0x10, 0x12345678) // Replace 0x10 with the register address and 0x12345678 with the value
|
||||
if err != nil {
|
||||
println("Failed to write register:", err)
|
||||
}
|
||||
|
||||
// Read from a register (example: reading a register value)
|
||||
value, err := tmc.ReadRegister(0x10)
|
||||
if err != nil {
|
||||
println("Failed to read register: ", err)
|
||||
}
|
||||
|
||||
// Output the read value
|
||||
println("Register value: ", value)
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
module tinygo.org/x/drivers
|
||||
|
||||
|
||||
go 1.22.1
|
||||
|
||||
toolchain go1.23.1
|
||||
|
||||
|
||||
require (
|
||||
github.com/eclipse/paho.mqtt.golang v1.2.0
|
||||
github.com/frankban/quicktest v1.10.2
|
||||
|
||||
@@ -136,6 +136,7 @@ tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mpu9150/mai
|
||||
tinygo build -size short -o ./build/test.hex -target=macropad-rp2040 ./examples/sh1106/macropad_spi
|
||||
tinygo build -size short -o ./build/test.hex -target=macropad-rp2040 ./examples/encoders/quadrature-interrupt
|
||||
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mcp9808/main.go
|
||||
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/tmc2209/main.go
|
||||
tinygo build -size short -o ./build/test.hex -target=pico ./examples/tmc5160/main.go
|
||||
tinygo build -size short -o ./build/test.uf2 -target=nicenano ./examples/sharpmem/main.go
|
||||
# network examples (espat)
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
# TMC2209 Go Package
|
||||
|
||||
This package provides a lightweight interface to communicate with the TMC2209 stepper motor driver via UART. It is designed to be used with microcontrollers and supports both default UART communication and custom interface implementations for flexibility.
|
||||
Currently this package only implements the communications with TMC2209. Functions to handle specific operations such as EnableStealthChop() etc. will need to be implemented by the user.
|
||||
## Features
|
||||
- **UART Communication:** Standard communication through UART for controlling the TMC2209 driver.
|
||||
- **Custom Communication Interfaces:** Allows custom implementations of communication interfaces (e.g., USB, SPI, etc.) via the `RegisterComm` interface. The usecase for this is if you have host system that can "talk" to the microcontroller connected to the TMC2209
|
||||
- **Error Handling:** Lightweight error handling for TinyGo compatibility.
|
||||
- **Register Access:** Provides methods to read and write registers on the TMC2209.
|
||||
|
||||
## Setup
|
||||
|
||||
### Prerequisites
|
||||
- **TinyGo**: This package is optimized for TinyGo, which is suitable for running Go on microcontrollers and embedded systems.
|
||||
- **UART Communication**: For microcontrollers with UART support, such as ESP32, STM32, and Raspberry Pi Pico.
|
||||
|
||||
|
||||
## Usage
|
||||
### Using with Microcontrollers (Default UART)
|
||||
|
||||
To use the package with a microcontroller, you need to initialize the UART communication and configure the TMC2209 driver.
|
||||
Example:
|
||||
|
||||
```aiignore
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"github.com/yourusername/tmc2209"
|
||||
"machine"
|
||||
)
|
||||
|
||||
func main() {
|
||||
uart := machine.UART0
|
||||
|
||||
// Create an instance of the TMC2209 with UART communication
|
||||
tmc := tmc2209.NewTMC2209(uart, 0x00) // Replace 0x00 with the appropriate address
|
||||
|
||||
// Set up the TMC2209 driver
|
||||
err := tmc.Setup()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to set up TMC2209: %v", err)
|
||||
}
|
||||
|
||||
// Write to a register (example: setting a register value)
|
||||
err = tmc.WriteRegister(0x10, 0x12345678) // Replace 0x10 with the register address and 0x12345678 with the value
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to write register: %v", err)
|
||||
}
|
||||
|
||||
// Read from a register (example: reading a register value)
|
||||
value, err := tmc.ReadRegister(0x10)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read register: %v", err)
|
||||
}
|
||||
|
||||
// Output the read value
|
||||
fmt.Printf("Register value: 0x%X\n", value)
|
||||
}
|
||||
|
||||
```
|
||||
## Microcontroller Notes
|
||||
|
||||
- **TinyGo Support:** This code is optimized for use with TinyGo on supported microcontrollers.
|
||||
- **UART Configuration:** Ensure the UART instance is configured correctly for your microcontroller.
|
||||
- The machine.UART0 in the example is for the default UART on TinyGo-compatible devices like the Raspberry Pi Pico. Check your microcontroller's documentation for the correct UART instance and pin configuration.
|
||||
|
||||
## 2. Custom Interface Implementation
|
||||
|
||||
If you want to use a custom communication interface (e.g., USB, SPI, etc.), you can implement the RegisterComm interface.
|
||||
Custom Interface Example (e.g., USB Communication):
|
||||
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"github.com/yourusername/tmc2209"
|
||||
"yourcustompackage" // Custom package for communication
|
||||
)
|
||||
|
||||
type CustomComm struct {
|
||||
// Implement your custom communication method here
|
||||
}
|
||||
|
||||
func (c *CustomComm) ReadRegister(register uint8, driverIndex uint8) (uint32, error) {
|
||||
// Implement the register read logic using your custom interface (USB, SPI, etc.)
|
||||
// For example, send the register read command over USB and read the response
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (c *CustomComm) WriteRegister(register uint8, value uint32, driverIndex uint8) error {
|
||||
// Implement the register write logic using your custom interface (USB, SPI, etc.)
|
||||
// For example, send the register write command over USB
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Create an instance of the TMC2209 with your custom communication interface
|
||||
customComm := &CustomComm{}
|
||||
tmc := tmc2209.NewTMC2209(customComm, 0x00) // Replace 0x00 with the appropriate address
|
||||
|
||||
// Set up the TMC2209 driver
|
||||
err := tmc.Setup()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to set up TMC2209: %v", err)
|
||||
}
|
||||
|
||||
// Write to a register (example: setting a register value)
|
||||
err = tmc.WriteRegister(0x10, 0x12345678) // Replace 0x10 with the register address and 0x12345678 with the value
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to write register: %v", err)
|
||||
}
|
||||
|
||||
// Read from a register (example: reading a register value)
|
||||
value, err := tmc.ReadRegister(0x10)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read register: %v", err)
|
||||
}
|
||||
|
||||
// Output the read value
|
||||
fmt.Printf("Register value: 0x%X\n", value)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Custom Interface Notes:
|
||||
|
||||
- RegisterComm Interface: Your custom communication interface (e.g., USB, SPI) should implement the RegisterComm interface. This ensures that the TMC2209 driver can interact with your custom interface for reading and writing registers.
|
||||
- Error Handling: Implement proper error handling in your custom interface methods (ReadRegister and WriteRegister).
|
||||
|
||||
#### Functions
|
||||
```
|
||||
NewTMC2209(comm RegisterComm, address uint8) *TMC2209
|
||||
```
|
||||
Creates a new TMC2209 instance with the provided communication interface (comm) and driver address (address).
|
||||
|
||||
```Setup() error```
|
||||
|
||||
Initializes the communication interface. This is required before interacting with the TMC2209 driver. The method checks if the communication interface is UART and sets it up accordingly.
|
||||
|
||||
```WriteRegister(register uint8, value uint32) error```
|
||||
|
||||
Writes a value to a specific register on the TMC2209 driver.
|
||||
|
||||
```ReadRegister(register uint8) (uint32, error)```
|
||||
|
||||
Reads a value from a specific register on the TMC2209 driver.
|
||||
|
||||
### Error Handling
|
||||
|
||||
This package uses a lightweight custom error type (CustomError) to ensure compatibility with TinyGo and reduce external dependencies.
|
||||
Example Error:
|
||||
|
||||
```CustomError("communication interface not set")```
|
||||
|
||||
|
||||
Created by Amken3d
|
||||
info@amken3d.us
|
||||
|
||||
|
||||
+1409
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
package tmc2209
|
||||
|
||||
func Constrain(value, low, high uint32) uint32 {
|
||||
if value < low {
|
||||
return low
|
||||
}
|
||||
if value > high {
|
||||
return high
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func SetRunCurrent(percent uint8) {
|
||||
_ = PercentToCurrentSetting(percent)
|
||||
|
||||
// Set the run current register to runCurrent value
|
||||
}
|
||||
|
||||
func SetHoldCurrent(percent uint8) {
|
||||
_ = PercentToCurrentSetting(percent)
|
||||
// Set the hold current register to holdCurrent value
|
||||
}
|
||||
func PercentToCurrentSetting(percent uint8) uint8 {
|
||||
constrainedPercent := Constrain(uint32(percent), 0, 100)
|
||||
return uint8(Map(constrainedPercent, 0, 100, 0, 255))
|
||||
}
|
||||
|
||||
func CurrentSettingToPercent(currentSetting uint8) uint8 {
|
||||
return uint8(Map(uint32(currentSetting), 0, 255, 0, 100))
|
||||
}
|
||||
|
||||
func PercentToHoldDelaySetting(percent uint8) uint8 {
|
||||
constrainedPercent := Constrain(uint32(percent), 0, 100)
|
||||
return uint8(Map(constrainedPercent, 0, 100, 0, 255))
|
||||
}
|
||||
|
||||
func HoldDelaySettingToPercent(holdDelaySetting uint8) uint8 {
|
||||
return uint8(Map(uint32(holdDelaySetting), 0, 255, 0, 100))
|
||||
}
|
||||
func Map(value, fromLow, fromHigh, toLow, toHigh uint32) uint32 {
|
||||
return (value-fromLow)*(toHigh-toLow)/(fromHigh-fromLow) + toLow
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package tmc2209
|
||||
|
||||
func SetMicrostepsPerStep(microsteps uint16) uint8 {
|
||||
exponent := uint8(0)
|
||||
microstepsShifted := microsteps >> 1
|
||||
|
||||
for microstepsShifted > 0 {
|
||||
microstepsShifted = microstepsShifted >> 1
|
||||
exponent++
|
||||
}
|
||||
|
||||
SetMicrostepsPerStepPowerOfTwo(exponent)
|
||||
return exponent
|
||||
}
|
||||
|
||||
func SetMicrostepsPerStepPowerOfTwo(exponent uint8) {
|
||||
switch exponent {
|
||||
case 0:
|
||||
// Set MRES_001
|
||||
case 1:
|
||||
// Set MRES_002
|
||||
case 2:
|
||||
// Set MRES_004
|
||||
case 3:
|
||||
// Set MRES_008
|
||||
case 4:
|
||||
// Set MRES_016
|
||||
case 5:
|
||||
// Set MRES_032
|
||||
case 6:
|
||||
// Set MRES_064
|
||||
case 7:
|
||||
// Set MRES_128
|
||||
default:
|
||||
// Set MRES_256
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package tmc2209
|
||||
|
||||
func EnableStealthChop() {
|
||||
// Set StealthChop enabled in the global config register
|
||||
}
|
||||
|
||||
func DisableStealthChop() {
|
||||
// Set StealthChop disabled in the global config register
|
||||
}
|
||||
|
||||
func EnableCoolStep(lowerThreshold, upperThreshold uint8) {
|
||||
// Enable CoolStep with specified thresholds
|
||||
}
|
||||
|
||||
func DisableCoolStep() {
|
||||
// Disable CoolStep feature
|
||||
}
|
||||
|
||||
func EnableAutomaticCurrentScaling() {
|
||||
// Enable Automatic Current Scaling
|
||||
}
|
||||
|
||||
func DisableAutomaticCurrentScaling() {
|
||||
// Disable Automatic Current Scaling
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
//go:build tinygo
|
||||
|
||||
package tmc2209
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
// TMC2209 represents a single TMC2209 stepper motor driver on the communication line.
|
||||
type TMC2209 struct {
|
||||
comm RegisterComm
|
||||
address uint8
|
||||
}
|
||||
|
||||
// NewTMC2209 creates a new instance of the TMC2209 driver for a specific address.
|
||||
func NewTMC2209(comm RegisterComm, address uint8) *TMC2209 {
|
||||
return &TMC2209{
|
||||
comm: comm,
|
||||
address: address,
|
||||
}
|
||||
}
|
||||
|
||||
// Setup initializes the communication interface with the TMC2209.
|
||||
func (driver *TMC2209) Setup() error {
|
||||
// Check if comm is of type *UARTComm
|
||||
if uartComm, ok := driver.comm.(*UARTComm); ok {
|
||||
// Call Setup only if comm is a *UARTComm
|
||||
err := uartComm.Setup()
|
||||
if err != nil {
|
||||
return CustomError("Failed to setup UART communication: " + err.Error())
|
||||
}
|
||||
} else {
|
||||
// If it's not a UARTComm, log that it's using a different communication method
|
||||
log.Println("Using a non-UART communication method")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteRegister sends a register write command to the TMC2209.
|
||||
func (driver *TMC2209) WriteRegister(reg uint8, value uint32) error {
|
||||
if driver.comm == nil {
|
||||
return CustomError("communication interface not set")
|
||||
}
|
||||
// Use the communication interface (RegisterComm) to write the register
|
||||
return driver.comm.WriteRegister(reg, value, driver.address)
|
||||
}
|
||||
|
||||
// ReadRegister sends a register read command to the TMC2209 and returns the read value.
|
||||
func (driver *TMC2209) ReadRegister(reg uint8) (uint32, error) {
|
||||
if driver.comm == nil {
|
||||
return 0, CustomError("communication interface not set")
|
||||
}
|
||||
// Use the communication interface (RegisterComm) to read the register
|
||||
return driver.comm.ReadRegister(reg, driver.address)
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
//go:build tinygo
|
||||
|
||||
package tmc2209
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CustomError is a lightweight error type used for TinyGo compatibility.
|
||||
type CustomError string
|
||||
|
||||
func (e CustomError) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
// UARTComm implements RegisterComm for UART-based communication
|
||||
type UARTComm struct {
|
||||
uart machine.UART
|
||||
address uint8
|
||||
}
|
||||
|
||||
// NewUARTComm creates a new UARTComm instance.
|
||||
func NewUARTComm(uart machine.UART, address uint8) *UARTComm {
|
||||
return &UARTComm{
|
||||
uart: uart,
|
||||
address: address,
|
||||
}
|
||||
}
|
||||
|
||||
// Setup initializes the UART communication with the TMC2209.
|
||||
func (comm *UARTComm) Setup() error {
|
||||
// Check if UART is initialized
|
||||
if comm.uart == (machine.UART{}) {
|
||||
return CustomError("UART not initialized")
|
||||
}
|
||||
|
||||
// Configure the UART interface with the desired baud rate and settings
|
||||
err := comm.uart.Configure(machine.UARTConfig{
|
||||
BaudRate: 115200,
|
||||
})
|
||||
if err != nil {
|
||||
return CustomError("Failed to configure UART")
|
||||
}
|
||||
|
||||
// No built-in timeout in TinyGo, so timeout will be handled in the read/write methods
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteRegister sends a register write command to the TMC2209 with a timeout.
|
||||
func (comm *UARTComm) WriteRegister(register uint8, value uint32, driverIndex uint8) error {
|
||||
buffer := []byte{
|
||||
0x05, // Sync byte
|
||||
comm.address, // Slave address
|
||||
register | 0x80, // Write command (set MSB to 1 for write)
|
||||
byte((value >> 24) & 0xFF), // MSB of value
|
||||
byte((value >> 16) & 0xFF), // Middle byte
|
||||
byte((value >> 8) & 0xFF), // Next byte
|
||||
byte(value & 0xFF), // LSB of value
|
||||
}
|
||||
|
||||
// Calculate checksum by XORing all bytes
|
||||
checksum := byte(0)
|
||||
for _, b := range buffer[:7] {
|
||||
checksum ^= b
|
||||
}
|
||||
buffer[7] = checksum // Set checksum byte
|
||||
|
||||
// Write the data to the TMC2209
|
||||
done := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
comm.uart.Write(buffer)
|
||||
done <- nil
|
||||
}()
|
||||
|
||||
// Implementing timeout using a 100ms timer
|
||||
select {
|
||||
case err := <-done:
|
||||
return err
|
||||
case <-time.After(100 * time.Millisecond): // Timeout after 100ms
|
||||
return CustomError("write timeout")
|
||||
}
|
||||
}
|
||||
|
||||
// ReadRegister sends a register read command to the TMC2209 with a timeout.
|
||||
func (comm *UARTComm) ReadRegister(register uint8, driverIndex uint8) (uint32, error) {
|
||||
var writeBuffer [4]byte
|
||||
writeBuffer[0] = 0x05 // Sync byte
|
||||
writeBuffer[1] = 0x00 // Slave address
|
||||
writeBuffer[2] = register & 0x7F // Read command (MSB clear for read)
|
||||
writeBuffer[3] = writeBuffer[0] ^ writeBuffer[1] ^ writeBuffer[2] // Checksum
|
||||
|
||||
// Send the read command
|
||||
done := make(chan []byte, 1)
|
||||
go func() {
|
||||
comm.uart.Write(writeBuffer[:])
|
||||
readBuffer := make([]byte, 8)
|
||||
comm.uart.Read(readBuffer)
|
||||
done <- readBuffer
|
||||
}()
|
||||
|
||||
// Implementing timeout using a 100ms timer
|
||||
select {
|
||||
case readBuffer := <-done:
|
||||
// Validate checksum
|
||||
checksum := byte(0)
|
||||
for i := 0; i < 7; i++ {
|
||||
checksum ^= readBuffer[i]
|
||||
}
|
||||
if checksum != readBuffer[7] {
|
||||
return 0, CustomError("checksum error")
|
||||
}
|
||||
|
||||
// Return the value from the register
|
||||
return uint32(readBuffer[3])<<24 | uint32(readBuffer[4])<<16 | uint32(readBuffer[5])<<8 | uint32(readBuffer[6]), nil
|
||||
case <-time.After(100 * time.Millisecond): // Timeout after 100ms
|
||||
return 0, CustomError("read timeout")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package tmc2209
|
||||
|
||||
import "log"
|
||||
|
||||
func CalculateCRC(data []byte) uint8 {
|
||||
crc := uint8(0)
|
||||
for _, byte := range data {
|
||||
for i := 0; i < 8; i++ {
|
||||
if (crc>>7)^(byte&0x01) == 1 {
|
||||
crc = (crc << 1) ^ 0x07
|
||||
} else {
|
||||
crc = crc << 1
|
||||
}
|
||||
byte >>= 1
|
||||
}
|
||||
}
|
||||
return crc
|
||||
}
|
||||
|
||||
// VerifyCommunication checks the communication with the TMC2209 by reading the version register (IOIN).
|
||||
// It returns true if the communication is successful (i.e., the version matches the expected version).
|
||||
// VerifyCommunication verifies the communication with the TMC2209 by reading the version register (IOIN).
|
||||
// It explicitly resets the struct and de-references it after the check to ensure memory is managed manually.
|
||||
func VerifyCommunication(comm RegisterComm, driverIndex uint8) bool {
|
||||
var io *Ioin
|
||||
if io == nil {
|
||||
io = NewIoin() // Initialize the struct if not already initialized
|
||||
} else {
|
||||
*io = Ioin{}
|
||||
}
|
||||
_, err := ReadRegister(comm, driverIndex, io.GetAddress())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if io.Version == expectedVersion {
|
||||
io = nil
|
||||
return true
|
||||
}
|
||||
io = nil
|
||||
return false
|
||||
}
|
||||
|
||||
// CheckErrorStatus verifies the communication and checks for error flags in the TMC2209 driver status.
|
||||
// It explicitly resets the struct and de-references it when done to ensure memory is managed manually.
|
||||
func CheckErrorStatus(comm RegisterComm, driverIndex uint8) bool {
|
||||
var d *DrvStatus
|
||||
if d == nil {
|
||||
d = NewDrvStatus()
|
||||
} else {
|
||||
*d = DrvStatus{}
|
||||
}
|
||||
_, err := d.Read(comm, driverIndex)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
errorFlags := d.Ola | d.S2vsa | d.S2vsb | d.Ot | d.S2ga | d.S2gb | d.Olb
|
||||
if errorFlags != 0 {
|
||||
log.Printf("TMC2209 Error Detected: %X", errorFlags)
|
||||
return false
|
||||
}
|
||||
d = nil
|
||||
return true
|
||||
}
|
||||
|
||||
// GetInterfaceTransmissionCount reads the IFCNT register to check for UART transmission status
|
||||
func GetInterfaceTransmissionCount(comm RegisterComm, driverIndex uint8) (uint32, error) {
|
||||
ifcnt := NewIfcnt()
|
||||
_, err := ReadRegister(comm, driverIndex, ifcnt.GetAddress())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return ifcnt.Bytes, nil
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package tmc2209
|
||||
|
||||
func MoveAtVelocity(microstepsPerPeriod int32) {
|
||||
// Write velocity to the relevant register
|
||||
}
|
||||
func MoveUsingStepDirInterface() {
|
||||
// Set the interface to use step/direction interface
|
||||
}
|
||||
func GetVelocity() uint32 {
|
||||
// Read the actual velocity register
|
||||
return 0 // Placeholder return value
|
||||
}
|
||||
Reference in New Issue
Block a user