From 617daf62c796f1753290cff2336fd07aea9bde8e Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Mon, 13 Feb 2023 21:55:18 +0300 Subject: [PATCH] add flash.c and all stubs for common functions --- F3:F303/Multistepper/can.c | 4 +- F3:F303/Multistepper/commonproto.c | 155 +++++++++++++++ F3:F303/Multistepper/commonproto.h | 131 +++++++++++++ F3:F303/Multistepper/flash.c | 246 ++++++++++++++++++++++++ F3:F303/Multistepper/flash.h | 77 ++++++++ F3:F303/Multistepper/hardware.h | 2 + F3:F303/Multistepper/main.c | 6 +- F3:F303/Multistepper/multistepper.bin | Bin 0 -> 16836 bytes F3:F303/Multistepper/multistepper.files | 5 + F3:F303/Multistepper/proto.c | 120 +++++++++++- F3:F303/Multistepper/proto.h | 1 + F3:F303/Multistepper/steppers.h | 72 +++++++ F3:F303/Multistepper/version.inc | 4 +- 13 files changed, 816 insertions(+), 7 deletions(-) create mode 100644 F3:F303/Multistepper/commonproto.c create mode 100644 F3:F303/Multistepper/commonproto.h create mode 100644 F3:F303/Multistepper/flash.c create mode 100644 F3:F303/Multistepper/flash.h create mode 100755 F3:F303/Multistepper/multistepper.bin create mode 100644 F3:F303/Multistepper/steppers.h diff --git a/F3:F303/Multistepper/can.c b/F3:F303/Multistepper/can.c index bd259ac..9e87afc 100644 --- a/F3:F303/Multistepper/can.c +++ b/F3:F303/Multistepper/can.c @@ -142,7 +142,7 @@ void CAN_setup(uint16_t speed){ CAN->BTR = 2 << 20 | 3 << 16 | (4500/speed - 1); //| CAN_BTR_SILM | CAN_BTR_LBKM; /* (4) */ CAN->MCR &= ~CAN_MCR_INRQ; /* (5) */ tmout = 10000; - while((CAN->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) /* (6) */ + while(CAN->MSR & CAN_MSR_INAK) /* (6) */ if(--tmout == 0) break; if(tmout==0){ DBG("timeout!\n");} // accept ALL @@ -355,6 +355,8 @@ static void can_process_fifo(uint8_t fifo_num){ *RFxR = 0; // clear FOVR & FULL } +; + void usb_lp_can1_rx0_isr(){ // Rx FIFO0 (overrun) if(CAN->RF0R & CAN_RF0R_FOVR0){ // FIFO overrun CAN->RF0R &= ~CAN_RF0R_FOVR0; diff --git a/F3:F303/Multistepper/commonproto.c b/F3:F303/Multistepper/commonproto.c new file mode 100644 index 0000000..3eedd1c --- /dev/null +++ b/F3:F303/Multistepper/commonproto.c @@ -0,0 +1,155 @@ +/* + * This file is part of the multistepper project. + * Copyright 2023 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 "commonproto.h" +#include "hdr.h" +#include "proto.h" +#include "usb.h" + + +#define NOPARCHK(par) do{if(PARBASE(par) != CANMESG_NOPAR) return ERR_BADPAR;}while(0) + +extern volatile uint32_t Tms; + +// common functions for CAN and USB (or CAN only functions) + +static errcodes cu_nosuchfn(_U_ uint8_t par, _U_ int32_t *val){ return ERR_BADCMD; } + +errcodes cu_ping(_U_ uint8_t par, _U_ int32_t *val){ + return ERR_OK; +} + +static errcodes cu_reset(uint8_t par, _U_ int32_t *val){ + NOPARCHK(par); + NVIC_SystemReset(); + return ERR_OK; +} +static errcodes cu_time(uint8_t par, int32_t *val){ + NOPARCHK(par); + *val = Tms; + return ERR_OK; +} + + +errcodes cu_abspos(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_accel(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_adc(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_button(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_canid(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_diagn(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_emstop(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_eraseflash(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_esw(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_eswreact(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_goto(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_gotoz(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_gpio(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_gpioconf(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_maxspeed(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_maxsteps(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_mcut(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_mcuvdd(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_microsteps(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_minspeed(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_motflags(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_motmul(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_motreinit(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_relpos(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_relslow(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_saveconf(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_screen(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_speedlimit(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_state(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_stop(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_tmcbus(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_udata(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} +errcodes cu_usartstatus(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;} + + +const fpointer cmdlist[CCMD_AMOUNT] = { + // different commands + [CCMD_PING] = cu_ping, + [CCMD_RELAY] = cu_nosuchfn, + [CCMD_BUZZER] = cu_nosuchfn, + [CCMD_ADC] = cu_adc, + [CCMD_BUTTONS] = cu_button, + [CCMD_ESWSTATE] = cu_esw, + [CCMD_MCUT] = cu_mcut, + [CCMD_MCUVDD] = cu_mcuvdd, + [CCMD_RESET] = cu_reset, + [CCMD_TIMEFROMSTART] = cu_time, + [CCMD_PWM] = cu_nosuchfn, + [CCMD_EXT] = cu_gpio, + // configuration + [CCMD_SAVECONF] = cu_saveconf, + [CCMD_ENCSTEPMIN] = cu_nosuchfn, + [CCMD_ENCSTEPMAX] = cu_nosuchfn, + [CCMD_MICROSTEPS] = cu_microsteps, + [CCMD_ACCEL] = cu_accel, + [CCMD_MAXSPEED] = cu_maxspeed, + [CCMD_MINSPEED] = cu_minspeed, + [CCMD_SPEEDLIMIT] = cu_speedlimit, + [CCMD_MAXSTEPS] = cu_maxsteps, + [CCMD_ENCREV] = cu_nosuchfn, + [CCMD_MOTFLAGS] = cu_motflags, + [CCMD_ESWREACT] = cu_eswreact, + // motor's commands + [CCMD_ABSPOS] = cu_goto, + [CCMD_RELPOS] = cu_relpos, + [CCMD_RELSLOW] = cu_relslow, + [CCMD_EMERGSTOP] = cu_emstop, + [CCMD_EMERGSTOPALL] = cu_emstop, // without args + [CCMD_STOP] = cu_stop, + [CCMD_REINITMOTORS] = cu_motreinit, + [CCMD_MOTORSTATE] = cu_state, + [CCMD_ENCPOS] = cu_nosuchfn, + [CCMD_SETPOS] = cu_abspos, + [CCMD_GOTOZERO] = cu_gotoz, + // Leave all commands upper for back-compatability with 3steppers +}; + +const char* cancmds[CCMD_AMOUNT] = { + [CCMD_PING] = "ping", + [CCMD_ADC] = "adc", + [CCMD_BUTTONS] = "button", + [CCMD_ESWSTATE] = "esw", + [CCMD_MCUT] = "mcut", + [CCMD_MCUVDD] = "mcuvdd", + [CCMD_RESET] = "reset", + [CCMD_TIMEFROMSTART] = "time", + [CCMD_EXT] = "gpio", + [CCMD_SAVECONF] = "saveconf", + [CCMD_MICROSTEPS] = "microsteps", + [CCMD_ACCEL] = "accel", + [CCMD_MAXSPEED] = "maxspeed", + [CCMD_MINSPEED] = "minspeed", + [CCMD_SPEEDLIMIT] = "speedlimit", + [CCMD_MAXSTEPS] = "maxsteps", + [CCMD_MOTFLAGS] = "motflags", + [CCMD_ESWREACT] = "eswreact", + [CCMD_ABSPOS] = "goto", + [CCMD_RELPOS] = "relpos", + [CCMD_RELSLOW] = "relslow", + [CCMD_EMERGSTOP] = "emstop N", + [CCMD_EMERGSTOPALL] = "emstop", + [CCMD_STOP] = "stop", + [CCMD_REINITMOTORS] = "motreinit", + [CCMD_MOTORSTATE] = "state", + [CCMD_SETPOS] = "abspos", + [CCMD_GOTOZERO] = "gotoz" +}; diff --git a/F3:F303/Multistepper/commonproto.h b/F3:F303/Multistepper/commonproto.h new file mode 100644 index 0000000..8d82e67 --- /dev/null +++ b/F3:F303/Multistepper/commonproto.h @@ -0,0 +1,131 @@ +/* + * This file is part of the multistepper project. + * Copyright 2023 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 + +#include + +#ifndef _U_ +#define _U_ __attribute__((unused)) +#endif + +// message have no parameter +#define CANMESG_NOPAR (127) +// message is setter (have value) +#define SETTERFLAG (0x80) +#define ISSETTER(x) ((x & SETTERFLAG) ? 1 : 0) +// base value of parameter (even if it is a setter) +#define PARBASE(x) (x & 0x7f) + +// error codes for answer message +typedef enum{ + ERR_OK, // 0 - all OK + ERR_BADPAR, // 1 - parameter's value is wrong + ERR_BADVAL, // 2 - wrong parameter's value + ERR_WRONGLEN, // 3 - wrong message length + ERR_BADCMD, // 4 - unknown command + ERR_CANTRUN, // 5 - can't run given command due to bad parameters or other + ERR_AMOUNT // amount of error codes +} errcodes; + +// pointer to function for command execution, both should be non-NULL for common cases +// if(par &0x80) it is setter, if not - getter +// if par == 0x127 it means absense of parameter!!! +// @return CANERR_OK (0) if OK or error code +typedef errcodes (*fpointer)(uint8_t par, int32_t *val); + +enum{ + CCMD_NONE // omit zero + ,CCMD_PING // ping device + ,CCMD_RELAY // relay on/off + ,CCMD_BUZZER // buzzer on/off + ,CCMD_ADC // ADC ch# + ,CCMD_BUTTONS // buttons + ,CCMD_ESWSTATE // end-switches state + ,CCMD_MCUT // MCU temperature + ,CCMD_MCUVDD // MCU Vdd + ,CCMD_RESET // software reset + ,CCMD_TIMEFROMSTART // get time from start + ,CCMD_PWM // PWM value + ,CCMD_EXT // value on EXTx outputs + ,CCMD_SAVECONF // save configuration + ,CCMD_ENCSTEPMIN // min ticks of encoder per one step + ,CCMD_ENCSTEPMAX // max ticks of encoder per one step + ,CCMD_MICROSTEPS // get/set microsteps + ,CCMD_ACCEL // set/get acceleration/deceleration + ,CCMD_MAXSPEED // set/get maximal speed + ,CCMD_MINSPEED // set/get minimal speed + ,CCMD_SPEEDLIMIT // get limit of speed for current microsteps settings + ,CCMD_MAXSTEPS // max steps (-max..+max) + ,CCMD_ENCREV // encoder's pulses per revolution + ,CCMD_MOTFLAGS // motor flags + ,CCMD_ESWREACT // ESW reaction flags + ,CCMD_REINITMOTORS // re-init motors after configuration changing + ,CCMD_ABSPOS // current position (set/get) + ,CCMD_RELPOS // set relative steps or get steps left + ,CCMD_RELSLOW // change relative position at lowest speed + ,CCMD_EMERGSTOP // stop moving NOW + ,CCMD_STOP // smooth motor stop + ,CCMD_EMERGSTOPALL // emergency stop for all motors + ,CCMD_GOTOZERO // go to zero's ESW + ,CCMD_MOTORSTATE // motor state + ,CCMD_ENCPOS // position of encoder (independing on settings) + ,CCMD_SETPOS // set motor position + // should be the last: + ,CCMD_AMOUNT // amount of common commands +}; + +extern const fpointer cancmdlist[CCMD_AMOUNT]; +extern const char* cancmds[CCMD_AMOUNT]; + +// all common functions +errcodes cu_ping(_U_ uint8_t par, _U_ int32_t *val); +// not realized yet +errcodes cu_abspos(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_accel(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_adc(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_button(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_canid(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_diagn(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_emstop(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_eraseflash(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_esw(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_eswreact(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_goto(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_gotoz(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_gpio(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_gpioconf(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_maxspeed(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_maxsteps(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_mcut(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_mcuvdd(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_microsteps(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_minspeed(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_motflags(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_motmul(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_motreinit(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_relpos(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_relslow(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_saveconf(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_screen(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_speedlimit(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_state(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_stop(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_tmcbus(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_udata(_U_ uint8_t par, _U_ int32_t *val); +errcodes cu_usartstatus(_U_ uint8_t par, _U_ int32_t *val); diff --git a/F3:F303/Multistepper/flash.c b/F3:F303/Multistepper/flash.c new file mode 100644 index 0000000..28165ed --- /dev/null +++ b/F3:F303/Multistepper/flash.c @@ -0,0 +1,246 @@ +/* + * This file is part of the multistepper project. + * Copyright 2023 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 +#include // memcpy +#include "flash.h" +#include "hdr.h" +#include "proto.h" +#include "steppers.h" +#include "strfunc.h" +#include "usb.h" + +extern const uint32_t __varsstart, _BLOCKSIZE; + +static const uint32_t FLASH_blocksize = (uint32_t)&_BLOCKSIZE; + +// max amount of Config records stored (will be recalculate in flashstorage_init() +static uint32_t maxCnum = 1024 / sizeof(user_conf); // can't use blocksize here + +#define DEFMF {.haveencoder = 1, .donthold = 1, .eswinv = 1, .keeppos = 1} + +#define USERCONF_INITIALIZER { \ + .userconf_sz = sizeof(user_conf) \ + ,.CANspeed = 100 \ + ,.CANID = 0xaa \ + ,.microsteps = {32, 32, 32} \ + ,.accel = {500, 500, 500} \ + ,.maxspd = {2000, 2000, 2000} \ + ,.minspd = {20, 20, 20} \ + ,.maxsteps = {500000, 500000, 500000} \ + ,.encrev = {4000,4000,4000} \ + ,.encperstepmin = {17,17,17} \ + ,.encperstepmax = {23,23,23} \ + ,.motflags = {DEFMF,DEFMF,DEFMF} \ + ,.ESW_reaction = {ESW_IGNORE, ESW_IGNORE, ESW_IGNORE} \ + } +static int erase_flash(const void*, const void*); +static int write2flash(const void*, const void*, uint32_t); +// don't write `static` here, or get error: +// 'memcpy' forming offset 8 is out of the bounds [0, 4] of object '__varsstart' with type 'uint32_t' +const user_conf *Flash_Data = (const user_conf *)(&__varsstart); + +user_conf the_conf = USERCONF_INITIALIZER; + +static int currentconfidx = -1; // index of current configuration + +/** + * @brief binarySearch - binary search in flash for last non-empty cell + * any struct searched should have its sizeof() @ the first field!!! + * @param l - left index + * @param r - right index (should be @1 less than last index!) + * @param start - starting address + * @param stor_size - size of structure to search + * @return index of non-empty cell or -1 + */ +static int binarySearch(int r, const uint8_t *start, int stor_size){ + int l = 0; + while(r >= l){ + int mid = l + (r - l) / 2; + const uint8_t *s = start + mid * stor_size; + if(*((const uint16_t*)s) == stor_size){ + if(*((const uint16_t*)(s + stor_size)) == 0xffff){ // next is free + return mid; + }else{ // element is to the right + l = mid + 1; + } + }else{ // element is to the left + r = mid - 1; + } + } + return -1; // not found +} + +/** + * @brief flashstorage_init - initialization of user conf storage + * run in once @ start + */ +void flashstorage_init(){ + if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ + uint32_t flsz = FLASH_SIZE * FLASH_blocksize; // size in bytes + flsz -= (uint32_t)(&__varsstart) - FLASH_BASE; + maxCnum = flsz / sizeof(user_conf); + } + // -1 if there's no data at all & flash is clear; maxnum-1 if flash is full + currentconfidx = binarySearch((int)maxCnum-2, (const uint8_t*)Flash_Data, sizeof(user_conf)); + if(currentconfidx > -1){ + memcpy(&the_conf, &Flash_Data[currentconfidx], sizeof(user_conf)); + } +} + +// store new configuration +// @return 0 if all OK +int store_userconf(){ + // maxnum - 3 means that there always should be at least one empty record after last data + // for binarySearch() checking that there's nothing more after it! + if(currentconfidx > (int)maxCnum - 3){ // there's no more place + currentconfidx = 0; + if(erase_flash(Flash_Data, NULL)) return 1; + }else ++currentconfidx; // take next data position (0 - within first run after firmware flashing) + return write2flash((const void*)&Flash_Data[currentconfidx], &the_conf, sizeof(the_conf)); +} + +static int write2flash(const void *start, const void *wrdata, uint32_t stor_size){ + int ret = 0; + if (FLASH->CR & FLASH_CR_LOCK){ // unloch flash + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; + } + while (FLASH->SR & FLASH_SR_BSY); + if(FLASH->SR & FLASH_SR_WRPERR){ + return 1; // write protection + } + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR; // clear all flags + FLASH->CR |= FLASH_CR_PG; + const uint16_t *data = (const uint16_t*) wrdata; + volatile uint16_t *address = (volatile uint16_t*) start; + uint32_t i, count = (stor_size + 1) / 2; + for (i = 0; i < count; ++i){ + IWDG->KR = IWDG_REFRESH; + *(volatile uint16_t*)(address + i) = data[i]; + while (FLASH->SR & FLASH_SR_BSY); + if(FLASH->SR & FLASH_SR_PGERR){ + ret = 1; // program error - meet not 0xffff + break; + }else while (!(FLASH->SR & FLASH_SR_EOP)); + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR; + } + FLASH->CR |= FLASH_CR_LOCK; // lock it back + FLASH->CR &= ~(FLASH_CR_PG); + return ret; +} + +/** + * @brief erase_flash - erase N pages of flash memory + * @param start - first address + * @param end - last address (or NULL if need to erase all flash remaining) + * @return 0 if succeed + */ +static int erase_flash(const void *start, const void *end){ + int ret = 0; + uint32_t nblocks = 1, flsz = 0; + if(!end){ // erase all remaining + if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ + flsz = FLASH_SIZE * FLASH_blocksize; // size in bytes + flsz -= (uint32_t)start - FLASH_BASE; + } + }else{ // erase a part + flsz = (uint32_t)end - (uint32_t)start; + } + nblocks = flsz / FLASH_blocksize; + if(nblocks == 0 || nblocks >= FLASH_SIZE) return 1; + for(uint32_t i = 0; i < nblocks; ++i){ + IWDG->KR = IWDG_REFRESH; + /* (1) Wait till no operation is on going */ + /* (2) Clear error & EOP bits */ + /* (3) Check that the Flash is unlocked */ + /* (4) Perform unlock sequence */ + while ((FLASH->SR & FLASH_SR_BSY) != 0){} /* (1) */ + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR; /* (2) */ + /* if (FLASH->SR & FLASH_SR_EOP){ + FLASH->SR |= FLASH_SR_EOP; + }*/ + if ((FLASH->CR & FLASH_CR_LOCK) != 0){ /* (3) */ + FLASH->KEYR = FLASH_KEY1; /* (4) */ + FLASH->KEYR = FLASH_KEY2; + } + /* (1) Set the PER bit in the FLASH_CR register to enable page erasing */ + /* (2) Program the FLASH_AR register to select a page to erase */ + /* (3) Set the STRT bit in the FLASH_CR register to start the erasing */ + /* (4) Wait until the EOP flag in the FLASH_SR register set */ + /* (5) Clear EOP flag by software by writing EOP at 1 */ + /* (6) Reset the PER Bit to disable the page erase */ + FLASH->CR |= FLASH_CR_PER; /* (1) */ + FLASH->AR = (uint32_t)Flash_Data + i*FLASH_blocksize; /* (2) */ + FLASH->CR |= FLASH_CR_STRT; /* (3) */ + while(!(FLASH->SR & FLASH_SR_EOP)); + FLASH->SR |= FLASH_SR_EOP; /* (5)*/ + if(FLASH->SR & FLASH_SR_WRPERR){ /* Check Write protection error */ + ret = 1; + FLASH->SR |= FLASH_SR_WRPERR; /* Clear the flag by software by writing it at 1*/ + break; + } + FLASH->CR &= ~FLASH_CR_PER; /* (6) */ + } + return ret; +} + +int erase_storage(){ + return erase_flash(Flash_Data, NULL); +} + +int fn_dumpconf(_U_ uint32_t hash, _U_ char *args){ // "dumpconf" (3271513185) +#ifdef EBUG + USB_sendstr("flashsize="); printu(FLASH_SIZE); USB_putbyte('*'); + printu(FLASH_blocksize); USB_putbyte('='); printu(FLASH_SIZE*FLASH_blocksize); + newline(); +#endif + USB_sendstr("userconf_addr="); printuhex((uint32_t)Flash_Data); + USB_sendstr("\nuserconf_idx="); printi(currentconfidx); + USB_sendstr("\nuserconf_sz="); printu(the_conf.userconf_sz); + USB_sendstr("\ncanspeed="); printu(the_conf.CANspeed); + USB_sendstr("\ncanid="); printu(the_conf.CANID); + // motors' data + for(int i = 0; i < MOTORSNO; ++i){ + char cur = '0' + i; +#define PROPNAME(nm) do{newline(); USB_sendstr(nm); USB_putbyte(cur); USB_putbyte('=');}while(0) + PROPNAME("microsteps"); + printu(the_conf.microsteps[i]); + PROPNAME("accel"); + printu(the_conf.accel[i]); + PROPNAME("maxspeed"); + printu(the_conf.maxspd[i]); + PROPNAME("minspeed"); + printu(the_conf.minspd[i]); + PROPNAME("maxsteps"); + printu(the_conf.maxsteps[i]); + PROPNAME("encperrev"); + printu(the_conf.encrev[i]); + PROPNAME("encperstepmin"); + printu(the_conf.encperstepmin[i]); + PROPNAME("encperstepmax"); + printu(the_conf.encperstepmax[i]); + PROPNAME("motflags"); + printuhex(*((uint8_t*)&the_conf.motflags[i])); + PROPNAME("eswreaction"); + printu(the_conf.ESW_reaction[i]); +#undef PROPNAME + } + newline(); + return RET_GOOD; +} diff --git a/F3:F303/Multistepper/flash.h b/F3:F303/Multistepper/flash.h new file mode 100644 index 0000000..3ce14f6 --- /dev/null +++ b/F3:F303/Multistepper/flash.h @@ -0,0 +1,77 @@ +/* + * This file is part of the multistepper project. + * Copyright 2023 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 + +#include "hardware.h" + +#ifndef _U_ +#define _U_ __attribute__((unused)) +#endif + +// limiting values +#define MICROSTEPSMAX (512) +// (STEPS per second^2) +#define ACCELMAXSTEPS (1000) +// max encoder steps per rev +#define MAXENCREV (100000) + +// register with flash size (in blocks) +#ifndef FLASH_SIZE_REG +#define FLASH_SIZE_REG ((uint32_t)0x1FFFF7CC) +#endif + +#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG) + +// motor flags +typedef struct{ + uint8_t reverse : 1; // bit0 - reversing motor rotation + uint8_t encreverse : 1; // bit1 - reversing encoder rotation TODO: configure encoder's timer to downcounting + uint8_t haveencoder : 1; // bit2 - have encoder + uint8_t donthold : 1; // bit3 - clear power @ stop (don't hold motor when stopped) + uint8_t eswinv : 1; // bit4 - inverse end-switches + uint8_t keeppos : 1; // bit5 - keep current position (as servo motor) +} motflags_t; + +/* + * struct to save user configurations + */ +typedef struct __attribute__((packed, aligned(4))){ + uint16_t userconf_sz; // "magick number" + uint16_t CANspeed; // default CAN speed + uint16_t CANID; // identifier + uint16_t microsteps[MOTORSNO]; // microsteps amount per step + uint16_t accel[MOTORSNO]; // acceleration/deceleration (steps/s^2) + uint16_t maxspd[MOTORSNO]; // max motor speed (steps per second) + uint16_t minspd[MOTORSNO]; // min motor speed (steps per second) + uint32_t maxsteps[MOTORSNO]; // maximal amount of steps + uint16_t encrev[MOTORSNO]; // encoders' counts per revolution + uint16_t encperstepmin[MOTORSNO]; // min amount of encoder ticks per one step + uint16_t encperstepmax[MOTORSNO]; // max amount of encoder ticks per one step + motflags_t motflags[MOTORSNO]; // motor's flags + uint8_t ESW_reaction[MOTORSNO]; // end-switches reaction (esw_react) +} user_conf; + +extern user_conf the_conf; // global user config (read from FLASH to RAM) + +// data from ld-file: start address of storage + +void flashstorage_init(); +int store_userconf(); +int erase_storage(); + diff --git a/F3:F303/Multistepper/hardware.h b/F3:F303/Multistepper/hardware.h index 7faf9c2..b9c4222 100644 --- a/F3:F303/Multistepper/hardware.h +++ b/F3:F303/Multistepper/hardware.h @@ -37,6 +37,8 @@ extern const uint32_t BTNpins[BTNSNO]; // state 1 - pressed, 0 - released (pin active is zero) #define BTN_state(x) ((BTNports[x]->IDR & BTNpins[x]) ? 0 : 1) +// motors amount +#define MOTORSNO (8) extern volatile uint32_t Tms; diff --git a/F3:F303/Multistepper/main.c b/F3:F303/Multistepper/main.c index 283bef4..4d3a56f 100644 --- a/F3:F303/Multistepper/main.c +++ b/F3:F303/Multistepper/main.c @@ -17,6 +17,7 @@ */ #include "can.h" +#include "flash.h" #include "hardware.h" #include "proto.h" #include "usb.h" @@ -37,11 +38,12 @@ int main(void){ StartHSI(); SysTick_Config((uint32_t)48000); // 1ms } - hw_setup(); + flashstorage_init(); + hw_setup(); // GPIO, ADC, timers, watchdog etc. USBPU_OFF(); // make a reconnection USB_setup(); USBPU_ON(); - CAN_setup(100); + CAN_setup(the_conf.CANspeed); uint32_t ctr = 0; CAN_message *can_mesg; while(1){ diff --git a/F3:F303/Multistepper/multistepper.bin b/F3:F303/Multistepper/multistepper.bin new file mode 100755 index 0000000000000000000000000000000000000000..457e329e3d1adf88814078b2fc8018f391592b75 GIT binary patch literal 16836 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 #include "can.h" +#include "flash.h" #include "hardware.h" #include "hdr.h" #include "proto.h" +#include "commonproto.h" #include "version.inc" // software ignore buffer size @@ -371,20 +373,134 @@ int fn_canresume(_U_ uint32_t hash, _U_ char *args){ return RET_GOOD; } -int fn_reset(_U_ uint32_t hash, _U_ char *args){ +// dump base commands codes (for CAN protocol) +int fn_dumpcmd(_U_ uint32_t hash, _U_ char *args){ // "dumpcmd" (1223955823) + USB_sendstr("CANbus commands list:\n"); + for(uint16_t i = 1; i < CCMD_AMOUNT; ++i){ + if(!cancmds[i]) continue; + printu(i); + USB_sendstr(" - "); + USB_sendstr(cancmds[i]); + newline(); + } + return RET_GOOD; +} + +int fn_reset(_U_ uint32_t hash, _U_ char *args){ // "reset" (1907803304) USB_sendstr("Soft reset\n"); USB_sendall(); // wait until everything will gone NVIC_SystemReset(); return RET_GOOD; } -int fn_time(_U_ uint32_t hash, _U_ char *args){ +int fn_time(_U_ uint32_t hash, _U_ char *args){ // "time" (19148340) USB_sendstr("Time (ms): "); printu(Tms); USB_putbyte('\n'); return RET_GOOD; } +static const char* errtxt[ERR_AMOUNT] = { + [ERR_OK] = "all OK", + [ERR_BADPAR] = "wrong parameter's value", + [ERR_BADVAL] = "wrong setter of parameter", + [ERR_WRONGLEN] = "bad message length", + [ERR_BADCMD] = "unknown command", + [ERR_CANTRUN] = "temporary can't run given command", +}; +int fn_dumperr(_U_ uint32_t hash, _U_ char *args){ // "dumperr" (1223989764) + USND("Error codes:"); + for(int i = 0; i < ERR_AMOUNT; ++i){ + printu(i); USB_sendstr(" - "); + USB_sendstr(errtxt[i]); newline(); + } + return RET_GOOD; +} + +static int canusb_function(uint32_t hash, char *args){ + errcodes e = ERR_BADCMD; + uint32_t N; + int32_t val = 0; + uint8_t par = CANMESG_NOPAR; + if(*args){ + const char *n = getnum(args, &N); + if(n != args){ // get parameter + if(N >= CANMESG_NOPAR){ + USND("Wrong parameter value"); + return RET_GOOD; + } + par = (uint8_t) N; + n = strchr(n, '='); + if(n){ + const char *nxt = getnum(n, &N); + if(nxt != n){ // give flag issetter + val = (int32_t) N; + par |= SETTERFLAG; + } + } + } + } + switch(hash){ + case CMD_PING: + e = cu_ping(par, &val); + break; + default: + break; + } + + //if(e < ERR_OK || e >= ERR_AMOUNT) USND("Bad return code"); + //else + if(ERR_OK != e){ + USB_sendstr(errtxt[e]); newline(); + }else{ + USB_sendstr("OK par"); + if(par != CANMESG_NOPAR) printu(PARBASE(par)); + USB_putbyte('='); printi(val); + newline(); + } + return RET_GOOD; +} + +#define AL __attribute__ ((alias ("canusb_function"))) + +// COMMON with CAN +int fn_ping(_U_ uint32_t hash, _U_ char *args) AL; //* "ping" (10561715) +// not realized yet +int fn_abspos(_U_ uint32_t hash, _U_ char *args) AL; //* "abspos" (3056382221) +int fn_accel(_U_ uint32_t hash, _U_ char *args) AL; //* "accel" (1490521981) +int fn_adc(_U_ uint32_t hash, _U_ char *args) AL; //* "adc" (2963026093) +int fn_button(_U_ uint32_t hash, _U_ char *args) AL; //* "button" (1093508897) +int fn_canid(_U_ uint32_t hash, _U_ char *args) AL; // "canid" (2040257924) +int fn_diagn(_U_ uint32_t hash, _U_ char *args) AL; // "diagn" (2334137736) +int fn_emstop(_U_ uint32_t hash, _U_ char *args) AL; //* "emstop" (2965919005) +int fn_eraseflash(_U_ uint32_t hash, _U_ char *args) AL; // "eraseflash" (3177247267) +int fn_esw(_U_ uint32_t hash, _U_ char *args) AL; //* "esw" (2963094612) +int fn_eswreact(_U_ uint32_t hash, _U_ char *args) AL; //* "eswreact" (1614224995) +int fn_goto(_U_ uint32_t hash, _U_ char *args) AL; // "goto" (4286309438) +int fn_gotoz(_U_ uint32_t hash, _U_ char *args) AL; //* "gotoz" (3178103736) +int fn_gpio(_U_ uint32_t hash, _U_ char *args) AL; //* "gpio" (4286324660) +int fn_gpioconf(_U_ uint32_t hash, _U_ char *args) AL; // "gpioconf" (1309721562) +int fn_maxspeed(_U_ uint32_t hash, _U_ char *args) AL; //* "maxspeed" (1498078812) +int fn_maxsteps(_U_ uint32_t hash, _U_ char *args) AL; //* "maxsteps" (1506667002) +int fn_mcut(_U_ uint32_t hash, _U_ char *args) AL; //* "mcut" (4022718) +int fn_mcuvdd(_U_ uint32_t hash, _U_ char *args) AL; //* "mcuvdd" (2517587080) +int fn_microsteps(_U_ uint32_t hash, _U_ char *args) AL; //* "microsteps" (3974395854) +int fn_minspeed(_U_ uint32_t hash, _U_ char *args) AL; //* "minspeed" (3234848090) +int fn_motflags(_U_ uint32_t hash, _U_ char *args) AL; //* "motflags" (2153634658) +int fn_motmul(_U_ uint32_t hash, _U_ char *args) AL; // "motmul" (1543400099) +int fn_motreinit(_U_ uint32_t hash, _U_ char *args) AL; //* "motreinit" (199682784) +int fn_relpos(_U_ uint32_t hash, _U_ char *args) AL; //* "relpos" (1278646042) +int fn_relslow(_U_ uint32_t hash, _U_ char *args) AL; //* "relslow" (1742971917) +int fn_saveconf(_U_ uint32_t hash, _U_ char *args) AL; //* "saveconf" (141102426) +int fn_screen(_U_ uint32_t hash, _U_ char *args) AL; // "screen" (2100809349) +int fn_speedlimit(_U_ uint32_t hash, _U_ char *args) AL; //* "speedlimit" (1654184245) +int fn_state(_U_ uint32_t hash, _U_ char *args) AL; //* "state" (2216628902) +int fn_stop(_U_ uint32_t hash, _U_ char *args) AL; //* "stop" (17184971) +int fn_tmcbus(_U_ uint32_t hash, _U_ char *args) AL; // "tmcbus" (1906135955) +int fn_udata(_U_ uint32_t hash, _U_ char *args) AL; // "udata" (2736127636) +int fn_usartstatus(_U_ uint32_t hash, _U_ char *args) AL; // "usartstatus" (4007098968) + + /** * @brief cmd_parser - command parsing * @param txt - buffer with commands & data diff --git a/F3:F303/Multistepper/proto.h b/F3:F303/Multistepper/proto.h index 6d14aec..3d56d91 100644 --- a/F3:F303/Multistepper/proto.h +++ b/F3:F303/Multistepper/proto.h @@ -24,6 +24,7 @@ #include "usb.h" #define printu(x) do{USB_sendstr(u2str(x));}while(0) +#define printi(x) do{USB_sendstr(i2str(x));}while(0) #define printuhex(x) do{USB_sendstr(uhex2str(x));}while(0) extern uint8_t ShowMsgs; // show CAN messages flag diff --git a/F3:F303/Multistepper/steppers.h b/F3:F303/Multistepper/steppers.h new file mode 100644 index 0000000..1b82651 --- /dev/null +++ b/F3:F303/Multistepper/steppers.h @@ -0,0 +1,72 @@ +/* + * This file is part of the multistepper project. + * Copyright 2023 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 + +#include +#include "commonproto.h" + +// amount of tries to detect motor stall +#define NSTALLEDMAX (5) +// amount of steps to detect stalled state +#define STALLEDSTEPS (15) +// amount of tries to keep current position (need for states near problem places) +#define KEEPPOSMAX (10) + +// stepper states +typedef enum{ + STP_RELAX, // 0 - no moving + STP_ACCEL, // 1 - start moving with acceleration + STP_MOVE, // 2 - moving with constant speed + STP_MVSLOW, // 3 - moving with slowest constant speed (end of moving) + STP_DECEL, // 4 - moving with deceleration + STP_STALL, // 5 - stalled + STP_ERR // 6 - wrong/error state +} stp_state; + +// end-switches reaction +enum{ + ESW_IGNORE, // don't stop @ end-switch + ESW_ANYSTOP, // stop @ esw in any moving direction + ESW_STOPMINUS, // stop only in negative moving + ESW_AMOUNT // number of records +}; + +// find zero stages: fast -> 0, slow -> +, slow -> 0 + +void addmicrostep(uint8_t i); +void encoders_UPD(uint8_t i); + +void init_steppers(); +int32_t encoder_position(uint8_t i); +int setencpos(uint8_t i, int32_t position); +errcodes setmotpos(uint8_t i, int32_t position); + +errcodes getpos(uint8_t i, int32_t *position); +errcodes getremainsteps(uint8_t i, int32_t *position); +errcodes motor_absmove(uint8_t i, int32_t abssteps); +errcodes motor_relmove(uint8_t i, int32_t relsteps); +errcodes motor_relslow(uint8_t i, int32_t relsteps); +errcodes motor_goto0(uint8_t i); + +uint8_t geteswreact(uint8_t i); + +void emstopmotor(uint8_t i); +void stopmotor(uint8_t i); +stp_state getmotstate(uint8_t i); +void process_steppers(); diff --git a/F3:F303/Multistepper/version.inc b/F3:F303/Multistepper/version.inc index c39972c..5141e3b 100644 --- a/F3:F303/Multistepper/version.inc +++ b/F3:F303/Multistepper/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "11" -#define BUILD_DATE "2023-02-07" +#define BUILD_NUMBER "20" +#define BUILD_DATE "2023-02-13"