Control AMIS-30543 with STM32F030R8 via SPI

2

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);
}

c
embedded
stm32
bare-metal
cmsis
asked on Stack Overflow Feb 7, 2020 by senuba91 • edited Feb 12, 2020 by senuba91

1 Answer

2

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.

answered on Stack Overflow Feb 7, 2020 by ralf htp • edited Feb 7, 2020 by ralf htp

User contributions licensed under CC BY-SA 3.0