STM32 communication with A4899 stepper motor driver - directory

I want to write a stepper motor driver with a STM32L152RE.
I would like to control the position of the stepper motor with a potentiometer.
As I am new, I do not know how to communicate with (DIR, STEP).
Can someone give me a light or show me a way?
I'm using an A4988 - DMOS Microstepping Driver with Translator And Overcurrent Protection
I tried to use STM32 tim, but I could not.

Actually I have wrote whole driver for a4988, it is irq based. But I can't uncover it.
I can describe a path how to start. Anyway you should have some kind of hardware, because A4988 needs extra components for current control (resistors), and some capacitors..
You could try POLOLU HW.
If you have some kind of custom board, there may be some flaws.. So recheck pins.
Especially ROSC pin, SENSE1, SENSE2 pins as those may cause that motor wont work even if other pins are ok.
ROSC pin is for low power mode, so here you should calculate, if you just ignore it, be sure to connect at least to 10k resistor. Don't let it float. SENSE1, SENSE2 pins can be connected to 0.25omh resistors. You should check it.
Also from power pins very decisive VREG pin. It should get from 0 to 2000mV if I remember. Actually it controls current for your motor. So it depends on your stepper motor. Here also may appear nasty flaws. For example you have small stepper motor, and setting too high VREG value, than A4988 will sink too much current and your motor will glitch. Anyway you should read A4988 data sheet very accurately.
DIR PIN is simply for direction, push-pull pin configuration and HIGH/LOW values controls direction, clock wise, anti clock wise.
RESET INPUT PIN A4988 must get HIGH from your MCU.
ENABLE INPUT PIN A4988 must get LOW from your MCU.
SLEEP INPUT PIN A4988 must get HIGH from your MCU, also it is very useful to control it when your stepper job done, else if you leave it always HIGH, stepper motor will eat current and will heat up at idle state.
Also there are 3 MICROSTEPPING PINS, those are for controlling stepping.
As you just starting to play, it will be enough connect those pins to GND, you'll get full stepping regime.If you'll control those pins you can get other regimes like 1/2 stepping, 1/4,1/8,1/16...
And general pin is STEP pin, it should be driven with TIMER as PWM output with constant pulse width and alternating period.
Here is an example of STEP PIN control:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
GPIO_InitTypeDef init;
init.GPIO_Mode = GPIO_Mode_AF;
init.GPIO_OType = GPIO_OType_PP;
init.GPIO_Pin = GPIO_Pin_9;
init.GPIO_PuPd = GPIO_PuPd_UP;
init.GPIO_Speed = GPIO_Speed_Level_2;
GPIO_Init(GPIOA,&init);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_2);
for example I connect STEP output from MCU PA9 to A4988 STEP input. Which can be driven from timer as PWM. Check your concrete MCU datasheet.
Firstly output pin should be configured as AF, with push-pull and resistor is UP.
Also setup line for alternating pin.
Now configuring timer:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TIM_TimeBaseInitTypeDef timerInitStructure;
timerInitStructure.TIM_Prescaler = 48;
timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitStructure.TIM_Period = 0;
timerInitStructure.TIM_ClockDivision = 0;
timerInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &timerInitStructure);
TIM_OCInitTypeDef osc;
osc.TIM_OCMode = TIM_OCMode_PWM1;
osc.TIM_OutputState = TIM_OutputState_Enable;
osc.TIM_OutputNState = TIM_OutputNState_Disable;
osc.TIM_Pulse = 1000;
osc.TIM_OCPolarity = TIM_OCNPolarity_High;
osc.TIM_OCNPolarity = TIM_OCNPolarity_Low;
osc.TIM_OCIdleState =TIM_OCIdleState_Reset;
osc.TIM_OCNIdleState =TIM_OCNIdleState_Set;
TIM_OC2Init(TIM1, &osc);
TIM_Cmd(TIM1, ENABLE);
Here I configure 1us timer, as my MCU frequency is 48MHz.
Also you have configure that timer would drive PWM output.
TIM1->CCR = 10; with this register I can control pulse width, in this example it is 10us.
TIM1->ARR = 30; with ARR register I can control period, so it means STEP pulse frequency which is equal to stepper motor speed. In this case 30us.
If you are using HAL and CUBEMX you can get those configurations pretty fast.

