add flash storage

This commit is contained in:
Edward Emelianov
2026-07-29 21:01:01 +03:00
parent 2b4a9cbd84
commit 940b60df99
15 changed files with 352 additions and 70 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -22,7 +22,7 @@ extern "C"{
#include <stm32g4.h>
#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<uint8_t>(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);

186
G4:G431/Servo/flash.c Normal file
View File

@@ -0,0 +1,186 @@
/*
* This file is part of the flash project.
* Copyright 2023 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 <stm32g4.h>
#include <string.h> // 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);
}

52
G4:G431/Servo/flash.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* This file is part of the flash project.
* Copyright 2023 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
#include <stdint.h>
#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();

View File

@@ -18,6 +18,7 @@
#include <stm32g4.h>
#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

View File

@@ -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];

View File

@@ -20,6 +20,7 @@
#include <string.h>
#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){

Binary file not shown.

View File

@@ -18,6 +18,7 @@
#include <stdint.h>
#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;
}

View File

@@ -1,5 +1,7 @@
commproto.cpp
commproto.h
flash.c
flash.h
hardware.c
hardware.h
main.c

View File

@@ -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);

View File

@@ -1,2 +1,2 @@
#define BUILD_NUMBER "9"
#define BUILD_DATE "2026-07-28"
#define BUILD_NUMBER "16"
#define BUILD_DATE "2026-07-29"