DRV8825 works, PCB should be rebuild for ability of encoder connection

This commit is contained in:
eddyem 2020-07-27 20:58:18 +03:00
parent 8d6aeb8f00
commit d8a4c99ec7
13 changed files with 347 additions and 57 deletions

View File

@ -1,5 +1,4 @@
EESchema Schematic File Version 4
LIBS:stm32-cache
EELAYER 30 0
EELAYER END
$Descr A3 16535 11693
@ -1888,4 +1887,6 @@ F 3 "" H 1600 2240 50 0000 C CNN
$EndComp
Text Label 1200 4540 2 60 ~ 0
12Vin
Text Notes 3850 5975 0 50 ~ 0
TODO:\nESW0 & ESW2 should be @ encoder interface!\nTIM1: ch1 - PA8, ch2 - PA9\nTIM2: ch2 - PA1, PB3, \nTIM3: ch1 - PA6, PB4, ch2 - PA7, PB5
$EndSCHEMATC

View File

@ -445,7 +445,7 @@ L Device:D_Zener D7
U 1 1 59684468
P 9140 1520
F 0 "D7" H 9140 1620 50 0000 C CNN
F 1 "MM3Z3V9" H 9140 1420 50 0000 C CNN
F 1 "MM3Z4V7" H 9140 1420 50 0000 C CNN
F 2 "Diode_SMD:D_0805_2012Metric_Pad1.15x1.40mm_HandSolder" H 9140 1520 50 0001 C CNN
F 3 "" H 9140 1520 50 0000 C CNN
1 9140 1520
@ -1056,7 +1056,7 @@ L Device:D_Zener D8
U 1 1 5E7D7999
P 10080 1510
F 0 "D8" H 10080 1610 50 0000 C CNN
F 1 "MM3Z3V9" H 10080 1410 50 0000 C CNN
F 1 "MM3Z4V7" H 10080 1410 50 0000 C CNN
F 2 "Diode_SMD:D_0805_2012Metric_Pad1.15x1.40mm_HandSolder" H 10080 1510 50 0001 C CNN
F 3 "" H 10080 1510 50 0000 C CNN
1 10080 1510

View File

@ -48,10 +48,10 @@ static uint32_t maxCnum = FLASH_BLOCK_SIZE / sizeof(user_conf);
.userconf_sz = sizeof(user_conf) \
,.defflags.reverse = 0 \
,.CANspeed = 100 \
,.driver_type = DRV_NONE \
,.driver_type = DRV_8825 \
,.microsteps = 16 \
,.accdecsteps = 100 \
,.motspd = 10 \
,.accdecsteps = 25 \
,.motspd = 1000 \
,.maxsteps = 50000 \
}

View File

@ -43,7 +43,7 @@ typedef struct __attribute__((packed, aligned(4))){
uint16_t CANspeed; // default CAN speed
uint16_t microsteps; // microsteps amount per step
uint16_t accdecsteps; // amount of steps need for full acceleration/deceleration cycle
uint16_t motspd; // max motor speed ([3000 / motspd] steps per second)
uint16_t motspd; // max motor speed (steps per second)
defflags_t defflags; // default flags
uint8_t driver_type; // user's settings: type of stepper's driver
} user_conf;

View File

