From 7ac9d908fa6841c740bae8a2874607a713ddd250 Mon Sep 17 00:00:00 2001 From: eddyem Date: Wed, 10 Jul 2019 23:38:56 +0300 Subject: [PATCH] add better version of EEPROM emulation in flash (for now - only in `chronometer`) --- F1-nolib/chronometer/GPS.c | 4 +- F1-nolib/chronometer/Makefile | 2 + F1-nolib/chronometer/Readme.md | 2 +- F1-nolib/chronometer/chrono.bin | Bin 9144 -> 12300 bytes F1-nolib/chronometer/flash.c | 240 ++++++++++++++++++++++++++++++++ F1-nolib/chronometer/flash.h | 48 +++++++ F1-nolib/chronometer/hardware.c | 16 +-- F1-nolib/chronometer/hardware.h | 18 ++- F1-nolib/chronometer/lidar.c | 7 +- F1-nolib/chronometer/lidar.h | 3 + F1-nolib/chronometer/main.c | 89 ++++++++++-- F1-nolib/chronometer/time.c | 71 ++++++++++ F1-nolib/chronometer/time.h | 11 +- F1-nolib/chronometer/usart.c | 41 +++++- F1-nolib/chronometer/usart.h | 10 +- F1-nolib/chronometer/usb.c | 4 + F1-nolib/inc/ld/stm32f01234.ld | 10 +- 17 files changed, 529 insertions(+), 47 deletions(-) create mode 100644 F1-nolib/chronometer/flash.c create mode 100644 F1-nolib/chronometer/flash.h diff --git a/F1-nolib/chronometer/GPS.c b/F1-nolib/chronometer/GPS.c index 0a0454c..ad6cb66 100644 --- a/F1-nolib/chronometer/GPS.c +++ b/F1-nolib/chronometer/GPS.c @@ -149,7 +149,9 @@ void GPS_send_start_seq(){ */ void GPS_parse_answer(const char *buf){ char *ptr; - DBG(buf); +#if defined USART1PROXY + usart_send(1, buf); newline(); +#endif if(buf[1] == 'P') return; // answers to proprietary messages if(cmpstr(buf+3, "RMC", 3)){ // not RMC message need2startseq = 1; diff --git a/F1-nolib/chronometer/Makefile b/F1-nolib/chronometer/Makefile index 76dd294..d253d7a 100644 --- a/F1-nolib/chronometer/Makefile +++ b/F1-nolib/chronometer/Makefile @@ -12,6 +12,8 @@ LDSCRIPT ?= stm32f103x8.ld DEFS = -DVERSION=\"0.0.1\" # debug DEFS += -DEBUG +# proxy GPS output over USART1 +DEFS += -DUSART1PROXY INDEPENDENT_HEADERS= diff --git a/F1-nolib/chronometer/Readme.md b/F1-nolib/chronometer/Readme.md index c37bb0b..3bf8cfb 100644 --- a/F1-nolib/chronometer/Readme.md +++ b/F1-nolib/chronometer/Readme.md @@ -11,7 +11,7 @@ Chronometer for downhill competitions - PB8, PB9 - onboard LEDs -- PA4 - TRIG2 - 12V trigger (EXTI) +- PA4 - TRIG2 - 12V trigger (EXTI) -- not implemented yet - PA13 - TRIG0 - button0 (EXTI) - PA14 - TRIG1 - button1/laser/etc (EXTI) - PA15 - USB pullup diff --git a/F1-nolib/chronometer/chrono.bin b/F1-nolib/chronometer/chrono.bin index 9d8617cb0120026beac0ed1c849b31a101da3929..2f8e1f6d291fafa1a0c101e6366ebf5001c5db10 100755 GIT binary patch literal 12300 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 YVZM6+*?;`~!vg=X!2jnK_->5&zxv$4IRF3v literal 9144 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 diff --git a/F1-nolib/chronometer/flash.c b/F1-nolib/chronometer/flash.c new file mode 100644 index 0000000..0a5d25b --- /dev/null +++ b/F1-nolib/chronometer/flash.c @@ -0,0 +1,240 @@ +/* + * geany_encoding=koi8-r + * flash.c + * + * Copyright 2017 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +/** + ATTENTION!! + This things works only if you will add next section: + + .myvars : + { + . = ALIGN(1024); + KEEP(*(.myvars)) + } > rom + + after section .data +*/ + +#include "stm32f1.h" +#include // memcpy + +#include "flash.h" +#include "lidar.h" +#ifdef EBUG +#include "usart.h" +#endif + +extern uint32_t _edata, _etext, _sdata; +static int maxnum = FLASH_BLOCK_SIZE / sizeof(user_conf); + + +typedef struct{ + const user_conf all_stored; +} flash_storage; + +#define USERCONF_INITIALIZER { \ + .userconf_sz = sizeof(user_conf) \ + ,.dist_min = LIDAR_MIN_DIST \ + ,.dist_max = LIDAR_MAX_DIST \ + } + +__attribute__((section(".myvars"))) static const flash_storage Flash_Storage = { + .all_stored = USERCONF_INITIALIZER +}; + +static const user_conf *Flash_Data = &Flash_Storage.all_stored; + +user_conf the_conf = USERCONF_INITIALIZER; + +static int erase_flash(); + +static int currentconfidx = -1; // index of current configuration + +/** + * @brief binarySearch - binary search in flash for last non-empty cell + * @param l - left index + * @param r - right index (should be @1 less than last index!) + * @return index of non-empty cell or -1 + */ +static int binarySearch(int l, int r){ + 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 + 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 + } + } + 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)); +} + +// 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; + DBG("Need to erase flash!"); + if(erase_flash()) return 1; + }else ++idx; // take next data position + currentconfidx = idx; + if (FLASH->CR & FLASH_CR_LOCK){ // unloch flash + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; + } + while (FLASH->SR & FLASH_SR_BSY); + if(FLASH->SR & FLASH_SR_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; + for (i = 0; i < count; ++i){ + *(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 + else while (!(FLASH->SR & FLASH_SR_EOP)); + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; + } + FLASH->CR &= ~(FLASH_CR_PG); + return ret; +} + +static int erase_flash(){ + 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 + } + for(uint32_t i = 0; i < nblocks; ++i){ + IWDG->KR = IWDG_REFRESH; + /* (1) Wait till no operation is on going */ + /* (2) Clear error & EOP bits */ + /* (3) Check that the Flash is unlocked */ + /* (4) Perform unlock sequence */ + while ((FLASH->SR & FLASH_SR_BSY) != 0){} /* (1) */ + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; /* (2) */ + /* if (FLASH->SR & FLASH_SR_EOP){ + FLASH->SR |= FLASH_SR_EOP; + }*/ + if ((FLASH->CR & FLASH_CR_LOCK) != 0){ /* (3) */ + FLASH->KEYR = FLASH_KEY1; /* (4) */ + FLASH->KEYR = FLASH_KEY2; + } + /* (1) Set the PER bit in the FLASH_CR register to enable page erasing */ + /* (2) Program the FLASH_AR register to select a page to erase */ + /* (3) Set the STRT bit in the FLASH_CR register to start the erasing */ + /* (4) Wait until the EOP flag in the FLASH_SR register set */ + /* (5) Clear EOP flag by software by writing EOP at 1 */ + /* (6) Reset the PER Bit to disable the page erase */ + FLASH->CR |= FLASH_CR_PER; /* (1) */ +#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)); + FLASH->SR |= FLASH_SR_EOP; /* (5)*/ + if(FLASH->SR & FLASH_SR_WRPRTERR){ /* Check Write protection error */ + ret = 1; + DBG("Write protection error!"); + FLASH->SR |= FLASH_SR_WRPRTERR; /* Clear the flag by software by writing it at 1*/ + break; + } + FLASH->CR &= ~FLASH_CR_PER; /* (6) */ + } + return ret; +} + +#ifdef EBUG +void dump_userconf(){ + SEND("userconf_sz="); printu(1, the_conf.userconf_sz); newline(); + SEND("dist_min="); printu(1, the_conf.dist_min); newline(); + SEND("dist_max="); printu(1, the_conf.dist_max); newline(); +} + +void addNrecs(int N){ + SEND("Try to store userconf for "); printu(1, N); SEND(" times\n"); + for(int i = 0; i < N; ++i){ + if(store_userconf()){ + SEND("Error @ "); printu(1, i); newline(); + return; + } + } + SEND("Curr idx: "); printu(1, currentconfidx); newline(); +} + +#endif diff --git a/F1-nolib/chronometer/flash.h b/F1-nolib/chronometer/flash.h new file mode 100644 index 0000000..8b2bd83 --- /dev/null +++ b/F1-nolib/chronometer/flash.h @@ -0,0 +1,48 @@ +/* + * flash.h + * + * Copyright 2017 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#pragma once +#ifndef __FLASH_H__ +#define __FLASH_H__ + +#include + +#define FLASH_BLOCK_SIZE (1024) +#define FLASH_SIZE_REG ((uint32_t)0x1FFFF7E0) +#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG) + +typedef struct{ + uint16_t userconf_sz; // "magick number" + uint32_t dist_min; // minimal distance for LIDAR + uint32_t dist_max; // maximal -//- +} user_conf; + +extern user_conf the_conf; + +void get_userconf(); +int store_userconf(); +#ifdef EBUG +void dump_userconf(); +void addNrecs(int N); +#endif + +#endif // __FLASH_H__ diff --git a/F1-nolib/chronometer/hardware.c b/F1-nolib/chronometer/hardware.c index 57d32ca..22b4f60 100644 --- a/F1-nolib/chronometer/hardware.c +++ b/F1-nolib/chronometer/hardware.c @@ -23,6 +23,7 @@ #include "adc.h" #include "hardware.h" +#include "time.h" #include "usart.h" static inline void gpio_setup(){ @@ -30,10 +31,10 @@ static inline void gpio_setup(){ RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN; // turn off SWJ/JTAG AFIO->MAPR = AFIO_MAPR_SWJ_CFG_DISABLE; - // pullups - GPIOA->ODR = (1<<12)|(1<<13)|(1<<14); - // Set led (PB8) as opendrain output - GPIOB->CRH = CRH(8, CNF_ODOUTPUT|MODE_SLOW); + // pullups: PA1 - PPS, PA13/PA14 - buttons + GPIOA->ODR = (1<<12)|(1<<13)|(1<<14)|(1<<15); + // Set leds (PB8) as opendrain output + GPIOB->CRH = CRH(8, CNF_ODOUTPUT|MODE_SLOW) | CRH(9, CNF_ODOUTPUT|MODE_SLOW); // PPS pin (PA1) - input with weak pullup GPIOA->CRL = CRL(1, CNF_PUDINPUT|MODE_INPUT); // Set buttons (PA13/14) as inputs with weak pullups, USB pullup (PA15) - opendrain output @@ -88,13 +89,8 @@ void hw_setup(){ } void exti1_isr(){ // PPS - PA1 - /* - if(trigger_ms[2] == DIDNT_TRIGGERED){ // prevent bounce - trigger_ms[2] = Timer; - memcpy(&trigger_time[2], ¤t_time, sizeof(curtime)); - } - */ DBG("exti1"); + systick_correction(); EXTI->PR = EXTI_PR_PR1; } diff --git a/F1-nolib/chronometer/hardware.h b/F1-nolib/chronometer/hardware.h index 0c9017e..cb2d123 100644 --- a/F1-nolib/chronometer/hardware.h +++ b/F1-nolib/chronometer/hardware.h @@ -35,10 +35,13 @@ #define CMD_ADC1MAX "adc1max" #define CMD_ADC2MAX "adc2max" #define CMD_PRINTTIME "time" +#define CMD_STORECONF "store" -// onboard LED - PB8 -#define LED_port GPIOB -#define LED_pin (1<<8) +// onboard LEDs - PB8/PB9 +#define LED0_port GPIOB +#define LED0_pin (1<<8) +#define LED1_port GPIOB +#define LED1_pin (1<<9) // PPS pin - PA1 #define PPS_port GPIOA @@ -55,9 +58,12 @@ #define USBPU_ON() pin_clear(USBPU_port, USBPU_pin) #define USBPU_OFF() pin_set(USBPU_port, USBPU_pin) -#define LED_blink() pin_toggle(LED_port, LED_pin) -#define LED_on() pin_clear(LED_port, LED_pin) -#define LED_off() pin_set(LED_port, LED_pin) +#define LED_blink() pin_toggle(LED0_port, LED0_pin) +#define LED_on() pin_clear(LED0_port, LED0_pin) +#define LED_off() pin_set(LED0_port, LED0_pin) +#define LED1_blink() pin_toggle(LED1_port, LED1_pin) +#define LED1_on() pin_clear(LED1_port, LED1_pin) +#define LED1_off() pin_set(LED1_port, LED1_pin) // GPS USART == USART2, LIDAR USART == USART3 #define GPS_USART (2) diff --git a/F1-nolib/chronometer/lidar.c b/F1-nolib/chronometer/lidar.c index b21810c..dd2ee14 100644 --- a/F1-nolib/chronometer/lidar.c +++ b/F1-nolib/chronometer/lidar.c @@ -16,11 +16,10 @@ * along with this program. If not, see . */ +#include "flash.h" #include "lidar.h" #include "usart.h" -uint16_t lidar_max_dist = 100; -uint16_t lidar_min_dist = 50; uint16_t last_lidar_dist = 0; uint16_t last_lidar_stren = 0; uint16_t lidar_triggered_dist = 0; @@ -35,7 +34,7 @@ void parse_lidar_data(char *txt){ return; } if(triggered){ // check if body gone - if(last_lidar_dist < lidar_min_dist || last_lidar_dist > lidar_max_dist || last_lidar_dist > lidar_triggered_dist + LIDAR_DIST_THRES){ + if(last_lidar_dist < the_conf.dist_min || last_lidar_dist > the_conf.dist_max || last_lidar_dist > lidar_triggered_dist + LIDAR_DIST_THRES){ triggered = 0; #ifdef EBUG SEND("Untriggered! distance="); @@ -46,7 +45,7 @@ void parse_lidar_data(char *txt){ #endif } }else{ - if(last_lidar_dist > lidar_min_dist && last_lidar_dist < lidar_max_dist){ + if(last_lidar_dist > the_conf.dist_min && last_lidar_dist < the_conf.dist_max){ triggered = 1; lidar_triggered_dist = last_lidar_dist; #ifdef EBUG diff --git a/F1-nolib/chronometer/lidar.h b/F1-nolib/chronometer/lidar.h index 80c15d3..ad90268 100644 --- a/F1-nolib/chronometer/lidar.h +++ b/F1-nolib/chronometer/lidar.h @@ -27,6 +27,9 @@ #define LIDAR_LOWER_STREN (10) // triggered distance threshold - 1 meter #define LIDAR_DIST_THRES (100) +#define LIDAR_MIN_DIST (50) +#define LIDAR_MAX_DIST (1000) + extern uint16_t last_lidar_dist; extern uint16_t lidar_triggered_dist; extern uint16_t last_lidar_stren; diff --git a/F1-nolib/chronometer/main.c b/F1-nolib/chronometer/main.c index 6e0e2e2..164e02b 100644 --- a/F1-nolib/chronometer/main.c +++ b/F1-nolib/chronometer/main.c @@ -21,6 +21,7 @@ //#include "adc.h" #include "GPS.h" +#include "flash.h" #include "hardware.h" #include "lidar.h" #include "str.h" @@ -33,11 +34,13 @@ #define VERSION "0.0.0" #endif +// global pseudo-milliseconds counter volatile uint32_t Tms = 0; /* Called when systick fires */ void sys_tick_handler(void){ ++Tms; + increment_timer(); } void iwdg_setup(){ @@ -65,8 +68,8 @@ void iwdg_setup(){ #ifdef EBUG char *parse_cmd(char *buf){ + int32_t N; static char btns[] = "BTN0=0, BTN1=0, PPS=0\n"; - if(buf[1] != '\n') return buf; switch(*buf){ case '0': LED_off(); @@ -80,6 +83,16 @@ char *parse_cmd(char *buf){ btns[20] = GET_PPS() + '0'; return btns; break; + case 'C': + if(getnum(&buf[1], &N)){ + SEND("Need a number!\n"); + }else{ + addNrecs(N); + } + break; + case 'd': + dump_userconf(); + break; case 'p': pin_toggle(USBPU_port, USBPU_pin); SEND("USB pullup is "); @@ -117,10 +130,13 @@ char *parse_cmd(char *buf){ while(1){nop();}; break; default: // help + if(buf[1] != '\n') return buf; return "0/1 - turn on/off LED1\n" "'b' - get buttons's state\n" + "'d' - dump current user conf\n" "'p' - toggle USB pullup\n" + "'C' - store userconf for N times\n" "'G' - get last LIDAR distance\n" "'L' - send long string over USB\n" "'R' - software reset\n" @@ -155,22 +171,55 @@ static char *get_USB(){ return NULL; } -#define CMP(a,b) cmpstr(a, b, sizeof(b)-1) static void parse_USBCMD(char *cmd){ +#define CMP(a,b) cmpstr(a, b, sizeof(b)-1) +#define GETNUM(x) if(getnum(cmd+sizeof(x)-1, &N)) goto bad_number; + static uint8_t conf_modified = 0; + uint8_t succeed = 0; + int32_t N; if(!cmd || !*cmd) return; if(*cmd == '?'){ // help USB_send("Commands:\n" - CMD_DISTMIN " - min distance threshold (cm)\n" - CMD_DISTMAX " - max distance threshold (cm)\n" + CMD_DISTMIN " - min distance threshold (cm)\n" + CMD_DISTMAX " - max distance threshold (cm)\n" CMD_PRINTTIME " - print time\n" + CMD_STORECONF " - store new configuration in flash\n" ); }else if(CMP(cmd, CMD_PRINTTIME) == 0){ USB_send(get_time(¤t_time, get_millis())); }else if(CMP(cmd, CMD_DISTMIN) == 0){ // set low limit DBG("CMD_DISTMIN"); + GETNUM(CMD_DISTMIN); + if(N < 0 || N > 0xffff) goto bad_number; + if(the_conf.dist_min != (uint16_t)N){ + conf_modified = 1; + the_conf.dist_min = (uint16_t) N; + succeed = 1; + } }else if(CMP(cmd, CMD_DISTMAX) == 0){ // set low limit DBG("CMD_DISTMAX"); + GETNUM(CMD_DISTMAX); + if(N < 0 || N > 0xffff) goto bad_number; + if(the_conf.dist_max != (uint16_t)N){ + conf_modified = 1; + the_conf.dist_max = (uint16_t) N; + succeed = 1; + } + }else if(CMP(cmd, CMD_STORECONF) == 0){ // store everything + DBG("Store"); + if(conf_modified){ + if(store_userconf()){ + USB_send("Error: can't save data!\n"); + }else{ + conf_modified = 0; + succeed = 1; + } + } } + if(succeed) USB_send("Success!\n"); + return; + bad_number: + USB_send("Error: bad number!\n"); } int main(void){ @@ -178,9 +227,10 @@ int main(void){ sysreset(); StartHSE(); hw_setup(); + LED1_off(); USBPU_OFF(); usarts_setup(); - SysTick_Config(72000); + SysTick_Config(SYSTICK_DEFLOAD); SEND("Chronometer version " VERSION ".\n"); if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured SEND("WDGRESET=1\n"); @@ -191,14 +241,27 @@ int main(void){ RCC->CSR |= RCC_CSR_RMVF; // remove reset flags USB_setup(); - //iwdg_setup(); + iwdg_setup(); USBPU_ON(); + // read data stored in flash +#ifdef EBUG + SEND("Old config:\n"); + dump_userconf(); +#endif + //writeatend(); + get_userconf(); +#ifdef EBUG + SEND("New config:\n"); + dump_userconf(); +#endif while (1){ IWDG->KR = IWDG_REFRESH; // refresh watchdog if(lastT > Tms || Tms - lastT > 499){ if(need2startseq) GPS_send_start_seq(); LED_blink(); + if(GPS_status != GPS_VALID) LED1_blink(); + else LED1_on(); lastT = Tms; if(usartrx(LIDAR_USART)){ char *txt; @@ -207,7 +270,7 @@ int main(void){ DBG(txt); } } -#ifdef EBUG +#if defined EBUG || defined USART1PROXY transmit_tbuf(1); // non-blocking transmission of data from UART buffer every 0.5s #endif transmit_tbuf(GPS_USART); @@ -215,23 +278,28 @@ int main(void){ } usb_proc(); int r = 0; - char *txt, *ans; + char *txt; if((txt = get_USB())){ parse_USBCMD(txt); DBG("Received data over USB:"); DBG(txt); USB_send(txt); // echo all back } -#ifdef EBUG +#if defined EBUG || defined USART1PROXY if(usartrx(1)){ // usart1 received data, store in in buffer r = usart_getline(1, &txt); if(r){ txt[r] = 0; - ans = parse_cmd(txt); +#ifdef EBUG + char *ans = parse_cmd(txt); if(ans){ + transmit_tbuf(1); usart_send(1, ans); transmit_tbuf(1); } +#else // USART1PROXY - send received data to GPS + usart_send(GPS_USART, txt); +#endif } } #endif @@ -251,4 +319,3 @@ int main(void){ } return 0; } - diff --git a/F1-nolib/chronometer/time.c b/F1-nolib/chronometer/time.c index c430e6f..6f8f0c3 100644 --- a/F1-nolib/chronometer/time.c +++ b/F1-nolib/chronometer/time.c @@ -21,9 +21,13 @@ #include "usb.h" #include +volatile uint32_t Timer; // milliseconds counter curtime current_time = TMNOTINI; volatile int need_sync = 1; +// SysTick->LOAD values for all milliseconds (RVR0) and last millisecond (RVR1) +static uint32_t RVR0 = SYSTICK_DEFLOAD, RVR1 = SYSTICK_DEFLOAD; + static inline uint8_t atou(const char *b){ return (b[0]-'0')*10 + b[1]-'0'; } @@ -36,6 +40,22 @@ void set_time(const char *buf){ current_time.S = atou(&buf[4]); } +/** + * @brief time_increment - increment system timer by systick + */ +void time_increment(){ + Timer = 0; + if(current_time.H == 25) return; // Time not initialized + if(++current_time.S == 60){ + current_time.S = 0; + if(++current_time.M == 60){ + current_time.M = 0; + if(++current_time.H == 24) + current_time.H = 0; + } + } +} + /** * print time: Tm - time structure, T - milliseconds */ @@ -90,3 +110,54 @@ uint32_t get_millis(){ // TODO: calculate right millis return Tms % 1000; // temporary gag } + +void systick_correction(){ + uint32_t t = 0, ticks; + static uint32_t ticksavr = 0, N = 0, last_corr_time = 0; + // correct + int32_t systick_val = SysTick->VAL; + // SysTick->LOAD values for all milliseconds (RVR0) and last millisecond (RVR1) + SysTick->VAL = RVR0; + int32_t timer_val = Timer; + Timer = 0; + // RVR -> SysTick->LOAD + systick_val = SysTick->LOAD + 1 - systick_val; // Systick counts down! + if(timer_val < 10) timer_val += 1000; // our closks go faster than real + else if(timer_val < 990){ // something wrong + RVR0 = RVR1 = SYSTICK_DEFLOAD; + SysTick->LOAD = RVR0; + need_sync = 1; + goto theend; + }else + time_increment(); // ms counter less than 1000 - we need to increment time + t = current_time.H * 3600 + current_time.M * 60 + current_time.S; + if(t - last_corr_time == 1){ // PPS interval == 1s + ticks = systick_val + (timer_val-1)*(RVR0 + 1) + RVR1 + 1; + ++N; + ticksavr += ticks; + if(N > 20){ + ticks = ticksavr / N; + RVR0 = ticks / 1000 - 1; // main RVR value + SysTick->LOAD = RVR0; + RVR1 = RVR0 + ticks % 1000; // last millisecond RVR value (with fine correction) + N = 0; + ticksavr = 0; + need_sync = 0; + } + }else{ + N = 0; + ticksavr = 0; + } +theend: + last_corr_time = t; +} + +void increment_timer(){ + ++Timer; + if(Timer == 999){ + SysTick->LOAD = RVR1; + }else if(Timer == 1000){ + SysTick->LOAD = RVR0; + time_increment(); + } +} diff --git a/F1-nolib/chronometer/time.h b/F1-nolib/chronometer/time.h index e8e61cc..d4f8f6c 100644 --- a/F1-nolib/chronometer/time.h +++ b/F1-nolib/chronometer/time.h @@ -21,8 +21,11 @@ #include -#define STK_RVR_DEFAULT_VAL (8999) -#define TIMEZONE_GMT_PLUS (3) +// default value for systick_config +#define SYSTICK_DEFCONF (72000) +// defaul for systick->load +#define SYSTICK_DEFLOAD (SYSTICK_DEFCONF - 1) +#define TIMEZONE_GMT_PLUS (3) #define DIDNT_TRIGGERED (2000) @@ -38,6 +41,7 @@ typedef struct{ } curtime; extern volatile uint32_t Tms; +extern volatile uint32_t Timer; extern curtime current_time; extern curtime trigger_time[]; @@ -48,5 +52,8 @@ extern volatile int need_sync; char *get_time(curtime *T, uint32_t m); void set_time(const char *buf); uint32_t get_millis(); // current milliseconds +void time_increment(); +void systick_correction(); +void increment_timer(); #endif // TIME_H__ diff --git a/F1-nolib/chronometer/usart.c b/F1-nolib/chronometer/usart.c index 91879f5..6a66524 100644 --- a/F1-nolib/chronometer/usart.c +++ b/F1-nolib/chronometer/usart.c @@ -94,7 +94,7 @@ void usart_send(int n, const char *str){ tbuf[n][tbufno[n]][odatalen[n][tbufno[n]]++] = *str++; } } -#ifdef EBUG +#if defined EBUG || defined USART1PROXY // only for USART1 void newline(){ usart_putchar(1, '\n'); @@ -168,8 +168,8 @@ static void usart_setup(int n, uint32_t BRR){ void usarts_setup(){ RCC->AHBENR |= RCC_AHBENR_DMA1EN; -#ifdef EBUG - usart_setup(1, 72000000 / 115200); // debug console +#if defined EBUG || defined USART1PROXY + usart_setup(1, 72000000 / 115200); // debug console or GPS proxy #endif usart_setup(2, 36000000 / 9600); // GPS usart_setup(3, 36000000 / 115200); // LIDAR @@ -215,7 +215,7 @@ void usart_isr(int n, USART_TypeDef *USART){ } } -#ifdef EBUG +#if defined EBUG || defined USART1PROXY void usart1_isr(){ usart_isr(1, USART1); } @@ -310,7 +310,7 @@ void hexdump(uint8_t *arr, uint16_t len){ } #endif -#ifdef EBUG +#if defined EBUG || defined USART1PROXY void dma1_channel4_isr(){ // USART1 if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx DMA1->IFCR = DMA_IFCR_CTCIF4; // clear TC flag @@ -332,3 +332,34 @@ void dma1_channel2_isr(){ // USART3 txrdy[3] = 1; } } + +// read `buf` and get first integer `N` in it +// @return 0 if all OK or 1 if there's not a number; omit spaces and '=' +int getnum(const char *buf, int32_t *N){ + char c; + int positive = -1; + int32_t val = 0; + while((c = *buf++)){ + if(c == '\t' || c == ' ' || c == '='){ + if(positive < 0) continue; // beginning spaces + else break; // spaces after number + } + if(c == '-'){ + if(positive < 0){ + positive = 0; + continue; + }else break; // there already was `-` or number + } + if(c < '0' || c > '9') break; + if(positive < 0) positive = 1; + val = val * 10 + (int32_t)(c - '0'); + } + if(positive != -1){ + if(positive == 0){ + if(val == 0) return 1; // single '-' + val = -val; + } + *N = val; + }else return 1; + return 0; +} diff --git a/F1-nolib/chronometer/usart.h b/F1-nolib/chronometer/usart.h index d92b605..4ddcf80 100644 --- a/F1-nolib/chronometer/usart.h +++ b/F1-nolib/chronometer/usart.h @@ -55,13 +55,13 @@ void usart_putchar(int n, char ch); char *u2str(uint32_t val); void printu(int n, uint32_t val); void printuhex(int n, uint32_t val); +int getnum(const char *buf, int32_t *N); -#ifdef EBUG +#if defined EBUG || defined USART1PROXY void newline(); +#endif +#ifdef EBUG void hexdump(uint8_t *arr, uint16_t len); #endif -/* -void hexdump16(uint16_t *arr, uint16_t len); -void hexdump32(uint32_t *arr, uint16_t len); -*/ + #endif // __USART_H__ diff --git a/F1-nolib/chronometer/usb.c b/F1-nolib/chronometer/usb.c index 4fc2fa8..f9ad6db 100644 --- a/F1-nolib/chronometer/usb.c +++ b/F1-nolib/chronometer/usb.c @@ -102,6 +102,10 @@ void usb_proc(){ } void USB_send(char *buf){ + if(!USB_configured()){ + DBG("USB not configured"); + return; + } uint16_t l = 0, ctr = 0; char *p = buf; while(*p++) ++l; diff --git a/F1-nolib/inc/ld/stm32f01234.ld b/F1-nolib/inc/ld/stm32f01234.ld index 76abafe..930bf36 100644 --- a/F1-nolib/inc/ld/stm32f01234.ld +++ b/F1-nolib/inc/ld/stm32f01234.ld @@ -52,7 +52,7 @@ SECTIONS { . = ALIGN(4); _etext = .; } >rom - + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) @@ -71,6 +71,12 @@ SECTIONS { _edata = .; } >ram AT >rom + .myvars : + { + . = ALIGN(1024); + KEEP(*(.myvars)) + } > rom + _ldata = LOADADDR(.data); .bss : @@ -84,4 +90,4 @@ SECTIONS { } >ram } -PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); \ No newline at end of file +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));