Start with events storage in MCU flash

This commit is contained in:
eddyem 2019-09-19 19:41:46 +03:00
parent 29d62c26c7
commit 7be1737383
15 changed files with 490 additions and 162 deletions

View File

@ -8,8 +8,8 @@ MCU ?= F103x8
# density (stm32f10x.h, lines 70-84)
DENSITY ?= MD
# change this linking script depending on particular MCU model,
LDSCRIPT ?= stm32f103xB.ld
DEFS = -DVERSION=\"0.0.1\"
LDSCRIPT ?= stm32F103xB.ld
DEFS = -DVERSION=\"0.0.2\"
# debug
#DEFS += -DEBUG
# proxy GPS output over USART1
@ -66,7 +66,7 @@ CFLAGS += $(ARCH_FLAGS)
###############################################################################
# Linker flags
LDFLAGS += -nostartfiles --static -nostdlibs
LDFLAGS += --static -nostartfiles -nostdlibs
LDFLAGS += -L$(LIB_DIR) -L$(TOOLCHLIB)
LDFLAGS += -T$(LDSCRIPT)
@ -114,7 +114,7 @@ $(LIST): $(ELF)
@echo " OBJDUMP $(LIST)"
$(OBJDUMP) -S $(ELF) > $(LIST)
$(ELF): $(OBJDIR) $(OBJS)
$(ELF): $(OBJDIR) $(OBJS) $(LDSCRIPT)
@echo " LD $(ELF)"
$(LD) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(ELF)

Binary file not shown.

View File

