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 9d8617c..2f8e1f6 100755 Binary files a/F1-nolib/chronometer/chrono.bin and b/F1-nolib/chronometer/chrono.bin differ 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));