Related

Problems sending SPI Data from STM32 to arduino

I'm trying to learn how to communicate via SPI with STM32 but I've run into some problems.
The first step i took was to implement SPI communications using two arduino unos: the master writes a byte and the slave responds with another byte according to the input (when the master sends anything, triggering the exchange). Everything worked as it should to the best of my knowledge.
The second step is the one I'm stuck at which is to replace the master arduino with a NUCLEO-F767ZI board. I've set up SPI1 using the auto generated code for now, and I've set it up with what I think are the default options. In the main, I send a single byte to the arduino, and this is where the problem starts:
By using the serial port in the arduino I can see that it does receive data, but usually bit shifted. So if I send a 16, i usually get a 32 or other power of two in the arduino (see attached image)
I'm using clock polarity 0 and clock phase 0 on both microcontrollers (so clock idle on low and sampling on the rising edge). Just to be sure I've tried all possibilities but to no avail, it still doesn't work properly, and I don't really know why. Another thing I considered was that perhaps the clock is running too fast (the peripheral clock is set to 16 MHz), but if I change the prescaler to anything other than SPI_BAUDRATEPRESCALER_2, i stop getting any data on the arduino, only 0s, which I find odd, I would expect it to work just the same if only the master controls the clock.
Just for completeness, here are the spi settings I'm using:
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
The arduino slave code (I've removed the reply part for now):
void setup (void)
{
pinMode(MISO, OUTPUT);
Serial.begin(115200);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
// turn on interrupts
SPCR |= _BV(SPIE);
//Check arduino SPI settings, outputs 11000000, so CPHA and CPOL = 0
Serial.println("SPCR");
Serial.println(SPCR,BIN);
} // end of setup
void loop(void){
}
// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR;
Serial.println(c);
}
}
STM32 master code (ommiting irrelevant parts):
MX_SPI1_Init();
uint8_t data = 16;
while (1)
{
HAL_SPI_Transmit(&hspi1, &data, 1, 100);
HAL_Delay(500);
}
Does anyone have a clue as to why this could be happening? I've found nothing on the prescaler issues and all bitshifting issue posts say that the problem is with clock phase or polarity discrepancies, which I've verified is not.
Thanks in advance
SPI clock rate input to Atmega328P should be lower than Fosc/4
SPI requires the use of nCS wire. An SPI slave will reset it's logic on deassertion of nCS, but if nCS is always at a low level - any missed clock pulse would propagate to the next transfer, shifting the data.
Stm32F7 has NSSP: NSS pulse management - the option for issuing CLK pulse between data bytes. To deassert nCS pin between larger transfers SPI shoud either be disabled and then reenabled before the next transfer, or nCS management should be implemented in the software. In a later case make sure to deassert nCS only after all CLK pulses are completed.
Arduino UNO have Atmega powered from 5V, Stm32 is powered from 3V (on some boards it's 3.3V). Logic high input minimum for the Atmega328 is 0.6VCC, 5V * 0.6V = 3V, wich is on the edge. See this question
A scope would help a lot to solve such cases.

Built-in led glowing on code of led on arduino mega

I had written a code on atmel studio for blinking a led on pin 13. After uploading the code with xloader mega's builtin led was blinking.
I uploaded fade code on my mega and the builtin led was blinking instead of led. What should i do?
I am using arduino mega 2560.
int main(void)
{
DDRB=0b00000000;
while (1)
{
PORTB=0b10000000;
_delay_ms(1000);
PORTB=0b00000000;
}
}
What you should do? Read the manual.
Please refer to https://ww1.microchip.com/downloads/en/devicedoc/atmel-2549-8-bit-avr-microcontroller-atmega640-1280-1281-2560-2561_datasheet.pdf
Chapter 13.2.
The DDxn bit in the DDRx Register selects the direction of this pin.
If DDxn is written logic one, Pxn is configured as an output pin. If
DDxn is written logic zero, Pxn is configured as an input pin.
Working with registers doesn't make sense if you don't know what they do.
DDRB=0b00000000;
Gives you inputs only.
why would you use Arduino and try to program it without its conventional macros and functions?
If you are trying to blink an led or make it breath then use the Arduino IDE and its built-in functions analogWrite() to generate a pwm pulse for your led or any led on suitable pins which support analogwrite(). You shouldn't try to do any direct modifications on registers if you have no suitable knowledge, because your risk destroying your development kit and maybe burning some other stuff around. Please use your kit's schematics to spot the pins which support analogwrite() and then use the code in examples.
That way you will achieve your goal faster and without any issues.
TL/DR: you have to set 7th bit in DDRB to one.
In AVR ports are configured by bits in two registers: DDRx and PORTx.
When the corresponding bit in the DDRx register is set to one, the port is configured as output. And the corresponding bit in the PORTx register chooses which electrical level is output on the pin. If it is 0 then internal MOSFET shorts the pin to "ground" lane, and sinks current from external source. When the bit of the PORTx is one, then the pin is connected to "VCC", sourcing big amount of current enough to lit up a LED.
But if the pin is connected to something, what consumes too much of current, or the pin is shorted to GND or VCC (let's say you have a button connected and pressed), then output MOSFETS might be overloaded and damaged.
If the bit in DDRx is set to zero, then the pin is configured as input. If the corresponding bit in the PORTx is zero, then the pin has no internal connection to power lines, it is called "Hi-impedance" state, or Tri-state. It does not source or sink any current. So, if no external source of current is connected, then pin level is floating, influenced by electrical interference. Logical level is not detectable and can change occasionally. If you want to connect, for example, a button (between the pin and GND), then logical level will be defined only when button is pressed. When it is released, the logical level will be undefined.
But! If the bit in the PORTx is set to one, then internal MOSFET connects the pin thru a resistor (about 35 kOhm) to VCC line. This make the pin to source a little amount of current, setting its logical level to high. Therefore, if a button is connected, when it is released, then pin will have defined high level. This is called "pull-up resistor". When button is pressed, it will not short and damage the MCU, because current flowing thru the button is limited by the resistor, but the logical level will be defined low.
What if instead of button you have a LED connected to the pin? Very small amount of current will flow thru the LED, makes it barely glow.
Read more in the datasheet (chapter 13. I/O-Ports)

Arduino and electronics beginner beginnering

I'm working through a set of beginner exercises with the Arduino Uno microcontroller. (A generic one, though, as this is what I've been supplied with.)
The program I'm running, which alternates between sending 1's and 0's to serial output depending on the state of a momentary switch, has set pin 2 to be the input for the switch. But. Whilst wiring up, I accidentally plugged the jumper cable in to pin 3 initially, and found it still mostly sent the 1's when the button was pushed. Some 0's, yet mostly 1's.
Initially I thought maybe it was just the board was a bit dodgy, but thought I'd experiment a bit. Plugging into pin 3 instead of pin 2 still fairly consistently sent 1's when the button was pushed, though the 1's flowed a little bit less consistently than when it was in pin 2. In pin 2 it was completely consistent by comparison. So I tried pin 4, but with that one there's no response at all.
Am I right in presuming the program's readings seems to get a little bit less responsive the further away I move the cable from the pin that I've programmed to act as input? Can anyone help me understand why this happens?
It's probably quite obvious that I'm new to electronics. :)
The program I've got uploaded to the board is as follows:
// digital pin 2 has a pushbutton attached to it. Give it a name:
int pushButton = 2;
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
// make the pushbutton's pin an input:
pinMode(pushButton, INPUT);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input pin:
int buttonState = digitalRead(pushButton);
// print out the state of the button:
Serial.println(buttonState);
delay(1); // delay in between reads for stability
}
Floating pins are prone to noise. If you are not actually connecting anything to pin 2, you will be reading noise. Any wire connected to pin 2 (even connections on the board) will act like an antenna and pick up noise. You should always use the pin number that you are physically connecting in situations like these.
Leaving input pins open makes the microcontroller read a floating value which swings between 0 to 1. Also when wiring a switch to any pin, make sure to hook some pull-down resistor to make the input 0.
These are common for many electronics and proper notice to be taken while designing circuits of your own.
You need to look into datasheet where described functions of the pins.
The pins of MCU can be assigned various functions through special registers.
Two most common functions of the pins are input and output. MCUs provide internal pull-up and pull-down resistors which when used properly significantly simplifies electronic schemas.
If the input activated as input without any pull-??? then it's state is not defined and can be used as initiator of random number generator. Due this reason it is better to define what is default state of the input pin by connecting pull-??? resistors.
In Arduino IDE you are not limited to functions provided -- you still can use register manipulation directly, you just need to learn internals of the MCU.
If you do it properly then 2kbit program very often can be made as small as a few hundred bytes and it will work hundred times faster.
Operating registers in C is not much different from assembly, in C++ you get right away significant overhead -- although some benefits of registers still can be significant.
Libraries hide from programmers internals of MCU what is nice as it simplifies the programming and does not require to understand how MCU works, what registers are changed in what sequence.
But when you know hardware in and out -- you can squeeze from small MCU what is not possible with use of libraries (code will just not fit into the chip). MCUs are not that complicated (Atmel) to learn about it's internals -- benefits are significant.
Knowledge is a power which many avoid.

