diff --git a/F0-nolib/CANbus_stepper/kicad/stm32.sch b/F0-nolib/CANbus_stepper/kicad/stm32.sch index 493bf7c..fee8ebb 100644 --- a/F0-nolib/CANbus_stepper/kicad/stm32.sch +++ b/F0-nolib/CANbus_stepper/kicad/stm32.sch @@ -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 diff --git a/F0-nolib/CANbus_stepper/kicad/stm32.sch-bak b/F0-nolib/CANbus_stepper/kicad/stm32.sch-bak index 1b283e8..493bf7c 100644 --- a/F0-nolib/CANbus_stepper/kicad/stm32.sch-bak +++ b/F0-nolib/CANbus_stepper/kicad/stm32.sch-bak @@ -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 diff --git a/F0-nolib/CANbus_stepper/src/canstepper.bin b/F0-nolib/CANbus_stepper/src/canstepper.bin index b2c1abe..0a5b949 100755 Binary files a/F0-nolib/CANbus_stepper/src/canstepper.bin and b/F0-nolib/CANbus_stepper/src/canstepper.bin differ diff --git a/F0-nolib/CANbus_stepper/src/flash.c b/F0-nolib/CANbus_stepper/src/flash.c index 2104943..05c18a7 100644 --- a/F0-nolib/CANbus_stepper/src/flash.c +++ b/F0-nolib/CANbus_stepper/src/flash.c @@ -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 \ } diff --git a/F0-nolib/CANbus_stepper/src/flash.h b/F0-nolib/CANbus_stepper/src/flash.h index 4f03c15..742990d 100644 --- a/F0-nolib/CANbus_stepper/src/flash.h +++ b/F0-nolib/CANbus_stepper/src/flash.h @@ -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; diff --git a/F0-nolib/CANbus_stepper/src/hardware.c b/F0-nolib/CANbus_stepper/src/hardware.c index 92d927f..8fb9b54 100644 --- a/F0-nolib/CANbus_stepper/src/hardware.c +++ b/F0-nolib/CANbus_stepper/src/hardware.c @@ -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(){ diff --git a/F0-nolib/CANbus_stepper/src/hardware.h b/F0-nolib/CANbus_stepper/src/hardware.h index bf434d3..ecdc62b 100644 --- a/F0-nolib/CANbus_stepper/src/hardware.h +++ b/F0-nolib/CANbus_stepper/src/hardware.h @@ -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 diff --git a/F0-nolib/CANbus_stepper/src/main.c b/F0-nolib/CANbus_stepper/src/main.c index aced506..e99a1e6 100644 --- a/F0-nolib/CANbus_stepper/src/main.c +++ b/F0-nolib/CANbus_stepper/src/main.c @@ -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(); diff --git a/F0-nolib/CANbus_stepper/src/proto.c b/F0-nolib/CANbus_stepper/src/proto.c index cd5c3ca..c0373f2 100644 --- a/F0-nolib/CANbus_stepper/src/proto.c +++ b/F0-nolib/CANbus_stepper/src/proto.c @@ -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" diff --git a/F0-nolib/CANbus_stepper/src/spi.c b/F0-nolib/CANbus_stepper/src/spi.c new file mode 100644 index 0000000..9dbddf2 --- /dev/null +++ b/F0-nolib/CANbus_stepper/src/spi.c @@ -0,0 +1,112 @@ +/* + * This file is part of the Stepper project. + * Copyright 2020 Edward V. Emelianov . + * + * 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 . + */ + +#include "hardware.h" +#include "proto.h" +#include "spi.h" + +#include // 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 = +}*/ diff --git a/F0-nolib/CANbus_stepper/src/spi.h b/F0-nolib/CANbus_stepper/src/spi.h new file mode 100644 index 0000000..f7c39a6 --- /dev/null +++ b/F0-nolib/CANbus_stepper/src/spi.h @@ -0,0 +1,38 @@ +/* + * This file is part of the Stepper project. + * Copyright 2020 Edward V. Emelianov . + * + * 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 . + */ + +#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__ diff --git a/F0-nolib/CANbus_stepper/src/steppers.c b/F0-nolib/CANbus_stepper/src/steppers.c index 9a21a29..6e4b597 100644 --- a/F0-nolib/CANbus_stepper/src/steppers.c +++ b/F0-nolib/CANbus_stepper/src/steppers.c @@ -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; } diff --git a/F0-nolib/CANbus_stepper/src/steppers.h b/F0-nolib/CANbus_stepper/src/steppers.h index 9635696..70606e4 100644 --- a/F0-nolib/CANbus_stepper/src/steppers.h +++ b/F0-nolib/CANbus_stepper/src/steppers.h @@ -21,10 +21,20 @@ #include -// 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();