diff --git a/F0:F030,F042,F072/3steppersLB/flash.c b/F0:F030,F042,F072/3steppersLB/flash.c index bef6a36..63ef062 100644 --- a/F0:F030,F042,F072/3steppersLB/flash.c +++ b/F0:F030,F042,F072/3steppersLB/flash.c @@ -94,7 +94,7 @@ static int binarySearch(int r, const uint8_t *start, int stor_size){ */ void flashstorage_init(){ if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ - uint32_t flsz = FLASH_SIZE * blocksize; // size in bytes + uint32_t flsz = FLASH_SIZE * 1024; // size in bytes flsz -= (uint32_t)(&__varsstart) - FLASH_BASE; maxCnum = flsz / sizeof(user_conf); } @@ -155,7 +155,7 @@ static int erase_flash(const void *start, const void *end){ uint32_t nblocks = 1, flsz = 0; if(!end){ // erase all remaining if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ - flsz = FLASH_SIZE * blocksize; // size in bytes + flsz = FLASH_SIZE * 1024; // size in bytes flsz -= (uint32_t)start - FLASH_BASE; } }else{ // erase a part diff --git a/F0:F030,F042,F072/Snippets/Flash_EEPROM/flash.c b/F0:F030,F042,F072/Snippets/Flash_EEPROM/flash.c index eea44e7..e48acd3 100644 --- a/F0:F030,F042,F072/Snippets/Flash_EEPROM/flash.c +++ b/F0:F030,F042,F072/Snippets/Flash_EEPROM/flash.c @@ -96,7 +96,7 @@ static int binarySearch(int r, const uint8_t *start, int stor_size){ */ void flashstorage_init(){ if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ - uint32_t flsz = FLASH_SIZE * blocksize; // size in bytes + uint32_t flsz = FLASH_SIZE * 1024; // size in bytes flsz -= (uint32_t)(&__varsstart) - FLASH_BASE; maxCnum = flsz / sizeof(user_conf); //SEND("flsz="); printu(flsz); @@ -165,7 +165,7 @@ static int erase_flash(const void *start, const void *end){ uint32_t nblocks = 1, flsz = 0; if(!end){ // erase all remaining if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ - flsz = FLASH_SIZE * blocksize; // size in bytes + flsz = FLASH_SIZE * 1024; // size in bytes flsz -= (uint32_t)start - FLASH_BASE; } }else{ // erase a part diff --git a/F0:F030,F042,F072/usbcan_gpio/flash.c b/F0:F030,F042,F072/usbcan_gpio/flash.c index ee1d11f..d8d64ad 100644 --- a/F0:F030,F042,F072/usbcan_gpio/flash.c +++ b/F0:F030,F042,F072/usbcan_gpio/flash.c @@ -103,7 +103,7 @@ static int binarySearch(int r, const uint8_t *start, int stor_size){ */ void flashstorage_init(){ if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ - uint32_t flsz = FLASH_SIZE * blocksize; // size in bytes + uint32_t flsz = FLASH_SIZE * 1024; // size in bytes flsz -= (uint32_t)(&__varsstart) - FLASH_BASE; maxCnum = flsz / sizeof(user_conf); } @@ -164,7 +164,7 @@ static int erase_flash(const void *start, const void *end){ uint32_t nblocks = 1, flsz = 0; if(!end){ // erase all remaining if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ - flsz = FLASH_SIZE * blocksize; // size in bytes + flsz = FLASH_SIZE * 1024; // size in bytes flsz -= (uint32_t)start - FLASH_BASE; } }else{ // erase a part diff --git a/G0:G070,G0B1/flash/flash.c b/G0:G070,G0B1/flash/flash.c index 9a6ab8d..49dea89 100644 --- a/G0:G070,G0B1/flash/flash.c +++ b/G0:G070,G0B1/flash/flash.c @@ -81,7 +81,7 @@ static int binarySearch(int r, const uint8_t *start, int stor_size){ */ void flashstorage_init(){ if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ - uint32_t flsz = FLASH_SIZE * blocksize; // size in bytes + uint32_t flsz = FLASH_SIZE * 1024; // size in bytes flsz -= (uint32_t)(&__varsstart) - FLASH_BASE; maxCnum = flsz / sizeof(user_conf); } @@ -149,7 +149,7 @@ static int erase_flash(const void *start, const void *end){ if(!start) return 1; uint32_t startb = (((uint32_t)start - FLASH_BASE) + blocksize - 1) / blocksize, endb; if(!end){ // erase all remaining - endb = FLASH_SIZE / blocksize; + endb = FLASH_SIZE * 1024 / blocksize; }else{ // erase a part endb = (((uint32_t)end - FLASH_BASE) + blocksize - 1) / blocksize; } diff --git a/G4:G431/Servo/commproto.cpp b/G4:G431/Servo/commproto.cpp index e08263d..eb7362a 100644 --- a/G4:G431/Servo/commproto.cpp +++ b/G4:G431/Servo/commproto.cpp @@ -22,7 +22,7 @@ extern "C"{ #include #include "commproto.h" -//#include "flash.h" +#include "flash.h" #include "hardware.h" #include "servo.h" #include "strfunc.h" @@ -42,12 +42,22 @@ extern volatile uint32_t Tms; // list of all commands and handlers #define COMMAND_TABLE \ + COMMAND(dumpconf, "dump current config") \ + COMMAND(eraseflash, "erase full flash storage") \ COMMAND(help, "show this help") \ + COMMAND(maxpos, "servoN maximal allowed position (conf)") \ + COMMAND(maxspeed, "servoN maximal allowed speed (from 1 to " STR(SERVO_MAXSPEED) ", conf)") \ COMMAND(mcureset, "reset MCU") \ - COMMAND(servo, "get/set servoN value, mks (from " STR(SG90_MINPULSE) " to " STR(SG90_MAXPULSE) ")") \ - COMMAND(servopos, "get/set servoN target position with given speed") \ - COMMAND(servospeed, "get/set servoN speed, mks per 20ms (1.." STR(SG90_MAXSPEED) ")") \ + COMMAND(minpos, "servoN minimal allowed position (conf)") \ + COMMAND(readconf, "re-read config from flash") \ + COMMAND(saveconf, "save config to flash") \ + COMMAND(servo, "servoN value, mks (in allowed range)") \ + COMMAND(servopos, "servoN target position with given speed") \ + COMMAND(servospeed, "servoN speed, mks per 20ms (1..maxspeed)") \ + COMMAND(startpos, "servoN started position (from " STR(SERVO_MINPULSE) " to " STR(SERVO_MAXPULSE) ", conf)") \ COMMAND(time, "show current time (ms)") \ + COMMAND(usart_speed,"speed of USART (set after reset, conf)") \ + typedef struct { const char *name; @@ -82,7 +92,8 @@ const char *EQ = " = "; // equal sign for getters #define CMDEQ() do{SEND(cmd); SEND(EQ);}while(0) // send `commandXXX = ` #define CMDEQP(x) do{SEND(cmd); SEND(u2str((uint32_t)x)); SEND(EQ);}while(0) - +// the same as last but with command as option and uint value +#define SHOWPARU(cmd, x, val) do{SEND(cmd); SEND(u2str((uint32_t)x)); SEND(EQ); SEND(u2str(val));}while(0) /** * @brief splitargs - get command parameter and setter from `args` @@ -117,8 +128,8 @@ static bool argsvals(char *args, int32_t *parno, int32_t *parval){ if(!setter) return false; int32_t I32; char *next = getint(setter, &I32); - if(next != setter && parval){ - *parval = I32; + if(next != setter){ + if(parval) *parval = I32; return true; } return false; @@ -176,69 +187,84 @@ static errcodes_t cmd_mcureset(const char*, char*){ NVIC_SystemReset(); return ERR_CANTRUN; // never reached } -#if 0 + static errcodes_t cmd_saveconf(const char*, char*){ if(store_userconf()) return ERR_CANTRUN; return ERR_OK; } static errcodes_t cmd_eraseflash(const char*, char*){ - if(erase_storage(-1)) return ERR_CANTRUN; + if(erase_storage()) return ERR_CANTRUN; return ERR_OK; } -static errcodes_t cmd_readconf(const char*, char* args){ - int32_t CHno = -1; - splitargs(args, &CHno); - if(CHno < 0 || CHno >= SENSORS_AMOUNT) return ERR_BADPAR; - as3935_channel = static_cast(CHno); - uint8_t par; - if(!as3935_get_gain(&par)) return ERR_CANTRUN; - the_conf.spars[CHno].AFE_GB = par; - if(!as3935_get_wdthres(&par)) return ERR_CANTRUN; - the_conf.spars[CHno].WDTH = par; - if(!as3935_get_nflev(&par)) return ERR_CANTRUN; - the_conf.spars[CHno].NF_LEV = par; - if(!as3935_get_srej(&par)) return ERR_CANTRUN; - the_conf.spars[CHno].SREJ = par; - if(!as3935_get_minnumlig(&par)) return ERR_CANTRUN; - the_conf.spars[CHno].MIN_NUM_LIG = par; - if(!as3935_get_maskdist(&par)) return ERR_CANTRUN; - the_conf.spars[CHno].MASK_DIST = par; - if(!as3935_get_lco_fdiv(&par)) return ERR_CANTRUN; - the_conf.spars[CHno].LCO_FDIV = par; - if(!as3935_get_tuncap(&par)) return ERR_CANTRUN; - the_conf.spars[CHno].TUN_CAP = par; +static errcodes_t cmd_readconf(const char*, char*){ + flashstorage_init(); return ERR_OK; } -static void showpar(const char *par, uint8_t n, uint8_t v){ - char c[2]; - c[0] = '0' + n; c[1] = 0; - SEND(par); SEND(c); SEND(EQ); - SEND(u2str(v)); -} - static errcodes_t cmd_dumpconf(const char*, char*){ SEND("userconf_sz="); SEND(u2str(the_conf.userconf_sz)); - SEND("\ncurr_idx="); SEND(u2str(currentconfidx)); + SEND("\ncurr_idx="); SEND(i2str(currentconfidx)); SEND("\ncapacity="); SEND(u2str(maxCnum-2)); - cmd_setiface("\nsetiface", NULL); - cmd_restonstart("restonstart", NULL); - for(int i = 0; i < SENSORS_AMOUNT; ++i){ - showpar("gain", i, the_conf.spars[i].AFE_GB); - showpar("\nlco_fdiv", i, the_conf.spars[i].LCO_FDIV); - showpar("\nmaskdist", i, the_conf.spars[i].MASK_DIST); - showpar("\nminnumlig", i, the_conf.spars[i].MIN_NUM_LIG); - showpar("\nnflev", i, the_conf.spars[i].NF_LEV); - showpar("\nsrej", i, the_conf.spars[i].SREJ); - showpar("\ntuncap", i, the_conf.spars[i].TUN_CAP); - showpar("\nwdthres", i, the_conf.spars[i].WDTH); - SEND("\n"); + SEND("\nusart_speed="); SEND(u2str(the_conf.usart_speed)); + for(int i = 0; i < SERVO_AMOUNT ; ++i){ + SHOWPARU("\nstartpos", i, the_conf.startpulse[i]); + SHOWPARU("\nminpos", i, the_conf.minpulse[i]); + SHOWPARU("\nmaxpos", i, the_conf.maxpulse[i]); + SHOWPARU("\nmaxspeed", i, the_conf.maxspeed[i]); } + SEND("\n"); + return ERR_AMOUNT; +} + +static errcodes_t cmd_usart_speed(const char* cmd, char* args){ + int32_t val; + if(argsvals(args, NULL, &val)){ // setter + if(val < MIN_USART_SPEED || val > MAX_USART_SPEED) return ERR_BADVAL; + the_conf.usart_speed = (uint32_t) val; + } + CMDEQ(); + SEND(u2str(the_conf.usart_speed)); + SEND("\n"); + return ERR_AMOUNT; +} + +static errcodes_t servo_valP(const char* cmd, char* args, uint16_t *confval){ + int32_t val, parno; + if(argsvals(args, &parno, &val)){ // setter + if(parno < 0 || parno >= SERVO_AMOUNT) return ERR_BADPAR; + if(val < SERVO_MINPULSE || val > SERVO_MAXPULSE) return ERR_BADVAL; + confval[parno] = (uint16_t) val; + } + SHOWPARU(cmd, parno, confval[parno]); + SEND("\n"); + return ERR_AMOUNT; +} + +static errcodes_t cmd_maxpos(const char* cmd, char* args){ + return servo_valP(cmd, args, the_conf.maxpulse); +} + +static errcodes_t cmd_minpos(const char* cmd, char* args){ + return servo_valP(cmd, args, the_conf.minpulse); +} + +static errcodes_t cmd_startpos(const char* cmd, char* args){ + return servo_valP(cmd, args, the_conf.startpulse); +} + +static errcodes_t cmd_maxspeed(const char* cmd, char* args){ + int32_t val, parno; + if(argsvals(args, &parno, &val)){ // setter + if(parno < 0 || parno >= SERVO_AMOUNT) return ERR_BADPAR; + if(val < 1 || val > SERVO_MAXSPEED) return ERR_BADVAL; + the_conf.maxspeed[parno] = (uint16_t) val; + } + SHOWPARU(cmd, parno, the_conf.maxspeed[parno]); + SEND("\n"); return ERR_AMOUNT; } -#endif static errcodes_t cmd_help(const char*, char*){ SEND(REPOURL); diff --git a/G4:G431/Servo/flash.c b/G4:G431/Servo/flash.c new file mode 100644 index 0000000..7b64cdf --- /dev/null +++ b/G4:G431/Servo/flash.c @@ -0,0 +1,186 @@ +/* + * This file is part of the flash 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 "servo.h" + +extern const uint32_t __varsstart, _BLOCKSIZE; + +static const uint32_t blocksize = (uint32_t)&_BLOCKSIZE; + +// max amount of Config records stored (will be recalculate in flashstorage_init() +uint32_t maxCnum = 1024 / sizeof(user_conf); // can't use blocksize here + +#define USERCONF_INITIALIZER { \ + .userconf_sz = sizeof(user_conf) \ + ,.usart_speed = 115200 \ + ,.startpulse = {SG90_MIDPULSE, SG90_MIDPULSE, SG90_MIDPULSE, SG90_MIDPULSE} \ + ,.minpulse = {SG90_MINPULSE, SG90_MINPULSE, SG90_MINPULSE, SG90_MINPULSE} \ + ,.maxpulse = {SG90_MAXPULSE, SG90_MAXPULSE, SG90_MAXPULSE, SG90_MAXPULSE} \ + ,.maxspeed = {SG90_MAXSPEED, SG90_MAXSPEED, SG90_MAXSPEED, SG90_MAXSPEED} \ + } + +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; + +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 * 1024; // 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; + } + // FLASH_SR_BSY2 for some + uint32_t count = (stor_size + 7) / 8; + volatile uint32_t *address = (volatile uint32_t*) start; + const uint32_t *data = (const uint32_t*) wrdata; + for(uint32_t i = 0; i < count; ++i){ + while (FLASH->SR & (FLASH_SR_BSY)); // 1: check BSY + if(FLASH->SR & FLASH_SR_WRPERR){ // 2: check errors + return 1; // write protection + } + FLASH->SR = 0xffff; // clear all flags + FLASH->CR |= FLASH_CR_PG; // 3: set PG bit + IWDG->KR = IWDG_REFRESH; + *address++ = *data++; // 4: write both 32 bit words + *address++ = *data++; + while(FLASH->SR & FLASH_SR_BSY); + if(FLASH->SR & FLASH_SR_PGSERR){ + ret = 1; // program error - meet not 0xffff + break; + }/*else{ + for(int _ = 0; _ < 9999 && (!(FLASH->SR & FLASH_SR_EOP)); ++_); + }*/ + FLASH->SR = 0xffff; + } + FLASH->CR &= ~(FLASH_CR_PG); // 7: clear PG bit at end of process + FLASH->CR |= FLASH_CR_LOCK; // lock it back + 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; + if(!start) return 1; + uint32_t startb = (((uint32_t)start - FLASH_BASE) + blocksize - 1) / blocksize, endb; + if(!end){ // erase all remaining + endb = FLASH_SIZE * 1024 / blocksize; + }else{ // erase a part + endb = (((uint32_t)end - FLASH_BASE) + blocksize - 1) / blocksize; + } + if ((FLASH->CR & FLASH_CR_LOCK) != 0){ + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; + } + for(uint32_t i = startb; i < endb; ++i){ + IWDG->KR = IWDG_REFRESH; + /* (1) Wait till no operation is on going */ + /* (2) Clear error & EOP bits */ + while ((FLASH->SR & FLASH_SR_BSY) != 0){} /* (1) */ + FLASH->SR = 0xffff; /* (2) */ + /* (1) Set the PER bit in the FLASH_CR register to enable page erasing */ + /* (2) Select the page to erase (PNB) */ + /* (3) Set the STRT bit in the FLASH_CR register to start the erasing */ + /* (4) Wait until BSY1 cleared */ + FLASH->CR |= FLASH_CR_PER | i << FLASH_CR_PNB_Pos; /* (1) (2) */ + FLASH->CR |= FLASH_CR_STRT; /* (3) */ + while ((FLASH->SR & FLASH_SR_BSY) != 0){} /* (4) */ + FLASH->SR = FLASH_SR_EOP; + 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; // clear PER + } + return ret; +} + +int erase_storage(){ + return erase_flash(Flash_Data, NULL); +} diff --git a/G4:G431/Servo/flash.h b/G4:G431/Servo/flash.h new file mode 100644 index 0000000..c7a0d04 --- /dev/null +++ b/G4:G431/Servo/flash.h @@ -0,0 +1,52 @@ +/* + * This file is part of the flash 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 "hardware.h" + +// register with flash size (in blocks) +#ifndef FLASH_SIZE_REG +#define FLASH_SIZE_REG ((uint32_t)0x1FFF75E0) +#endif +#ifndef FLASH_SIZE +#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG) +#endif + +/* + * struct to save user configurations + */ +typedef struct __attribute__((packed, aligned(8))){ + uint16_t userconf_sz; // "magick number" + uint32_t usart_speed; // speed of interface + uint16_t startpulse[SERVO_AMOUNT]; // starting position + uint16_t minpulse[SERVO_AMOUNT]; // minimal position + uint16_t maxpulse[SERVO_AMOUNT]; // maximal position + uint16_t maxspeed[SERVO_AMOUNT]; // maximal speed +} user_conf; + +extern user_conf the_conf; // global user config (read from FLASH to RAM) +extern int currentconfidx; +extern uint32_t maxCnum; + +void flashstorage_init(); +int store_userconf(); +void dump_userconf(); +int erase_storage(); + diff --git a/G4:G431/Servo/hardware.c b/G4:G431/Servo/hardware.c index 48bece7..b9b9bb1 100644 --- a/G4:G431/Servo/hardware.c +++ b/G4:G431/Servo/hardware.c @@ -18,6 +18,7 @@ #include +#include "flash.h" #include "hardware.h" #include "servo.h" @@ -32,7 +33,7 @@ void sys_tick_handler(){ // try to set servo; if wrong return false bool set_servo(uint8_t N, uint16_t val){ if(N >= SERVO_AMOUNT) return false; - if(val < SG90_MINPULSE || val > SG90_MAXPULSE) return false; + if(val < the_conf.minpulse[N] || val > the_conf.maxpulse[N]) return false; volatile uint32_t *CCR = &(TIM3->CCR1); CCR[N] = val; return true; @@ -56,11 +57,14 @@ static void tim3_setup(){ TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC3PE | TIM_CCMR2_OC4PE; // frequency - TIM3->PSC = 169; // 1MHz -> 1us per tick + TIM3->PSC = 84; // 1MHz -> 1us per tick // ARR for PWM TIM3->ARR = 19999; // 20ms, 50Hz // CCRx - minimal position - TIM3->CCR1 = TIM3->CCR2 = TIM3->CCR3 = TIM3->CCR4 = SG90_MINPULSE; + TIM3->CCR1 = the_conf.startpulse[0]; + TIM3->CCR2 = the_conf.startpulse[1]; + TIM3->CCR3 = the_conf.startpulse[2]; + TIM3->CCR4 = the_conf.startpulse[3]; // enable CCx interrupts TIM3->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE; // enable main output diff --git a/G4:G431/Servo/hardware.h b/G4:G431/Servo/hardware.h index 3eb6e4e..5dee284 100644 --- a/G4:G431/Servo/hardware.h +++ b/G4:G431/Servo/hardware.h @@ -31,6 +31,9 @@ #define SERVO_AMOUNT 4 +#define MIN_USART_SPEED 1200 +#define MAX_USART_SPEED 3000000 + extern volatile uint32_t Tms; extern volatile bool tim_triggered[SERVO_AMOUNT]; diff --git a/G4:G431/Servo/main.c b/G4:G431/Servo/main.c index c5851fa..b22c0ec 100644 --- a/G4:G431/Servo/main.c +++ b/G4:G431/Servo/main.c @@ -20,6 +20,7 @@ #include #include "commproto.h" +#include "flash.h" #include "hardware.h" #include "servo.h" #include "usart.h" @@ -29,8 +30,10 @@ int main(void){ StartHSE(); + // init storage first to take base values + flashstorage_init(); gpio_setup(); - usart_setup(115200); + usart_setup(the_conf.usart_speed); bool pressed = false; uint32_t Tblink = 0, Tkey = 0; // blink and key pressed time while(1){ diff --git a/G4:G431/Servo/servo.bin b/G4:G431/Servo/servo.bin index e7a0cdc..0aaa07a 100755 Binary files a/G4:G431/Servo/servo.bin and b/G4:G431/Servo/servo.bin differ diff --git a/G4:G431/Servo/servo.c b/G4:G431/Servo/servo.c index 0df3a79..e5c5189 100644 --- a/G4:G431/Servo/servo.c +++ b/G4:G431/Servo/servo.c @@ -18,6 +18,7 @@ #include +#include "flash.h" #include "hardware.h" #include "servo.h" @@ -45,7 +46,7 @@ void process_servo(){ // set speed in steps per tick bool servo_set_speed(uint8_t N, uint16_t s){ if(N >= SERVO_AMOUNT) return false; - if(s < 1 || s > SG90_MAXSPEED) return false; + if(s < 1 || s > the_conf.maxspeed[N]) return false; servo_speed[N] = s; return true; } @@ -58,7 +59,7 @@ bool servo_get_speed(uint8_t N, uint16_t *s){ bool servo_set_tagpos(uint8_t N, uint16_t pos){ if(N >= SERVO_AMOUNT) return false; - if(pos < SG90_MINPULSE || pos > SG90_MAXPULSE) return false; + if(pos < the_conf.minpulse[N] || pos > the_conf.maxpulse[N]) return false; servo_tagpos[N] = pos; return true; } diff --git a/G4:G431/Servo/servo.files b/G4:G431/Servo/servo.files index 4d8ca89..b91881e 100644 --- a/G4:G431/Servo/servo.files +++ b/G4:G431/Servo/servo.files @@ -1,5 +1,7 @@ commproto.cpp commproto.h +flash.c +flash.h hardware.c hardware.h main.c diff --git a/G4:G431/Servo/servo.h b/G4:G431/Servo/servo.h index 0dbea5e..7f29491 100644 --- a/G4:G431/Servo/servo.h +++ b/G4:G431/Servo/servo.h @@ -18,14 +18,19 @@ #pragma once +// Default starting values // minimal and maximal pulse length for SG90 -#define SG90_MINPULSE 700 -#define SG90_MAXPULSE 2100 +#define SG90_MINPULSE 400 +#define SG90_MAXPULSE 2600 #define SG90_MIDPULSE ((SG90_MINPULSE+SG90_MAXPULSE)/2) #define SG90_AMPL (SG90_MAXPULSE-SG90_MINPULSE) // maximal speed: 0.1s (5 ticks) per 60degr (1/3 of range): (SG90_AMPL/15) #define SG90_MAXSPEED 93 +// Limiting values +#define SERVO_MINPULSE 100 +#define SERVO_MAXPULSE 5000 +#define SERVO_MAXSPEED 300 void process_servo(); bool servo_set_speed(uint8_t N, uint16_t s); diff --git a/G4:G431/Servo/version.inc b/G4:G431/Servo/version.inc index 03a3241..df3da95 100644 --- a/G4:G431/Servo/version.inc +++ b/G4:G431/Servo/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "9" -#define BUILD_DATE "2026-07-28" +#define BUILD_NUMBER "16" +#define BUILD_DATE "2026-07-29"