2020-02-12 01:47 PM
I'm setting up a MCU to control a stepper motor. I'm aiming to control the stepper motor driver (AMIS-30543) over SPI. My current goal is to get the driver to respond to my SPI commands so I know it's correctly receiving my commands. The driver responds, but only ever with 0xFF. Once earlier today I got it to respond with 0x02 (the hexadecimal I should receive), but it hasn't repeated since then. So where I need help is figuring out why its behaving like this and how to get the driver to respond correctly.
I'm using Keil uVision 5. Writing in C as a beginner of beginners.
The pins are connected according to the following description.
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
Relevant segments of my code is below.
int main(void)
{
Clock_Init();
USART2_Init();
SPI1_Init();
init();
nxtLow();
dirLow();
DelayMS(1);
resetSettings();
setCurrentMilliamps(132);
setStepMode(16);
enableDriver();
printf("WR: ");
printHex(readReg(WR));
printf("\r\n");
printf("CR0: ");
printHex(readReg(CR0));
printf("\r\n");
printf("CR1: ");
printHex(readReg(CR1));
printf("\r\n");
printf("CR2: ");
printHex(readReg(CR2));
printf("\r\n");
printf("CR3: ");
printHex(readReg(CR3));
printf("\r\n");
while (1)
{
dirHigh();
for (unsigned int i = 0; i < 16; i++)
{
Step();
}
DelayMS(300);
dirLow();
for (unsigned int i = 0; i < 16; 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 8
// -> 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
//
//
// 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_RXNE));
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();
}
// SPI1: 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));
}
// GENERAL FUNCTIONALITY: end
Solved! Go to Solution.
2020-02-21 11:38 AM
So, I've gone back through the documentation for the MCU and the slave device (AMIS-30543) and got a logic analyzer. I've updated the code some and I think I've narrowed down where the error may lay. Here is a screen grab of the logic analyzer results and updated code.
The slave device's documentation is here. It states it must receive a command+address byte followed by an empty byte in order for one of its registers to be read.
https://www.pololu.com/file/0J869/AMIS-30543-D.pdf
It looks like I'm correctly sending 8 bits of data to the slave device, but am still receiving blank data in return.
Code:
int main(void)
{
Clock_Init();
USART2_Init();
SPI1_Init();
while (1)
{
DelayMS(1);
writeReg(CR0, 0x11);
readReg(CR0);
}
}
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 SPI1_Init(void)
{
// define GPIO pins -> PC7, output
// -> PB3, output
// -> PB4, output
// -> PA5, alternate function
// -> PA6, alternate function
// -> PA7, alternate function
GPIOC->MODER = 0x00004000;
GPIOB->MODER = 0x00000140;
GPIOA->MODER |= 0x0000A800;
// define alt. func.s -> PA5, AF0, SPI1 SCK
// -> PA6, AF0, SPI1 MISO
// -> PA7, AF0, SPI1 MOSI
GPIOA->AFR[0] |= 0x00000000;
// format spi
SPI1->CR1 = 0x00000014; // br = f_pclk / 8
// format spi
SPI1->CR2 = 0x00001704; // ds = 8 bit
// enable spi
SPI1->CR1 |= 0x00000040;
// flush data register
uint8_t flushValue = SPI1->DR;
}
void writeReg(uint8_t address, uint8_t value)
{
selectChip();
transfer(0x80 | (address & 0b11111));
transfer(value);
deselectChip();
}
uint8_t readReg(uint8_t address)
{
selectChip();
transfer(address & 0b11111);
uint8_t dataOut = transfer(0x00);
deselectChip();
return dataOut;
}
uint8_t transfer(uint8_t value)
{
while (!(SPI1->SR & 0x00000002)); // wait for the transmission to complete
*(uint8_t*)&SPI1->DR = value; // start the transmission
while (!(SPI1->SR & 0x00000001)); // wait for the reception buffer to be full
return (uint8_t)SPI1->DR; // return the received byte
}
void selectChip(void)
{
csLow();
}
void deselectChip(void)
{
csHigh();
}
2020-02-24 02:13 AM
At this point, I don't know. As it's the AMIS chip which does not answer to what appears to be a correct sequence, it's then either incorrect wiring, bad solder joints, or faulty chip...
JW
2020-02-24 06:37 AM
I'm very happy to report it is working now; soldering the joints did the trick. I soldered the pins now instead of simply laying the chip on top of the breakout pins (I thought the contact was sufficient, but was clearly wrong in that assessment). The stepper motor now spins as instructed.
I did notice that I'm unable to flash the MCU while the power supply is connected to the stepper motor and the motor will continue spinning when the MCU is unplugged from the computer (I was powering the MCU via USB for development). The LD2 LED is also faintly illuminated, for some reason.
My frankenstein-ian translation of the Arduino AMIS-30543/SPI libraries here:
https://www.dropbox.com/s/rd56urolci0ou82/main.txt?dl=0
Thank you for your help, JW.
2020-02-24 07:47 AM
Thanks for coming back with the result.
JW