@ -17,6 +17,8 @@
*/
#include "hardware.h"
#include "proto.h"
#include "steppers.h"
TIM_TypeDef *TIMx = TIM15; // stepper's timer
@ -117,20 +119,30 @@ void gpio_setup(){
brdADDR = READ_BRD_ADDR();
}
// PA3 (STEP): TIM15_CH2; 48MHz -> 48kHz
// PA3 (STEP): TIM15_CH2; 48MHz -> 1MHz
void timer_setup(){
// PA3 - Tim15Ch2 (AF0)
GPIOA->AFR[0] = (GPIOA->AFR[0] & ~GPIO_AFRL_AFRL3);
GPIOA->MODER = (GPIOA->MODER & ~GPIO_MODER_MODER3) | GPIO_MODER_MODER3_AF; // set alternate output
RCC->APB2ENR |= RCC_APB2ENR_TIM15EN; // enable clocking
TIM15->CR1 &= ~TIM_CR1_CEN; // turn off timer
TIM15->CR1 = 0; // turn off timer
TIM15->CCMR1 = TIM_CCMR1_OC2M_2; // Force inactive
TIM15->PSC = 999;
TIM15->CCER = TIM_CCER_CC2E;
TIM15->CCR1 = 1; // very short pulse
TIM15->ARR = 1000;
TIM15->PSC = TIM15PSC;
TIM15->CCR2 = TIM15CCR2;
TIM15->ARR = 1000; // this value will be changed later
TIM15->CCER = TIM_CCER_CC2E; // enable PWM out
TIM15->BDTR = TIM_BDTR_MOE; // enable main output
// enable IRQ & update values
TIM15->EGR = TIM_EGR_UG;
TIM15->DIER = TIM_DIER_CC2IE;
NVIC_EnableIRQ(TIM15_IRQn);
NVIC_SetPriority(TIM15_IRQn, 0);
/*
TIM15->CCMR1 = TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1; // PWM mode 1: active->inacive
TIM15->BDTR = TIM_BDTR_MOE;
TIM15->CR1 = TIM_CR1_CEN;
*/
MSG("Timer is ON\n");
}
uint8_t refreshBRDaddr(){

View File

@ -68,12 +68,15 @@
#define RESET_UST2() do{GPIOC->BRR = 1<<14;}while(0)
#define CS_ACTIVE() do{GPIOC->BRR = 1<<14;}while(0)
#define CS_PASSIVE() do{GPIOC->BSRR = 1<<14;}while(0)
// microstepping0 (PA7), 1 (PA5) - set PP
#define UST01_CFG_PP() do{GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER5|GPIO_MODER_MODER7)) | (GPIO_MODER_MODER5_O|GPIO_MODER_MODER7_O);}while(0)
// microstepping0 (PA7), 1 (PA5), ~reset (PA6) - PP config
#define UST01_CFG_PP() do{GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER5|GPIO_MODER_MODER6|GPIO_MODER_MODER7)) | (GPIO_MODER_MODER5_O|GPIO_MODER_MODER6_O|GPIO_MODER_MODER7_O);}while(0)
#define SET_UST0() do{GPIOA->BSRR = 1<<7;}while(0)
#define SET_UST1() do{GPIOA->BSRR = 1<<5;}while(0)
#define RESET_UST0() do{GPIOA->BRR = 1<<7;}while(0)
#define RESET_UST1() do{GPIOA->BRR = 1<<5;}while(0)
// ~RESET pin (inverse), PA6
#define DRV_RESET_ON() do{GPIOA->BRR = 1<<6;}while(0)
#define DRV_RESET_OFF() do{GPIOA->BSRR = 1<<6;}while(0)
// end-switches state
#define ESW_STATE() ((GPIOB->IDR & 0x07) | ((GPIOB->IDR>>7) & 0x08))
// configure ~CS as PP output

View File

@ -102,9 +102,10 @@ int main(void){
USB_setup();
iwdg_setup();
while (1){
while (1){
IWDG->KR = IWDG_REFRESH; // refresh watchdog
if(Tms - lastT > 499){
sendbuf();
lastT = Tms;
}
can_proc();

View File

@ -218,7 +218,7 @@ TRUE_INLINE void setdefflags(char *txt){
the_conf.defflags.reverse = U&1;
break;
default:
SEND("\nFlag commands:"
SEND("\nFlag commands:\n"
"r - set/clear reverse\n"
);
}
@ -230,7 +230,7 @@ TRUE_INLINE void setters(char *txt){
uint8_t u8;
const char *drvshould = "Driver type should be one of: 2130, 4988, 8825";
const char *usshould = "Microsteps amount is a power of two: 1..512";
const char *motspdshould = "Motor speed should be from 2 to " STR(0xffff/LOWEST_SPEED_DIV);
const char *motspdshould = "Motor speed should be from 1 to " STR(10000);
txt = omit_spaces(txt);
if(!*txt){
SEND("Setters need more arguments");
@ -322,10 +322,11 @@ TRUE_INLINE void setters(char *txt){
if(U != the_conf.maxsteps){
the_conf.maxsteps = U;
userconf_changed = 1;
SEND("Set maxsteps to "); printu(U);
}
break;
case 's': // motor speed
if(nxt == txt + 1 || U < 2 || U > (0xffff/LOWEST_SPEED_DIV)){ // no number
if(nxt == txt + 1 || U < 1 || U > MAX_SPEED){ // no number
SEND(motspdshould); break;
}
if(the_conf.motspd != (uint16_t)U){
@ -339,7 +340,7 @@ TRUE_INLINE void setters(char *txt){
"a - set accdecsteps\n"
"c - set default CAN speed\n"
"d - set driver type\n"
"F - set flags"
"F - set flags\n"
"m - set microsteps\n"
"M - set maxsteps\n"
"s - set motspd\n"
@ -364,6 +365,17 @@ TRUE_INLINE void driver_commands(char *txt){
char *nxt = getnum(txt, &U);
stp_status st;
switch(cmd){
case '0':
state = STP_MOVE0;
stp_process();
break;
case '1':
state = STP_MOVE1;
stp_process();
break;
case 'd':
SEND(stp_getdrvtype());
break;
case 'e':
SEND("ESW=");
printu(ESW_STATE());
@ -371,8 +383,12 @@ TRUE_INLINE void driver_commands(char *txt){
case 'i': // init
initDriver();
break;
case 'l':
SEND("Stepsleft=");
printu(stpleft());
break;
case 'm':
if(nxt == txt + 1 || U > (INT32_MAX-1)){
if(nxt == txt || U > (INT32_MAX-1)){
SEND("Give right steps amount: from -INT32_MAX to INT32_MAX");
return;
}
@ -395,16 +411,32 @@ TRUE_INLINE void driver_commands(char *txt){
SEND("Move to given steps amount");
}
break;
case 'p':
SEND("Motpos=");
if(stppos() < 0){
U = (uint32_t) -stppos();
bufputchar('-');
}else U = (uint32_t) stppos();
printu(U);
break;
case 's':
stp_stop();
SEND("Stop motor");
break;
case 'S':
SEND(stp_getstate());
break;
default:
SEND("\nDriver commands:\n"
"0/1 - move to ESW0/ESW3 and stop there\n"
"d - current driver type\n"
"e - end-switches state\n"
"i - init stepper driver (8825, 4988, 2130)\n"
"l - steps left\n"
"m - move N steps\n"
"p - motor position\n"
"s - stop\n"
"S - state\n"
);
}
}
@ -448,6 +480,9 @@ void cmd_parser(char *txt, uint8_t isUSB){
can_accept_one();
SEND("Accept only my ID @CAN");
break;
case '1':
timer_setup();
break;
case '@':
can_accept_any();
SEND("Accept any ID @CAN");
@ -460,9 +495,6 @@ void cmd_parser(char *txt, uint8_t isUSB){
sendbuf();
Jump2Boot();
break;
case 'd':
dump_userconf();
break;
case 'g':
SEND("Board address: ");
printuhex(refreshBRDaddr());
@ -498,7 +530,6 @@ void cmd_parser(char *txt, uint8_t isUSB){
"@ - accept any IDs\n"
"a - get raw ADC values\n"
"b - switch to bootloader\n"
"d - dump userconf\n"
"D? - stepper driver commands\n"
"g - get board address\n"
"j - get MCU temperature\n"

View File

@ -0,0 +1,112 @@
/*
* This file is part of the Stepper project.
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "hardware.h"
#include "proto.h"
#include "spi.h"
#include <string.h> // memcpy
// buffers for DMA rx/tx
static uint8_t inbuff[SPIBUFSZ], outbuf[SPIBUFSZ];
spiStatus SPI_status = SPI_NOTREADY;
//SPI: PA5 - SCK, PA6 -MISO, PA7 - MOSI, PC14 - ~CS
void spi_setup(){
/* (1) Select AF mode on PA5, PA6, PA7 */
/* (2) AF0 for SPI1 signals */
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER5 | GPIO_MODER_MODER6 | GPIO_MODER_MODER7)) |
(GPIO_MODER_MODER5_AF | GPIO_MODER_MODER6_AF | GPIO_MODER_MODER7_AF); /* (1) */
GPIOA->AFR[0] = (GPIOA->AFR[0] & (GPIO_AFRL_AFRL5 | GPIO_AFRL_AFRL6 | GPIO_AFRL_AFRL7)); /* (2) */
// Configure DMA SPI
/* Enable the peripheral clock DMA11 */
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
/* DMA1 Channel2 SPI1_RX config */
/* (1) Peripheral address */
/* (2) Memory address */
/* (3) Data size */
/* (4) Memory increment */
/* Peripheral to memory */
/* 8-bit transfer */
DMA1_Channel2->CPAR = (uint32_t)&(SPI1->DR); /* (1) */
DMA1_Channel2->CMAR = (uint32_t)inbuff; /* (2) */
DMA1_Channel2->CNDTR = SPIBUFSZ; /* (3) */
DMA1_Channel2->CCR |= DMA_CCR_MINC | DMA_CCR_EN; /* (4) */
/* DMA1 Channel3 SPI1_TX config */
/* (5) Peripheral address */
/* (6) Memory address */
/* (7) Memory increment */
/* Memory to peripheral*/
/* 8-bit transfer */
/* Transfer complete IT */
DMA1_Channel3->CPAR = (uint32_t)&(SPI1->DR); /* (5) */
DMA1_Channel3->CMAR = (uint32_t)outbuf; /* (6) */
DMA1_Channel3->CCR |= DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_DIR; /* (7) */
/* Configure IT */
/* (8) Set priority for DMA1_Channel2_3_IRQn */
/* (9) Enable DMA1_Channel2_3_IRQn */
NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0); /* (8) */
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /* (9) */
// configure SPI (transmit only)
/* Enable the peripheral clock SPI1 */
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
/* Configure SPI1 in master */
/* (1) Master selection, BR: Fpclk/256 CPOL and CPHA at zero (rising first edge) */
/* (2) TX and RX with DMA, slave select output enabled, 8-bit Rx fifo */
/* (3) Enable SPI1 */
SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR; /* (1) */
SPI1->CR2 = SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN | SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0; /* (2) */
SPI1->CR1 |= SPI_CR1_SPE; /* (3) */
SPI_status = SPI_READY;
}
void dma1_channel2_3_isr(){
if(DMA1->ISR & DMA_ISR_TCIF3){
DMA1->IFCR |= DMA_IFCR_CTCIF3;
SPI_status = SPI_READY;
#ifdef EBUG
SEND("rxCNDTR="); printu(DMA1_Channel2->CNDTR); SEND(", txCNDTR="); printu(DMA1_Channel3->CNDTR); newline(); sendbuf();
#endif
}
}
/**
* @brief SPI_transmit - transmit data over SPI DMA
* @param buf - data to transmit
* @param len - its length
* @return 0 if all OK
*/
uint8_t SPI_transmit(const uint8_t *buf, uint8_t len){
if(!buf || !len || len > SPIBUFSZ) return 1; // bad data format
if(SPI_status != SPI_READY) return 2; // spi not ready to transmit data
DMA1_Channel3->CCR &=~ DMA_CCR_EN;
memcpy(outbuf, buf, len);
DMA1_Channel3->CNDTR = len;
SPI_status = SPI_BUSY;
#ifdef EBUG
SEND("SPI tx "); printu(len); SEND(" bytes\n"); sendbuf();
#endif
DMA1_Channel3->CCR |= DMA_CCR_EN;
return 0;
}
/*
static uint8_t *SPI_receive(uint8_t *len){
if(!len || SPI_status != SPI_READY) return NULL;
*len =
}*/

View File

@ -0,0 +1,38 @@
/*
* This file is part of the Stepper project.
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef SPI_H__
#define SPI_H__
#include "stm32f0.h"
#define SPIBUFSZ 64
typedef enum{
SPI_NOTREADY,
SPI_READY,
SPI_BUSY
} spiStatus;
extern spiStatus SPI_status;
void spi_setup();
uint8_t SPI_transmit(const uint8_t *buf, uint8_t len);
#endif // SPI_H__

View File

@ -18,6 +18,7 @@
#include "flash.h"
#include "hardware.h"
#include "proto.h"
#include "spi.h"
#include "steppers.h"
static drv_type driver = DRV_NONE;
@ -32,11 +33,6 @@ static const uint16_t maxusteps[] = {
[DRV_2130] = 256
};
// amount of steps need for full acceleration/deceleration cycle
#define ACCDECSTEPS (the_conf.accdecsteps)
// amount of microsteps in each step
#define USTEPS (the_conf.microsteps)
int32_t mot_position = -1; // current position of motor (from zero endswitch, -1 means inactive)
uint32_t steps_left = 0; // amount of steps left
stp_state state = STP_SLEEP;// current state of motor
@ -44,6 +40,7 @@ stp_state state = STP_SLEEP;// current state of motor
static uint16_t stplowarr, stphigharr, stpsteparr;
static int8_t dir = 0; // moving direction: -1 (negative) or 1 (positive)
#if 0
/**
* @brief checkDrv - test if driver connected
*/
@ -109,17 +106,19 @@ static void checkDrv(){
ret:
DRV_DISABLE();
EN_CFG_OUT(); // return OUT conf
SLEEP_OFF();
SLEEP_ON();
SLP_CFG_OUT();
#ifdef EBUG
sendbuf();
#endif
}
#endif
static drv_type ini2130(){ // init 2130: SPI etc.
if(driver != DRV_2130) return DRV_MAILF;
;
return DRV_MAILF;
VIO_ON();
spi_setup();
CS_ACTIVE();
return DRV_2130;
}
static drv_type ini4988_8825(){ // init 4988 or 8825
@ -135,7 +134,9 @@ static drv_type ini4988_8825(){ // init 4988 or 8825
SEND("Configure microstepping first\n");
return DRV_MAILF;
}
if(driver == DRV_4988) VIO_ON();
// init microstepping pins and set config
DRV_RESET_ON(); // reset counters
UST01_CFG_PP();
uint8_t PINS = 0;
if(the_conf.microsteps == 16 && driver == DRV_4988) PINS = 7; // microstepping settings for 4988 in 1/16 differs from 8825
@ -153,6 +154,8 @@ static drv_type ini4988_8825(){ // init 4988 or 8825
timer_setup();
// recalculate defaults
stp_chspd();
DRV_RESET_OFF(); // normal mode
SLEEP_OFF();
SEND("Init OK\n");
return driver;
}
@ -162,6 +165,10 @@ static drv_type ini4988_8825(){ // init 4988 or 8825
* @return driver type
*/
drv_type initDriver(){
stp_stop();
DRV_DISABLE();
VIO_OFF();
SLEEP_ON();
if(driver != DRV_NOTINIT){ // reset all settings
MSG("clear GPIO & other setup\n");
STEP_TIMER_OFF();
@ -169,7 +176,8 @@ drv_type initDriver(){
gpio_setup(); // reset pins control
}
driver = the_conf.driver_type;
checkDrv();
//checkDrv();
state = STP_SLEEP;
if(driver > DRV_MAX-1) return (driver = DRV_NONE);
MSG("init pins\n");
switch(driver){
@ -192,14 +200,55 @@ uint16_t getMaxUsteps(){
return maxusteps[driver];
}
static const char *stpstates[] = {
[STP_SLEEP] = "Relax"
,[STP_ACCEL] = "Accelerated"
,[STP_MOVE] = "Moving"
,[STP_MVSLOW] = "Slowmoving"
,[STP_DECEL] = "Decelerated"
,[STP_STOP] = "Stopping"
,[STP_STOPZERO] = "Stop0"
,[STP_MOVE0] = "Moveto0"
,[STP_MOVE1] = "Moveto1"
};
const char *stp_getstate(){
return stpstates[state];
}
static const char *drvtypes[] = {
[DRV_NONE] = "Absent"
,[DRV_NOTINIT] = "NotInit"
,[DRV_MAILF] = "Mailfunction"
,[DRV_8825] = "DRV8825"
,[DRV_4988] = "A4988"
,[DRV_2130] = "TMC2130"
};
const char *stp_getdrvtype(){
return drvtypes[driver];
}
void stp_chspd(){
int i;
for(i = 0; i < 2; ++i){
uint16_t spd = the_conf.motspd;
stplowarr = spd;
stphigharr = spd * LOWEST_SPEED_DIV;
stpsteparr = (spd * (LOWEST_SPEED_DIV - 1)) / ((uint16_t)ACCDECSTEPS) + 1;
uint32_t arrval = DEFTICKSPERSEC / the_conf.motspd;
arrval /= the_conf.microsteps;
if(arrval > 0xffff){
SEND("The speed is too little for this microstepping settings, set min available\n");
arrval = 0xffff;
}else if(arrval < TIM15ARRMIN){
SEND("The speed is too big for this microstepping settings, set max available\n");
arrval = TIM15ARRMIN;
}
stplowarr = (uint16_t)arrval;
arrval *= LOW_SPEED_DIVISOR;
if(arrval > 0xffff) arrval = 0xffff;
stphigharr = (uint16_t)arrval;
stpsteparr = (stphigharr - stplowarr) / ((uint16_t)the_conf.accdecsteps);
if(stpsteparr < 1) stpsteparr = 1;
#ifdef EBUG
SEND("stplowarr="); printu(stplowarr);
SEND("\nstphigharr="); printu(stphigharr);
SEND("\nstpsteparr="); printu(stpsteparr);
newline();
#endif
}
// check end-switches for stepper motors
@ -221,8 +270,10 @@ void stp_process(){
case STP_MVSLOW:
if((esw&1) && dir == -1){ // move through ESW0
state = STP_STOPZERO; // stop @ end-switch
MSG("ESW0 active\n");
}else if((esw&8) && dir == 1){ // move through ESW3
state = STP_STOP; // stop @ ESW3
MSG("ESW3 active\n");
}
break;
default: // stopping states - do nothing
@ -233,17 +284,26 @@ void stp_process(){
// move motor to `steps` steps, @return 0 if all OK
stp_status stp_move(int32_t steps){
if(state != STP_SLEEP && state != STP_MOVE0 && state != STP_MOVE1) return STPS_ACTIVE;
if(steps == 0)
if(steps == 0){
MSG("Zero move\n");
return STPS_ZEROMOVE;
if(the_conf.maxsteps && steps > (int32_t)the_conf.maxsteps) return STPS_TOOBIG;
}
if(the_conf.maxsteps && steps > (int32_t)the_conf.maxsteps){
MSG("Too much steps\n");
return STPS_TOOBIG;
}
int8_t d;
if(steps < 0){
MSG("Negative direction\n");
d = -1;
steps = -steps;
}else d = 1; // positive direction
// check end-switches
uint8_t esw = ESW_STATE();
if(((esw&1) && d == -1) || ((esw&8) && d == 1)) return STPS_ONESW; // can't move through esw
if(((esw&1) && d == -1) || ((esw&8) && d == 1)){
MSG("Stay @esw\n");
return STPS_ONESW; // can't move through esw
}
dir = d;
// change value of DIR pin
if(the_conf.defflags.reverse){
@ -264,14 +324,16 @@ stp_status stp_move(int32_t steps){
TIMx->ARR = stphigharr;
TIMx->CCMR1 = TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1; // PWM mode 1: active->inacive, preload enable
TIMx->CR1 |= TIM_CR1_CEN;
if(steps < ACCDECSTEPS*2) state = STP_MVSLOW; // move without acceleration
if(steps < the_conf.accdecsteps*2) state = STP_MVSLOW; // move without acceleration
else state = STP_ACCEL; // move with acceleration
MSG("Start moving\n");
return STPS_ALLOK;
}
// change ARR value
void stp_chARR(uint32_t val){
if(val < 2) val = 2;
if(val < TIM15ARRMIN) val = TIM15ARRMIN;
else if(val > 0xffff) val = 0xffff;
TIMx->ARR = (uint32_t)val;
}
@ -292,51 +354,67 @@ void stp_stop(){ // stop motor by demand or @ end-switch
void timer_isr(){
static uint16_t ustep = 0;
uint16_t tmp, arrval;
if(USTEPS == ++ustep){ // prevent stop @ not full step
TIMx->SR = 0;
if(the_conf.microsteps == ++ustep){ // prevent stop @ not full step
ustep = 0;
if(state == STP_STOPZERO)
if(state == STP_STOPZERO){
MSG("Stop @zero\n");
mot_position = 0;
else{
if(0 == --steps_left) state = STP_STOP;
}else{
if(0 == --steps_left){
MSG("End moving\n");
state = STP_STOP;
}
mot_position += dir;
}
//SEND("Left ");printu(steps_left); newline(); sendbuf();
}else return;
//SEND("state="); printu(state); newline(); sendbuf();
switch(state){
case STP_ACCEL: // acceleration phase
//SEND("ACC"); newline(); sendbuf();
arrval = (uint16_t)TIMx->ARR - stpsteparr;
tmp = stplowarr;
if(arrval <= tmp || arrval > stphigharr){
arrval = tmp;
state = STP_MOVE; // end of acceleration phase
MSG("Accel end\n");
}
TIMx->ARR = arrval;
break;
case STP_DECEL: // deceleration phase
//SEND("DEC"); newline(); sendbuf();
arrval = (uint16_t)TIMx->ARR + stpsteparr;
tmp = stphigharr;
if(arrval >= tmp || arrval < stplowarr){
arrval = tmp;
state = STP_MVSLOW; // end of deceleration phase, move @ lowest speed
MSG("Decel end\n");
}
TIMx->ARR = arrval;
break;
case STP_MOVE: // moving with constant speed phases
if(steps_left <= ACCDECSTEPS){
//SEND("MOVE"); newline(); sendbuf();
if(steps_left <= the_conf.accdecsteps){
MSG("Decel start\n");
state = STP_DECEL; // change moving status to decelerate
}
break;
case STP_MVSLOW:
//SEND("MVSLOW"); newline(); sendbuf();
// nothing to do here: all done before switch()
break;
default: // STP_STOP, STP_STOPZERO
//SEND("DEFAULT"); newline(); sendbuf();
ustep = 0;
TIMx->CCMR1 = TIM_CCMR1_OC1M_2; // Force inactive
TIMx->CCMR1 = TIM_CCMR1_OC2M_2; // Force inactive
TIMx->CR1 &= ~TIM_CR1_CEN; // stop timer
DRV_DISABLE();
CLEAR_DIR();
dir = 0;
steps_left = 0;
state = STP_SLEEP;
MSG("Stop motor\n");
break;
}
TIMx->SR = 0;
}

View File

@ -21,10 +21,20 @@
#include <stm32f0.h>
// the lowest speed equal to [max speed] / LOWEST_SPEED_DIV
#define LOWEST_SPEED_DIV 30
// TIM15->PSC for 4MHz (48MHz/(PSC+1))
#define TIM15PSC 47
// TIM15->CCR2: 20us for pulse duration, according to datasheet 1.9us is enough
#define TIM15CCR2 20
// TIM15->ARR minimum value
#define TIM15ARRMIN (2*TIM15CCR2)
// timer settings give DEFTICKSPERSEC ticks per second
#define DEFTICKSPERSEC (48000000/(TIM15PSC+1))
// max speed (steps per second)
#define MAX_SPEED 10000
// The lowest speed @acceleration (= current speed / LOW_SPEED_DIVISOR)
#define LOW_SPEED_DIVISOR 30
// min/max value of ACCDECSTEPS
#define ACCDECSTEPS_MIN 30
#define ACCDECSTEPS_MIN 1
#define ACCDECSTEPS_MAX 2000
typedef enum{
@ -59,14 +69,18 @@ typedef enum{
} stp_status;
extern int32_t mot_position;
#define stppos() (mot_position)
extern uint32_t steps_left;
#define stpleft() (steps_left)
extern stp_state state;
#define stp_getstate() (state)
#define stpstate() (state)
drv_type initDriver();
drv_type getDrvType();
uint16_t getMaxUsteps();
const char *stp_getstate();
const char *stp_getdrvtype();
void stp_chspd();
stp_status stp_move(int32_t steps);
void stp_stop();