@ -39,117 +39,162 @@
#include "adc.h"
#include "flash.h"
#include "lidar.h"
#include "str.h"
#include "usart.h" // DBG
#include "usb.h" // printout
#include <string.h> // memcpy
extern uint32_t _edata, _etext, _sdata;
static int maxnum = FLASH_BLOCK_SIZE / sizeof(user_conf);
// max amount of records stored: Config & Logs
static int maxCnum = FLASH_BLOCK_SIZE / sizeof(user_conf);
static int maxLnum = FLASH_BLOCK_SIZE / sizeof(user_conf);
// common structure for all datatypes stored
/*typedef struct {
uint16_t userconf_sz;
} flash_storage;*/
typedef struct{
const user_conf all_stored;
} flash_storage;
#define USERCONF_INITIALIZER { \
#define USERCONF_INITIALIZER { \
/* .magick = 0xAB, */ \
.userconf_sz = sizeof(user_conf) \
,.dist_min = LIDAR_MIN_DIST \
,.dist_max = LIDAR_MAX_DIST \
,.trig_pullups = 0xff \
,.trigstate = 0 \
,.trigpause = {400, 400, 400, 300, 300} \
,.ADC_min = ADC_MIN_VAL \
,.ADC_max = ADC_MAX_VAL \
,.USART_speed = USART1_DEFAULT_SPEED \
,.strendRN = 0 \
}
__attribute__((section(".myvars"))) static const flash_storage Flash_Storage = {
.all_stored = USERCONF_INITIALIZER
};
// change to placement
/*
__attribute__ ((section(".logs"))) const uint32_t *logsstart;
__attribute__ ((section(".myvars"))) const user_conf *Flash_Data;
*/
static const user_conf *Flash_Data = &Flash_Storage.all_stored;
static int erase_flash(const void*, const void*);
static int write2flash(const void*, const void*, int);
const user_conf *Flash_Data = (const user_conf *)&__varsstart;
const event_log *logsstart = (event_log*) &__logsstart;
user_conf the_conf = USERCONF_INITIALIZER;
static int erase_flash();
static int currentconfidx = -1; // index of current configuration
static int currentlogidx = -1; // index of current logs record
/**
* @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 l, int r){
static int binarySearch(int l, int r, uint8_t *start, int stor_size){
/*DBG("start: "); printuhex(1, (uint32_t)start);
DBG("\nsizeof: "); printu(1, stor_size);
newline();*/
while(r >= l){
int mid = l + (r - l) / 2;
// If the element is present at the middle
// itself
uint16_t sz = Flash_Data[mid].userconf_sz;
if(sz == sizeof(user_conf)){
if(Flash_Data[mid+1].userconf_sz == 0xffff){
#if 0
SEND("Found at "); printu(1, mid); newline();
#endif
uint8_t *s = start + mid * stor_size;
if(*((uint16_t*)s) == stor_size){
if(*((uint16_t*)(s + stor_size)) == 0xffff){
return mid;
}else{ // element is to the right
l = mid + 1;
#if 0
SEND("To the right, L="); printu(1, l); newline();
#endif
}
}else{ // element is to the left
r = mid - 1;
#if 0
SEND("To the left, R="); printu(1, r); newline();
#endif
}
}
DBG("Not found!");
return -1; // not found
}
static int get_gooddata(){
static uint8_t firstrun = 1;
if(firstrun){
firstrun = 0;
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
uint32_t flsz = FLASH_SIZE * 1024; // size in bytes
flsz -= (uint32_t)Flash_Data - FLASH_BASE;
#if 0
SEND("All size: "); printu(1, flsz); newline();
#endif
uint32_t usz = (sizeof(user_conf) + 1) / 2;
maxnum = flsz / 2 / usz;
#if 0
SEND("Maxnum: "); printu(1, maxnum); newline();
#endif
}
/**
* @brief flashstorage_init - initialization of user conf & logs storage
* run in once @ start
*/
void flashstorage_init(){
maxCnum = ((uint32_t)&_varslen) / sizeof(user_conf);
//SEND("maxCnum="); printu(1, maxCnum);
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
uint32_t flsz = FLASH_SIZE * 1024; // size in bytes
flsz -= (uint32_t)logsstart - FLASH_BASE;
maxLnum = flsz / sizeof(event_log);
//SEND("\nmaxLnum="); printu(1, maxLnum);
}
return binarySearch(0, maxnum-2); // -1 if there's no data at all & flash is clear; maxnum-1 if flash is full
}
void get_userconf(){
const user_conf *c = Flash_Data;
int idx = get_gooddata();
if(idx < 0) return; // no data stored
currentconfidx = idx;
memcpy(&the_conf, &c[idx], sizeof(user_conf));
// -1 if there's no data at all & flash is clear; maxnum-1 if flash is full
currentconfidx = binarySearch(0, maxCnum-2, (uint8_t*)Flash_Data, sizeof(user_conf));
if(currentconfidx > -1){
memcpy(&the_conf, &Flash_Data[currentconfidx], sizeof(user_conf));
}
currentlogidx = binarySearch(0, maxLnum-2, (uint8_t*)logsstart, sizeof(event_log));
SEND("\ncurrentconfidx="); printu(1, currentconfidx);
SEND("\ncurrentlogidx="); printu(1, currentlogidx);
newline();
}
// store new configuration
// @return 0 if all OK
int store_userconf(){
IWDG->KR = IWDG_REFRESH;
int ret = 0;
const user_conf *c = Flash_Data;
int idx = currentconfidx;
// maxnum - 3 means that there always should be at least one empty record after last data
if(idx < 0 || idx > maxnum - 3){ // data corruption or there's no more place
idx = 0;
// for binarySearch() checking that there's nothing more after it!
if(currentconfidx > maxCnum - 3){ // there's no more place
currentconfidx = 0;
DBG("Need to erase flash!");
if(erase_flash()) return 1;
}else ++idx; // take next data position
currentconfidx = idx;
if(erase_flash(Flash_Data, &__varsend)) return 1;
}else ++currentconfidx; // take next data position (0 - within first run after firmware flashing)
SEND("store_userconf\n");
SEND("\ncurrentconfidx="); printu(1, currentconfidx);
newline();
return write2flash(&Flash_Data[currentconfidx], &the_conf, sizeof(the_conf));
}
/**
* @brief store_log - save log record L into flash memory
* @param L - event log
* @return 0 if all OK
*/
int store_log(event_log *L){
if(currentlogidx > maxLnum - 3){ // there's no more place
currentlogidx = 0;
DBG("Need to erase flash!");
if(erase_flash(logsstart, NULL)) return 1;
}else ++currentlogidx; // take next data position (0 - within first run after firmware flashing)
SEND("sore_log\n");
SEND("\ncurrentlogidx="); printu(1, currentlogidx);
newline();
return write2flash(&logsstart[currentlogidx], L, sizeof(event_log));
}
/**
* @brief dump_log - dump N log records
* @param start - first record to show (if start<0, then first=last+start)
* @param Nlogs - amount of logs to show (if Nlogs<=0, then show all logs)
* @return 0 if all OK, 1 if there's no logs in flash
*/
int dump_log(int start, int Nlogs){
if(currentlogidx < 0) return 1;
if(start < 0) start += currentlogidx;
if(start > currentlogidx) return 1;
int nlast;
if(Nlogs > 0){
nlast = start + Nlogs;
if(nlast > currentlogidx) nlast = currentlogidx;
}else nlast = currentlogidx;
++nlast;
const event_log *l = logsstart + start;
for(int i = start; i < nlast; ++i, ++l){
IWDG->KR = IWDG_REFRESH;
USB_send(get_trigger_shot(i, l));
}
return 0;
}
static int write2flash(const void *start, const void *wrdata, int stor_size){
int ret = 0;
if (FLASH->CR & FLASH_CR_LOCK){ // unloch flash
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
@ -158,10 +203,11 @@ int store_userconf(){
if(FLASH->SR & FLASH_SR_WRPRTERR) return 1; // write protection
FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; // clear all flags
FLASH->CR |= FLASH_CR_PG;
uint16_t *data = (uint16_t*) &the_conf;
uint16_t *address = (uint16_t*) &c[idx];
uint32_t i, count = (sizeof(user_conf) + 1) / 2;
uint16_t *data = (uint16_t*) wrdata;
uint16_t *address = (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
@ -172,18 +218,29 @@ int store_userconf(){
return ret;
}
static int erase_flash(){
/**
* @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;
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
uint32_t flsz = FLASH_SIZE * 1024; // size in bytes
flsz -= (uint32_t)Flash_Data - FLASH_BASE;
nblocks = flsz / FLASH_BLOCK_SIZE;
#if 0
SEND("N blocks:"); printu(1, nblocks); newline();
#endif
uint32_t nblocks = 1, flsz = 0;
if(!end){ // erase all remaining
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
flsz = FLASH_SIZE * 1024; // size in bytes
flsz -= (uint32_t)start - FLASH_BASE;
}
}else{ // erase a part
flsz = (uint32_t)end - (uint32_t)start;
}
nblocks = flsz / FLASH_BLOCK_SIZE;
if(nblocks == 0 || nblocks >= FLASH_SIZE) return 1;
for(uint32_t i = 0; i < nblocks; ++i){
#ifdef EBUG
SEND("Try to erase page #"); printu(1,i); newline();
#endif
IWDG->KR = IWDG_REFRESH;
/* (1) Wait till no operation is on going */
/* (2) Clear error & EOP bits */
@ -205,9 +262,6 @@ static int erase_flash(){
/* (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) */
#if 0
SEND("Delete block number "); printu(1, i); newline();
#endif
FLASH->AR = (uint32_t)Flash_Data + i*FLASH_BLOCK_SIZE; /* (2) */
FLASH->CR |= FLASH_CR_STRT; /* (3) */
while(!(FLASH->SR & FLASH_SR_EOP));
@ -228,7 +282,6 @@ void dump_userconf(){
SEND("userconf_sz="); printu(1, the_conf.userconf_sz);
SEND("\ndist_min="); printu(1, the_conf.dist_min);
SEND("\ndist_max="); printu(1, the_conf.dist_max);
SEND("\ntrig_pullups="); printuhex(1, the_conf.trig_pullups);
SEND("\ntrigstate="); printuhex(1, the_conf.trigstate);
SEND("\ntrigpause={");
for(int i = 0; i < TRIGGERS_AMOUNT; ++i){

View File

@ -31,21 +31,45 @@
#define FLASH_SIZE_REG ((uint32_t)0x1FFFF7E0)
#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG)
typedef struct __attribute__((packed)){
/*
* struct to save user configurations
*/
typedef struct __attribute__((packed, aligned(4))){
uint16_t userconf_sz; // "magick number"
uint32_t dist_min; // minimal distance for LIDAR
uint32_t dist_max; // maximal -//-
uint8_t trig_pullups; // trigger pullups: each bit ==0 to set OFF, ==1 to set ON pullup with given number
uint8_t trigstate; // level in `triggered` state
int32_t trigpause[TRIGGERS_AMOUNT]; // pause (ms) for false shots
int16_t ADC_min; // min&max values of ADC (shot when ADval > ADC_min && < ADC_max)
int16_t ADC_max; // !!! BOTH ARE SIGNED! so you can include 0 & 4096
uint8_t trigstate; // level in `triggered` state
uint8_t strendRN; // strings ends with "\r\n" instead of normal "\n"
uint8_t defflags; // default flags
uint32_t dist_min; // minimal distance for LIDAR
uint32_t dist_max; // maximal -//-
uint32_t USART_speed; // USART1 speed (115200 by default)
int32_t trigpause[TRIGGERS_AMOUNT]; // pause (ms) for false shots
} user_conf;
extern user_conf the_conf;
// values for user_conf.defflags:
#define FLAG_SAVE_EVENTS (1 << 0)
void get_userconf();
/*
* struct to save events logs
*/
typedef struct __attribute__((packed, aligned(4))){
uint16_t elog_sz;
uint8_t trigno;
trigtime shottime;
int16_t triglen;
uint16_t lidar_dist;
} event_log;
extern user_conf the_conf;
extern const user_conf *Flash_Data;
extern const event_log *logsstart;
extern uint32_t _varslen, __varsstart, __varsend, __logsstart;
void flashstorage_init();
int store_userconf();
int store_log(event_log *L);
int dump_log(int start, int Nlogs);
#ifdef EBUG
void dump_userconf();

View File

@ -80,11 +80,8 @@ static inline void gpio_setup(){
uint16_t pin = trigpin[i];
// fill trigstate array
uint8_t trgs = (the_conf.trigstate & (1<<i)) ? 1 : 0;
#ifdef EBUG
trigstate[i] = trgs;
#endif
// turn on pullups
if(the_conf.trig_pullups & (1<<i)) trigport[i]->ODR |= pin;
trigport[i]->ODR |= pin; // turn on pullups
EXTI->IMR |= pin;
if(trgs){ // triggered @1 -> rising interrupt
EXTI->RTSR |= pin;
@ -172,6 +169,7 @@ void fillunshotms(){
if(!trigger_shot) return;
uint8_t X = 1;
for(int i = 0; i < TRIGGERS_AMOUNT; ++i, X<<=1){
IWDG->KR = IWDG_REFRESH;
// check whether trigger is OFF but shot recently
if(trigger_shot & X){
uint32_t len = Tms - shotms[i];
@ -229,15 +227,26 @@ uint8_t gettrig(uint8_t N){
#endif
void chk_buzzer(){
if(!trigger_shot && BUZZER_GET()){ // should we turn off buzzer?
static uint32_t Ton = 0; // Time of first buzzer check
if(!BUZZER_GET()) return; // buzzer if OFF
if(!trigger_shot){ // should we turn off buzzer?
uint8_t notrg = 1;
for(int i = 0; i < DIGTRIG_AMOUNT; ++i){
uint8_t curval = (trigport[i]->IDR & trigpin[i]) ? 1 : 0;
if(curval == trigstate[i]){
notrg = 0;
notrg = 0; // cheep while digital trigger is ON
break;
}
}
if(notrg) BUZZER_OFF(); // turn off buzzer when there's no trigger events
if(notrg){ // turn off buzzer when there's no trigger events & timeout came
if(Tms - Ton < BUZZER_CHEEP_TIME) return;
Ton = 0;
BUZZER_OFF();
}
}else{ // buzzer is ON - check timer
if(Ton == 0){
Ton = Tms;
if(!Ton) Ton = 1;
}
}
}

View File

@ -40,6 +40,8 @@ extern uint8_t buzzer_on;
#define BUZZER_ON() do{if(buzzer_on)pin_set(BUZZER_port, BUZZER_pin);}while(0)
#define BUZZER_OFF() pin_clear(BUZZER_port, BUZZER_pin)
#define BUZZER_GET() (pin_read(BUZZER_port, BUZZER_pin))
// minimal time to buzzer to cheep (ms)
#define BUZZER_CHEEP_TIME (500)
// PPS pin - PA1
#define PPS_port GPIOA

View File

@ -72,6 +72,7 @@ void iwdg_setup(){
char *parse_cmd(char *buf){
int32_t N;
static char btns[] = "BTN0=0, BTN1=0, BTN2=0, PPS=0\n";
event_log l = {.elog_sz = sizeof(event_log), .trigno = 2};
switch(*buf){
case '0':
LED_off(); // LED0 off @dbg
@ -79,6 +80,14 @@ char *parse_cmd(char *buf){
case '1':
LED_on(); // LED0 on @dbg
break;
case 'a':
l.shottime.Time = current_time;
l.shottime.millis = Timer;
l.triglen = getADCval(1);
if(store_log(&l)) SEND("Error storing");
else SEND("Store OK");
newline();
break;
case 'b':
btns[5] = gettrig(0) + '0';
btns[13] = gettrig(1) + '0';
@ -100,6 +109,9 @@ char *parse_cmd(char *buf){
case 'd':
dump_userconf();
break;
case 'D':
if(dump_log(0, -1)) DBG("Error dumping log: empty?");
break;
case 'p':
pin_toggle(USBPU_port, USBPU_pin);
SEND("USB pullup is ");
@ -140,9 +152,11 @@ char *parse_cmd(char *buf){
if(buf[1] != '\n') return buf;
return
"0/1 - turn on/off LED1\n"
"'a' - add test log record\n"
"'b' - get buttons's state\n"
"'c' - send cold start\n"
"'d' - dump current user conf\n"
"'D' - dump log\n"
"'p' - toggle USB pullup\n"
"'C' - store userconf for N times\n"
"'G' - get last LIDAR distance\n"
@ -167,10 +181,15 @@ static char *get_USB(){
if(!x) return NULL;
curptr[x] = 0;
USB_send(curptr); // echo
//USB_send("ENDOINPUT\n");
//if(x == 1 && *curptr < 32){USB_send("\n"); USB_send(u2str(*curptr)); USB_send("\n");}
if(curptr[x-1] == '\n'){
if(curptr[x-1] == '\n' || curptr[x-1] == '\r'){
curptr = tmpbuf;
rest = USBBUF;
// omit empty lines
if(tmpbuf[0] == '\n') return NULL;
// and wrong empty lines
if(tmpbuf[0] == '\r' && tmpbuf[1] == '\n') return NULL;
return tmpbuf;
}
curptr += x; rest -= x;
@ -190,16 +209,10 @@ void linecoding_handler(usb_LineCoding __attribute__((unused)) *lc){ // get/set
#endif
}
static uint8_t USBconn = 0;
void clstate_handler(uint16_t __attribute__((unused)) val){ // lesser bits of val: RTS|DTR
static uint32_t Tlast = 0;
SEND("Tms/Tlast: ");
printu(1, Tms);
newline();
printu(1, Tlast);
newline();
if(Tms - Tlast < 500) return;
Tlast = Tms;
USB_send("Chronometer version " VERSION ".\n");
USBconn = 1;
#ifdef EBUG
if(val & 2){
DBG("RTS set");
@ -225,8 +238,6 @@ int main(void){
sysreset();
StartHSE();
SysTick_Config(SYSTICK_DEFCONF); // function SysTick_Config decrements argument!
// read data stored in flash
get_userconf();
// !!! hw_setup() should be the first in setup stage
hw_setup();
USB_setup();
@ -242,11 +253,17 @@ int main(void){
}
#endif
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
// read data stored in flash
flashstorage_init();
iwdg_setup();
while (1){
IWDG->KR = IWDG_REFRESH; // refresh watchdog
if(Timer > 499) LED_on(); // turn ON LED0 over 0.25s after PPS pulse
if(USBconn && Tms > 100){ // USB connection
USBconn = 0;
USB_send("Chronometer version " VERSION ".\n");
}
// check if triggers that was recently shot are off now
fillunshotms();
if(lastT > Tms || Tms - lastT > 499){
@ -301,17 +318,19 @@ int main(void){
}
#endif
}
//if(trigger_shot) show_trigger_shot(trigger_shot);
IWDG->KR = IWDG_REFRESH;
usb_proc();
IWDG->KR = IWDG_REFRESH;
int r = 0;
char *txt;
char *txt = NULL;
if((txt = get_USB())){
DBG("Received data over USB:");
DBG(txt);
if(parse_USBCMD(txt))
USB_send("Bad command!");
if(parse_USBCMD(txt)){
USB_send("Bad command: ");
USB_send(txt);
USB_send("\n");
}
IWDG->KR = IWDG_REFRESH;
}
#if defined EBUG || defined USART1PROXY

View File

@ -0,0 +1,97 @@
/*
********************************************************************************
* *
* Copyright (c) 2017 Andrea Loi *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included *
* in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
* DEALINGS IN THE SOFTWARE. *
* *
********************************************************************************
*/
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}
/******************************************************************************/
/* DON'T EDIT THIS FILE UNLESS YOU KNOW WHAT YOU'RE DOING! */
/******************************************************************************/
/* _isrvectors_tend = 0x00000150; - different for different series */
ENTRY(reset_handler)
SECTIONS {
.vector_table 0x08000000 :
{
_sisrvectors = .;
KEEP(*(.vector_table))
/* ASSERT(. == _isrvectors_tend, "The vector table needs to be 84 elements long!"); */
_eisrvectors = .;
} >rom
.text :
{
. = ALIGN(4);
_stext = .;
*(.text*)
*(.rodata*)
. = ALIGN(4);
_etext = .;
} >rom
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} >rom
.ARM : {
*(.ARM.exidx*)
} >rom
.data :
{
. = ALIGN(4);
_sdata = .;
*(.data*)
. = ALIGN(4);
_edata = .;
} >ram AT >rom
.myvars :
{
. = ALIGN(1024);
KEEP(*(.myvars))
} > rom
_ldata = LOADADDR(.data);
.bss :
{
. = ALIGN(4);
_sbss = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram
}
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));

View File

@ -17,7 +17,6 @@
*/
#include "adc.h"
#include "flash.h"
#include "GPS.h"
#include "lidar.h"
#include "str.h"
@ -74,11 +73,10 @@ static void sendi(int32_t I){
* @brief showuserconf - show configuration over USB
*/
static void showuserconf(){
USB_send("\nCONFIG:\nDISTMIN="); sendu(the_conf.dist_min);
USB_send("DISTMIN="); sendu(the_conf.dist_min);
USB_send("\nDISTMAX="); sendu(the_conf.dist_max);
USB_send("\nADCMIN="); sendi(the_conf.ADC_min);
USB_send("\nADCMAX="); sendi(the_conf.ADC_max);
USB_send("\nPULLUPS="); sendu(the_conf.trig_pullups);
USB_send("\nTRIGLVL="); sendu(the_conf.trigstate);
USB_send("\nTRIGPAUSE={");
for(int i = 0; i < TRIGGERS_AMOUNT; ++i){
@ -86,7 +84,15 @@ static void showuserconf(){
sendu(the_conf.trigpause[i]);
}
USB_send("}");
USB_send("\nENDCONFIG\n");
USB_send("\nUSART1SPD="); sendu(the_conf.USART_speed);
USB_send("\nSTREND=");
if(the_conf.strendRN) USB_send("RN");
else USB_send("N");
uint8_t f = the_conf.defflags;
USB_send("\nSAVE_EVENTS=");
if(f & FLAG_SAVE_EVENTS) USB_send("1");
else USB_send("0");
USB_send("\n");
}
/**
@ -95,7 +101,7 @@ static void showuserconf(){
* @return 0 if got command, 1 if command not recognized
*/
int parse_USBCMD(char *cmd){
#define CMP(a,b) cmpstr(a, b, sizeof(b)-1)
#define CMP(a,b) cmpstr(a, b, sizeof(b))
#define GETNUM(x) if(getnum(cmd+sizeof(x)-1, &N)) goto bad_number;
static uint8_t conf_modified = 0;
uint8_t succeed = 0;
@ -105,23 +111,28 @@ int parse_USBCMD(char *cmd){
if(*cmd == '?'){ // help
USB_send("Commands:\n"
CMD_ADCMAX " - max ADC value treshold for trigger\n"
CMD_ADCMIN " - min -//- (triggered when ADval>min & <max\n"
CMD_ADCMIN " - min -//- (triggered when ADval>min & <max)\n"
CMD_GETADCVAL " - get ADC value\n"
CMD_BUZZER "S - turn buzzer ON/OFF\n"
CMD_DISTMIN " - min distance threshold (cm)\n"
CMD_DISTMAX " - max distance threshold (cm)\n"
CMD_DUMP " - dump stored events\n"
CMD_FLASH " - FLASH info\n"
CMD_GPSRESTART " - send Full Cold Restart to GPS\n"
CMD_GPSSTAT " - get GPS status\n"
CMD_GPSSTR " - current GPS data string\n"
CMD_LEDS "S - turn leds on/off (1/0)\n"
CMD_GETMCUTEMP " - MCU temperature\n"
CMD_PULLUP "NS - triggers pullups state (N - trigger No, S - 0/1 for off/on)\n"
CMD_SHOWCONF " - show current configuration\n"
CMD_PRINTTIME " - print time\n"
CMD_RESET " - reset MCU\n"
CMD_SAVEEVTS "x - save/don't save (1/0) trigger events into flash\n"
CMD_STORECONF " - store new configuration in flash\n"
CMD_STREND "x - string ends with \\n (x=n) or \\r\\n (x=r)\n"
CMD_TRIGLVL "NS - working trigger N level S\n"
CMD_TRGPAUSE "NP - pause (P, ms) after trigger N shots\n"
CMD_TRGTIME "N - show last trigger N time\n"
CMD_USARTSPD "V - set USART1 speed to V\n"
CMD_GETVDD " - Vdd value\n"
);
}else if(CMP(cmd, CMD_PRINTTIME) == 0){
@ -157,7 +168,8 @@ int parse_USBCMD(char *cmd){
}
}else if(CMP(cmd, CMD_GPSSTR) == 0){ // show GPS status string
showGPSstr = 1;
}else if(CMP(cmd, CMD_PULLUP) == 0){
}/*
else if(CMP(cmd, CMD_PULLUP) == 0){
DBG("Pullups");
cmd += sizeof(CMD_PULLUP) - 1;
uint8_t Nt = *cmd++ - '0';
@ -169,7 +181,8 @@ int parse_USBCMD(char *cmd){
else the_conf.trig_pullups = oldval | (1<<Nt);
if(oldval != the_conf.trig_pullups) conf_modified = 1;
succeed = 1;
}else if(CMP(cmd, CMD_TRIGLVL) == 0){
} */
else if(CMP(cmd, CMD_TRIGLVL) == 0){
DBG("Trig levels");
cmd += sizeof(CMD_TRIGLVL) - 1;
uint8_t Nt = *cmd++ - '0';
@ -288,7 +301,53 @@ int parse_USBCMD(char *cmd){
USB_send(", PPS working\n");
else
USB_send(", no PPS\n");
}else if(CMP(cmd, CMD_USARTSPD) == 0){
GETNUM(CMD_USARTSPD);
if(N < 400 || N > 3000000) goto bad_number;
if(the_conf.USART_speed != (uint32_t)N){
the_conf.USART_speed = (uint32_t)N;
conf_modified = 1;
succeed = 1;
}
}else if(CMP(cmd, CMD_RESET) == 0){
USB_send("Soft reset\n");
NVIC_SystemReset();
}else if(CMP(cmd, CMD_STREND) == 0){
char c = cmd[sizeof(CMD_STREND) - 1];
succeed = 1;
if(c == 'n' || c == 'N') the_conf.strendRN = 0;
else if(c == 'r' || c == 'R') the_conf.strendRN = 1;
else{
succeed = 0;
USB_send("Bad letter, should be 'n' or 'r'\n");
}
}else if(CMP(cmd, CMD_FLASH) == 0){ // show flash size
USB_send("FLASHSIZE=");
sendu(FLASH_SIZE);
USB_send("kB\nFLASH_BASE=");
sendu(FLASH_BASE);
USB_send("\nFlash_Data=");
sendu((uint32_t)Flash_Data);
USB_send("\nvarslen=");
sendu((uint32_t)&_varslen);
USB_send("\nvarsend=");
sendu((uint32_t)&__varsend);
USB_send("\nvarsstart=");
sendu((uint32_t)&__varsstart);
USB_send("\nlogsstart=");
sendu((uint32_t)logsstart);
USB_send("\n");
}else if(CMP(cmd, CMD_SAVEEVTS) == 0){
if('0' == cmd[sizeof(CMD_SAVEEVTS) - 1]) the_conf.defflags &= ~FLAG_SAVE_EVENTS;
else the_conf.defflags |= FLAG_SAVE_EVENTS;
succeed = 1;
}else if(CMP(cmd, CMD_DUMP) == 0){
if(dump_log(0, -1)) USB_send("Event log empty!\n");
}else return 1;
/*else if(CMP(cmd, CMD_) == 0){
;
}*/
IWDG->KR = IWDG_REFRESH;
if(succeed) USB_send("Success!\n");
return 0;
@ -298,7 +357,38 @@ int parse_USBCMD(char *cmd){
}
/**
* @brief show_trigger_shot - print on USB message about last trigger shot time
* @brief get_trigger_shot - print on USB message about last trigger shot time
* @param number - number of event (if > -1)
* @param logdata - record from event log
* @return string with data
*/
char *get_trigger_shot(int number, const event_log *logdata){
static char buf[64];
char *bptr = buf;
if(number > -1){
bptr = strcp(bptr, u2str(number));
bptr = strcp(bptr, ": ");
}
if(logdata->trigno == LIDAR_TRIGGER){
bptr = strcp(bptr, "LIDAR, dist=");
bptr = strcp(bptr, u2str(logdata->lidar_dist));
bptr = strcp(bptr, ", TRIG" STR(LIDAR_TRIGGER) "=");
}else{
bptr = strcp(bptr, "TRIG");
*bptr++ = '0' + logdata->trigno;
}
*bptr++ = '=';
IWDG->KR = IWDG_REFRESH;
bptr = strcp(bptr, get_time(&logdata->shottime.Time, logdata->shottime.millis));
bptr = strcp(bptr, ", len=");
if(logdata->triglen < 0) bptr = strcp(bptr, ">1s");
else bptr = strcp(bptr, u2str((uint32_t) logdata->triglen));
*bptr++ = '\n'; *bptr++ = 0;
return buf;
}
/**
* @brief show_trigger_shot printout @ USB data with all triggers shot recently (+ save it in flash)
* @param tshot - each bit consists information about trigger
*/
void show_trigger_shot(uint8_t tshot){
@ -307,20 +397,39 @@ void show_trigger_shot(uint8_t tshot){
IWDG->KR = IWDG_REFRESH;
if(tshot & X) tshot &= ~X;
else continue;
if(!triglen[i]) continue; // noice
if(i == LIDAR_TRIGGER){
USB_send("LIDAR, dist=");
sendu(lidar_triggered_dist);
USB_send(", TRIG=");
}else{
USB_send("TRIG");
sendu(i);
event_log l;
l.elog_sz = sizeof(event_log);
l.trigno = i;
if(i == LIDAR_TRIGGER) l.lidar_dist = lidar_triggered_dist;
l.shottime = shottime[i];
l.triglen = triglen[i];
USB_send(get_trigger_shot(-1, &l));
if(the_conf.defflags & FLAG_SAVE_EVENTS){
if(store_log(&l)) USB_send("\n\nError saving event!\n\n");
}
USB_send("=");
USB_send(get_time(&shottime[i].Time, shottime[i].millis));
USB_send(", len=");
if(triglen[i] < 0) USB_send(">1s");
else sendu((uint32_t) triglen[i]);
USB_send("\n");
}
}
/**
* @brief strln == strlen
* @param s - string
* @return length
*/
int strln(const char *s){
int i = 0;
while(*s++) ++i;
return i;
}
/**
* @brief strcp - strcpy (be carefull: it doesn't checks destination length!)
* @param dst - destination
* @param src - source
* @return pointer to '\0' @ dst`s end
*/
char *strcp(char* dst, const char *src){
int l = strln(src);
if(l < 1) return dst;
while((*dst++ = *src++));
return dst - 1;
}

View File

@ -20,6 +20,7 @@
#define STR_H__
#include "stm32f1.h"
#include "flash.h"
#include "hardware.h"
// usb commands
@ -31,7 +32,6 @@
#define CMD_PRINTTIME "time"
#define CMD_STORECONF "store"
#define CMD_GPSSTR "gpsstring"
#define CMD_PULLUP "pullup"
#define CMD_SHOWCONF "showconf"
#define CMD_TRIGLVL "triglevel"
#define CMD_TRGPAUSE "trigpause"
@ -43,12 +43,20 @@
#define CMD_GPSRESTART "gpsrestart"
#define CMD_BUZZER "buzzer"
#define CMD_GPSSTAT "gpsstat"
#define CMD_USARTSPD "usartspd"
#define CMD_RESET "reset"
#define CMD_STREND "strend"
#define CMD_FLASH "flash"
#define CMD_SAVEEVTS "saveevt"
#define CMD_DUMP "dump"
extern uint8_t showGPSstr;
int strln(const char *s);
char *strcp(char* dst, const char *src);
int cmpstr(const char *s1, const char *s2, int n);
char *getchr(const char *str, char symbol);
int parse_USBCMD(char *cmd);
char *get_trigger_shot(int number, const event_log *logdata);
void show_trigger_shot(uint8_t trigger_shot);
#endif // STR_H__

View File

@ -102,7 +102,7 @@ static void ms2str(char **str, uint32_t T){
/**
* print time: Tm - time structure, T - milliseconds
*/
char *get_time(curtime *Tm, uint32_t T){
char *get_time(const curtime *Tm, uint32_t T){
static char buf[64];
char *bstart = &buf[5], *bptr = bstart;
int S = 0;

View File

@ -53,7 +53,7 @@ extern uint32_t trigger_ms[];
extern volatile int need_sync;
char *get_time(curtime *T, uint32_t m);
char *get_time(const curtime *T, uint32_t m);
void set_time(const char *buf);
void time_increment();
void systick_correction();

View File

@ -18,6 +18,7 @@
#include "stm32f1.h"
#include "flash.h"
#include "usart.h"
#include "lidar.h"
@ -169,7 +170,7 @@ static void usart_setup(int n, uint32_t BRR){
void usarts_setup(){
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
#if defined EBUG || defined USART1PROXY
usart_setup(1, 72000000 / 115200); // debug console or GPS proxy
usart_setup(1, 72000000 / the_conf.USART_speed); // debug console or GPS proxy
#endif
usart_setup(2, 36000000 / 9600); // GPS
usart_setup(3, 36000000 / 115200); // LIDAR
@ -253,27 +254,20 @@ void usart3_isr(){
// return string buffer with val
char *u2str(uint32_t val){
static char bufa[11];
char bufb[10];
int l = 0, bpos = 0;
IWDG->KR = IWDG_REFRESH;
static char buf[11];
char *bufptr = &buf[10];
*bufptr = 0;
if(!val){
bufa[0] = '0';
l = 1;
*(--bufptr) = '0';
}else{
while(val){
bufb[l++] = val % 10 + '0';
*(--bufptr) = val % 10 + '0';
val /= 10;
}
int i;
bpos += l;
for(i = 0; i < l; ++i){
bufa[--bpos] = bufb[i];
}
}
bufa[l + bpos] = 0;
return bufa;
return bufptr;
}
// print 32bit unsigned int
void printu(int n, uint32_t val){
usart_send(n, u2str(val));

View File

@ -29,6 +29,9 @@
#define TIMEOUT_MS (1500)
#endif
// USART1 default speed
#define USART1_DEFAULT_SPEED (115200)
#define STR_HELPER(s) #s
#define STR(s) STR_HELPER(s)

View File

@ -20,6 +20,7 @@
* MA 02110-1301, USA.
*
*/
#include "flash.h"
#include "usb.h"
#include "usb_lib.h"
#include "usart.h"
@ -106,17 +107,26 @@ void USB_send(const char *buf){
DBG("USB not configured");
return;
}
char tmpbuf[USB_TXBUFSZ];
uint16_t l = 0, ctr = 0;
const char *p = buf;
while(*p++) ++l;
while(l){
uint16_t s = (l > USB_TXBUFSZ) ? USB_TXBUFSZ : l;
uint16_t proc = 0, s = (l > USB_TXBUFSZ - 1) ? USB_TXBUFSZ - 1: l;
for(int i = 0; i < s; ++i, ++proc){
char c = buf[ctr+proc];
if(c == '\n' && the_conf.strendRN){ // add '\r' before '\n'
tmpbuf[i++] = '\r';
if(i == s) ++s;
}
tmpbuf[i] = c;
}
tx_succesfull = 0;
EP_Write(3, (uint8_t*)&buf[ctr], s);
EP_Write(3, (uint8_t*)tmpbuf, s);
uint32_t ctra = 1000000;
while(--ctra && tx_succesfull == 0);
l -= s;
ctr += s;
l -= proc;
ctr += proc;
}
}