Can I use this to dim a 10w LED with an Arduino?

Currently I have this and a 12v power supply: http://www.ebay.com.au/itm/High-Power-10W-LED-Driver-MBI6651-PWM-DIM-
I want to dim a 12v 10w LED with PWM. Is there any way I can do this with an Arduino?
The pin description says this:
PWM terminal. When applied with +5v or suspended, full amount of current will be output and when connected with ground, output current will be 0.
So, as the Arduino runs off 5v, does that mean I can use the Arduino PWM to tell this board to DIM? Or I am I getting that totally wrong?
I'm a bit of an electronics noob, so forgive me if these questions are simple.
You can generate an PWM signal in the Arduino and link it to the PWM pin in the power supply, it should work as specified in the link.
PWM terminal. When applied with +5v or suspended, full amount of
current will be output and when connected with ground, output current
will be 0.
So if you generate a full signal, you will have the full power in the power supply, 100% light, 50% PWM will generate 50% power to the LED and so on...
You can check Arduino documentation for more information about how to use the PWM using analogWrite()
https://www.arduino.cc/en/Tutorial/PWM

Arduino Uno same frequency on ALL PWM pins

I'm controlling a BLDC motor with an inverter/driver IC doing the switching work.
I need to provide 6 PWM signals for the driver all at the same frequency. The exact frequency doesn't really matter, as long as its between 5kHz to 10kHz and all the PWM pins are the same.
I'm currently using an Arduino Uno, I'm not sure how to program each PWM pin (3, 5, 6, 9, 10, 11) for all the same frequency as the timers(0, 1 and 2) for particular pins have different clock speeds.
Pins 5 and 6: controlled by timer0, base frequency 62500Hz
Pins 9 and 10: controlled by timer1, base frequency 31250Hz
Pins 11 and 3: controlled by timer2, base frequency 31250Hz
timer1 and timer2 will be okay and can be scaled down by the prescaler value 8 (7812.5Hz). Not sure how to get timer0 to the same frequency?
http://playground.arduino.cc/Main/TimerPWMCheatsheet
I'm sure a work around is relatively simple. Is it possible to divide the frequency for timer0 by a number which is not a prescaler value, say 40?
Thanks in advance.
Pat.
You haven't included the chip number for your motor controller, but I'm pretty sure you won't be able to achieve what you want with six different timers. The issue is that the PWM on the different pins all have to be synchronized, not just toggled on and off for the right amount of time.
Instead, you should use a single timer and toggle all the outputs at the correct synchronization. This page has the start of an example in the section "Bit-banging Pulse Width Modulation". You would have to modify it to toggle more pins.
That example is probably still not good enough. Instead, you should be using an interrupt service routine to toggle the pins. That way, the PWM runs more independently and allows the loop function to do more.
Your routine will be attached to an output compare interrupt on a timer, and you will have to keep the values of the various PWM outputs in some volatile variables. The output compare register will be set to wake up for the next toggle. When the routine runs, it will perform the toggle and set the output compare register for the toggle. The details of the timing and synchronization will depend on the datasheet for your controller.
The loop function can read inputs and adjust the volatile variables to change the motor speed.
There are also motor drivers that do all this for you. All you have to do is provide a direction and speed, and the chip creates the 6 PWMs for you.

Resources