I'm attempting to get my STM32 board to control a stepper motor (using an AMIS-30543 driver, 26M024B2B stepper motor) using SPI. I'm using Keil uVision 5 and taking a bare-metal approach in C. My problem is that the motor is not spinning and I'm unsure where the error(s) are hiding. I would appreciate input pointing out where I've gone wrong on this, and how to fix it. Thank you for your time!
I have it wired together as shown below.
STM AMIS
3.3v IOREF
GND GND
PB3 NXT
PB5 DIR
PA7 DO
PA6 DI
PA5 CLK
PA4 CS
AMIS 9v Battery
VMOT + terminal (also tried with STM 5V)
GND - terminal (also tried with STM GND)
AMIS 26M024B2B
MXP + coil 1
MXN - coil 1
MYP + coil 2
MYN - coil 2
The code I've written is below. The code attempts to write to the driver's control register then toggle the NXT pin so that the motor increments with each toggle according to its control register. I've read through the data sheet for the driver and have linked it to this post for your convenience.
The section(s) on the datasheet that are relevant is the SPI Interface section (page 31) in conjunction with tables 11 and 12 and figure 19. My interpretation is that the driver can be written to by sending it an 8bit message that specifies what type of command and where the data will go then 8 bits of data that will populate the control register. I assembled the first packet by using the following logic...
writing to CR0 -> 1000 0001 -> 0x81
writing to CR1 -> 1000 0010 -> 0x82
writing to CR2 -> 1000 0011 -> 0x83
#include "stm32f0xx.h"
#include <stdio.h>
#include <string.h>
// GPIO -> PB5 -> direction
// GPIO -> PB3 -> next
// USART2 TX -> PA2, AF1 -> transmit
// USART2 RX -> PA3, AF1 -> receive
// SPI1 NSS -> PA4 -> slave select
// SPI1 SCK -> PA5, AF0 -> clock
// SPI1 MISO -> PA6, AF0 -> master in slave out
// SPI1 MOSI -> PA7, AF0 -> master out slave in
void Clock_Init(void);
void GPIO_Init(void);
void USART2_Init(void);
void SPI1_Init(void);
void SPI1_Write(uint8_t data);
void DelayMS(int n);
int main(void)
{
Clock_Init();
GPIO_Init();
USART2_Init();
SPI1_Init();
// char str[100];
// set stepper rotation direction
GPIOB->ODR |= 0x00000020;
// apply settings to the stepper motor driver
uint8_t packet0;
uint8_t packet1;
GPIOA->ODR = 0x00000010; // write NSS high
packet0 = 0x81; // write to CR0
packet1 = 0x20; // set rotation amount
SPI1_Write(packet0); // send WRITE command & register address
SPI1_Write(packet1); // send register data
GPIOA->ODR = 0x00000000; // write NSS low
GPIOA->ODR = 0x00000010; // write NSS high
packet0 = 0x82; // write to CR1
packet1 = 0x80; // set rotation amount
SPI1_Write(packet0); // send WRITE command & register address
SPI1_Write(packet1); // send register data
GPIOA->ODR = 0x00000000; // write NSS low
GPIOA->ODR = 0x00000010; // write NSS high
packet0 = 0x83; // write to CR2
packet1 = 0x80; // set motor enable
SPI1_Write(packet0); // send WRITE command & register address
SPI1_Write(packet1); // send register data
GPIOA->ODR = 0x00000000; // write NSS low
printf("\r\nTest Interface\r\n");
while (1)
{
// printf("Command: ");
// gets(str);
// printf("\r\n");
// printf("Your command is: ");
// puts(str);
// printf("\r\n");
GPIOB->ODR ^= 0x00000008; // toggle the step signal
DelayMS(50);
}
}
// initialize device clock
void Clock_Init(void)
{
// enable port A -> bit 17, AHB
// enable port B -> bit 18, AHB
RCC->AHBENR |= 0x00060000;
// enable USART2 -> bit 17, APB1
RCC->APB1ENR |= 0x00020000;
// enable SPI1 -> bit 12, APB2
RCC->APB2ENR |= 0x00001000;
}
// initialize GPIO pins
void GPIO_Init(void)
{
// set GPIO to general purpose -> PB3, bit 6:7
// -> PB5, bit 10:11
GPIOB->MODER |= 0x00000440;
}
// initialize USART2
void USART2_Init(void)
{
// set GPIO to alternate function -> PA2, bit 4:5
// -> PA3, bit 6:7
GPIOA->MODER |= 0x000000A0;
// define alternate function -> PA2, AF1
// -> PA3, AF1
GPIOA->AFR[0] |= 0x00001100;
// set the baud rate -> 8000000 / 9600 to HEX, 9600 @ 8MHz
USART2->BRR = 0x00000341;
// enable transmit -> bit 3
// enable receive -> bit 2
USART2->CR1 = 0x0000000C;
// enable usart enable -> bit 0
USART2->CR1 |= 0x00000001;
}
// initialize SPI1
void SPI1_Init(void)
{
// clear GPIO pin -> PA5, bit 10:11
// -> PA6, bit 12:13
// -> PA7, bit 14:15
GPIOA->MODER &=~ 0x0000FC00;
// set GPIO to alternate function -> PA5, bit 10:11
// -> PA6, bit 12:13
// -> PA7, bit 14:15
GPIOA->MODER |= 0x0000A800;
// clear alternate function -> PA5, AF0
// -> PA6, AF0
// -> PA7, AF0
GPIOA->AFR[0] &=~ 0xFFF00000;
// define alternate function -> PA5, AF0
// -> PA6, AF0
// -> PA7, AF0
GPIOA->AFR[0] |= 0x00000000;
// clear GPIO pin -> PA4, bit 8:9
GPIOA->MODER &=~ 0x00000300;
// set GPIO to output -> PA4, bit 8:9
GPIOA->MODER |= 0x00000100;
// set the baud rate -> f_PCLK / 16
// set the data frame -> 8 bit
SPI1->CR1 = 0x0000031C;
SPI1->CR2 = 0x00000000;
SPI1->CR1 |= 0x00000040;
}
// delay for a given ms limit
void DelayMS(int n)
{
SysTick->LOAD = 8000 - 1;
SysTick->VAL = 0;
SysTick->CTRL = 0x00000005;
for (int i = 0; i < n; i++)
{
while ((SysTick->CTRL & 0x00010000) == 0);
}
SysTick->CTRL = 0x00000000;
}
// write 8 bits via SPI1
void SPI1_Write(uint8_t data)
{
while (!(SPI1->SR & 0x00000002)); // wait for the transfer buffer to be empty
GPIOA->BSRR = 0x00100000; // assert slave select
SPI1->DR = data; // write data
while (SPI1->SR & 0x00000080); // wait for transmission to be complete
GPIOA->BSRR = 0x00000010; // de-assert slave select
}
// write character to PC
int USART2_Write(int ch)
{
while (!(USART2->ISR & 0x00000080));
USART2->TDR = (ch & 0xFF);
return ch;
}
// read character from PC
int USART2_Read(void)
{
while (!(USART2->ISR & 0x00000020));
return USART2->RDR;
}
// implement stdin/stdout/stderr functionality
struct __FILE{int handle;};
FILE __stdin = {0};
FILE __stdout = {1};
FILE __stderr = {2};
int fgetc(FILE *f)
{
int c;
c = USART2_Read();
if (c == '\r')
{
USART2_Write(c);
c = '\n';
}
USART2_Write(c);
return c;
}
int fputc(int c, FILE *f)
{
return USART2_Write(c);
}
UPDATE:
Here is the second iteration of my attempt. I've gone through more documentation and examples and am attempting to get a response from the driver to prove I'm correctly writing to the driver's registers. So far I'm not getting a response. Trying to translate the libraries proved to be too difficult and confusing for me at this time (maybe I'm missing something obvious?), so I'm still taking the bare-bones approach.
Thank you very much for your help thus far, @ralf htp.
UPDATE:
I've set up an Arduino Uno according to the directions set here and here with the aforementioned libraries. The stepper motor did not spin. I switched out the driver for another one and the stepper motor still did not spin. Could I have two faulty drivers?
#include "stm32f0xx.h"
#include <stdio.h>
#include <string.h>
void setDirection(int cw);
void Step(void);
void ssHigh(void);
void ssLow(void);
void SPI1_Reset(void);
void SPI1_Write(uint8_t address, uint8_t data);
uint8_t SPI1_Read(uint8_t address);
void SPI1_Send(uint8_t packet);
uint8_t SPI1_Receive(void);
void DelayMS(int n);
void Clock_Init(void);
void GPIO_Init(void);
void USART2_Init(void);
void SPI1_Init(void);
void printHex(uint8_t data);
int main(void)
{
// initialize
Clock_Init();
GPIO_Init();
USART2_Init();
SPI1_Init();
// set NXT and DIR pins low
GPIOB->ODR = 0x00000000;
// short delay
DelayMS(100);
// reset driver settings
SPI1_Reset();
// set current value (mA)
SPI1_Write(0x11, 0x11);
// set step mode
SPI1_Write(0x19, 0x02);
// enable motor outputs(?)
SPI1_Write(0x13, 0x80);
// check register
uint8_t response = SPI1_Read(0x09);
printHex(response);
// inifinite loop
while (1)
{
// step cw(?) 20 times
setDirection(0);
for (unsigned int i = 0; i < 20; i++)
{
Step();
//printf("spin cw\r\n");
}
DelayMS(300);
// step ccw(?) 20 times
setDirection(1);
for (unsigned int i = 0; i < 20; i++)
{
Step();
//printf("spin ccw\r\n");
}
DelayMS(300);
}
}
void setDirection(int cw)
{
if (cw == 0)
{
GPIOB->BSRR |= 0x00000020;
}
else if (cw == 1)
{
GPIOB->BSRR |= 0x00200000;
}
}
void Step(void)
{
GPIOB->BSRR |= 0x00000008;
DelayMS(3);
GPIOB->BSRR |= 0x00080000;
DelayMS(3);
DelayMS(500);
}
void ssHigh(void)
{
GPIOA->BSRR |= 0x00000010;
}
void ssLow(void)
{
GPIOA->BSRR |= 0x00100000;
}
void SPI1_Reset(void)
{
uint8_t addressWR = 0x10;
uint8_t addressCR0 = 0x11;
uint8_t addressCR1 = 0x12;
uint8_t addressCR2 = 0x13;
uint8_t addressCR3 = 0x19;
uint8_t dataWR = 0xF8;
uint8_t dataCR0 = 0x06;
uint8_t dataCR1 = 0xC2;
uint8_t dataCR2 = 0x00;
uint8_t dataCR3 = 0x00;
SPI1_Write(addressWR, dataWR);
SPI1_Write(addressCR0, dataCR0);
SPI1_Write(addressCR1, dataCR1);
SPI1_Write(addressCR2, dataCR2);
SPI1_Write(addressCR3, dataCR3);
}
void SPI1_Write(uint8_t address, uint8_t data)
{
ssHigh(); // set CS high
ssLow(); // set CS low
SPI1_Send(address); // send the register address
SPI1_Send(data); // send the register data
ssHigh(); // set CS high
ssLow(); // set CS low
}
uint8_t SPI1_Read(uint8_t address)
{
ssHigh(); // set CS high
ssLow(); // set CS low
SPI1_Send(address);
uint8_t output = SPI1_Receive();
ssHigh(); // set CS high
ssLow(); // set CS low
return output;
}
void SPI1_Send(uint8_t packet)
{
while (!(SPI1->SR & 0x00000002)); // wait for TX buffer to be empty
SPI1->DR = packet;
while (SPI1->SR & 0x00000080); // wait for TX to be complete
}
uint8_t SPI1_Receive(void)
{
while (SPI1->SR & 0x00000001); // wait for RX buffer to be empty
return SPI1->DR;
}
int USART2_Write(int ch)
{
while (!(USART2->ISR & 0x00000080));
USART2->TDR = (ch & 0xFF);
return ch;
}
int USART2_Read(void)
{
while (!(USART2->ISR & 0x00000020));
return USART2->RDR;
}
void DelayMS(int n)
{
SysTick->LOAD = 8000 - 1;
SysTick->VAL = 0;
SysTick->CTRL = 0x00000005;
for (int i = 0; i < n; i++)
{
while ((SysTick->CTRL & 0x00010000) == 0);
}
SysTick->CTRL = 0x00000000;
}
void Clock_Init(void)
{
// enable port A -> bit 17, AHB
// enable port B -> bit 18, AHB
RCC->AHBENR |= 0x00060000;
// enable USART2 -> bit 17, APB1
RCC->APB1ENR |= 0x00020000;
// enable SPI1 -> bit 12, APB2
RCC->APB2ENR |= 0x00001000;
}
void GPIO_Init(void)
{
// set GPIO to general purpose -> PB3, bit 6:7
// -> PB5, bit 10:11
GPIOB->MODER |= 0x00000440;
}
void USART2_Init(void)
{
// set GPIO to alternate function -> PA2, bit 4:5
// -> PA3, bit 6:7
GPIOA->MODER |= 0x000000A0;
// define alternate function -> PA2, AF1
// -> PA3, AF1
GPIOA->AFR[0] |= 0x00001100;
// set the baud rate -> 8000000 / 9600 to HEX, 9600 @ 8MHz
USART2->BRR = 0x00000341;
// enable transmit -> bit 3
// enable receive -> bit 2
USART2->CR1 = 0x0000000C;
// enable usart enable -> bit 0
USART2->CR1 |= 0x00000001;
}
void SPI1_Init(void)
{
// clear GPIO pin -> PA5, bit 10:11
// -> PA6, bit 12:13
// -> PA7, bit 14:15
GPIOA->MODER &=~ 0x0000FC00;
// set GPIO to alternate function -> PA5, bit 10:11
// -> PA6, bit 12:13
// -> PA7, bit 14:15
GPIOA->MODER |= 0x0000A800;
// clear alternate function -> PA5, AF0
// -> PA6, AF0
// -> PA7, AF0
GPIOA->AFR[0] &=~ 0xFFF00000;
// define alternate function -> PA5, AF0
// -> PA6, AF0
// -> PA7, AF0
GPIOA->AFR[0] |= 0x00000000;
// clear GPIO pin -> PA4, bit 8:9
GPIOA->MODER &=~ 0x00000300;
// set GPIO to output -> PA4, bit 8:9
GPIOA->MODER |= 0x00000100;
// set the baud rate -> f_PCLK / 8
// set the data frame -> 8 bit
SPI1->CR1 = 0x00000314;
SPI1->CR2 = 0x00000000;
SPI1->CR1 |= 0x00000040;
}
void printHex(uint8_t data)
{
printf("0x%02x", data);
}
// implement stdin/stdout/stderr functionality
struct __FILE{int handle;};
FILE __stdin = {0};
FILE __stdout = {1};
FILE __stderr = {2};
int fgetc(FILE *f)
{
int c;
c = USART2_Read();
if (c == '\r')
{
USART2_Write(c);
c = '\n';
}
USART2_Write(c);
return c;
}
int fputc(int c, FILE *f)
{
return USART2_Write(c);
}
UPDATE: I've gone through the libraries mentioned by ralf htp and translated them as best I can. I'm now able to get a response via SPI from the driver, but only value I get back is "0xFF". On one instance I got the control register response I expected, but it did not repeat and I'm trying to recreate the exact setup (although I'm pretty sure I already have). The new code is below.
#include "stm32f0xx.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
// initializations
void Clock_Init(void);
void USART2_Init(void);
void SPI1_Init(void);
// spi1
void csHigh(void);
void csLow(void);
void selectChip(void);
void deselectChip(void);
uint8_t transfer(uint8_t value);
uint8_t readReg(uint8_t address);
void writeReg(uint8_t address, uint8_t value);
void writeWR(void);
void writeCR0(void);
void writeCR1(void);
void writeCR2(void);
void writeCR3(void);
// driver functionality
void init(void);
bool verifySettings(void);
void applySettings(void);
void resetSettings(void);
void enableDriver(void);
void disableDriver(void);
void setCurrentMilliamps(uint16_t current);
uint16_t readPosition(void);
void setDirection(bool value);
void setStepMode(uint8_t mode);
void sleep(void);
void sleepStop(void);
void stepOnRisingEdge(void);
void stepOnFallingEdge(void);
void setPwmFrequencyDouble(void);
void setPwmFrequencyDefault(void);
void setPwmJitterOn(void);
void setPwmJitterOff(void);
void setPwmSlope(uint8_t emc);
void setSlaGainDefault(void);
void setSlaGainHalf(void);
void setSlaTransparencyOff(void);
void setSlaTransparencyOn(void);
uint8_t readStatusReg(uint8_t address);
void nxtHigh(void);
void nxtLow(void);
void dirHigh(void);
void dirLow(void);
void Step(void);
// general functionality
void DelayTicks(uint32_t ticks);
void DelayMS(int n);
void DelayUS(uint32_t n);
void printHex(uint8_t data);
// ENUMERATIONS: start
enum stepMode
{
MicroStep128 = 128,
MicroStep64 = 64,
MicroStep32 = 32,
MicroStep16 = 16,
MicroStep8 = 8,
MicroStep4 = 4,
MicroStep2 = 2,
MicroStep1 = 1,
CompensatedHalf = MicroStep2,
CompensatedFullTwoPhaseOn = MicroStep1,
CompensatedFullOnePhaseOn = 200,
UncompensatedHalf = 201,
UncompensatedFull = 202,
};
enum nonLatchedStatusFlag
{
OPENY = (1 << 2),
OPENX = (1 << 3),
WD = (1 << 4),
CPFAIL = (1 << 5),
TW = (1 << 6)
};
enum latchedStatusFlag
{
OVCXNB = (1 << 3),
OVCXNT = (1 << 4),
OVCXPB = (1 << 5),
OVCXPT = (1 << 6),
TSD = (1 << 10),
OVCYNB = (1 << 11),
OVCYNT = (1 << 12),
OVCYPB = (1 << 13),
OVCYPT = (1 << 14)
};
enum regAddr
{
WR = 0x00,
CR0 = 0x10,
CR1 = 0x20,
CR2 = 0x30,
CR3 = 0x90,
SR0 = 0x40,
SR1 = 0x50,
SR2 = 0x60,
SR3 = 0x70,
SR4 = 0xA0
};
// ENUMERATIONS: end
// declarations
uint8_t wr;
uint8_t cr0;
uint8_t cr1;
uint8_t cr2;
uint8_t cr3;
// PA2 / D1 -> USART2 TX -> transmit to PC
// PA3 / D2 -> USART2 RX -> receive from PC
// PA4 / A2 -> CS -> chip select (official)
// PA5 / D13 -> SCK -> clock source
// PA6 / D12 -> MISO -> master in slave out
// PA7 / D11 -> MOSI -> master out slave in
// PB3 / D3 -> NXT -> next step
// PB4 / D5 -> DIR -> direction
// PC7 / D9 -> CS -> chip select (unofficial)
int main(void)
{
Clock_Init();
USART2_Init();
SPI1_Init();
init();
nxtLow();
dirLow();
DelayMS(1);
resetSettings();
setCurrentMilliamps(132);
setStepMode(64);
enableDriver();
printHex(readReg(CR2));
printf("\r\n");
while (1)
{
dirHigh();
for (unsigned int i = 0; i < 64; i++)
{
Step();
}
DelayMS(300);
dirLow();
for (unsigned int i = 0; i < 64; i++)
{
Step();
}
DelayMS(300);
}
}
//
//
//
// INITIALIZATIONS: start
void Clock_Init(void)
{
// enable ports -> port A, AHB, bit 17
// -> port B, AHB, bit 18
// -> port C, AHB, bit 19
RCC->AHBENR = 0x000E0000;
// enable USART2 -> bit 17, APB1
RCC->APB1ENR = 0x00020000;
// enable SPI1 -> bit 12, APB2
RCC->APB2ENR = 0x00001000;
}
void USART2_Init(void)
{
// define GPIO pins -> PA2, alternate function
// -> PA3, alternate function
GPIOA->MODER = 0x000000A0;
// define alternate functions -> PA2, AF1, USART2 TX
// -> PA3, AF1, USART2 RX
GPIOA->AFR[0] = 0x00001100;
// set baud rate -> 8000000 / 9600 to HEX = 9600 @ 8MHz
USART2->BRR = 0x00000341;
// format usart -> enable tx, bit 3
// -> enable rx, bit 2
USART2->CR1 = 0x0000000C;
// enable usart -> enable ue, bit 0
USART2->CR1 |= 0x00000001;
}
void SPI1_Init(void)
{
// define GPIO pins -> PC7, output
// -> PB3, output
// -> PB4, output
// -> PA4, alternate function
// -> PA5, alternate function
// -> PA6, alternate function
// -> PA7, alternate function
GPIOC->MODER = 0x00004000;
GPIOB->MODER = 0x00000140;
GPIOA->MODER |= 0x0000AA00;
// define alternate functions -> PA4, AF0, SPI1 CS / NSS
// -> PA5, AF0, SPI1 SCK
// -> PA6, AF0, SPI1 MISO
// -> PA7, AF0, SPI1 MOSI
GPIOA->AFR[0] |= 0x00000000;
// format spi -> set br, bit 3-5
// -> enable ssm, bit 9
// -> enable ssi, bit 9
// -> set mstr, bit 2
SPI1->CR1 = 0x00000314;
// format spi -> set ds, bit 8-11
SPI1->CR2 = 0x00000700;
// enable spi -> enable spe
SPI1->CR1 |= 0x00000040;
}
// INITIALIZATIONS: end
//
//
// USART2: start
int USART2_Write(int ch)
{
while (!(USART2->ISR & 0x00000080));
USART2->TDR = (ch & 0xFF);
return ch;
}
int USART2_Read(void)
{
while (!(USART2->ISR & 0x00000020));
return USART2->RDR;
}
// USART2: end
//
//
// SPI1: start
void csHigh(void)
{
GPIOC->BSRR = 0x00000080;
GPIOA->BSRR = 0x00000010;
}
void csLow(void)
{
GPIOC->BSRR = 0x00800000;
GPIOA->BSRR = 0x00100000;
}
void selectChip(void)
{
csLow();
// begin spi transaction, unnecessary?
}
void deselectChip(void)
{
csHigh();
// end spi transaction, unnecessary?
// stabilization delay
DelayUS(3);
}
uint8_t transfer(uint8_t value)
{
// while (!(SPI1->SR & 0x00000002)); // wait for TX buffer to be empty
// SPI1->DR = value; // start the transmission
// while (!(SPI1->SR & 0x00000080)); // wait for TX to be complete
// return SPI1->DR; // return the received byte
while (!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = value;
while (!(SPI1->SR & SPI_SR_BSY));
return SPI1->DR;
}
uint8_t readReg(uint8_t address)
{
selectChip();
transfer(address & 0b11111);
uint8_t dataOut = transfer(0);
deselectChip();
return dataOut;
}
void writeReg(uint8_t address, uint8_t value)
{
selectChip();
transfer(0x80 | (address & 0b11111));
transfer(value);
deselectChip();
}
void writeWR(void)
{
writeReg(WR, wr);
}
void writeCR0(void)
{
writeReg(CR0, cr0);
}
void writeCR1(void)
{
writeReg(CR1, cr1);
}
void writeCR2(void)
{
writeReg(CR2, cr2);
}
void writeCR3(void)
{
writeReg(CR3, cr3);
}
// SPI1: end
//
//
// DRIVER FUNCTIONALITY: start
void init(void)
{
csHigh();
}
bool verifySettings(void)
{
return readReg(WR) == wr && readReg(CR0) == cr0 && readReg(CR1) == cr1 && readReg(CR2) == cr2 && readReg(CR3) == cr3;
}
void applySettings(void)
{
writeReg(CR2, cr2);
writeReg(WR, wr);
writeReg(CR0, cr0);
writeReg(CR1, cr1);
writeReg(CR3, cr3);
}
void resetSettings(void)
{
wr = cr0 = cr1 = cr2 = cr3 = 0;
applySettings();
}
void enableDriver(void)
{
cr2 |= 0b10000000;
applySettings();
}
void disableDriver(void)
{
cr2 &= ~0b10000000;
applySettings();
}
void setCurrentMilliamps(uint16_t current)
{
uint8_t code = 0;
if (current >= 3000) { code = 0b11001; }
else if (current >= 2845) { code = 0b11000; }
else if (current >= 2700) { code = 0b10111; }
else if (current >= 2440) { code = 0b10110; }
else if (current >= 2240) { code = 0b10101; }
else if (current >= 2070) { code = 0b10100; }
else if (current >= 1850) { code = 0b10011; }
else if (current >= 1695) { code = 0b10010; }
else if (current >= 1520) { code = 0b10001; }
else if (current >= 1405) { code = 0b10000; }
else if (current >= 1260) { code = 0b01111; }
else if (current >= 1150) { code = 0b01110; }
else if (current >= 1060) { code = 0b01101; }
else if (current >= 955) { code = 0b01100; }
else if (current >= 870) { code = 0b01011; }
else if (current >= 780) { code = 0b01010; }
else if (current >= 715) { code = 0b01001; }
else if (current >= 640) { code = 0b01000; }
else if (current >= 585) { code = 0b00111; }
else if (current >= 540) { code = 0b00110; }
else if (current >= 485) { code = 0b00101; }
else if (current >= 445) { code = 0b00100; }
else if (current >= 395) { code = 0b00011; }
else if (current >= 355) { code = 0b00010; }
else if (current >= 245) { code = 0b00001; }
cr0 = (cr0 & 0b11100000) | code;
writeCR0();
}
uint16_t readPosition(void)
{
uint8_t sr3 = readStatusReg(SR3);
uint8_t sr4 = readStatusReg(SR4);
return ((uint16_t)sr3 << 2) | (sr4 & 3);
}
void setDirection(bool value)
{
if (value)
{
cr1 |= 0x80;
}
else
{
cr1 &= ~0x80;
}
writeCR1();
}
int getDirection(void)
{
return cr1 >> 7 & 1;
}
void setStepMode(uint8_t mode)
{
uint8_t esm = 0b000;
uint8_t sm = 0b000;
switch (mode)
{
case MicroStep32: sm = 0b000; break;
case MicroStep16: sm = 0b001; break;
case MicroStep8: sm = 0b010; break;
case MicroStep4: sm = 0b011; break;
case CompensatedHalf: sm = 0b100; break;
case UncompensatedHalf: sm = 0b101; break;
case UncompensatedFull: sm = 0b110; break;
case MicroStep128: esm = 0b001; break;
case MicroStep64: esm = 0b010; break;
case CompensatedFullTwoPhaseOn: esm = 0b011; break;
case CompensatedFullOnePhaseOn: esm = 0b100; break;
}
cr0 = (cr0 & ~0b11100000) | (sm << 5);
cr3 = (cr3 & ~0b111) | esm;
writeCR0();
writeCR3();
}
void sleep(void)
{
cr2 |= (1 << 6);
applySettings();
}
void sleepStop(void)
{
cr2 &= ~(1 << 6);
applySettings();
}
void stepOnRisingEdge(void)
{
cr1 &= ~0b01000000;
writeCR1();
}
void stepOnFallingEdge(void)
{
cr1 |= 0b01000000;
writeCR1();
}
void setPwmFrequencyDouble(void)
{
cr1 |= (1 << 3);
writeCR1();
}
void setPwmFrequencyDefault(void)
{
cr1 &= ~(1 << 3);
writeCR1();
}
void setPwmJitterOn(void)
{
cr1 |= (1 << 2);
writeCR1();
}
void setPwmJitterOff(void)
{
cr1 &= ~(1 << 2);
writeCR1();
}
void setPwmSlope(uint8_t emc)
{
cr1 = (cr1 & ~0b11) | (emc & 0b11);
writeCR1();
}
void setSlaGainDefault(void)
{
cr2 &= ~(1 << 5);
applySettings();
}
void setSlaGainHalf(void)
{
cr2 |= (1 << 5);
applySettings();
}
void setSlaTransparencyOff(void)
{
cr2 &= ~(1 << 4);
applySettings();
}
void setSlaTransparencyOn(void)
{
cr2 |= (1 << 4);
applySettings();
}
uint8_t readStatusReg(uint8_t address)
{
return readReg(address) & 0x7F;
}
void nxtHigh(void)
{
GPIOB->BSRR |= 0x00000008;
}
void nxtLow(void)
{
GPIOB->BSRR |= 0x00080000;
}
void dirHigh(void)
{
GPIOB->BSRR |= 0x00000010;
}
void dirLow(void)
{
GPIOB->BSRR |= 0x00100000;
}
void Step(void)
{
nxtHigh();
DelayUS(3);
nxtLow();
DelayUS(3);
DelayUS(1000);
}
// DRIVER FUNCTIONALITY: end
//
//
// GENERAL FUNCTIONALITY: start
void DelayTicks(uint32_t ticks)
{
SysTick->LOAD = ticks;
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0);
SysTick->CTRL = 0;
}
void DelayMS(int n)
{
SysTick->LOAD = 8000 - 1;
SysTick->VAL = 0;
SysTick->CTRL = 0x00000005;
for (int i = 0; i < n; i++)
{
while ((SysTick->CTRL & 0x00010000) == 0);
}
SysTick->CTRL = 0x00000000;
}
void DelayUS(uint32_t n)
{
DelayTicks((n * 1000));
}
void printHex(uint8_t data)
{
printf("0x%02x", data);
}
// GENERAL FUNCTIONALITY: end
//
//
// INTERFACE FUNCTIONALITY: start
struct __FILE{int handle;};
FILE __stdin = {0};
FILE __stdout = {1};
FILE __stderr = {2};
int fgetc(FILE *f)
{
int c;
c = USART2_Read();
if (c == '\r')
{
USART2_Write(c);
c = '\n';
}
USART2_Write(c);
return c;
}
int fputc(int c, FILE *f)
{
return USART2_Write(c);
}
You did not correctly set up the AMIS-30543-D. For configuring the AMIS-30543-D accurately you have to write several registers using SPI with configuration infos (sm
, esm
,...) A complete driver for the AMIS-30543-D is in https://pololu.github.io/amis-30543-arduino/_a_m_i_s30543_8h_source.html the registers that have to be written are specified in the code section
void writeWR()
554 {
555 driver.writeReg(WR, wr);
556 }
557
559 void writeCR0()
560 {
561 driver.writeReg(CR0, cr0);
562 }
563
565 void writeCR1()
566 {
567 driver.writeReg(CR1, cr1);
568 }
569
571 void writeCR3()
572 {
573 driver.writeReg(CR3, cr3);
574 }
This is Arduino C however you can easily translate this to common C.
What is written to the registers via SPI and why you can see in the datasheet / reference manual of the AMIS-30543 : https://www.onsemi.com/pub/Collateral/AMIS-30543-D.PDF
I.e. setting the step mode, datasheet page 12-24
void setStepMode(uint8_t mode)
341 {
342 // Pick 1/32 micro-step by default.
343 uint8_t esm = 0b000;
344 uint8_t sm = 0b000;
345
346 // The order of these cases matches the order in Table 12 of the
347 // AMIS-30543 datasheet.
348 switch(mode)
349 {
350 case MicroStep32: sm = 0b000; break;
351 case MicroStep16: sm = 0b001; break;
352 case MicroStep8: sm = 0b010; break;
353 case MicroStep4: sm = 0b011; break;
354 case CompensatedHalf: sm = 0b100; break; /* a.k.a. MicroStep2 */
355 case UncompensatedHalf: sm = 0b101; break;
356 case UncompensatedFull: sm = 0b110; break;
357 case MicroStep128: esm = 0b001; break;
358 case MicroStep64: esm = 0b010; break;
359 case CompensatedFullTwoPhaseOn: esm = 0b011; break; /* a.k.a. MicroStep 1 */
360 case CompensatedFullOnePhaseOn: esm = 0b100; break;
361 }
362
363 cr0 = (cr0 & ~0b11100000) | (sm << 5);
364 cr3 = (cr3 & ~0b111) | esm;
365 writeCR0();
366 writeCR3();
367 }
In addition check if the SPI communication works
answer to comment :
The SPI code is
27 class AMIS30543SPI
28 {
29 public:
30
33 void init(uint8_t slaveSelectPin) { ssPin = slaveSelectPin;
34
35 digitalWrite(ssPin, HIGH);
36 pinMode(ssPin, OUTPUT);
37 }
38
40 uint8_t readReg(uint8_t address)
41 {
42 selectChip();
43 transfer(address & 0b11111);
44 uint8_t dataOut = transfer(0);
45 deselectChip();
46 return dataOut;
47 }
48
50 void writeReg(uint8_t address, uint8_t value)
51 {
52 selectChip();
53 transfer(0x80 | (address & 0b11111));
54 transfer(value);
55
56 // The CS line must go high after writing for the value to actually take
57 // effect.
58 deselectChip();
59 }
60
61 private:
62
63 SPISettings settings = SPISettings(500000, MSBFIRST, SPI_MODE0);
64
65 uint8_t transfer(uint8_t value)
66 {
67 return SPI.transfer(value);
68 }
69
70 void selectChip()
71 {
72 digitalWrite(ssPin, LOW);
73 SPI.beginTransaction(settings);
74 }
75
76 void deselectChip()
77 {
78 digitalWrite(ssPin, HIGH);
79 SPI.endTransaction();
80
81 // The CS high time is specified as 2.5 us in the AMIS-30543 datasheet.
82 delayMicroseconds(3);
83 }
84
85 uint8_t ssPin;
86 };
It contains some Arduino-specific syntax like digitalWrite()
that can be translated to GPIO_SetBits(GPIOx, GPIO_Piny)
, ... (full GPIO tutorial is in https://stm32f4-discovery.net/2014/04/stm32f429-discovery-gpio-tutorial-with-onboard-leds-and-button/ ). The same can be done with the Arduino SPI code, the source code of the arduino spi.h
is in https://www.arduino.cc/en/Reference/SPI and https://github.com/arduino/ArduinoCore-avr/blob/master/libraries/SPI/src/SPI.h for AVR that can be translated to ARM.
User contributions licensed under CC BY-SA 3.0