The Trinamic TMC5160 has a motion controller mode which is very cool. It allows you to set things like acceleration parameters, destination, speed via SPI, instead of using the STEP / DIR pins.
I have been using the TMC5160 SilentStepStick as a board for many applications but by default it isn't configured as a motion controller and it doesn't expose a pin to change it.
You can cut a trace to put it in motion controller mode, and even though the documentation says it needs to be connected to ground, I've never actually had to do so (your results may vary).
made with the polarisation microscope
Check out the datasheet on this page and check page 34, register IOIN. This register can be read out to see if the cut was successful, Bit 6 should be 0 now and the motion controller should be active.
In order to test it out I wrote a simple program in C that runs on my raspberry pi. It initializes the TMC and accellerates until a maximum velocity is reached. After pressing enter it will decelerate and stop.
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
static const char* s_spidev = "/dev/spidev0.0";
static uint8_t s_mode = 3;
static uint8_t s_bits = 8;
static uint16_t s_delay = 0;
static uint32_t s_speed = 1000000;
static int transfer(int fd, uint8_t reg, uint32_t val)
{
printf("Transfer\n");
uint8_t tx[5] = { reg,
(val>>24) & 0xFF,
(val>>16) & 0xFF,
(val>> 8) & 0xFF,
(val>> 0) & 0xFF };
uint8_t rx[5] = {0};
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long) tx,
.rx_buf = (unsigned long) rx,
.len = 5,
.delay_usecs = s_delay,
.speed_hz = 0,
.bits_per_word = 0,
};
int rc = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (rc == 1) return rc;
printf("%02X %02X%02X%02X%02X -> %02X %02x%02x%02x%02x\n",
tx[0], tx[1], tx[2], tx[3], tx[4],
rx[0], rx[1], rx[2], rx[3], rx[4]);
return 0;
}
int main()
{
int rc;
int fd = open(s_spidev, O_RDWR);
if (fd < 0) { perror("SPI OPEN"); return -1; }
rc = ioctl(fd, SPI_IOC_WR_MODE, &s_mode);
if (rc < 0) { perror("SPI WR MODE"); return -1; }
rc = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &s_bits);
if (rc < 0) { perror("SPI BIT PER WORD"); return -1; }
rc = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &s_speed);
if (rc < 0) { perror("SPI MAX SPEED HZ"); return -1; }
transfer(fd, 0x01, 0x00000000);// READ GSTAT
transfer(fd, 0x04, 0x00000000);// READ IOIN
transfer(fd, 0x8b, 0x000000EE);// WRITE GLOBAL SCALER: 0xEE
transfer(fd, 0x90, 0x000003E1);// WRITE IHOLD:0x01 IRUN:0x1F
transfer(fd, 0x93, 0x00014000);// WRITE STEALTHCHOP UPPER VELOCITY
transfer(fd, 0x94, 0x00018000);// WRITE COOLSTEP LOWER VELOCITY
transfer(fd, 0x95, 0x0000002F);// WRITE COOLSTEP UPPER VELOCITY
transfer(fd, 0xA0, 0x00000001);// WRITE RAMPMODE: 0 = POSITION MODE / 1 = VELOCITY MODE
transfer(fd, 0xA3, 0x00000500);// WRITE START VELOCITY
transfer(fd, 0xA4, 0x00000600);// WRITE A1 ACCELLERATION (FROM VSTART TO V1 IN POSITION MODE)
transfer(fd, 0xA5, 0x00010000);// WRITE V1 VELOCITY (POSITION MODE)
transfer(fd, 0xA6, 0x00000300);// WRITE AMAX ACCELLERATION (FROM V1 TO VMAX IN POSITION MODE, GENERAL IN VELOCITY MODE)
transfer(fd, 0xA8, 0x00000F00);// WRITE DMAX DECELLERATION (FROM VMAX TO V1 IN POSITION MODE, GENERAL IN VELOCITY MODE)
transfer(fd, 0xAA, 0x00000D00);// WRITE D1 DECELLERATION (FROM V1 TO VSTOP IN POSITION MODE)
transfer(fd, 0xAB, 0x00000600);// WRITE VSTOP VELOCITY (POSITION MODE)
transfer(fd, 0xAC, 0x00000800);// WRITE TZEROWAIT
transfer(fd, 0xB3, 0x00000000);// WRITE DCSTEP = OFF
transfer(fd, 0xB4, 0x00000000);// WRITE SWITCH MODE NO SWITCH STUFF
transfer(fd, 0xEE, 0x0000001C);// WRITE DC CONTROL, GUESS
transfer(fd, 0xEC, 0x10410155);// WRITE CHOPCONF
transfer(fd, 0xA1, 0x00000000);// WRITE ACTUAL POSITION
transfer(fd, 0xA7, 0x00060000);// WRITE VMAX / TARGET VELOCITY
transfer(fd, 0xAD, 0x00400000);// WRITE TARGET POSITION (POSITION MODE)
transfer(fd, 0x00, 0x00000000);// WRITE GCONF, diag0 = interrupt, diag1 = position compare
printf("Waiting... ");
fgetc(stdin);
transfer(fd, 0xA7, 0x00000000);// WRITE VMAX / TARGET VELOCITY
transfer(fd, 0xAD, 0x00000000);// WRITE TARGET POSITION (POSITION MODE)
printf("Done.\n");
close(fd);
return 0;
}
Next up: setting X_COMPARE to get a sync signal, and updating it in an interrupt handler.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.