diff --git a/F1-nolib/chronometer/GPS.c b/F1-nolib/chronometer/GPS.c index ad6cb66..65f218b 100644 --- a/F1-nolib/chronometer/GPS.c +++ b/F1-nolib/chronometer/GPS.c @@ -29,7 +29,7 @@ #define GPS_endline() do{usart_send(GPS_USART, "\r\n"); transmit_tbuf(GPS_USART); }while(0) #define GPS_send_string(str) do{usart_send(GPS_USART, str);}while(0) -gps_status GPS_status = GPS_WAIT; +gps_status GPS_status = GPS_NOTFOUND; int need2startseq = 1; static uint8_t hex(uint8_t n){ diff --git a/F1-nolib/chronometer/GPS.h b/F1-nolib/chronometer/GPS.h index 2feeef2..8545af5 100644 --- a/F1-nolib/chronometer/GPS.h +++ b/F1-nolib/chronometer/GPS.h @@ -28,7 +28,8 @@ extern int need2startseq; typedef enum{ - GPS_WAIT // wait for satellites + GPS_NOTFOUND // default status before first RMC message + ,GPS_WAIT // wait for satellites ,GPS_NOT_VALID // time known, but not valid ,GPS_VALID } gps_status; diff --git a/F1-nolib/chronometer/Readme.md b/F1-nolib/chronometer/Readme.md index 3bf8cfb..3c64c24 100644 --- a/F1-nolib/chronometer/Readme.md +++ b/F1-nolib/chronometer/Readme.md @@ -16,3 +16,4 @@ Chronometer for downhill competitions - PA14 - TRIG1 - button1/laser/etc (EXTI) - PA15 - USB pullup +- PB0,1,2 - free for other functions diff --git a/F1-nolib/chronometer/chrono.bin b/F1-nolib/chronometer/chrono.bin index 8577c2e..c5f312d 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 index 0a5d25b..e55fffe 100644 --- a/F1-nolib/chronometer/flash.c +++ b/F1-nolib/chronometer/flash.c @@ -55,6 +55,9 @@ typedef struct{ .userconf_sz = sizeof(user_conf) \ ,.dist_min = LIDAR_MIN_DIST \ ,.dist_max = LIDAR_MAX_DIST \ + ,.trig_pullups = 0xff \ + ,.trigstate = 0 \ + ,.trigpause = {400, 400, 400} \ } __attribute__((section(".myvars"))) static const flash_storage Flash_Storage = { @@ -221,9 +224,18 @@ static int erase_flash(){ #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(); + 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){ + if(i) SEND(", "); + printu(1, the_conf.trigpause[i]); + } + SEND("}\n"); + transmit_tbuf(1); } void addNrecs(int N){ diff --git a/F1-nolib/chronometer/flash.h b/F1-nolib/chronometer/flash.h index 8b2bd83..14d5293 100644 --- a/F1-nolib/chronometer/flash.h +++ b/F1-nolib/chronometer/flash.h @@ -25,21 +25,26 @@ #define __FLASH_H__ #include +#include "hardware.h" #define FLASH_BLOCK_SIZE (1024) #define FLASH_SIZE_REG ((uint32_t)0x1FFFF7E0) #define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG) -typedef struct{ +typedef struct __attribute__((packed)){ 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 } user_conf; extern user_conf the_conf; void get_userconf(); int store_userconf(); + #ifdef EBUG void dump_userconf(); void addNrecs(int N); diff --git a/F1-nolib/chronometer/hardware.c b/F1-nolib/chronometer/hardware.c index 61f6630..49e5a9a 100644 --- a/F1-nolib/chronometer/hardware.c +++ b/F1-nolib/chronometer/hardware.c @@ -23,29 +23,66 @@ #include "adc.h" #include "hardware.h" +#include "flash.h" #include "time.h" #include "usart.h" +#include // memcpy + +// ports of triggers +GPIO_TypeDef *trigport[TRIGGERS_AMOUNT] = {GPIOA, GPIOA, GPIOA}; +// pins of triggers: PA13, PA14, PA4 +uint16_t trigpin[TRIGGERS_AMOUNT] = {1<<13, 1<<14, 1<<4}; +// value of pin in `triggered` state +uint8_t trigstate[TRIGGERS_AMOUNT]; +// time of triggers shot +trigtime shottime[TRIGGERS_AMOUNT]; +// Tms value when they shot +static uint32_t shotms[TRIGGERS_AMOUNT]; +// if trigger[N] shots, the bit N will be 1 +uint8_t trigger_shot = 0; + static inline void gpio_setup(){ // Enable clocks to the GPIO subsystems (PB for ADC), turn on AFIO clocking to disable SWD/JTAG 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: PA1 - PPS, PA13/PA14 - buttons - GPIOA->ODR = (1<<12)|(1<<13)|(1<<14)|(1<<15); + // pullups: PA1 - PPS, PA15 - USB pullup + GPIOA->ODR = (1<<12)|(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 - GPIOA->CRH = CRH(13, CNF_PUDINPUT|MODE_INPUT) | CRH(14, CNF_PUDINPUT|MODE_INPUT) | - CRH(15, CNF_ODOUTPUT|MODE_SLOW); + // Set USB pullup (PA15) - opendrain output + GPIOA->CRH = CRH(15, CNF_ODOUTPUT|MODE_SLOW); + // ---------------------> config-depengent block, interrupts & pullup inputs: + GPIOA->CRH |= CRH(13, CNF_PUDINPUT|MODE_INPUT) | CRH(14, CNF_PUDINPUT|MODE_INPUT); + GPIOA->CRL |= CRL(4, CNF_PUDINPUT|MODE_INPUT); + // <--------------------- // EXTI: all three EXTI are on PA -> AFIO_EXTICRx = 0 // interrupt on pulse front: buttons - 1->0, PPS - 0->1 - EXTI->IMR = EXTI_IMR_MR1 | EXTI_IMR_MR13 | EXTI_IMR_MR14; // unmask + EXTI->IMR = EXTI_IMR_MR1; EXTI->RTSR = EXTI_RTSR_TR1; // rising trigger - EXTI->FTSR = EXTI_FTSR_TR13 | EXTI_FTSR_TR14; // falling trigger + // PA4/PA13/PA14 - buttons + for(int i = 0; i < TRIGGERS_AMOUNT; ++i){ + uint16_t pin = trigpin[i]; + // fill trigstate array + uint8_t trgs = (the_conf.trigstate & (1<ODR |= pin; + EXTI->IMR |= pin; + if(trgs){ // triggered @1 -> rising interrupt + EXTI->RTSR |= pin; + }else{ // falling interrupt + EXTI->FTSR |= pin; + } + } + // ---------------------> config-depengent block, interrupts & pullup inputs: + // !!! change AFIO_EXTICRx if some triggers not @GPIOA + NVIC_EnableIRQ(EXTI4_IRQn); NVIC_EnableIRQ(EXTI15_10_IRQn); + // <--------------------- NVIC_EnableIRQ(EXTI1_IRQn); } @@ -94,25 +131,49 @@ void exti1_isr(){ // PPS - PA1 EXTI->PR = EXTI_PR_PR1; } +static trigtime trgtm; +static void savetrigtime(){ + trgtm.millis = Timer; + memcpy(&trgtm.Time, ¤t_time, sizeof(curtime)); +} + +static void fillshotms(int i){ + if(i < 0 || i > TRIGGERS_AMOUNT) return; + if(shotms[i] - Tms > (uint32_t)the_conf.trigpause[i]){ + shotms[i] = Tms; + memcpy(&shottime[i], &trgtm, sizeof(trigtime)); + trigger_shot |= 1<PR = EXTI_PR_PR4; +} + void exti15_10_isr(){ // PA13 - button0, PA14 - button1 + savetrigtime(); if(EXTI->PR & EXTI_PR_PR13){ - /* - if(trigger_ms[0] == DIDNT_TRIGGERED){ // prevent bounce - trigger_ms[0] = Timer; - memcpy(&trigger_time[0], ¤t_time, sizeof(curtime)); - } - */ + fillshotms(0); DBG("exti13"); EXTI->PR = EXTI_PR_PR13; } if(EXTI->PR & EXTI_PR_PR14){ - /* - if(trigger_ms[3] == DIDNT_TRIGGERED){ // prevent bounce - trigger_ms[3] = Timer; - memcpy(&trigger_time[3], ¤t_time, sizeof(curtime)); - } - */ + fillshotms(1); DBG("exti14"); EXTI->PR = EXTI_PR_PR14; } } + +/** + * @brief gettrig - get trigger state + * @return 1 if trigger active or 0 + */ +uint8_t gettrig(uint8_t N){ + if(N >= TRIGGERS_AMOUNT) return 0; + uint8_t curval = (trigport[N]->IDR & trigpin[N]) ? 1 : 0; + if(curval == trigstate[N]) return 1; + else return 0; +} diff --git a/F1-nolib/chronometer/hardware.h b/F1-nolib/chronometer/hardware.h index 00a3842..d392e39 100644 --- a/F1-nolib/chronometer/hardware.h +++ b/F1-nolib/chronometer/hardware.h @@ -25,6 +25,7 @@ #define __HARDWARE_H__ #include "stm32f1.h" +#include "time.h" // onboard LEDs - PB8/PB9 #define LED0_port GPIOB @@ -36,10 +37,14 @@ #define PPS_port GPIOA #define PPS_pin (1<<1) -// Buttons' state: PA13 (0)/PA14 (1) -#define GET_BTN0() ((GPIOA->IDR & (1<<13)) ? 0 : 1) -#define GET_BTN1() ((GPIOA->IDR & (1<<14)) ? 0 : 1) -#define GET_PPS() ((GPIOA->IDR & (1<<1)) ? 1 : 0) +// PPS and triggers state +// amount of triggers, should be less than 9 +#define TRIGGERS_AMOUNT (3) +extern GPIO_TypeDef *trigport[TRIGGERS_AMOUNT]; +extern uint16_t trigpin[TRIGGERS_AMOUNT]; +extern uint8_t trigstate[TRIGGERS_AMOUNT]; +uint8_t gettrig(uint8_t N); +#define GET_PPS() ((GPIOA->IDR & (1<<1)) ? 1 : 0) // USB pullup - PA15 #define USBPU_port GPIOA @@ -58,6 +63,16 @@ #define GPS_USART (2) #define LIDAR_USART (3) +typedef struct{ + uint32_t millis; + curtime Time; +} trigtime; + +// time of triggers shot +extern trigtime shottime[TRIGGERS_AMOUNT]; +// if trigger[N] shots, the bit N will be 1 +extern uint8_t trigger_shot; + void hw_setup(); #endif // __HARDWARE_H__ diff --git a/F1-nolib/chronometer/main.c b/F1-nolib/chronometer/main.c index cd68b43..f479409 100644 --- a/F1-nolib/chronometer/main.c +++ b/F1-nolib/chronometer/main.c @@ -71,7 +71,7 @@ void iwdg_setup(){ #ifdef EBUG char *parse_cmd(char *buf){ int32_t N; - static char btns[] = "BTN0=0, BTN1=0, PPS=0\n"; + static char btns[] = "BTN0=0, BTN1=0, BTN2=0, PPS=0\n"; switch(*buf){ case '0': LED_off(); @@ -80,9 +80,10 @@ char *parse_cmd(char *buf){ LED_on(); break; case 'b': - btns[5] = GET_BTN0() + '0'; - btns[13] = GET_BTN1() + '0'; - btns[20] = GET_PPS() + '0'; + btns[5] = gettrig(0) + '0'; + btns[13] = gettrig(1) + '0'; + btns[21] = gettrig(2) + '0'; + btns[28] = GET_PPS() + '0'; return btns; break; case 'C': @@ -177,11 +178,14 @@ int main(void){ uint32_t lastT = 0; sysreset(); StartHSE(); - hw_setup(); LED1_off(); USBPU_OFF(); - usarts_setup(); 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(); + usarts_setup(); SEND("Chronometer version " VERSION ".\n"); if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured SEND("WDGRESET=1\n"); @@ -194,17 +198,6 @@ int main(void){ USB_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 @@ -227,6 +220,7 @@ int main(void){ transmit_tbuf(GPS_USART); transmit_tbuf(LIDAR_USART); } + if(trigger_shot) show_trigger_shot(trigger_shot); usb_proc(); int r = 0; char *txt; @@ -258,6 +252,10 @@ int main(void){ r = usart_getline(GPS_USART, &txt); if(r){ txt[r] = 0; + if(showGPSstr){ + showGPSstr = 0; + USB_send(txt); + } GPS_parse_answer(txt); } } diff --git a/F1-nolib/chronometer/str.c b/F1-nolib/chronometer/str.c index f22cc17..7d89339 100644 --- a/F1-nolib/chronometer/str.c +++ b/F1-nolib/chronometer/str.c @@ -22,6 +22,9 @@ #include "usart.h" #include "usb.h" +// flag to show new GPS message over USB +uint8_t showGPSstr = 0; + /** * @brief cmpstr - the same as strncmp * @param s1,s2 - strings to compare @@ -30,9 +33,14 @@ */ int cmpstr(const char *s1, const char *s2, int n){ int ret = 0; - do{ + while(--n){ ret = *s1 - *s2; - }while(*s1++ && *s2++ && --n); + if(ret == 0 && *s1 && *s2){ + ++s1; ++s2; + continue; + } + break; + } return ret; } @@ -49,6 +57,23 @@ char *getchr(const char *str, char symbol){ return NULL; } +/** + * @brief showuserconf - show configuration over USB + */ +static void showuserconf(){ + USB_send("\nCONFIG:\nDISTMIN="); USB_send(u2str(the_conf.dist_min)); + USB_send("\nDISTMAX="); USB_send(u2str(the_conf.dist_max)); + USB_send("\nPULLUPS="); USB_send(u2str(the_conf.trig_pullups)); + USB_send("\nTRIGLVL="); USB_send(u2str(the_conf.trigstate)); + USB_send("\nTRIGPAUSE={"); + for(int i = 0; i < TRIGGERS_AMOUNT; ++i){ + if(i) USB_send(", "); + USB_send(u2str(the_conf.trigpause[i])); + } + USB_send("}"); + USB_send("\nENDCONFIG\n"); +} + /** * @brief parse_USBCMD - parsing of string buffer got by USB * @param cmd - buffer with commands @@ -61,12 +86,19 @@ int parse_USBCMD(char *cmd){ uint8_t succeed = 0; int32_t N; if(!cmd || !*cmd) return 0; + IWDG->KR = IWDG_REFRESH; if(*cmd == '?'){ // help USB_send("Commands:\n" CMD_DISTMIN " - min distance threshold (cm)\n" CMD_DISTMAX " - max distance threshold (cm)\n" + CMD_GPSSTR " - current GPS data string\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_STORECONF " - store new configuration in flash\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" ); }else if(CMP(cmd, CMD_PRINTTIME) == 0){ USB_send(get_time(¤t_time, get_millis())); @@ -98,10 +130,77 @@ int parse_USBCMD(char *cmd){ succeed = 1; } } + }else if(CMP(cmd, CMD_GPSSTR) == 0){ // show GPS status string + showGPSstr = 1; + return 0; + }else if(CMP(cmd, CMD_PULLUP) == 0){ + DBG("Pullups"); + cmd += sizeof(CMD_PULLUP) - 1; + uint8_t Nt = *cmd++ - '0'; + if(Nt > TRIGGERS_AMOUNT - 1) goto bad_number; + uint8_t state = *cmd -'0'; + if(state > 1) goto bad_number; + uint8_t oldval = the_conf.trig_pullups; + if(!state) the_conf.trig_pullups = oldval & ~(1< TRIGGERS_AMOUNT - 1) goto bad_number; + uint8_t state = *cmd -'0'; + if(state > 1) goto bad_number; + uint8_t oldval = the_conf.trigstate; + if(!state) the_conf.trigstate = oldval & ~(1< TRIGGERS_AMOUNT - 1) goto bad_number; + if(getnum(cmd, &N)) goto bad_number; + if(N < 0 || N > 10000) goto bad_number; + if(the_conf.trigpause[Nt] != N) conf_modified = 1; + the_conf.trigpause[Nt] = N; + succeed = 1; + }else if(CMP(cmd, CMD_TRGTIME) == 0){ + DBG("Trigger time"); + cmd += sizeof(CMD_TRGTIME) - 1; + uint8_t Nt = *cmd++ - '0'; + if(Nt > TRIGGERS_AMOUNT - 1) goto bad_number; + show_trigger_shot((uint8_t)1<KR = IWDG_REFRESH; if(succeed) USB_send("Success!\n"); return 0; bad_number: USB_send("Error: bad number!\n"); return 0; } + +/** + * @brief show_trigger_shot - print on USB message about last trigger shot time + * @param tshot - each bit consists information about trigger + */ +void show_trigger_shot(uint8_t tshot){ + uint8_t X = 1; + for(int i = 0; i < TRIGGERS_AMOUNT && tshot; ++i, X <<= 1){ + IWDG->KR = IWDG_REFRESH; + if(tshot & X) tshot &= ~X; + else continue; + if(trigger_shot & X) trigger_shot &= ~X; + USB_send("TRIG"); + USB_send(u2str(i)); + USB_send("="); + USB_send(get_time(&shottime[i].Time, shottime[i].millis)); + USB_send("\n"); + } +} diff --git a/F1-nolib/chronometer/str.h b/F1-nolib/chronometer/str.h index 95d86ea..7f06f47 100644 --- a/F1-nolib/chronometer/str.h +++ b/F1-nolib/chronometer/str.h @@ -19,6 +19,9 @@ #ifndef STR_H__ #define STR_H__ +#include "stm32f1.h" +#include "hardware.h" + // usb commands // lower and upper limits to capture #define CMD_DISTMIN "distmin" @@ -29,8 +32,18 @@ #define CMD_ADC2MAX "adc2max" #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" +#define CMD_TRGTIME "trigtime" + +extern uint8_t showGPSstr; int cmpstr(const char *s1, const char *s2, int n); char *getchr(const char *str, char symbol); int parse_USBCMD(char *cmd); +void show_trigger_shot(uint8_t trigger_shot); + #endif // STR_H__ diff --git a/F1-nolib/chronometer/time.c b/F1-nolib/chronometer/time.c index 64908ba..1eef0c3 100644 --- a/F1-nolib/chronometer/time.c +++ b/F1-nolib/chronometer/time.c @@ -72,15 +72,8 @@ void time_increment(){ char *get_time(curtime *Tm, uint32_t T){ static char buf[64]; char *bstart = &buf[5], *bptr = bstart; - /* - void putint(int i){ // put integer from 0 to 99 into buffer with leading zeros - if(i > 9){ - *bptr++ = i/10 + '0'; - i = i%10; - }else *bptr++ = '0'; - *bptr++ = i + '0'; - }*/ int S = 0; + if(T > 999) return "Wrong time"; if(Tm->S < 60 && Tm->M < 60 && Tm->H < 24) S = Tm->S + Tm->H*3600 + Tm->M*60; // seconds from day beginning if(!S) *(--bstart) = '0'; @@ -107,6 +100,10 @@ char *get_time(curtime *Tm, uint32_t T){ strcpy(bptr, " need PPS sync"); bptr += 14; } + if(GPS_status == GPS_NOTFOUND){ + strcpy(bptr, " GPS not found"); + bptr += 14; + } *bptr++ = '\n'; *bptr = 0; return bstart;