add better version of EEPROM emulation in flash (for now - only in chronometer)

This commit is contained in:
eddyem 2019-07-10 23:38:56 +03:00
parent 3a5ef823db
commit 7ac9d908fa
17 changed files with 529 additions and 47 deletions

View File

@ -149,7 +149,9 @@ void GPS_send_start_seq(){
*/ */
void GPS_parse_answer(const char *buf){ void GPS_parse_answer(const char *buf){
char *ptr; char *ptr;
DBG(buf); #if defined USART1PROXY
usart_send(1, buf); newline();
#endif
if(buf[1] == 'P') return; // answers to proprietary messages if(buf[1] == 'P') return; // answers to proprietary messages
if(cmpstr(buf+3, "RMC", 3)){ // not RMC message if(cmpstr(buf+3, "RMC", 3)){ // not RMC message
need2startseq = 1; need2startseq = 1;

View File

@ -12,6 +12,8 @@ LDSCRIPT ?= stm32f103x8.ld
DEFS = -DVERSION=\"0.0.1\" DEFS = -DVERSION=\"0.0.1\"
# debug # debug
DEFS += -DEBUG DEFS += -DEBUG
# proxy GPS output over USART1
DEFS += -DUSART1PROXY
INDEPENDENT_HEADERS= INDEPENDENT_HEADERS=

View File

@ -11,7 +11,7 @@ Chronometer for downhill competitions
- PB8, PB9 - onboard LEDs - PB8, PB9 - onboard LEDs
- PA4 - TRIG2 - 12V trigger (EXTI) - PA4 - TRIG2 - 12V trigger (EXTI) -- not implemented yet
- PA13 - TRIG0 - button0 (EXTI) - PA13 - TRIG0 - button0 (EXTI)
- PA14 - TRIG1 - button1/laser/etc (EXTI) - PA14 - TRIG1 - button1/laser/etc (EXTI)
- PA15 - USB pullup - PA15 - USB pullup

Binary file not shown.

View File

@ -0,0 +1,240 @@
/*
* geany_encoding=koi8-r
* flash.c
*
* Copyright 2017 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 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 <string.h> // 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

View File

@ -0,0 +1,48 @@
/*
* flash.h
*
* Copyright 2017 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 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 <stm32f1.h>
#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__

View File

@ -23,6 +23,7 @@
#include "adc.h" #include "adc.h"
#include "hardware.h" #include "hardware.h"
#include "time.h"
#include "usart.h" #include "usart.h"
static inline void gpio_setup(){ 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; RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN;
// turn off SWJ/JTAG // turn off SWJ/JTAG
AFIO->MAPR = AFIO_MAPR_SWJ_CFG_DISABLE; AFIO->MAPR = AFIO_MAPR_SWJ_CFG_DISABLE;
// pullups // pullups: PA1 - PPS, PA13/PA14 - buttons
GPIOA->ODR = (1<<12)|(1<<13)|(1<<14); GPIOA->ODR = (1<<12)|(1<<13)|(1<<14)|(1<<15);
// Set led (PB8) as opendrain output // Set leds (PB8) as opendrain output
GPIOB->CRH = CRH(8, CNF_ODOUTPUT|MODE_SLOW); GPIOB->CRH = CRH(8, CNF_ODOUTPUT|MODE_SLOW) | CRH(9, CNF_ODOUTPUT|MODE_SLOW);
// PPS pin (PA1) - input with weak pullup // PPS pin (PA1) - input with weak pullup
GPIOA->CRL = CRL(1, CNF_PUDINPUT|MODE_INPUT); GPIOA->CRL = CRL(1, CNF_PUDINPUT|MODE_INPUT);
// Set buttons (PA13/14) as inputs with weak pullups, USB pullup (PA15) - opendrain output // 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 void exti1_isr(){ // PPS - PA1
/*
if(trigger_ms[2] == DIDNT_TRIGGERED){ // prevent bounce
trigger_ms[2] = Timer;
memcpy(&trigger_time[2], &current_time, sizeof(curtime));
}
*/
DBG("exti1"); DBG("exti1");
systick_correction();
EXTI->PR = EXTI_PR_PR1; EXTI->PR = EXTI_PR_PR1;
} }

View File

@ -35,10 +35,13 @@
#define CMD_ADC1MAX "adc1max" #define CMD_ADC1MAX "adc1max"
#define CMD_ADC2MAX "adc2max" #define CMD_ADC2MAX "adc2max"
#define CMD_PRINTTIME "time" #define CMD_PRINTTIME "time"
#define CMD_STORECONF "store"
// onboard LED - PB8 // onboard LEDs - PB8/PB9
#define LED_port GPIOB #define LED0_port GPIOB
#define LED_pin (1<<8) #define LED0_pin (1<<8)
#define LED1_port GPIOB
#define LED1_pin (1<<9)
// PPS pin - PA1 // PPS pin - PA1
#define PPS_port GPIOA #define PPS_port GPIOA
@ -55,9 +58,12 @@
#define USBPU_ON() pin_clear(USBPU_port, USBPU_pin) #define USBPU_ON() pin_clear(USBPU_port, USBPU_pin)
#define USBPU_OFF() pin_set(USBPU_port, USBPU_pin) #define USBPU_OFF() pin_set(USBPU_port, USBPU_pin)
#define LED_blink() pin_toggle(LED_port, LED_pin) #define LED_blink() pin_toggle(LED0_port, LED0_pin)
#define LED_on() pin_clear(LED_port, LED_pin) #define LED_on() pin_clear(LED0_port, LED0_pin)
#define LED_off() pin_set(LED_port, LED_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 // GPS USART == USART2, LIDAR USART == USART3
#define GPS_USART (2) #define GPS_USART (2)

View File

@ -16,11 +16,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "flash.h"
#include "lidar.h" #include "lidar.h"
#include "usart.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_dist = 0;
uint16_t last_lidar_stren = 0; uint16_t last_lidar_stren = 0;
uint16_t lidar_triggered_dist = 0; uint16_t lidar_triggered_dist = 0;
@ -35,7 +34,7 @@ void parse_lidar_data(char *txt){
return; return;
} }
if(triggered){ // check if body gone 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; triggered = 0;
#ifdef EBUG #ifdef EBUG
SEND("Untriggered! distance="); SEND("Untriggered! distance=");
@ -46,7 +45,7 @@ void parse_lidar_data(char *txt){
#endif #endif
} }
}else{ }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; triggered = 1;
lidar_triggered_dist = last_lidar_dist; lidar_triggered_dist = last_lidar_dist;
#ifdef EBUG #ifdef EBUG

