mirror of
https://github.com/eddyem/stm32samples.git
synced 2025-12-06 10:45:11 +03:00
add better version of EEPROM emulation in flash (for now - only in chronometer)
This commit is contained in:
parent
3a5ef823db
commit
7ac9d908fa
@ -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;
|
||||
|
||||
@ -12,6 +12,8 @@ LDSCRIPT ?= stm32f103x8.ld
|
||||
DEFS = -DVERSION=\"0.0.1\"
|
||||
# debug
|
||||
DEFS += -DEBUG
|
||||
# proxy GPS output over USART1
|
||||
DEFS += -DUSART1PROXY
|
||||
|
||||
INDEPENDENT_HEADERS=
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Binary file not shown.
240
F1-nolib/chronometer/flash.c
Normal file
240
F1-nolib/chronometer/flash.c
Normal 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
|
||||
48
F1-nolib/chronometer/flash.h
Normal file
48
F1-nolib/chronometer/flash.h
Normal 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__
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -16,11 +16,10 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -21,9 +21,13 @@
|
||||
#include "usb.h"
|
||||
#include <string.h>
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,8 +21,11 @@
|
||||
|
||||
#include <stm32f1.h>
|
||||
|
||||
#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__
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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__
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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));
|
||||
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user