mirror of
https://github.com/eddyem/stm32samples.git
synced 2026-08-12 09:39:25 +03:00
add flash storage
This commit is contained in:
@@ -94,7 +94,7 @@ static int binarySearch(int r, const uint8_t *start, int stor_size){
|
|||||||
*/
|
*/
|
||||||
void flashstorage_init(){
|
void flashstorage_init(){
|
||||||
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
|
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;
|
flsz -= (uint32_t)(&__varsstart) - FLASH_BASE;
|
||||||
maxCnum = flsz / sizeof(user_conf);
|
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;
|
uint32_t nblocks = 1, flsz = 0;
|
||||||
if(!end){ // erase all remaining
|
if(!end){ // erase all remaining
|
||||||
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
|
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;
|
flsz -= (uint32_t)start - FLASH_BASE;
|
||||||
}
|
}
|
||||||
}else{ // erase a part
|
}else{ // erase a part
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ static int binarySearch(int r, const uint8_t *start, int stor_size){
|
|||||||
*/
|
*/
|
||||||
void flashstorage_init(){
|
void flashstorage_init(){
|
||||||
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
|
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;
|
flsz -= (uint32_t)(&__varsstart) - FLASH_BASE;
|
||||||
maxCnum = flsz / sizeof(user_conf);
|
maxCnum = flsz / sizeof(user_conf);
|
||||||
//SEND("flsz="); printu(flsz);
|
//SEND("flsz="); printu(flsz);
|
||||||
@@ -165,7 +165,7 @@ static int erase_flash(const void *start, const void *end){
|
|||||||
uint32_t nblocks = 1, flsz = 0;
|
uint32_t nblocks = 1, flsz = 0;
|
||||||
if(!end){ // erase all remaining
|
if(!end){ // erase all remaining
|
||||||
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
|
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;
|
flsz -= (uint32_t)start - FLASH_BASE;
|
||||||
}
|
}
|
||||||
}else{ // erase a part
|
}else{ // erase a part
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ static int binarySearch(int r, const uint8_t *start, int stor_size){
|
|||||||
*/
|
*/
|
||||||
void flashstorage_init(){
|
void flashstorage_init(){
|
||||||
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
|
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;
|
flsz -= (uint32_t)(&__varsstart) - FLASH_BASE;
|
||||||
maxCnum = flsz / sizeof(user_conf);
|
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;
|
uint32_t nblocks = 1, flsz = 0;
|
||||||
if(!end){ // erase all remaining
|
if(!end){ // erase all remaining
|
||||||
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
|
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;
|
flsz -= (uint32_t)start - FLASH_BASE;
|
||||||
}
|
}
|
||||||
}else{ // erase a part
|
}else{ // erase a part
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ static int binarySearch(int r, const uint8_t *start, int stor_size){
|
|||||||
*/
|
*/
|
||||||
void flashstorage_init(){
|
void flashstorage_init(){
|
||||||
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
|
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;
|
flsz -= (uint32_t)(&__varsstart) - FLASH_BASE;
|
||||||
maxCnum = flsz / sizeof(user_conf);
|
maxCnum = flsz / sizeof(user_conf);
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,7 @@ static int erase_flash(const void *start, const void *end){
|
|||||||
if(!start) return 1;
|
if(!start) return 1;
|
||||||
uint32_t startb = (((uint32_t)start - FLASH_BASE) + blocksize - 1) / blocksize, endb;
|
uint32_t startb = (((uint32_t)start - FLASH_BASE) + blocksize - 1) / blocksize, endb;
|
||||||
if(!end){ // erase all remaining
|
if(!end){ // erase all remaining
|
||||||
endb = FLASH_SIZE / blocksize;
|
endb = FLASH_SIZE * 1024 / blocksize;
|
||||||
}else{ // erase a part
|
}else{ // erase a part
|
||||||
endb = (((uint32_t)end - FLASH_BASE) + blocksize - 1) / blocksize;
|
endb = (((uint32_t)end - FLASH_BASE) + blocksize - 1) / blocksize;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ extern "C"{
|
|||||||
#include <stm32g4.h>
|
#include <stm32g4.h>
|
||||||
|
|
||||||
#include "commproto.h"
|
#include "commproto.h"
|
||||||
//#include "flash.h"
|
#include "flash.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
#include "servo.h"
|
#include "servo.h"
|
||||||
#include "strfunc.h"
|
#include "strfunc.h"
|
||||||
@@ -42,12 +42,22 @@ extern volatile uint32_t Tms;
|
|||||||
|
|
||||||
// list of all commands and handlers
|
// list of all commands and handlers
|
||||||
#define COMMAND_TABLE \
|
#define COMMAND_TABLE \
|
||||||
|
COMMAND(dumpconf, "dump current config") \
|
||||||
|
COMMAND(eraseflash, "erase full flash storage") \
|
||||||
COMMAND(help, "show this help") \
|
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(mcureset, "reset MCU") \
|
||||||
COMMAND(servo, "get/set servoN value, mks (from " STR(SG90_MINPULSE) " to " STR(SG90_MAXPULSE) ")") \
|
COMMAND(minpos, "servoN minimal allowed position (conf)") \
|
||||||
COMMAND(servopos, "get/set servoN target position with given speed") \
|
COMMAND(readconf, "re-read config from flash") \
|
||||||
COMMAND(servospeed, "get/set servoN speed, mks per 20ms (1.." STR(SG90_MAXSPEED) ")") \
|
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(time, "show current time (ms)") \
|
||||||
|
COMMAND(usart_speed,"speed of USART (set after reset, conf)") \
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -82,7 +92,8 @@ const char *EQ = " = "; // equal sign for getters
|
|||||||
#define CMDEQ() do{SEND(cmd); SEND(EQ);}while(0)
|
#define CMDEQ() do{SEND(cmd); SEND(EQ);}while(0)
|
||||||
// send `commandXXX = `
|
// send `commandXXX = `
|
||||||
#define CMDEQP(x) do{SEND(cmd); SEND(u2str((uint32_t)x)); SEND(EQ);}while(0)
|
#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`
|
* @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;
|
if(!setter) return false;
|
||||||
int32_t I32;
|
int32_t I32;
|
||||||
char *next = getint(setter, &I32);
|
char *next = getint(setter, &I32);
|
||||||
if(next != setter && parval){
|
if(next != setter){
|
||||||
*parval = I32;
|
if(parval) *parval = I32;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -176,69 +187,84 @@ static errcodes_t cmd_mcureset(const char*, char*){
|
|||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
return ERR_CANTRUN; // never reached
|
return ERR_CANTRUN; // never reached
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
static errcodes_t cmd_saveconf(const char*, char*){
|
static errcodes_t cmd_saveconf(const char*, char*){
|
||||||
if(store_userconf()) return ERR_CANTRUN;
|
if(store_userconf()) return ERR_CANTRUN;
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static errcodes_t cmd_eraseflash(const char*, char*){
|
static errcodes_t cmd_eraseflash(const char*, char*){
|
||||||
if(erase_storage(-1)) return ERR_CANTRUN;
|
if(erase_storage()) return ERR_CANTRUN;
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static errcodes_t cmd_readconf(const char*, char* args){
|
static errcodes_t cmd_readconf(const char*, char*){
|
||||||
int32_t CHno = -1;
|
flashstorage_init();
|
||||||
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;
|
|
||||||
return ERR_OK;
|
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*){
|
static errcodes_t cmd_dumpconf(const char*, char*){
|
||||||
SEND("userconf_sz="); SEND(u2str(the_conf.userconf_sz));
|
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));
|
SEND("\ncapacity="); SEND(u2str(maxCnum-2));
|
||||||
cmd_setiface("\nsetiface", NULL);
|
SEND("\nusart_speed="); SEND(u2str(the_conf.usart_speed));
|
||||||
cmd_restonstart("restonstart", NULL);
|
for(int i = 0; i < SERVO_AMOUNT ; ++i){
|
||||||
for(int i = 0; i < SENSORS_AMOUNT; ++i){
|
SHOWPARU("\nstartpos", i, the_conf.startpulse[i]);
|
||||||
showpar("gain", i, the_conf.spars[i].AFE_GB);
|
SHOWPARU("\nminpos", i, the_conf.minpulse[i]);
|
||||||
showpar("\nlco_fdiv", i, the_conf.spars[i].LCO_FDIV);
|
SHOWPARU("\nmaxpos", i, the_conf.maxpulse[i]);
|
||||||
showpar("\nmaskdist", i, the_conf.spars[i].MASK_DIST);
|
SHOWPARU("\nmaxspeed", i, the_conf.maxspeed[i]);
|
||||||
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("\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;
|
return ERR_AMOUNT;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static errcodes_t cmd_help(const char*, char*){
|
static errcodes_t cmd_help(const char*, char*){
|
||||||
SEND(REPOURL);
|
SEND(REPOURL);
|
||||||
|
|||||||
186
G4:G431/Servo/flash.c
Normal file
186
G4:G431/Servo/flash.c
Normal 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
52
G4:G431/Servo/flash.h
Normal 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();
|
||||||
|
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <stm32g4.h>
|
#include <stm32g4.h>
|
||||||
|
|
||||||
|
#include "flash.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
#include "servo.h"
|
#include "servo.h"
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ void sys_tick_handler(){
|
|||||||
// try to set servo; if wrong return false
|
// try to set servo; if wrong return false
|
||||||
bool set_servo(uint8_t N, uint16_t val){
|
bool set_servo(uint8_t N, uint16_t val){
|
||||||
if(N >= SERVO_AMOUNT) return false;
|
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);
|
volatile uint32_t *CCR = &(TIM3->CCR1);
|
||||||
CCR[N] = val;
|
CCR[N] = val;
|
||||||
return true;
|
return true;
|
||||||
@@ -56,11 +57,14 @@ static void tim3_setup(){
|
|||||||
TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 |
|
TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 |
|
||||||
TIM_CCMR2_OC3PE | TIM_CCMR2_OC4PE;
|
TIM_CCMR2_OC3PE | TIM_CCMR2_OC4PE;
|
||||||
// frequency
|
// frequency
|
||||||
TIM3->PSC = 169; // 1MHz -> 1us per tick
|
TIM3->PSC = 84; // 1MHz -> 1us per tick
|
||||||
// ARR for PWM
|
// ARR for PWM
|
||||||
TIM3->ARR = 19999; // 20ms, 50Hz
|
TIM3->ARR = 19999; // 20ms, 50Hz
|
||||||
// CCRx - minimal position
|
// 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
|
// enable CCx interrupts
|
||||||
TIM3->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE;
|
TIM3->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE;
|
||||||
// enable main output
|
// enable main output
|
||||||
|
|||||||
@@ -31,6 +31,9 @@
|
|||||||
|
|
||||||
#define SERVO_AMOUNT 4
|
#define SERVO_AMOUNT 4
|
||||||
|
|
||||||
|
#define MIN_USART_SPEED 1200
|
||||||
|
#define MAX_USART_SPEED 3000000
|
||||||
|
|
||||||
extern volatile uint32_t Tms;
|
extern volatile uint32_t Tms;
|
||||||
extern volatile bool tim_triggered[SERVO_AMOUNT];
|
extern volatile bool tim_triggered[SERVO_AMOUNT];
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "commproto.h"
|
#include "commproto.h"
|
||||||
|
#include "flash.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
#include "servo.h"
|
#include "servo.h"
|
||||||
#include "usart.h"
|
#include "usart.h"
|
||||||
@@ -29,8 +30,10 @@
|
|||||||
|
|
||||||
int main(void){
|
int main(void){
|
||||||
StartHSE();
|
StartHSE();
|
||||||
|
// init storage first to take base values
|
||||||
|
flashstorage_init();
|
||||||
gpio_setup();
|
gpio_setup();
|
||||||
usart_setup(115200);
|
usart_setup(the_conf.usart_speed);
|
||||||
bool pressed = false;
|
bool pressed = false;
|
||||||
uint32_t Tblink = 0, Tkey = 0; // blink and key pressed time
|
uint32_t Tblink = 0, Tkey = 0; // blink and key pressed time
|
||||||
while(1){
|
while(1){
|
||||||
|
|||||||
Binary file not shown.
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "flash.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
#include "servo.h"
|
#include "servo.h"
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ void process_servo(){
|
|||||||
// set speed in steps per tick
|
// set speed in steps per tick
|
||||||
bool servo_set_speed(uint8_t N, uint16_t s){
|
bool servo_set_speed(uint8_t N, uint16_t s){
|
||||||
if(N >= SERVO_AMOUNT) return false;
|
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;
|
servo_speed[N] = s;
|
||||||
return true;
|
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){
|
bool servo_set_tagpos(uint8_t N, uint16_t pos){
|
||||||
if(N >= SERVO_AMOUNT) return false;
|
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;
|
servo_tagpos[N] = pos;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
commproto.cpp
|
commproto.cpp
|
||||||
commproto.h
|
commproto.h
|
||||||
|
flash.c
|
||||||
|
flash.h
|
||||||
hardware.c
|
hardware.c
|
||||||
hardware.h
|
hardware.h
|
||||||
main.c
|
main.c
|
||||||
|
|||||||
@@ -18,14 +18,19 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// Default starting values
|
||||||
// minimal and maximal pulse length for SG90
|
// minimal and maximal pulse length for SG90
|
||||||
#define SG90_MINPULSE 700
|
#define SG90_MINPULSE 400
|
||||||
#define SG90_MAXPULSE 2100
|
#define SG90_MAXPULSE 2600
|
||||||
#define SG90_MIDPULSE ((SG90_MINPULSE+SG90_MAXPULSE)/2)
|
#define SG90_MIDPULSE ((SG90_MINPULSE+SG90_MAXPULSE)/2)
|
||||||
#define SG90_AMPL (SG90_MAXPULSE-SG90_MINPULSE)
|
#define SG90_AMPL (SG90_MAXPULSE-SG90_MINPULSE)
|
||||||
// maximal speed: 0.1s (5 ticks) per 60degr (1/3 of range): (SG90_AMPL/15)
|
// maximal speed: 0.1s (5 ticks) per 60degr (1/3 of range): (SG90_AMPL/15)
|
||||||
#define SG90_MAXSPEED 93
|
#define SG90_MAXSPEED 93
|
||||||
|
|
||||||
|
// Limiting values
|
||||||
|
#define SERVO_MINPULSE 100
|
||||||
|
#define SERVO_MAXPULSE 5000
|
||||||
|
#define SERVO_MAXSPEED 300
|
||||||
|
|
||||||
void process_servo();
|
void process_servo();
|
||||||
bool servo_set_speed(uint8_t N, uint16_t s);
|
bool servo_set_speed(uint8_t N, uint16_t s);
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
#define BUILD_NUMBER "9"
|
#define BUILD_NUMBER "16"
|
||||||
#define BUILD_DATE "2026-07-28"
|
#define BUILD_DATE "2026-07-29"
|
||||||
|
|||||||
Reference in New Issue
Block a user