View File

@ -27,6 +27,9 @@
#define LIDAR_LOWER_STREN (10) #define LIDAR_LOWER_STREN (10)
// triggered distance threshold - 1 meter // triggered distance threshold - 1 meter
#define LIDAR_DIST_THRES (100) #define LIDAR_DIST_THRES (100)
#define LIDAR_MIN_DIST (50)
#define LIDAR_MAX_DIST (1000)
extern uint16_t last_lidar_dist; extern uint16_t last_lidar_dist;
extern uint16_t lidar_triggered_dist; extern uint16_t lidar_triggered_dist;
extern uint16_t last_lidar_stren; extern uint16_t last_lidar_stren;

View File

@ -21,6 +21,7 @@
//#include "adc.h" //#include "adc.h"
#include "GPS.h" #include "GPS.h"
#include "flash.h"
#include "hardware.h" #include "hardware.h"
#include "lidar.h" #include "lidar.h"
#include "str.h" #include "str.h"
@ -33,11 +34,13 @@
#define VERSION "0.0.0" #define VERSION "0.0.0"
#endif #endif
// global pseudo-milliseconds counter
volatile uint32_t Tms = 0; volatile uint32_t Tms = 0;
/* Called when systick fires */ /* Called when systick fires */
void sys_tick_handler(void){ void sys_tick_handler(void){
++Tms; ++Tms;
increment_timer();
} }
void iwdg_setup(){ void iwdg_setup(){
@ -65,8 +68,8 @@ void iwdg_setup(){
#ifdef EBUG #ifdef EBUG
char *parse_cmd(char *buf){ 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, PPS=0\n";
if(buf[1] != '\n') return buf;
switch(*buf){ switch(*buf){
case '0': case '0':
LED_off(); LED_off();
@ -80,6 +83,16 @@ char *parse_cmd(char *buf){
btns[20] = GET_PPS() + '0'; btns[20] = GET_PPS() + '0';
return btns; return btns;
break; break;
case 'C':
if(getnum(&buf[1], &N)){
SEND("Need a number!\n");
}else{
addNrecs(N);
}
break;
case 'd':
dump_userconf();
break;
case 'p': case 'p':
pin_toggle(USBPU_port, USBPU_pin); pin_toggle(USBPU_port, USBPU_pin);
SEND("USB pullup is "); SEND("USB pullup is ");
@ -117,10 +130,13 @@ char *parse_cmd(char *buf){
while(1){nop();}; while(1){nop();};
break; break;
default: // help default: // help
if(buf[1] != '\n') return buf;
return return
"0/1 - turn on/off LED1\n" "0/1 - turn on/off LED1\n"
"'b' - get buttons's state\n" "'b' - get buttons's state\n"
"'d' - dump current user conf\n"
"'p' - toggle USB pullup\n" "'p' - toggle USB pullup\n"
"'C' - store userconf for N times\n"
"'G' - get last LIDAR distance\n" "'G' - get last LIDAR distance\n"
"'L' - send long string over USB\n" "'L' - send long string over USB\n"
"'R' - software reset\n" "'R' - software reset\n"
@ -155,22 +171,55 @@ static char *get_USB(){
return NULL; return NULL;
} }
#define CMP(a,b) cmpstr(a, b, sizeof(b)-1)
static void parse_USBCMD(char *cmd){ 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 || !*cmd) return;
if(*cmd == '?'){ // help if(*cmd == '?'){ // help
USB_send("Commands:\n" USB_send("Commands:\n"
CMD_DISTMIN " - min distance threshold (cm)\n" CMD_DISTMIN " - min distance threshold (cm)\n"
CMD_DISTMAX " - max distance threshold (cm)\n" CMD_DISTMAX " - max distance threshold (cm)\n"
CMD_PRINTTIME " - print time\n" CMD_PRINTTIME " - print time\n"
CMD_STORECONF " - store new configuration in flash\n"
); );
}else if(CMP(cmd, CMD_PRINTTIME) == 0){ }else if(CMP(cmd, CMD_PRINTTIME) == 0){
USB_send(get_time(&current_time, get_millis())); USB_send(get_time(&current_time, get_millis()));
}else if(CMP(cmd, CMD_DISTMIN) == 0){ // set low limit }else if(CMP(cmd, CMD_DISTMIN) == 0){ // set low limit
DBG("CMD_DISTMIN"); 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 }else if(CMP(cmd, CMD_DISTMAX) == 0){ // set low limit
DBG("CMD_DISTMAX"); 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){ int main(void){
@ -178,9 +227,10 @@ int main(void){
sysreset(); sysreset();
StartHSE(); StartHSE();
hw_setup(); hw_setup();
LED1_off();
USBPU_OFF(); USBPU_OFF();
usarts_setup(); usarts_setup();
SysTick_Config(72000); SysTick_Config(SYSTICK_DEFLOAD);
SEND("Chronometer version " VERSION ".\n"); SEND("Chronometer version " VERSION ".\n");
if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured
SEND("WDGRESET=1\n"); SEND("WDGRESET=1\n");
@ -191,14 +241,27 @@ int main(void){
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
USB_setup(); USB_setup();
//iwdg_setup(); iwdg_setup();
USBPU_ON(); 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){ while (1){
IWDG->KR = IWDG_REFRESH; // refresh watchdog IWDG->KR = IWDG_REFRESH; // refresh watchdog
if(lastT > Tms || Tms - lastT > 499){ if(lastT > Tms || Tms - lastT > 499){
if(need2startseq) GPS_send_start_seq(); if(need2startseq) GPS_send_start_seq();
LED_blink(); LED_blink();
if(GPS_status != GPS_VALID) LED1_blink();
else LED1_on();
lastT = Tms; lastT = Tms;
if(usartrx(LIDAR_USART)){ if(usartrx(LIDAR_USART)){
char *txt; char *txt;
@ -207,7 +270,7 @@ int main(void){
DBG(txt); DBG(txt);
} }
} }
#ifdef EBUG #if defined EBUG || defined USART1PROXY
transmit_tbuf(1); // non-blocking transmission of data from UART buffer every 0.5s transmit_tbuf(1); // non-blocking transmission of data from UART buffer every 0.5s
#endif #endif
transmit_tbuf(GPS_USART); transmit_tbuf(GPS_USART);
@ -215,23 +278,28 @@ int main(void){
} }
usb_proc(); usb_proc();
int r = 0; int r = 0;
char *txt, *ans; char *txt;
if((txt = get_USB())){ if((txt = get_USB())){
parse_USBCMD(txt); parse_USBCMD(txt);
DBG("Received data over USB:"); DBG("Received data over USB:");
DBG(txt); DBG(txt);
USB_send(txt); // echo all back USB_send(txt); // echo all back
} }
#ifdef EBUG #if defined EBUG || defined USART1PROXY
if(usartrx(1)){ // usart1 received data, store in in buffer if(usartrx(1)){ // usart1 received data, store in in buffer
r = usart_getline(1, &txt); r = usart_getline(1, &txt);
if(r){ if(r){
txt[r] = 0; txt[r] = 0;
ans = parse_cmd(txt); #ifdef EBUG
char *ans = parse_cmd(txt);
if(ans){ if(ans){
transmit_tbuf(1);
usart_send(1, ans); usart_send(1, ans);
transmit_tbuf(1); transmit_tbuf(1);
} }
#else // USART1PROXY - send received data to GPS
usart_send(GPS_USART, txt);
#endif
} }
} }
#endif #endif
@ -251,4 +319,3 @@ int main(void){
} }
return 0; return 0;
} }

View File

@ -21,9 +21,13 @@
#include "usb.h" #include "usb.h"
#include <string.h> #include <string.h>
volatile uint32_t Timer; // milliseconds counter
curtime current_time = TMNOTINI; curtime current_time = TMNOTINI;
volatile int need_sync = 1; 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){ static inline uint8_t atou(const char *b){
return (b[0]-'0')*10 + b[1]-'0'; return (b[0]-'0')*10 + b[1]-'0';
} }
@ -36,6 +40,22 @@ void set_time(const char *buf){
current_time.S = atou(&buf[4]); 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 * print time: Tm - time structure, T - milliseconds
*/ */
@ -90,3 +110,54 @@ uint32_t get_millis(){
// TODO: calculate right millis // TODO: calculate right millis
return Tms % 1000; // temporary gag 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();
}
}

View File

@ -21,7 +21,10 @@
#include <stm32f1.h> #include <stm32f1.h>
#define STK_RVR_DEFAULT_VAL (8999) // 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 TIMEZONE_GMT_PLUS (3)
#define DIDNT_TRIGGERED (2000) #define DIDNT_TRIGGERED (2000)
@ -38,6 +41,7 @@ typedef struct{
} curtime; } curtime;
extern volatile uint32_t Tms; extern volatile uint32_t Tms;
extern volatile uint32_t Timer;
extern curtime current_time; extern curtime current_time;
extern curtime trigger_time[]; extern curtime trigger_time[];
@ -48,5 +52,8 @@ extern volatile int need_sync;
char *get_time(curtime *T, uint32_t m); char *get_time(curtime *T, uint32_t m);
void set_time(const char *buf); void set_time(const char *buf);
uint32_t get_millis(); // current milliseconds uint32_t get_millis(); // current milliseconds
void time_increment();
void systick_correction();
void increment_timer();
#endif // TIME_H__ #endif // TIME_H__

View File

@ -94,7 +94,7 @@ void usart_send(int n, const char *str){
tbuf[n][tbufno[n]][odatalen[n][tbufno[n]]++] = *str++; tbuf[n][tbufno[n]][odatalen[n][tbufno[n]]++] = *str++;
} }
} }
#ifdef EBUG #if defined EBUG || defined USART1PROXY
// only for USART1 // only for USART1
void newline(){ void newline(){
usart_putchar(1, '\n'); usart_putchar(1, '\n');
@ -168,8 +168,8 @@ static void usart_setup(int n, uint32_t BRR){
void usarts_setup(){ void usarts_setup(){
RCC->AHBENR |= RCC_AHBENR_DMA1EN; RCC->AHBENR |= RCC_AHBENR_DMA1EN;
#ifdef EBUG #if defined EBUG || defined USART1PROXY
usart_setup(1, 72000000 / 115200); // debug console usart_setup(1, 72000000 / 115200); // debug console or GPS proxy
#endif #endif
usart_setup(2, 36000000 / 9600); // GPS usart_setup(2, 36000000 / 9600); // GPS
usart_setup(3, 36000000 / 115200); // LIDAR 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(){ void usart1_isr(){
usart_isr(1, USART1); usart_isr(1, USART1);
} }
@ -310,7 +310,7 @@ void hexdump(uint8_t *arr, uint16_t len){
} }
#endif #endif
#ifdef EBUG #if defined EBUG || defined USART1PROXY
void dma1_channel4_isr(){ // USART1 void dma1_channel4_isr(){ // USART1
if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx
DMA1->IFCR = DMA_IFCR_CTCIF4; // clear TC flag DMA1->IFCR = DMA_IFCR_CTCIF4; // clear TC flag
@ -332,3 +332,34 @@ void dma1_channel2_isr(){ // USART3
txrdy[3] = 1; 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;
}

View File

@ -55,13 +55,13 @@ void usart_putchar(int n, char ch);
char *u2str(uint32_t val); char *u2str(uint32_t val);
void printu(int n, uint32_t val); void printu(int n, uint32_t val);
void printuhex(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(); void newline();
#endif
#ifdef EBUG
void hexdump(uint8_t *arr, uint16_t len); void hexdump(uint8_t *arr, uint16_t len);
#endif #endif
/*
void hexdump16(uint16_t *arr, uint16_t len);
void hexdump32(uint32_t *arr, uint16_t len);
*/
#endif // __USART_H__ #endif // __USART_H__

View File

@ -102,6 +102,10 @@ void usb_proc(){
} }
void USB_send(char *buf){ void USB_send(char *buf){
if(!USB_configured()){
DBG("USB not configured");
return;
}
uint16_t l = 0, ctr = 0; uint16_t l = 0, ctr = 0;
char *p = buf; char *p = buf;
while(*p++) ++l; while(*p++) ++l;

View File

@ -71,6 +71,12 @@ SECTIONS {
_edata = .; _edata = .;
} >ram AT >rom } >ram AT >rom
.myvars :
{
. = ALIGN(1024);
KEEP(*(.myvars))
} > rom
_ldata = LOADADDR(.data); _ldata = LOADADDR(.data);
.bss : .bss :