mirror of
https://github.com/eddyem/stm32samples.git
synced 2026-02-28 03:44:30 +03:00
hide deprecated code; make USB snippet common for F0/F1/F3
This commit is contained in:
159
F1:F103/deprecated/CDC_ACM/Makefile
Normal file
159
F1:F103/deprecated/CDC_ACM/Makefile
Normal file
@@ -0,0 +1,159 @@
|
||||
# make debug adds -DEBUG -Werror
|
||||
# make ADDEFS="additional defs"
|
||||
BINARY = cdcacm
|
||||
BOOTPORT ?= /dev/ttyUSB0
|
||||
BOOTSPEED ?= 115200
|
||||
# MCU FAMILY
|
||||
FAMILY ?= F1
|
||||
# MCU code
|
||||
MCU ?= F103x8
|
||||
# density (stm32f10x.h, lines 70-84)
|
||||
DENSITY ?= MD
|
||||
# change this linking script depending on particular MCU model,
|
||||
LDSCRIPT ?= stm32f103x8.ld
|
||||
DEFS = ${ADDEFS} -DVERSION=\"0.0.1\"
|
||||
TARGET := RELEASE
|
||||
# proxy GPS output over USART1
|
||||
#DEFS += -DUSART1PROXY
|
||||
|
||||
FP_FLAGS ?= -msoft-float -mfloat-abi=soft
|
||||
ASM_FLAGS ?= -mthumb -mcpu=cortex-m3 -mfix-cortex-m3-ldrd
|
||||
ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS)
|
||||
|
||||
###############################################################################
|
||||
# Executables
|
||||
#PREFIX ?= arm-none-eabi
|
||||
# gcc from arm web site
|
||||
PREFIX ?= /opt/bin/arm-none-eabi
|
||||
TOOLCHLIB ?= /opt/arm-none-eabi/lib
|
||||
RM := rm -f
|
||||
RMDIR := rmdir
|
||||
CC := $(PREFIX)-gcc
|
||||
# don't replace ld with gcc: the binary size would be much greater!!
|
||||
LD := $(PREFIX)-ld
|
||||
AR := $(PREFIX)-ar
|
||||
AS := $(PREFIX)-as
|
||||
SIZE := $(PREFIX)-size
|
||||
OBJCOPY := $(PREFIX)-objcopy
|
||||
OBJDUMP := $(PREFIX)-objdump
|
||||
GDB := $(PREFIX)-gdb
|
||||
STFLASH := $(shell which st-flash)
|
||||
STBOOT := $(shell which stm32flash)
|
||||
DFUUTIL := $(shell which dfu-util)
|
||||
|
||||
###############################################################################
|
||||
# Source files
|
||||
OBJDIR = mk
|
||||
SRC := $(wildcard *.c)
|
||||
OBJS := $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o))
|
||||
STARTUP = $(OBJDIR)/startup.o
|
||||
OBJS += $(STARTUP)
|
||||
# dependencies: we need them to recompile files if their headers-dependencies changed
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
|
||||
INC_DIR ?= ../inc
|
||||
|
||||
INCLUDE := -I$(INC_DIR)/Fx -I$(INC_DIR)/cm
|
||||
LIB_DIR := $(INC_DIR)/ld
|
||||
|
||||
###############################################################################
|
||||
# C flags
|
||||
CFLAGS += -O2 -g -D__thumb2__=1 -MD
|
||||
CFLAGS += -Wall -Wextra -Wshadow
|
||||
CFLAGS += -fno-common -ffunction-sections -fdata-sections -fno-stack-protector
|
||||
CFLAGS += $(ARCH_FLAGS)
|
||||
|
||||
###############################################################################
|
||||
# Linker flags
|
||||
LDFLAGS += --static -nostartfiles -nostdlibs
|
||||
LDFLAGS += -L$(LIB_DIR) -L$(TOOLCHLIB)
|
||||
LDFLAGS += -T$(LDSCRIPT)
|
||||
|
||||
###############################################################################
|
||||
# Used libraries
|
||||
LDLIBS += -lc $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
|
||||
|
||||
DEFS += -DSTM32$(FAMILY) -DSTM32$(MCU) -DSTM32F10X_$(DENSITY)
|
||||
|
||||
ELF := $(OBJDIR)/$(BINARY).elf
|
||||
LIST := $(OBJDIR)/$(BINARY).list
|
||||
BIN := $(BINARY).bin
|
||||
HEX := $(BINARY).hex
|
||||
|
||||
all: $(OBJDIR)/RELEASE bin list size
|
||||
release: all
|
||||
|
||||
debug: CFLAGS += -DEBUG -Werror
|
||||
debug: $(OBJDIR)/DEBUG bin list size
|
||||
|
||||
$(OBJDIR)/DEBUG:
|
||||
@rm -rf $(OBJDIR)
|
||||
@mkdir $(OBJDIR)
|
||||
@> $(OBJDIR)/DEBUG
|
||||
@echo "TARGET: DEBUG"
|
||||
echo "CFLAGS += -DEBUG -Werror" > $(OBJDIR)/CFLAGS
|
||||
$(OBJDIR)/RELEASE:
|
||||
@rm -rf $(OBJDIR)
|
||||
@mkdir $(OBJDIR)
|
||||
@> $(OBJDIR)/RELEASE
|
||||
@echo "TARGET: RELEASE"
|
||||
echo "" > $(OBJDIR)/CFLAGS
|
||||
|
||||
elf: $(ELF)
|
||||
bin: $(BIN)
|
||||
hex: $(HEX)
|
||||
list: $(LIST)
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(DEPS)
|
||||
-include $(OBJDIR)/CFLAGS
|
||||
endif
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir $(OBJDIR)
|
||||
|
||||
$(STARTUP): $(INC_DIR)/startup/vector.c
|
||||
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $<
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
@echo " CC $<"
|
||||
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $<
|
||||
|
||||
$(BIN): $(ELF)
|
||||
@echo " OBJCOPY $(BIN)"
|
||||
$(OBJCOPY) -Obinary $(ELF) $(BIN)
|
||||
|
||||
$(HEX): $(ELF)
|
||||
@echo " OBJCOPY $(HEX)"
|
||||
$(OBJCOPY) -Oihex $(ELF) $(HEX)
|
||||
|
||||
$(LIST): $(ELF)
|
||||
@echo " OBJDUMP $(LIST)"
|
||||
$(OBJDUMP) -S $(ELF) > $(LIST)
|
||||
|
||||
$(ELF): $(OBJDIR) $(OBJS)
|
||||
@echo " LD $(ELF)"
|
||||
$(LD) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(ELF)
|
||||
|
||||
size: $(ELF)
|
||||
$(SIZE) $(ELF)
|
||||
|
||||
clean:
|
||||
@echo " CLEAN"
|
||||
@$(RM) $(HEX)
|
||||
@$(RM) -rf $(OBJDIR) 2>/dev/null || true
|
||||
|
||||
|
||||
flash: $(BIN)
|
||||
@echo " FLASH $(BIN)"
|
||||
$(STFLASH) --reset write $(BIN) 0x8000000
|
||||
|
||||
boot: $(BIN)
|
||||
@echo " LOAD $(BIN) through bootloader"
|
||||
$(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN)
|
||||
|
||||
dfuboot: $(BIN)
|
||||
@echo " LOAD $(BIN) THROUGH DFU"
|
||||
$(DFUUTIL) -a0 -D $(BIN) -s 0x08000000
|
||||
|
||||
.PHONY: clean flash boot
|
||||
1
F1:F103/deprecated/CDC_ACM/Readme
Normal file
1
F1:F103/deprecated/CDC_ACM/Readme
Normal file
@@ -0,0 +1 @@
|
||||
Base CDC snippet
|
||||
BIN
F1:F103/deprecated/CDC_ACM/cdcacm.bin
Executable file
BIN
F1:F103/deprecated/CDC_ACM/cdcacm.bin
Executable file
Binary file not shown.
47
F1:F103/deprecated/CDC_ACM/hardware.c
Normal file
47
F1:F103/deprecated/CDC_ACM/hardware.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* hardware.c - hardware-dependent macros & functions
|
||||
*
|
||||
* Copyright 2018 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
// pause in milliseconds for some purposes
|
||||
void pause_ms(uint32_t pause){
|
||||
uint32_t Tnxt = Tms + pause;
|
||||
while(Tms < Tnxt) nop();
|
||||
}
|
||||
|
||||
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_IOPCEN | RCC_APB2ENR_AFIOEN;
|
||||
// turn off SWJ/JTAG
|
||||
// AFIO->MAPR = AFIO_MAPR_SWJ_CFG_DISABLE;
|
||||
// turn off USB pullup
|
||||
GPIOA->ODR = (1<<13); // turn off usb pullup & turn on pullups for buttons
|
||||
// Set led as opendrain output
|
||||
GPIOC->CRH |= CRH(13, CNF_ODOUTPUT|MODE_SLOW);
|
||||
// USB pullup (PA13) - opendrain output
|
||||
GPIOA->CRH = CRH(13, CNF_ODOUTPUT|MODE_SLOW);
|
||||
}
|
||||
|
||||
void hw_setup(){
|
||||
gpio_setup();
|
||||
}
|
||||
48
F1:F103/deprecated/CDC_ACM/hardware.h
Normal file
48
F1:F103/deprecated/CDC_ACM/hardware.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* hardware.h
|
||||
*
|
||||
* Copyright 2018 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 __HARDWARE_H__
|
||||
#define __HARDWARE_H__
|
||||
|
||||
#include "stm32f1.h"
|
||||
|
||||
// LED0 - PC13 (bluepill), blinking each second
|
||||
#define LED0_port GPIOC
|
||||
#define LED0_pin (1<<13)
|
||||
|
||||
// USB pullup (not present in bluepill) - PA13
|
||||
#define USBPU_port GPIOA
|
||||
#define USBPU_pin (1<<13)
|
||||
#define USBPU_ON() pin_clear(USBPU_port, USBPU_pin)
|
||||
#define USBPU_OFF() pin_set(USBPU_port, USBPU_pin)
|
||||
|
||||
#define LED_blink(x) pin_toggle(x ## _port, x ## _pin)
|
||||
#define LED_on(x) pin_clear(x ## _port, x ## _pin)
|
||||
#define LED_off(x) pin_set(x ## _port, x ## _pin)
|
||||
|
||||
extern volatile uint32_t Tms;
|
||||
|
||||
void pause_ms(uint32_t pause);
|
||||
void hw_setup();
|
||||
|
||||
#endif // __HARDWARE_H__
|
||||
146
F1:F103/deprecated/CDC_ACM/main.c
Normal file
146
F1:F103/deprecated/CDC_ACM/main.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* main.c
|
||||
*
|
||||
* Copyright 2017 Edward V. Emelianoff <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.
|
||||
*/
|
||||
|
||||
#include "hardware.h"
|
||||
#include "proto.h"
|
||||
#include "usb.h"
|
||||
#include "usb_lib.h"
|
||||
|
||||
volatile uint32_t Tms = 0;
|
||||
|
||||
/* Called when systick fires */
|
||||
void sys_tick_handler(void){
|
||||
++Tms;
|
||||
}
|
||||
|
||||
void iwdg_setup(){
|
||||
uint32_t tmout = 16000000;
|
||||
/* Enable the peripheral clock RTC */
|
||||
/* (1) Enable the LSI (40kHz) */
|
||||
/* (2) Wait while it is not ready */
|
||||
RCC->CSR |= RCC_CSR_LSION; /* (1) */
|
||||
while((RCC->CSR & RCC_CSR_LSIRDY) != RCC_CSR_LSIRDY){if(--tmout == 0) break;} /* (2) */
|
||||
/* Configure IWDG */
|
||||
/* (1) Activate IWDG (not needed if done in option bytes) */
|
||||
/* (2) Enable write access to IWDG registers */
|
||||
/* (3) Set prescaler by 64 (1.6ms for each tick) */
|
||||
/* (4) Set reload value to have a rollover each 2s */
|
||||
/* (5) Check if flags are reset */
|
||||
/* (6) Refresh counter */
|
||||
IWDG->KR = IWDG_START; /* (1) */
|
||||
IWDG->KR = IWDG_WRITE_ACCESS; /* (2) */
|
||||
IWDG->PR = IWDG_PR_PR_1; /* (3) */
|
||||
IWDG->RLR = 1250; /* (4) */
|
||||
tmout = 16000000;
|
||||
while(IWDG->SR){if(--tmout == 0) break;} /* (5) */
|
||||
IWDG->KR = IWDG_REFRESH; /* (6) */
|
||||
}
|
||||
|
||||
#define USBBUF 63
|
||||
// usb getline
|
||||
static char *get_USB(){
|
||||
static char tmpbuf[USBBUF+1], *curptr = tmpbuf;
|
||||
static int rest = USBBUF;
|
||||
uint8_t x = USB_receive((uint8_t*)curptr);
|
||||
if(!x) return NULL;
|
||||
curptr[x] = 0;
|
||||
if(x == 1 && *curptr == 0x7f){ // backspace
|
||||
if(curptr > tmpbuf){
|
||||
--curptr;
|
||||
USND("\b \b");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
USB_sendstr(curptr); // echo
|
||||
if(curptr[x-1] == '\n'){ // || curptr[x-1] == '\r'){
|
||||
curptr = tmpbuf;
|
||||
rest = USBBUF;
|
||||
// omit empty lines
|
||||
if(tmpbuf[0] == '\n') return NULL;
|
||||
// and wrong empty lines
|
||||
if(tmpbuf[0] == '\r' && tmpbuf[1] == '\n') return NULL;
|
||||
return tmpbuf;
|
||||
}
|
||||
curptr += x; rest -= x;
|
||||
if(rest <= 0){ // buffer overflow
|
||||
curptr = tmpbuf;
|
||||
rest = USBBUF;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* - these functions need for true USB-TTY
|
||||
static uint32_t newrate = 0;
|
||||
// redefine weak handlers
|
||||
void linecoding_handler(usb_LineCoding *lcd){
|
||||
newrate = lcd->dwDTERate;
|
||||
}
|
||||
static uint16_t cl = 0xffff;
|
||||
void clstate_handler(uint16_t val){
|
||||
cl = val;
|
||||
}
|
||||
static int8_t br = 0;
|
||||
void break_handler(){
|
||||
br = 1;
|
||||
}*/
|
||||
|
||||
int main(void){
|
||||
uint32_t lastT = 0;
|
||||
sysreset();
|
||||
StartHSE();
|
||||
SysTick_Config(72000);
|
||||
hw_setup();
|
||||
|
||||
USBPU_OFF();
|
||||
/* if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured
|
||||
SEND("WDGRESET=1"); newline();
|
||||
}
|
||||
if(RCC->CSR & RCC_CSR_SFTRSTF){ // software reset occured
|
||||
SEND("SOFTRESET=1"); newline();
|
||||
}*/
|
||||
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
|
||||
|
||||
USB_setup();
|
||||
iwdg_setup();
|
||||
USBPU_ON();
|
||||
|
||||
while (1){
|
||||
IWDG->KR = IWDG_REFRESH; // refresh watchdog
|
||||
if(Tms - lastT > 499){
|
||||
LED_blink(LED0);
|
||||
lastT = Tms;
|
||||
}
|
||||
usb_proc();
|
||||
char *txt = get_USB();
|
||||
if(txt){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
cmd_parser(txt);
|
||||
}
|
||||
/*
|
||||
int n = 0;
|
||||
if(newrate){SEND("new speed: "); printu(newrate); n = 1; newrate = 0;}
|
||||
if(cl!=0xffff){SEND("controls: "); printuhex(cl); n = 1; cl = 0xffff;}
|
||||
if(br){SEND("break"); n = 1; br = 0;}
|
||||
if(n){newline(); transmit_tbuf();}*/
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
205
F1:F103/deprecated/CDC_ACM/proto.c
Normal file
205
F1:F103/deprecated/CDC_ACM/proto.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* proto.c
|
||||
*
|
||||
* Copyright 2018 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.
|
||||
*
|
||||
*/
|
||||
#include "hardware.h"
|
||||
#include "proto.h"
|
||||
#include "usb.h"
|
||||
|
||||
#include <string.h> // strlen
|
||||
|
||||
static char buff[BUFSZ+1], *bptr = buff;
|
||||
static uint8_t blen = 0;
|
||||
|
||||
void sendbuf(){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(blen == 0) return;
|
||||
*bptr = 0;
|
||||
USB_sendstr(buff);
|
||||
bptr = buff;
|
||||
blen = 0;
|
||||
}
|
||||
|
||||
void bufputchar(char ch){
|
||||
if(blen > BUFSZ-1){
|
||||
sendbuf();
|
||||
}
|
||||
*bptr++ = ch;
|
||||
++blen;
|
||||
}
|
||||
|
||||
void addtobuf(const char *txt){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
while(*txt) bufputchar(*txt++);
|
||||
}
|
||||
|
||||
char *omit_spaces(char *buf){
|
||||
while(*buf){
|
||||
if(*buf > ' ') break;
|
||||
++buf;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
// THERE'S NO OVERFLOW PROTECTION IN NUMBER READ PROCEDURES!
|
||||
// read decimal number
|
||||
static char *getdec(char *buf, uint32_t *N){
|
||||
uint32_t num = 0;
|
||||
while(*buf){
|
||||
char c = *buf;
|
||||
if(c < '0' || c > '9'){
|
||||
break;
|
||||
}
|
||||
num *= 10;
|
||||
num += c - '0';
|
||||
++buf;
|
||||
}
|
||||
*N = num;
|
||||
return buf;
|
||||
}
|
||||
// read hexadecimal number (without 0x prefix!)
|
||||
static char *gethex(char *buf, uint32_t *N){
|
||||
uint32_t num = 0;
|
||||
while(*buf){
|
||||
char c = *buf;
|
||||
uint8_t M = 0;
|
||||
if(c >= '0' && c <= '9'){
|
||||
M = '0';
|
||||
}else if(c >= 'A' && c <= 'F'){
|
||||
M = 'A' - 10;
|
||||
}else if(c >= 'a' && c <= 'f'){
|
||||
M = 'a' - 10;
|
||||
}
|
||||
if(M){
|
||||
num <<= 4;
|
||||
num += c - M;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
++buf;
|
||||
}
|
||||
*N = num;
|
||||
return buf;
|
||||
}
|
||||
// read binary number (without 0b prefix!)
|
||||
static char *getbin(char *buf, uint32_t *N){
|
||||
uint32_t num = 0;
|
||||
while(*buf){
|
||||
char c = *buf;
|
||||
if(c < '0' || c > '1'){
|
||||
break;
|
||||
}
|
||||
num <<= 1;
|
||||
if(c == '1') num |= 1;
|
||||
++buf;
|
||||
}
|
||||
*N = num;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief getnum - read uint32_t from string (dec, hex or bin: 127, 0x7f, 0b1111111)
|
||||
* @param buf - buffer with number and so on
|
||||
* @param N - the number read
|
||||
* @return pointer to first non-number symbol in buf (if it is == buf, there's no number)
|
||||
*/
|
||||
char *getnum(char *txt, uint32_t *N){
|
||||
if(*txt == '0'){
|
||||
if(txt[1] == 'x' || txt[1] == 'X') return gethex(txt+2, N);
|
||||
if(txt[1] == 'b' || txt[1] == 'B') return getbin(txt+2, N);
|
||||
}
|
||||
return getdec(txt, N);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief cmd_parser - command parsing
|
||||
* @param txt - buffer with commands & data
|
||||
* @param isUSB - == 1 if data got from USB
|
||||
*/
|
||||
void cmd_parser(char *txt){
|
||||
char _1st = txt[0];
|
||||
/*
|
||||
* parse long commands here
|
||||
*/
|
||||
/*switch(_1st){
|
||||
case 'a':
|
||||
addIGN(txt + 1);
|
||||
goto eof;
|
||||
break;
|
||||
}*/
|
||||
if(txt[1] != '\n') *txt = '?'; // help for wrong message length
|
||||
switch(_1st){
|
||||
case 'R':
|
||||
SEND("Soft reset\n");
|
||||
sendbuf();
|
||||
pause_ms(5); // a little pause to transmit data
|
||||
NVIC_SystemReset();
|
||||
break;
|
||||
case 'T':
|
||||
SEND("Time (ms): ");
|
||||
printu(Tms);
|
||||
newline();
|
||||
break;
|
||||
default: // help
|
||||
SEND(
|
||||
"'R' - software reset\n"
|
||||
"'T' - get time from start (ms)\n"
|
||||
);
|
||||
break;
|
||||
}
|
||||
newline();
|
||||
sendbuf();
|
||||
}
|
||||
|
||||
// print 32bit unsigned int
|
||||
void printu(uint32_t val){
|
||||
char buf[11], *bufptr = &buf[10];
|
||||
*bufptr = 0;
|
||||
if(!val){
|
||||
*(--bufptr) = '0';
|
||||
}else{
|
||||
while(val){
|
||||
*(--bufptr) = val % 10 + '0';
|
||||
val /= 10;
|
||||
}
|
||||
}
|
||||
addtobuf(bufptr);
|
||||
}
|
||||
|
||||
// print 32bit unsigned int as hex
|
||||
void printuhex(uint32_t val){
|
||||
addtobuf("0x");
|
||||
uint8_t *ptr = (uint8_t*)&val + 3;
|
||||
int8_t i, j, z=1;
|
||||
for(i = 0; i < 4; ++i, --ptr){
|
||||
if(*ptr == 0){ // omit leading zeros
|
||||
if(i == 3) z = 0;
|
||||
if(z) continue;
|
||||
}
|
||||
else z = 0;
|
||||
for(j = 1; j > -1; --j){
|
||||
uint8_t half = (*ptr >> (4*j)) & 0x0f;
|
||||
if(half < 10) bufputchar(half + '0');
|
||||
else bufputchar(half - 10 + 'a');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
55
F1:F103/deprecated/CDC_ACM/proto.h
Normal file
55
F1:F103/deprecated/CDC_ACM/proto.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* proto.h
|
||||
*
|
||||
* Copyright 2018 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 __PROTO_H__
|
||||
#define __PROTO_H__
|
||||
|
||||
#include "stm32f1.h"
|
||||
#include "hardware.h"
|
||||
|
||||
#define BUFSZ (64)
|
||||
|
||||
// macro for static strings
|
||||
#define SEND(str) do{addtobuf(str);}while(0)
|
||||
|
||||
#ifdef EBUG
|
||||
#define MSG(str) do{addtobuf(__FILE__ " (L" STR(__LINE__) "): " str);}while(0)
|
||||
#else
|
||||
#define MSG(str)
|
||||
#endif
|
||||
|
||||
#define newline() do{bufputchar('\n');}while(0)
|
||||
// newline with buffer sending over USART
|
||||
#define NL() do{bufputchar('\n'); sendbuf();}while(0)
|
||||
|
||||
void cmd_parser(char *buf);
|
||||
void addtobuf(const char *txt);
|
||||
void bufputchar(char ch);
|
||||
void printu(uint32_t val);
|
||||
void printuhex(uint32_t val);
|
||||
void sendbuf();
|
||||
|
||||
char *omit_spaces(char *buf);
|
||||
char *getnum(char *buf, uint32_t *N);
|
||||
|
||||
#endif // __PROTO_H__
|
||||
158
F1:F103/deprecated/CDC_ACM/usb.c
Normal file
158
F1:F103/deprecated/CDC_ACM/usb.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb.c - base functions for different USB types
|
||||
*
|
||||
* Copyright 2018 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.
|
||||
*
|
||||
*/
|
||||
#include "usb.h"
|
||||
#include "usb_lib.h"
|
||||
|
||||
static volatile uint8_t tx_succesfull = 1;
|
||||
static uint8_t rxNE = 0;
|
||||
|
||||
static void rxtx_Handler(){
|
||||
uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]);
|
||||
if(RX_FLAG(epstatus)){
|
||||
rxNE = 1;
|
||||
epstatus = (epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_CTR_RX)) ^ USB_EPnR_STAT_RX; // keep stat Tx & set valid RX, clear CTR Rx
|
||||
}else{
|
||||
tx_succesfull = 1;
|
||||
epstatus = (epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX; // keep stat Tx & set valid RX, clear CTR Tx
|
||||
}
|
||||
USB->EPnR[1] = epstatus;
|
||||
}
|
||||
|
||||
void USB_setup(){
|
||||
NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||
NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||
USB->CNTR = USB_CNTR_FRES; // Force USB Reset
|
||||
for(uint32_t ctr = 0; ctr < 72000; ++ctr) nop(); // wait >1ms
|
||||
USB->CNTR = 0;
|
||||
USB->BTABLE = 0;
|
||||
USB->DADDR = 0;
|
||||
USB->ISTR = 0;
|
||||
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_WKUPM; // allow only wakeup & reset interrupts
|
||||
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||
}
|
||||
|
||||
|
||||
static int usbwr(const uint8_t *buf, uint16_t l){
|
||||
uint32_t ctra = 1000000;
|
||||
while(--ctra && tx_succesfull == 0){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
}
|
||||
tx_succesfull = 0;
|
||||
EP_Write(1, buf, l);
|
||||
ctra = 1000000;
|
||||
while(--ctra && tx_succesfull == 0){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
}
|
||||
if(tx_succesfull == 0){usbON = 0; return 1;} // usb is OFF?
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t usbbuff[USB_TXBUFSZ-1]; // temporary buffer (63 - to prevent need of ZLP)
|
||||
static uint8_t buflen = 0; // amount of symbols in usbbuff
|
||||
|
||||
// send next up to 64 bytes of data in usbbuff
|
||||
static void send_next(){
|
||||
if(!buflen || !tx_succesfull) return;
|
||||
tx_succesfull = 0;
|
||||
EP_Write(1, usbbuff, buflen);
|
||||
buflen = 0;
|
||||
}
|
||||
|
||||
// unblocking sending - just fill a buffer
|
||||
void USB_send(const uint8_t *buf, uint16_t len){
|
||||
if(!usbON || !len) return;
|
||||
if(len > USB_TXBUFSZ-1 - buflen){
|
||||
usbwr(usbbuff, buflen);
|
||||
buflen = 0;
|
||||
}
|
||||
if(len > USB_TXBUFSZ-1){
|
||||
USB_send_blk(buf, len);
|
||||
return;
|
||||
}
|
||||
while(len--) usbbuff[buflen++] = *buf++;
|
||||
}
|
||||
|
||||
// send zero-terminated string
|
||||
void USB_sendstr(const char *str){
|
||||
uint16_t l = 0;
|
||||
const char *ptr = str;
|
||||
while(*ptr++) ++l;
|
||||
USB_send((uint8_t*)str, l);
|
||||
}
|
||||
|
||||
// blocking sending
|
||||
void USB_send_blk(const uint8_t *buf, uint16_t len){
|
||||
if(!usbON || !len) return; // USB disconnected
|
||||
if(buflen){
|
||||
usbwr(usbbuff, buflen);
|
||||
buflen = 0;
|
||||
}
|
||||
int needzlp = 0;
|
||||
while(len){
|
||||
if(len == USB_TXBUFSZ) needzlp = 1;
|
||||
uint16_t s = (len > USB_TXBUFSZ) ? USB_TXBUFSZ : len;
|
||||
if(usbwr(buf, s)) return;
|
||||
len -= s;
|
||||
buf += s;
|
||||
}
|
||||
if(needzlp){
|
||||
usbwr(NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_proc(){
|
||||
switch(USB_Dev.USB_Status){
|
||||
case USB_STATE_CONFIGURED:
|
||||
// make new BULK endpoint
|
||||
// Buffer have 1024 bytes, but last 256 we use for CAN bus (30.2 of RM: USB main features)
|
||||
//EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit
|
||||
EP_Init(1, EP_TYPE_BULK, USB_TXBUFSZ, USB_RXBUFSZ, rxtx_Handler); // INOUT1 - transmit/receive data
|
||||
USB_Dev.USB_Status = USB_STATE_CONNECTED;
|
||||
break;
|
||||
case USB_STATE_DEFAULT:
|
||||
case USB_STATE_ADDRESSED:
|
||||
if(usbON){
|
||||
usbON = 0;
|
||||
}
|
||||
break;
|
||||
default: // USB_STATE_CONNECTED - send next data portion
|
||||
if(!usbON) return;
|
||||
send_next();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB_receive
|
||||
* @param buf (i) - buffer[64] for received data
|
||||
* @return amount of received bytes
|
||||
*/
|
||||
uint8_t USB_receive(uint8_t *buf){
|
||||
if(!usbON || !rxNE) return 0;
|
||||
uint8_t sz = EP_Read(1, (uint16_t*)buf);
|
||||
uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]);
|
||||
// keep stat_tx & set ACK rx
|
||||
USB->EPnR[1] = (epstatus & ~(USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX;
|
||||
rxNE = 0;
|
||||
return sz;
|
||||
}
|
||||
39
F1:F103/deprecated/CDC_ACM/usb.h
Normal file
39
F1:F103/deprecated/CDC_ACM/usb.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb.h
|
||||
*
|
||||
* Copyright 2018 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 __USB_H__
|
||||
#define __USB_H__
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
// send string with constant length
|
||||
#define USND(str) do{USB_send((uint8_t*)str, sizeof(str)-1);}while(0)
|
||||
|
||||
void USB_setup();
|
||||
void usb_proc();
|
||||
void USB_send(const uint8_t *buf, uint16_t len);
|
||||
void USB_sendstr(const char *str);
|
||||
void USB_send_blk(const uint8_t *buf, uint16_t len);
|
||||
uint8_t USB_receive(uint8_t *buf);
|
||||
|
||||
#endif // __USB_H__
|
||||
107
F1:F103/deprecated/CDC_ACM/usb_defs.h
Normal file
107
F1:F103/deprecated/CDC_ACM/usb_defs.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb_defs.h
|
||||
*
|
||||
* Copyright 2018 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 __USB_DEFS_H__
|
||||
#define __USB_DEFS_H__
|
||||
|
||||
#include <stm32f1.h>
|
||||
|
||||
// max endpoints number
|
||||
#define STM32ENDPOINTS 8
|
||||
/**
|
||||
* Buffers size definition
|
||||
**/
|
||||
#define USB_BTABLE_SIZE 512
|
||||
// first 64 bytes of USB_BTABLE are registers!
|
||||
//#define USB_EP0_BASEADDR 64
|
||||
// for USB FS EP0 buffers are from 8 to 64 bytes long (64 for PL2303)
|
||||
#define USB_EP0_BUFSZ 64
|
||||
// USB transmit buffer size (64 for PL2303)
|
||||
#define USB_TXBUFSZ 64
|
||||
// USB receive buffer size (64 for PL2303)
|
||||
#define USB_RXBUFSZ 64
|
||||
// EP1 - interrupt - buffer size
|
||||
#define USB_EP1BUFSZ 8
|
||||
|
||||
#define USB_BTABLE_BASE 0x40006000
|
||||
#define USB_BASE ((uint32_t)0x40005C00)
|
||||
#define USB ((USB_TypeDef *) USB_BASE)
|
||||
|
||||
#ifdef USB_BTABLE
|
||||
#undef USB_BTABLE
|
||||
#endif
|
||||
#define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE))
|
||||
#define USB_ISTR_EPID 0x0000000F
|
||||
#define USB_FNR_LSOF_0 0x00000800
|
||||
#define USB_FNR_lSOF_1 0x00001000
|
||||
#define USB_LPMCSR_BESL_0 0x00000010
|
||||
#define USB_LPMCSR_BESL_1 0x00000020
|
||||
#define USB_LPMCSR_BESL_2 0x00000040
|
||||
#define USB_LPMCSR_BESL_3 0x00000080
|
||||
#define USB_EPnR_CTR_RX 0x00008000
|
||||
#define USB_EPnR_DTOG_RX 0x00004000
|
||||
#define USB_EPnR_STAT_RX 0x00003000
|
||||
#define USB_EPnR_STAT_RX_0 0x00001000
|
||||
#define USB_EPnR_STAT_RX_1 0x00002000
|
||||
#define USB_EPnR_SETUP 0x00000800
|
||||
#define USB_EPnR_EP_TYPE 0x00000600
|
||||
#define USB_EPnR_EP_TYPE_0 0x00000200
|
||||
#define USB_EPnR_EP_TYPE_1 0x00000400
|
||||
#define USB_EPnR_EP_KIND 0x00000100
|
||||
#define USB_EPnR_CTR_TX 0x00000080
|
||||
#define USB_EPnR_DTOG_TX 0x00000040
|
||||
#define USB_EPnR_STAT_TX 0x00000030
|
||||
#define USB_EPnR_STAT_TX_0 0x00000010
|
||||
#define USB_EPnR_STAT_TX_1 0x00000020
|
||||
#define USB_EPnR_EA 0x0000000F
|
||||
#define USB_COUNTn_RX_BLSIZE 0x00008000
|
||||
#define USB_COUNTn_NUM_BLOCK 0x00007C00
|
||||
#define USB_COUNTn_RX 0x0000003F
|
||||
|
||||
#ifdef USB_TypeDef
|
||||
#define USB_TypeDef USB_TypeDef_custom
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
__IO uint32_t EPnR[STM32ENDPOINTS];
|
||||
__IO uint32_t RESERVED[STM32ENDPOINTS];
|
||||
__IO uint32_t CNTR;
|
||||
__IO uint32_t ISTR;
|
||||
__IO uint32_t FNR;
|
||||
__IO uint32_t DADDR;
|
||||
__IO uint32_t BTABLE;
|
||||
} USB_TypeDef;
|
||||
|
||||
typedef struct{
|
||||
__IO uint32_t USB_ADDR_TX;
|
||||
__IO uint32_t USB_COUNT_TX;
|
||||
__IO uint32_t USB_ADDR_RX;
|
||||
__IO uint32_t USB_COUNT_RX;
|
||||
} USB_EPDATA_TypeDef;
|
||||
|
||||
typedef struct{
|
||||
__IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS];
|
||||
} USB_BtableDef;
|
||||
|
||||
#endif // __USB_DEFS_H__
|
||||
489
F1:F103/deprecated/CDC_ACM/usb_lib.c
Normal file
489
F1:F103/deprecated/CDC_ACM/usb_lib.c
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb_lib.c
|
||||
*
|
||||
* Copyright 2018 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "usb_lib.h"
|
||||
|
||||
ep_t endpoints[STM32ENDPOINTS];
|
||||
|
||||
usb_dev_t USB_Dev;
|
||||
static usb_LineCoding lineCoding = {115200, 0, 0, 8};
|
||||
static config_pack_t setup_packet;
|
||||
static uint8_t ep0databuf[EP0DATABUF_SIZE];
|
||||
static uint8_t ep0dbuflen = 0;
|
||||
|
||||
usb_LineCoding getLineCoding(){return lineCoding;}
|
||||
|
||||
uint8_t usbON = 0; // device disconnected from terminal
|
||||
|
||||
// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor
|
||||
#define bcdUSB_L 0x00
|
||||
#define bcdUSB_H 0x02
|
||||
#define bDeviceClass 0
|
||||
#define bDeviceSubClass 0
|
||||
#define bDeviceProtocol 0
|
||||
#define bNumConfigurations 1
|
||||
|
||||
static const uint8_t USB_DeviceDescriptor[] = {
|
||||
18, // bLength
|
||||
0x01, // bDescriptorType - Device descriptor
|
||||
bcdUSB_L, // bcdUSB_L - 1.10
|
||||
bcdUSB_H, // bcdUSB_H
|
||||
bDeviceClass, // bDeviceClass - USB_COMM
|
||||
bDeviceSubClass, // bDeviceSubClass
|
||||
bDeviceProtocol, // bDeviceProtocol
|
||||
USB_EP0_BUFSZ, // bMaxPacketSize
|
||||
// 0483:5740 (VID:PID) - stm32 VCP
|
||||
0x83, 0x04, 0x40, 0x57,
|
||||
0x00, // bcdDevice_Ver_L
|
||||
0x02, // bcdDevice_Ver_H
|
||||
0x01, // iManufacturer
|
||||
0x02, // iProduct
|
||||
0x03, // iSerialNumber
|
||||
bNumConfigurations // bNumConfigurations
|
||||
};
|
||||
|
||||
static const uint8_t USB_DeviceQualifierDescriptor[] = {
|
||||
10, //bLength
|
||||
0x06, // bDescriptorType - Device qualifier
|
||||
bcdUSB_L, // bcdUSB_L
|
||||
bcdUSB_H, // bcdUSB_H
|
||||
bDeviceClass, // bDeviceClass
|
||||
bDeviceSubClass, // bDeviceSubClass
|
||||
bDeviceProtocol, // bDeviceProtocol
|
||||
USB_EP0_BUFSZ, // bMaxPacketSize0
|
||||
bNumConfigurations, // bNumConfigurations
|
||||
0x00 // Reserved
|
||||
};
|
||||
|
||||
static const uint8_t USB_ConfigDescriptor[] = {
|
||||
/*Configuration Descriptor*/
|
||||
0x09, /* bLength: Configuration Descriptor size */
|
||||
0x02, /* bDescriptorType: Configuration */
|
||||
67, /* wTotalLength:no of returned bytes */
|
||||
0x00,
|
||||
0x02, /* bNumInterfaces: 2 interface */
|
||||
0x01, /* bConfigurationValue: Configuration value */
|
||||
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
|
||||
0x80, /* bmAttributes - Bus powered */
|
||||
0x32, /* MaxPower 100 mA */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*Interface Descriptor */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
0x04, /* bDescriptorType: Interface */
|
||||
0x00, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x01, /* bNumEndpoints: One endpoints used */
|
||||
0x02, /* bInterfaceClass: Communication Interface Class */
|
||||
0x02, /* bInterfaceSubClass: Abstract Control Model */
|
||||
0x01, /* bInterfaceProtocol: Common AT commands */
|
||||
0x00, /* iInterface: */
|
||||
/*Header Functional Descriptor*/
|
||||
0x05, /* bLength: Endpoint Descriptor size */
|
||||
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||
0x00, /* bDescriptorSubtype: Header Func Desc */
|
||||
0x10, /* bcdCDC: spec release number */
|
||||
0x01,
|
||||
/*Call Management Functional Descriptor*/
|
||||
0x05, /* bFunctionLength */
|
||||
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||
0x01, /* bDescriptorSubtype: Call Management Func Desc */
|
||||
0x00, /* bmCapabilities: D0+D1 */
|
||||
0x01, /* bDataInterface: 1 */
|
||||
/*ACM Functional Descriptor*/
|
||||
0x04, /* bFunctionLength */
|
||||
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||
0x02, /* bDescriptorSubtype: Abstract Control Management desc */
|
||||
0x02, /* bmCapabilities */
|
||||
/*Union Functional Descriptor*/
|
||||
0x05, /* bFunctionLength */
|
||||
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||
0x06, /* bDescriptorSubtype: Union func desc */
|
||||
0x00, /* bMasterInterface: Communication class interface */
|
||||
0x01, /* bSlaveInterface0: Data Class Interface */
|
||||
/*Endpoint 1 Descriptor*/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
0x05, /* bDescriptorType: Endpoint */
|
||||
0x8A, /* bEndpointAddress IN10 */
|
||||
0x03, /* bmAttributes: Interrupt */
|
||||
(USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */
|
||||
(USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */
|
||||
0x10, /* bInterval: */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*Data class interface descriptor*/
|
||||
0x09, /* bLength: Endpoint Descriptor size */
|
||||
0x04, /* bDescriptorType: */
|
||||
0x01, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x02, /* bNumEndpoints: Two endpoints used */
|
||||
0x0A, /* bInterfaceClass: CDC */
|
||||
0x02, /* bInterfaceSubClass: */
|
||||
0x00, /* bInterfaceProtocol: */
|
||||
0x00, /* iInterface: */
|
||||
/*Endpoint IN3 Descriptor*/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
0x05, /* bDescriptorType: Endpoint */
|
||||
0x81, /* bEndpointAddress: IN1 */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
(USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
|
||||
(USB_TXBUFSZ >> 8),
|
||||
0x00, /* bInterval: ignore for Bulk transfer */
|
||||
/*Endpoint OUT1 Descriptor*/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
0x05, /* bDescriptorType: Endpoint */
|
||||
0x01, /* bEndpointAddress: OUT1 */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
(USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
|
||||
(USB_TXBUFSZ >> 8),
|
||||
0x00 /* bInterval: ignore for Bulk transfer */
|
||||
};
|
||||
|
||||
|
||||
USB_LANG_ID(USB_StringLangDescriptor, LANG_US);
|
||||
|
||||
USB_STRING(USB_StringSerialDescriptor, u"000001");
|
||||
USB_STRING(USB_StringManufacturingDescriptor, u"Eddy @ SAO RAS");
|
||||
USB_STRING(USB_StringProdDescriptor, u"USB-Serial Controller");
|
||||
|
||||
/*
|
||||
* default handlers
|
||||
*/
|
||||
// SET_LINE_CODING
|
||||
void WEAK linecoding_handler(usb_LineCoding __attribute__((unused)) *lcd){
|
||||
//MSG("linecoding_handler()");
|
||||
}
|
||||
|
||||
// SET_CONTROL_LINE_STATE
|
||||
void WEAK clstate_handler(uint16_t __attribute__((unused)) val){
|
||||
//MSG("clstate_handler()");
|
||||
}
|
||||
|
||||
// SEND_BREAK
|
||||
void WEAK break_handler(){
|
||||
//MSG("break_handler()");
|
||||
}
|
||||
|
||||
static void wr0(const uint8_t *buf, uint16_t size){
|
||||
if(setup_packet.wLength < size) size = setup_packet.wLength; // shortened request
|
||||
if(size < endpoints[0].txbufsz){
|
||||
EP_WriteIRQ(0, buf, size);
|
||||
return;
|
||||
}
|
||||
while(size){
|
||||
uint16_t l = size;
|
||||
if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz;
|
||||
EP_WriteIRQ(0, buf, l);
|
||||
buf += l;
|
||||
size -= l;
|
||||
uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0;
|
||||
if(size || needzlp){ // send last data buffer
|
||||
uint16_t status = KEEP_DTOG(USB->EPnR[0]);
|
||||
// keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx
|
||||
USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX))
|
||||
^ USB_EPnR_STAT_TX;
|
||||
uint32_t ctr = 1000000;
|
||||
while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;};
|
||||
if((USB->ISTR & USB_ISTR_CTR) == 0){
|
||||
return;
|
||||
}
|
||||
if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void get_descriptor(){
|
||||
switch(setup_packet.wValue){
|
||||
case DEVICE_DESCRIPTOR:
|
||||
wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor));
|
||||
break;
|
||||
case CONFIGURATION_DESCRIPTOR:
|
||||
wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor));
|
||||
break;
|
||||
case STRING_LANG_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringLangDescriptor, STRING_LANG_DESCRIPTOR_SIZE_BYTE);
|
||||
break;
|
||||
case STRING_MAN_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringManufacturingDescriptor, USB_StringManufacturingDescriptor.bLength);
|
||||
break;
|
||||
case STRING_PROD_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringProdDescriptor, USB_StringProdDescriptor.bLength);
|
||||
break;
|
||||
case STRING_SN_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringSerialDescriptor, USB_StringSerialDescriptor.bLength);
|
||||
break;
|
||||
case DEVICE_QUALIFIER_DESCRIPTOR:
|
||||
wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured)
|
||||
static inline void std_d2h_req(){
|
||||
uint16_t state = 0; // bus powered
|
||||
switch(setup_packet.bRequest){
|
||||
case GET_DESCRIPTOR:
|
||||
get_descriptor();
|
||||
break;
|
||||
case GET_STATUS:
|
||||
EP_WriteIRQ(0, (uint8_t *)&state, 2); // send status: Bus Powered
|
||||
break;
|
||||
case GET_CONFIGURATION:
|
||||
EP_WriteIRQ(0, &configuration, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void std_h2d_req(){
|
||||
switch(setup_packet.bRequest){
|
||||
case SET_ADDRESS:
|
||||
// new address will be assigned later - after acknowlegement or request to host
|
||||
USB_Dev.USB_Addr = setup_packet.wValue;
|
||||
break;
|
||||
case SET_CONFIGURATION:
|
||||
// Now device configured
|
||||
USB_Dev.USB_Status = USB_STATE_CONFIGURED;
|
||||
configuration = setup_packet.wValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bmRequestType: 76543210
|
||||
7 direction: 0 - host->device, 1 - device->host
|
||||
65 type: 0 - standard, 1 - class, 2 - vendor
|
||||
4..0 getter: 0 - device, 1 - interface, 2 - endpoint, 3 - other
|
||||
*/
|
||||
/**
|
||||
* Endpoint0 (control) handler
|
||||
*/
|
||||
static void EP0_Handler(){
|
||||
uint8_t reqtype = setup_packet.bmRequestType & 0x7f;
|
||||
uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0;
|
||||
uint16_t epstatus = USB->EPnR[0];
|
||||
int rxflag = RX_FLAG(epstatus);
|
||||
if(rxflag && SETUP_FLAG(epstatus)){
|
||||
switch(reqtype){
|
||||
case STANDARD_DEVICE_REQUEST_TYPE: // standard device request
|
||||
if(dev2host){
|
||||
std_d2h_req();
|
||||
}else{
|
||||
std_h2d_req();
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}
|
||||
break;
|
||||
case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request
|
||||
if(setup_packet.bRequest == CLEAR_FEATURE){
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}else{
|
||||
}
|
||||
break;
|
||||
case CONTROL_REQUEST_TYPE:
|
||||
switch(setup_packet.bRequest){
|
||||
case GET_LINE_CODING:
|
||||
EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding));
|
||||
break;
|
||||
case SET_LINE_CODING: // omit this for next stage, when data will come
|
||||
break;
|
||||
case SET_CONTROL_LINE_STATE:
|
||||
usbON = 1;
|
||||
clstate_handler(setup_packet.wValue);
|
||||
break;
|
||||
case SEND_BREAK:
|
||||
usbON = 0;
|
||||
break_handler();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(setup_packet.bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
break;
|
||||
default:
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}
|
||||
}else if(rxflag){ // got data over EP0 or host acknowlegement
|
||||
if(endpoints[0].rx_cnt){
|
||||
if(setup_packet.bRequest == SET_LINE_CODING){
|
||||
linecoding_handler((usb_LineCoding*)ep0databuf);
|
||||
}
|
||||
}
|
||||
}else if(TX_FLAG(epstatus)){ // package transmitted
|
||||
// now we can change address after enumeration
|
||||
if((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){
|
||||
USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr;
|
||||
// change state to ADRESSED
|
||||
USB_Dev.USB_Status = USB_STATE_ADDRESSED;
|
||||
}
|
||||
}
|
||||
epstatus = KEEP_DTOG(USB->EPnR[0]);
|
||||
if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP/data transmission
|
||||
else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged
|
||||
// keep DTOGs, clear CTR_RX,TX, set RX VALID
|
||||
USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX;
|
||||
}
|
||||
|
||||
static uint16_t lastaddr = LASTADDR_DEFAULT;
|
||||
/**
|
||||
* Endpoint initialisation
|
||||
* @param number - EP num (0...7)
|
||||
* @param type - EP type (EP_TYPE_BULK, EP_TYPE_CONTROL, EP_TYPE_ISO, EP_TYPE_INTERRUPT)
|
||||
* @param txsz - transmission buffer size @ USB/CAN buffer
|
||||
* @param rxsz - reception buffer size @ USB/CAN buffer
|
||||
* @param uint16_t (*func)(ep_t *ep) - EP handler function
|
||||
* @return 0 if all OK
|
||||
*/
|
||||
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)(ep_t ep)){
|
||||
if(number >= STM32ENDPOINTS) return 4; // out of configured amount
|
||||
if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large
|
||||
if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE) return 2; // out of btable
|
||||
USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA);
|
||||
USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1;
|
||||
if(rxsz & 1 || rxsz > 512) return 3; // wrong rx buffer size
|
||||
uint16_t countrx = 0;
|
||||
if(rxsz < 64) countrx = rxsz / 2;
|
||||
else{
|
||||
if(rxsz & 0x1f) return 3; // should be multiple of 32
|
||||
countrx = 31 + rxsz / 32;
|
||||
}
|
||||
USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr;
|
||||
endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr*2);
|
||||
endpoints[number].txbufsz = txsz;
|
||||
lastaddr += txsz;
|
||||
USB_BTABLE->EP[number].USB_COUNT_TX = 0;
|
||||
USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr;
|
||||
endpoints[number].rx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr*2);
|
||||
lastaddr += rxsz;
|
||||
USB_BTABLE->EP[number].USB_COUNT_RX = countrx << 10;
|
||||
endpoints[number].func = func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//extern int8_t dump;
|
||||
// standard IRQ handler
|
||||
void usb_lp_can_rx0_isr(){
|
||||
if(USB->ISTR & USB_ISTR_RESET){
|
||||
usbON = 0;
|
||||
// Reinit registers
|
||||
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
|
||||
// Endpoint 0 - CONTROL
|
||||
// ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes!
|
||||
lastaddr = LASTADDR_DEFAULT;
|
||||
// clear address, leave only enable bit
|
||||
USB->DADDR = USB_DADDR_EF;
|
||||
// state is default - wait for enumeration
|
||||
USB_Dev.USB_Status = USB_STATE_DEFAULT;
|
||||
USB->ISTR = ~USB_ISTR_RESET;
|
||||
if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(USB->ISTR & USB_ISTR_CTR){
|
||||
// EP number
|
||||
uint8_t n = USB->ISTR & USB_ISTR_EPID;
|
||||
// copy status register
|
||||
uint16_t epstatus = USB->EPnR[n];
|
||||
// copy received bytes amount
|
||||
endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter
|
||||
// check direction
|
||||
if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit)
|
||||
if(n == 0){ // control endpoint
|
||||
if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack
|
||||
EP_Read(0, (uint16_t*)&setup_packet);
|
||||
ep0dbuflen = 0;
|
||||
// interrupt handler will be called later
|
||||
}else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf
|
||||
ep0dbuflen = endpoints[0].rx_cnt;
|
||||
EP_Read(0, (uint16_t*)&ep0databuf);
|
||||
}
|
||||
}
|
||||
}else{ // IN interrupt - transmit data, only CTR_TX == 1
|
||||
// enumeration end could be MSG (if EP0)
|
||||
}
|
||||
// call EP handler
|
||||
if(endpoints[n].func) endpoints[n].func(endpoints[n]);
|
||||
}
|
||||
if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep
|
||||
usbON = 0;
|
||||
USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LP_MODE;
|
||||
USB->ISTR = ~USB_ISTR_SUSP;
|
||||
}
|
||||
if(USB->ISTR & USB_ISTR_WKUP){ // wakeup
|
||||
USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LP_MODE); // clear suspend flags
|
||||
USB->ISTR = ~USB_ISTR_WKUP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to EP buffer (called from IRQ handler)
|
||||
* @param number - EP number
|
||||
* @param *buf - array with data
|
||||
* @param size - its size
|
||||
*/
|
||||
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
|
||||
uint8_t i;
|
||||
if(size > endpoints[number].txbufsz) size = endpoints[number].txbufsz;
|
||||
uint16_t N2 = (size + 1) >> 1;
|
||||
// the buffer is 16-bit, so we should copy data as it would be uint16_t
|
||||
uint16_t *buf16 = (uint16_t *)buf;
|
||||
uint32_t *out = (uint32_t *)endpoints[number].tx_buf;
|
||||
for(i = 0; i < N2; ++i, ++out){
|
||||
*out = buf16[i];
|
||||
}
|
||||
USB_BTABLE->EP[number].USB_COUNT_TX = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to EP buffer (called outside IRQ handler)
|
||||
* @param number - EP number
|
||||
* @param *buf - array with data
|
||||
* @param size - its size
|
||||
*/
|
||||
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){
|
||||
EP_WriteIRQ(number, buf, size);
|
||||
uint16_t status = KEEP_DTOG(USB->EPnR[number]);
|
||||
// keep DTOGs, clear CTR_TX & set TX VALID to start transmission
|
||||
USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy data from EP buffer into user buffer area
|
||||
* @param *buf - user array for data
|
||||
* @return amount of data read
|
||||
*/
|
||||
int EP_Read(uint8_t number, uint16_t *buf){
|
||||
int sz = endpoints[number].rx_cnt;
|
||||
if(!sz) return 0;
|
||||
endpoints[number].rx_cnt = 0;
|
||||
int n = (sz + 1) >> 1;
|
||||
uint32_t *in = (uint32_t *)endpoints[number].rx_buf;
|
||||
if(n){
|
||||
for(int i = 0; i < n; ++i, ++in)
|
||||
buf[i] = *(uint16_t*)in;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
215
F1:F103/deprecated/CDC_ACM/usb_lib.h
Normal file
215
F1:F103/deprecated/CDC_ACM/usb_lib.h
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb_lib.h
|
||||
*
|
||||
* Copyright 2018 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 __USB_LIB_H__
|
||||
#define __USB_LIB_H__
|
||||
|
||||
#include <wchar.h>
|
||||
#include "usb_defs.h"
|
||||
|
||||
#define EP0DATABUF_SIZE (64)
|
||||
#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8)
|
||||
|
||||
// Max EP amount (EP0 + other used)
|
||||
//#define ENDPOINTS_NUM 4
|
||||
// bmRequestType & 0x7f
|
||||
#define STANDARD_DEVICE_REQUEST_TYPE 0
|
||||
#define STANDARD_ENDPOINT_REQUEST_TYPE 2
|
||||
#define VENDOR_REQUEST_TYPE 0x40
|
||||
#define CONTROL_REQUEST_TYPE 0x21
|
||||
// bRequest, standard; for bmRequestType == 0x80
|
||||
#define GET_STATUS 0x00
|
||||
#define GET_DESCRIPTOR 0x06
|
||||
#define GET_CONFIGURATION 0x08
|
||||
// for bmRequestType == 0
|
||||
#define CLEAR_FEATURE 0x01
|
||||
#define SET_FEATURE 0x03 // unused
|
||||
#define SET_ADDRESS 0x05
|
||||
#define SET_DESCRIPTOR 0x07 // unused
|
||||
#define SET_CONFIGURATION 0x09
|
||||
// for bmRequestType == 0x81, 1 or 0xB2
|
||||
#define GET_INTERFACE 0x0A // unused
|
||||
#define SET_INTERFACE 0x0B // unused
|
||||
#define SYNC_FRAME 0x0C // unused
|
||||
#define VENDOR_REQUEST 0x01 // unused
|
||||
|
||||
// Class-Specific Control Requests
|
||||
#define SEND_ENCAPSULATED_COMMAND 0x00 // unused
|
||||
#define GET_ENCAPSULATED_RESPONSE 0x01 // unused
|
||||
#define SET_COMM_FEATURE 0x02 // unused
|
||||
#define GET_COMM_FEATURE 0x03 // unused
|
||||
#define CLEAR_COMM_FEATURE 0x04 // unused
|
||||
#define SET_LINE_CODING 0x20
|
||||
#define GET_LINE_CODING 0x21
|
||||
#define SET_CONTROL_LINE_STATE 0x22
|
||||
#define SEND_BREAK 0x23
|
||||
|
||||
// control line states
|
||||
#define CONTROL_DTR 0x01
|
||||
#define CONTROL_RTS 0x02
|
||||
|
||||
// wValue
|
||||
#define DEVICE_DESCRIPTOR 0x100
|
||||
#define CONFIGURATION_DESCRIPTOR 0x200
|
||||
#define STRING_LANG_DESCRIPTOR 0x300
|
||||
#define STRING_MAN_DESCRIPTOR 0x301
|
||||
#define STRING_PROD_DESCRIPTOR 0x302
|
||||
#define STRING_SN_DESCRIPTOR 0x303
|
||||
#define DEVICE_QUALIFIER_DESCRIPTOR 0x600
|
||||
|
||||
#define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX)
|
||||
#define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX)
|
||||
#define SETUP_FLAG(epstat) (epstat & USB_EPnR_SETUP)
|
||||
|
||||
// keep all DTOGs and STATs
|
||||
#define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
|
||||
#define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
|
||||
|
||||
//#define RX_CNT(N) (USB_BTABLE->EP[N].USB_COUNT_RX & 0x3FF)
|
||||
|
||||
/*
|
||||
// EPnR bits manipulation
|
||||
#define CLEAR_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? R : (R & (~USB_EPnR_DTOG_RX))
|
||||
#define SET_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? (R & (~USB_EPnR_DTOG_RX)) : R
|
||||
#define TOGGLE_DTOG_RX(R) (R | USB_EPnR_DTOG_RX)
|
||||
#define KEEP_DTOG_RX(R) (R & (~USB_EPnR_DTOG_RX))
|
||||
#define CLEAR_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? R : (R & (~USB_EPnR_DTOG_TX))
|
||||
#define SET_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? (R & (~USB_EPnR_DTOG_TX)) : R
|
||||
#define TOGGLE_DTOG_TX(R) (R | USB_EPnR_DTOG_TX)
|
||||
#define KEEP_DTOG_TX(R) (R & (~USB_EPnR_DTOG_TX))
|
||||
#define SET_VALID_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX) | (R & (~USB_EPnR_STAT_RX))
|
||||
#define SET_NAK_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_1) | (R & (~USB_EPnR_STAT_RX))
|
||||
#define SET_STALL_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_0) | (R & (~USB_EPnR_STAT_RX))
|
||||
#define KEEP_STAT_RX(R) (R & (~USB_EPnR_STAT_RX))
|
||||
#define SET_VALID_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX) | (R & (~USB_EPnR_STAT_TX))
|
||||
#define SET_NAK_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_1) | (R & (~USB_EPnR_STAT_TX))
|
||||
#define SET_STALL_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_0) | (R & (~USB_EPnR_STAT_TX))
|
||||
#define KEEP_STAT_TX(R) (R & (~USB_EPnR_STAT_TX))
|
||||
#define CLEAR_CTR_RX(R) (R & (~USB_EPnR_CTR_RX))
|
||||
#define CLEAR_CTR_TX(R) (R & (~USB_EPnR_CTR_TX))
|
||||
#define CLEAR_CTR_RX_TX(R) (R & (~(USB_EPnR_CTR_TX | USB_EPnR_CTR_RX)))
|
||||
*/
|
||||
|
||||
// USB state: uninitialized, addressed, ready for use
|
||||
typedef enum{
|
||||
USB_STATE_DEFAULT,
|
||||
USB_STATE_ADDRESSED,
|
||||
USB_STATE_CONFIGURED,
|
||||
USB_STATE_CONNECTED
|
||||
} USB_state;
|
||||
|
||||
// EP types
|
||||
#define EP_TYPE_BULK 0x00
|
||||
#define EP_TYPE_CONTROL 0x01
|
||||
#define EP_TYPE_ISO 0x02
|
||||
#define EP_TYPE_INTERRUPT 0x03
|
||||
|
||||
#define LANG_US (uint16_t)0x0409
|
||||
|
||||
#define USB_STRING(name, str) \
|
||||
static const struct name \
|
||||
{ \
|
||||
uint8_t bLength; \
|
||||
uint8_t bDescriptorType; \
|
||||
uint16_t bString[(sizeof(str) - 2) / 2]; \
|
||||
\
|
||||
} \
|
||||
name = {sizeof(name), 0x03, str}
|
||||
|
||||
#define USB_LANG_ID(name, lng_id) \
|
||||
\
|
||||
static const struct name \
|
||||
{ \
|
||||
uint8_t bLength; \
|
||||
uint8_t bDescriptorType; \
|
||||
uint16_t bString; \
|
||||
\
|
||||
} \
|
||||
name = {0x04, 0x03, lng_id}
|
||||
#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4)
|
||||
|
||||
// EP0 configuration packet
|
||||
typedef struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} config_pack_t;
|
||||
|
||||
// endpoints state
|
||||
typedef struct __ep_t{
|
||||
uint16_t *tx_buf; // transmission buffer address
|
||||
uint16_t txbufsz; // transmission buffer size
|
||||
uint16_t *rx_buf; // reception buffer address
|
||||
void (*func)(); // endpoint action function
|
||||
unsigned rx_cnt : 10; // received data counter
|
||||
} ep_t;
|
||||
|
||||
// USB status & its address
|
||||
typedef struct {
|
||||
uint8_t USB_Status;
|
||||
uint16_t USB_Addr;
|
||||
}usb_dev_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t dwDTERate;
|
||||
uint8_t bCharFormat;
|
||||
#define USB_CDC_1_STOP_BITS 0
|
||||
#define USB_CDC_1_5_STOP_BITS 1
|
||||
#define USB_CDC_2_STOP_BITS 2
|
||||
uint8_t bParityType;
|
||||
#define USB_CDC_NO_PARITY 0
|
||||
#define USB_CDC_ODD_PARITY 1
|
||||
#define USB_CDC_EVEN_PARITY 2
|
||||
#define USB_CDC_MARK_PARITY 3
|
||||
#define USB_CDC_SPACE_PARITY 4
|
||||
uint8_t bDataBits;
|
||||
} __attribute__ ((packed)) usb_LineCoding;
|
||||
|
||||
typedef struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bNotificationType;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} __attribute__ ((packed)) usb_cdc_notification;
|
||||
|
||||
extern ep_t endpoints[];
|
||||
extern usb_dev_t USB_Dev;
|
||||
extern uint8_t usbON;
|
||||
|
||||
void USB_Init();
|
||||
void USB_ResetState();
|
||||
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)());
|
||||
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size);
|
||||
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size);
|
||||
int EP_Read(uint8_t number, uint16_t *buf);
|
||||
usb_LineCoding getLineCoding();
|
||||
|
||||
void linecoding_handler(usb_LineCoding *lc);
|
||||
void clstate_handler(uint16_t val);
|
||||
void break_handler();
|
||||
|
||||
#endif // __USB_LIB_H__
|
||||
BIN
F1:F103/deprecated/MLX90640/MLX90640.bin
Executable file
BIN
F1:F103/deprecated/MLX90640/MLX90640.bin
Executable file
Binary file not shown.
151
F1:F103/deprecated/MLX90640/Makefile
Normal file
151
F1:F103/deprecated/MLX90640/Makefile
Normal file
@@ -0,0 +1,151 @@
|
||||
BINARY = MLX90640
|
||||
BOOTPORT ?= /dev/ttyUSB0
|
||||
BOOTSPEED ?= 115200
|
||||
# MCU FAMILY
|
||||
FAMILY ?= F1
|
||||
# MCU code
|
||||
MCU ?= F103x8
|
||||
# density (stm32f10x.h, lines 70-84)
|
||||
DENSITY ?= MD
|
||||
# change this linking script depending on particular MCU model,
|
||||
LDSCRIPT ?= stm32f103x8.ld
|
||||
# debug
|
||||
DEFS = -DEBUG
|
||||
|
||||
# autoincremental version & build date
|
||||
VERSION_FILE = version.inc
|
||||
NEXTVER := $(shell expr $$(awk '/#define BUILD_NUMBER/' $(VERSION_FILE) | tr -cd "[0-9]") + 1)
|
||||
BUILDDATE := $(shell date +%Y-%m-%d)
|
||||
|
||||
INDEPENDENT_HEADERS=
|
||||
|
||||
FP_FLAGS ?= -msoft-float -mfloat-abi=soft
|
||||
ASM_FLAGS ?= -mthumb -mcpu=cortex-m3 -mfix-cortex-m3-ldrd
|
||||
ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS)
|
||||
|
||||
###############################################################################
|
||||
# Executables
|
||||
#PREFIX ?= arm-none-eabi
|
||||
# gcc from arm web site
|
||||
PREFIX ?= /opt/bin/arm-none-eabi
|
||||
TOOLCHLIB ?= /opt/arm-none-eabi/lib
|
||||
RM := rm -f
|
||||
RMDIR := rmdir
|
||||
CC := $(PREFIX)-gcc
|
||||
# don't replace ld with gcc: the binary size would be much greater!!
|
||||
LD := $(PREFIX)-ld
|
||||
AR := $(PREFIX)-ar
|
||||
AS := $(PREFIX)-as
|
||||
SIZE := $(PREFIX)-size
|
||||
OBJCOPY := $(PREFIX)-objcopy
|
||||
OBJDUMP := $(PREFIX)-objdump
|
||||
GDB := $(PREFIX)-gdb
|
||||
STFLASH := $(shell which st-flash)
|
||||
STBOOT := $(shell which stm32flash)
|
||||
DFUUTIL := $(shell which dfu-util)
|
||||
|
||||
###############################################################################
|
||||
# Source files
|
||||
OBJDIR = mk
|
||||
SRC := $(wildcard *.c)
|
||||
OBJS := $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o))
|
||||
STARTUP = $(OBJDIR)/startup.o
|
||||
OBJS += $(STARTUP)
|
||||
# dependencies: we need them to recompile files if their headers-dependencies changed
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
|
||||
INC_DIR ?= ../inc
|
||||
|
||||
INCLUDE := -I$(INC_DIR)/Fx -I$(INC_DIR)/cm
|
||||
LIB_DIR := $(INC_DIR)/ld
|
||||
|
||||
###############################################################################
|
||||
# C flags
|
||||
CFLAGS += -O2 -g -D__thumb2__=1 -MD
|
||||
CFLAGS += -Wall -Werror -Wextra -Wshadow
|
||||
CFLAGS += -fno-common -ffunction-sections -fdata-sections -fno-stack-protector
|
||||
CFLAGS += $(ARCH_FLAGS)
|
||||
|
||||
###############################################################################
|
||||
# Linker flags
|
||||
LDFLAGS += -nostartfiles --static -nostdlibs --gc-sections --print-memory-usage
|
||||
LDFLAGS += -L$(LIB_DIR) -L$(TOOLCHLIB)
|
||||
LDFLAGS += -T$(LDSCRIPT)
|
||||
|
||||
###############################################################################
|
||||
# Used libraries
|
||||
LDLIBS += -lm -lc $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
|
||||
|
||||
DEFS += -DSTM32$(FAMILY) -DSTM32$(MCU) -DSTM32F10X_$(DENSITY)
|
||||
|
||||
ELF := $(OBJDIR)/$(BINARY).elf
|
||||
LIST := $(OBJDIR)/$(BINARY).list
|
||||
BIN := $(BINARY).bin
|
||||
HEX := $(BINARY).hex
|
||||
|
||||
all: bin list size
|
||||
|
||||
elf: $(ELF)
|
||||
bin: $(BIN)
|
||||
hex: $(HEX)
|
||||
list: $(LIST)
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(DEPS)
|
||||
endif
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir $(OBJDIR)
|
||||
|
||||
$(STARTUP): $(INC_DIR)/startup/vector.c
|
||||
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $<
|
||||
|
||||
$(VERSION_FILE): *.[ch]
|
||||
@echo " Generate version: $(NEXTVER) for date $(BUILDDATE)"
|
||||
@sed -i "s/#define BUILD_NUMBER.*/#define BUILD_NUMBER \"$(NEXTVER)\"/" $(VERSION_FILE)
|
||||
@sed -i "s/#define BUILD_DATE.*/#define BUILD_DATE \"$(BUILDDATE)\"/" $(VERSION_FILE)
|
||||
|
||||
$(OBJDIR)/proto.o: proto.c $(VERSION_FILE)
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
@echo " CC $<"
|
||||
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $<
|
||||
|
||||
$(BIN): $(ELF)
|
||||
@echo " OBJCOPY $(BIN)"
|
||||
$(OBJCOPY) -Obinary $(ELF) $(BIN)
|
||||
|
||||
$(HEX): $(ELF)
|
||||
@echo " OBJCOPY $(HEX)"
|
||||
$(OBJCOPY) -Oihex $(ELF) $(HEX)
|
||||
|
||||
$(LIST): $(ELF)
|
||||
@echo " OBJDUMP $(LIST)"
|
||||
$(OBJDUMP) -S $(ELF) > $(LIST)
|
||||
|
||||
$(ELF): $(OBJDIR) $(OBJS)
|
||||
@echo " LD $(ELF)"
|
||||
$(LD) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(ELF)
|
||||
|
||||
size: $(ELF)
|
||||
$(SIZE) $(ELF)
|
||||
|
||||
clean:
|
||||
@echo " CLEAN"
|
||||
$(RM) $(OBJS) $(DEPS) $(ELF) $(HEX) $(LIST)
|
||||
@rmdir $(OBJDIR) 2>/dev/null || true
|
||||
|
||||
|
||||
flash: $(BIN)
|
||||
@echo " FLASH $(BIN)"
|
||||
$(STFLASH) write $(BIN) 0x8000000
|
||||
|
||||
boot: $(BIN)
|
||||
@echo " LOAD $(BIN) through bootloader"
|
||||
$(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN)
|
||||
|
||||
dfuboot: $(BIN)
|
||||
@echo " LOAD $(BIN) THROUGH DFU"
|
||||
$(DFUUTIL) -a0 -D $(BIN) -s 0x08000000
|
||||
|
||||
.PHONY: clean flash boot
|
||||
2
F1:F103/deprecated/MLX90640/Readme
Normal file
2
F1:F103/deprecated/MLX90640/Readme
Normal file
@@ -0,0 +1,2 @@
|
||||
Working with MLX90640
|
||||
|
||||
51
F1:F103/deprecated/MLX90640/hardware.c
Normal file
51
F1:F103/deprecated/MLX90640/hardware.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2022 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
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;
|
||||
AFIO->MAPR = AFIO_MAPR_SWJ_CFG_JTAGDISABLE; // for PA15
|
||||
// Set led as opendrain output
|
||||
GPIOC->CRH |= CRH(13, CNF_ODOUTPUT | MODE_SLOW);
|
||||
// USB pullup (PA15) - pushpull output
|
||||
GPIOA->CRH = CRH(15, CNF_PPOUTPUT | MODE_SLOW);
|
||||
// PB5 is powered MLX sensor (less than 23mA) - OD output
|
||||
MLXPOW_OFF();
|
||||
GPIOB->CRL = CRL(5, CNF_ODOUTPUT | MODE_SLOW);
|
||||
}
|
||||
|
||||
void hw_setup(){
|
||||
gpio_setup();
|
||||
}
|
||||
|
||||
void iwdg_setup(){
|
||||
uint32_t tmout = 16000000;
|
||||
RCC->CSR |= RCC_CSR_LSION;
|
||||
while((RCC->CSR & RCC_CSR_LSIRDY) != RCC_CSR_LSIRDY){if(--tmout == 0) break;} /* (2) */
|
||||
IWDG->KR = IWDG_START;
|
||||
IWDG->KR = IWDG_WRITE_ACCESS;
|
||||
IWDG->PR = IWDG_PR_PR_1;
|
||||
IWDG->RLR = 1250;
|
||||
tmout = 16000000;
|
||||
while(IWDG->SR){if(--tmout == 0) break;}
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
}
|
||||
47
F1:F103/deprecated/MLX90640/hardware.h
Normal file
47
F1:F103/deprecated/MLX90640/hardware.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2022 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef __HARDWARE_H__
|
||||
#define __HARDWARE_H__
|
||||
|
||||
#include "stm32f1.h"
|
||||
|
||||
// LED0 - PC13 (bluepill), blinking each second
|
||||
#define LED0_port GPIOC
|
||||
#define LED0_pin (1<<13)
|
||||
|
||||
// USB pullup (not present in bluepill, should be soldered) - PA15
|
||||
#define USBPU_port GPIOA
|
||||
#define USBPU_pin (1<<15)
|
||||
#define MLXPOW_port GPIOB
|
||||
#define MLXPOW_pin (1<<5)
|
||||
#define USBPU_ON() pin_set(USBPU_port, USBPU_pin)
|
||||
#define USBPU_OFF() pin_clear(USBPU_port, USBPU_pin)
|
||||
#define MLXPOW_ON() pin_clear(MLXPOW_port, MLXPOW_pin)
|
||||
#define MLXPOW_OFF() pin_set(MLXPOW_port, MLXPOW_pin)
|
||||
#define MLXPOW_VAL() ((MLXPOW_port->IDR & MLXPOW_pin)?0:1)
|
||||
|
||||
#define LED_blink(x) pin_toggle(x ## _port, x ## _pin)
|
||||
#define LED_on(x) pin_clear(x ## _port, x ## _pin)
|
||||
#define LED_off(x) pin_set(x ## _port, x ## _pin)
|
||||
|
||||
void hw_setup();
|
||||
void iwdg_setup();
|
||||
|
||||
#endif // __HARDWARE_H__
|
||||
270
F1:F103/deprecated/MLX90640/i2c.c
Normal file
270
F1:F103/deprecated/MLX90640/i2c.c
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2022 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hardware.h"
|
||||
#include "i2c.h"
|
||||
/* don't run debugging info */
|
||||
#ifdef EBUG
|
||||
#undef EBUG
|
||||
#endif
|
||||
|
||||
#include "strfunct.h"
|
||||
|
||||
extern volatile uint32_t Tms;
|
||||
|
||||
volatile i2c_dma_status i2cDMAr = I2C_DMA_NOTINIT;
|
||||
|
||||
// current addresses for read/write (should be set with i2c_set_addr7)
|
||||
static uint8_t addr7r = 0, addr7w = 0;
|
||||
|
||||
// setup DMA receiver
|
||||
static void i2c_DMAr_setup(){
|
||||
/* Enable the peripheral clock DMA1 */
|
||||
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
|
||||
DMA1_Channel7->CPAR = (uint32_t)&(I2C1->DR);
|
||||
DMA1_Channel7->CCR |= DMA_CCR_MINC | DMA_CCR_TCIE;
|
||||
NVIC_SetPriority(DMA1_Channel7_IRQn, 0);
|
||||
NVIC_EnableIRQ(DMA1_Channel7_IRQn);
|
||||
I2C1->CR2 |= I2C_CR2_DMAEN;
|
||||
i2cDMAr = I2C_DMA_RELAX;
|
||||
}
|
||||
|
||||
/*
|
||||
* PB10/PB6 - I2C_SCL, PB11/PB7 - I2C_SDA or remap @ PB8 & PB9
|
||||
* @param withDMA == 1 to setup DMA receiver too
|
||||
*/
|
||||
void i2c_setup(uint8_t withDMA){
|
||||
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
|
||||
GPIOB->CRL = (GPIOB->CRL & ~(GPIO_CRL_CNF6 | GPIO_CRL_CNF7)) |
|
||||
CRL(6, CNF_AFOD | MODE_NORMAL) | CRL(7, CNF_AFOD | MODE_NORMAL);
|
||||
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
|
||||
I2C1->CR1 = 0; // clear all previous settings
|
||||
I2C1->SR1 = 0;
|
||||
RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST; // reset peripherial
|
||||
RCC->APB1RSTR &= ~RCC_APB1RSTR_I2C1RST;
|
||||
I2C1->CR2 = 8; // FREQR=8MHz, T=125ns
|
||||
//I2C1->CR2 = 10; // FREQR=10MHz, T=100ns
|
||||
I2C1->TRISE = 9; // (9-1)*125 = 1us
|
||||
//I2C1->TRISE = 4; // (4-1)*100 = 300ns
|
||||
I2C1->CCR = 40; // normal mode, 8MHz/2/40 = 100kHz
|
||||
//I2C1->CCR = I2C_CCR_FS | 10; // fast mode, 10MHz/2/10 = 500kHz
|
||||
if(withDMA) i2c_DMAr_setup();
|
||||
I2C1->CR1 |= I2C_CR1_PE; // enable periph
|
||||
}
|
||||
|
||||
void i2c_set_addr7(uint8_t addr){
|
||||
addr7w = addr << 1;
|
||||
addr7r = addr7w | 1;
|
||||
}
|
||||
|
||||
// wait for event evt no more than 2 ms
|
||||
#define I2C_WAIT(evt) do{ register uint32_t wait4 = Tms + 2; \
|
||||
while(Tms < wait4 && !(evt)) IWDG->KR = IWDG_REFRESH; \
|
||||
if(!(evt)){ret = I2C_TMOUT; goto eotr;}}while(0)
|
||||
// wait for !busy
|
||||
#define I2C_LINEWAIT() do{ register uint32_t wait4 = Tms + 2; \
|
||||
while(Tms < wait4 && (I2C1->SR2 & I2C_SR2_BUSY)) IWDG->KR = IWDG_REFRESH; \
|
||||
if(I2C1->SR2 & I2C_SR2_BUSY){I2C1->CR1 |= I2C_CR1_SWRST; return I2C_LINEBUSY;}\
|
||||
}while(0)
|
||||
|
||||
// start writing
|
||||
static i2c_status i2c_7bit_startw(){
|
||||
i2c_status ret = I2C_LINEBUSY;
|
||||
if(I2C1->CR1 != I2C_CR1_PE) i2c_setup(i2cDMAr != I2C_DMA_NOTINIT);
|
||||
if(I2C1->SR1) I2C1->SR1 = 0; // clear NACK and other problems
|
||||
(void) I2C1->SR2;
|
||||
I2C_LINEWAIT();
|
||||
DBG("linew");
|
||||
I2C1->CR1 |= I2C_CR1_START; // generate start sequence
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_SB); // wait for SB
|
||||
DBG("SB");
|
||||
(void) I2C1->SR1; // clear SB
|
||||
I2C1->DR = addr7w; // set address
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_ADDR); // wait for ADDR flag (timeout @ NACK)
|
||||
DBG("ADDR");
|
||||
if(I2C1->SR1 & I2C_SR1_AF){ // NACK
|
||||
return I2C_NACK;
|
||||
}
|
||||
DBG("ACK");
|
||||
(void) I2C1->SR2; // clear ADDR
|
||||
ret = I2C_OK;
|
||||
eotr:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// send data array
|
||||
i2c_status i2c_7bit_send(const uint8_t *data, int datalen, uint8_t stop){
|
||||
i2c_status ret = i2c_7bit_startw();
|
||||
if(ret != I2C_OK){
|
||||
DBG("NACK!");
|
||||
I2C1->CR1 |= I2C_CR1_STOP;
|
||||
goto eotr;
|
||||
}
|
||||
for(int i = 0; i < datalen; ++i){
|
||||
I2C1->DR = data[i];
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_TXE);
|
||||
}
|
||||
DBG("GOOD");
|
||||
ret = I2C_OK;
|
||||
if(datalen || stop) I2C_WAIT(I2C1->SR1 & I2C_SR1_BTF);
|
||||
eotr:
|
||||
if(stop){
|
||||
I2C1->CR1 |= I2C_CR1_STOP; // generate stop event
|
||||
}else{DBG("No STOP");}
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_status i2c_7bit_receive_onebyte(uint8_t *data, uint8_t stop){
|
||||
i2c_status ret = I2C_LINEBUSY;
|
||||
I2C1->CR1 |= I2C_CR1_START; // generate start sequence
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_SB); // wait for SB
|
||||
DBG("got SB");
|
||||
(void) I2C1->SR1; // clear SB
|
||||
I2C1->DR = addr7r; // set address
|
||||
DBG("Rx addr");
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_ADDR); // wait for ADDR flag
|
||||
DBG("Rx ack");
|
||||
I2C1->CR1 &= ~I2C_CR1_ACK; // clear ACK
|
||||
if(I2C1->SR1 & I2C_SR1_AF){ // NACK
|
||||
DBG("Rx nak");
|
||||
ret = I2C_NACK;
|
||||
goto eotr;
|
||||
}
|
||||
(void) I2C1->SR2; // clear ADDR
|
||||
DBG("Rx stop");
|
||||
if(stop) I2C1->CR1 |= I2C_CR1_STOP; // program STOP
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_RXNE); // wait for RxNE
|
||||
DBG("Rx OK");
|
||||
*data = I2C1->DR; // read data & clear RxNE
|
||||
ret = I2C_OK;
|
||||
eotr:
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_status i2c_7bit_receive_twobytes(uint8_t *data){
|
||||
i2c_status ret = I2C_LINEBUSY;
|
||||
I2C1->CR1 |= I2C_CR1_START | I2C_CR1_POS | I2C_CR1_ACK; // generate start sequence, set pos & ack
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_SB); // wait for SB
|
||||
DBG("2 got sb");
|
||||
(void) I2C1->SR1; // clear SB
|
||||
I2C1->DR = addr7r; // set address
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_ADDR); // wait for ADDR flag
|
||||
DBG("2 ADDR");
|
||||
if(I2C1->SR1 & I2C_SR1_AF){ // NACK
|
||||
ret = I2C_NACK;
|
||||
DBG("2 NACK");
|
||||
goto eotr;
|
||||
}
|
||||
DBG("2 ACK");
|
||||
(void) I2C1->SR2; // clear ADDR
|
||||
I2C1->CR1 &= ~I2C_CR1_ACK; // clear ACK
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_BTF); // wait for BTF
|
||||
DBG("2 BTF");
|
||||
I2C1->CR1 |= I2C_CR1_STOP; // program STOP
|
||||
*data++ = I2C1->DR; *data = I2C1->DR; // read data & clear RxNE
|
||||
ret = I2C_OK;
|
||||
eotr:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// receive any amount of bytes
|
||||
i2c_status i2c_7bit_receive(uint8_t *data, uint16_t nbytes){
|
||||
if(nbytes == 0) return I2C_HWPROBLEM;
|
||||
//DBG("linew");
|
||||
//I2C_LINEWAIT();
|
||||
I2C1->SR1 = 0; // clear previous NACK flag & other error flags
|
||||
if(nbytes == 1) return i2c_7bit_receive_onebyte(data, 1);
|
||||
else if(nbytes == 2) return i2c_7bit_receive_twobytes(data);
|
||||
i2c_status ret = I2C_LINEBUSY;
|
||||
I2C1->CR1 |= I2C_CR1_START | I2C_CR1_ACK; // generate start sequence, set pos & ack
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_SB); // wait for SB
|
||||
DBG("n got SB");
|
||||
(void) I2C1->SR1; // clear SB
|
||||
I2C1->DR = addr7r; // set address
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_ADDR); // wait for ADDR flag
|
||||
DBG("n send addr");
|
||||
if(I2C1->SR1 & I2C_SR1_AF){ // NACK
|
||||
DBG("n NACKed");
|
||||
ret = I2C_NACK;
|
||||
goto eotr;
|
||||
}
|
||||
DBG("n ACKed");
|
||||
(void) I2C1->SR2; // clear ADDR
|
||||
for(uint16_t x = nbytes - 3; x > 0; --x){
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_RXNE); // wait next byte
|
||||
*data++ = I2C1->DR; // get data
|
||||
}
|
||||
DBG("n three left");
|
||||
// three bytes remain to be read
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_RXNE); // wait dataN-2
|
||||
DBG("n dataN-2");
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_BTF); // wait for BTF
|
||||
DBG("n BTF");
|
||||
I2C1->CR1 &= ~I2C_CR1_ACK; // clear ACK
|
||||
*data++ = I2C1->DR; // read dataN-2
|
||||
I2C1->CR1 |= I2C_CR1_STOP; // program STOP
|
||||
*data++ = I2C1->DR; // read dataN-1
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_RXNE); // wait next byte
|
||||
*data = I2C1->DR; // read dataN
|
||||
DBG("n got it");
|
||||
ret = I2C_OK;
|
||||
eotr:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief i2c_7bit_receive_DMA - receive data using DMA
|
||||
* @param data - pointer to external array
|
||||
* @param nbytes - data len
|
||||
* @return I2C_OK when receiving started; poll end of receiving by flag i2cDMAr;
|
||||
*/
|
||||
i2c_status i2c_7bit_receive_DMA(uint8_t *data, uint16_t nbytes){
|
||||
if(i2cDMAr == I2C_DMA_BUSY) return I2C_LINEBUSY; // previous receiving still works
|
||||
if(i2cDMAr == I2C_DMA_NOTINIT) i2c_DMAr_setup();
|
||||
i2c_status ret = I2C_LINEBUSY;
|
||||
DBG("Conf DMA");
|
||||
DMA1_Channel7->CCR &= ~DMA_CCR_EN;
|
||||
DMA1_Channel7->CMAR = (uint32_t)data;
|
||||
DMA1_Channel7->CNDTR = nbytes;
|
||||
// now send address and start I2C receiving
|
||||
//DBG("linew");
|
||||
//I2C_LINEWAIT();
|
||||
I2C1->SR1 = 0;
|
||||
I2C1->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
|
||||
DBG("wait sb");
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_SB);
|
||||
(void) I2C1->SR1;
|
||||
I2C1->DR = addr7r;
|
||||
DBG("wait addr");
|
||||
I2C_WAIT(I2C1->SR1 & I2C_SR1_ADDR);
|
||||
if(I2C1->SR1 & I2C_SR1_AF) return I2C_NACK;
|
||||
(void) I2C1->SR2;
|
||||
DBG("start");
|
||||
DMA1_Channel7->CCR |= DMA_CCR_EN;
|
||||
i2cDMAr = I2C_DMA_BUSY;
|
||||
ret = I2C_OK;
|
||||
eotr:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dma1_channel7_isr(){
|
||||
I2C1->CR1 |= I2C_CR1_STOP; // send STOP
|
||||
DMA1->IFCR = DMA_IFCR_CTCIF7;
|
||||
DMA1_Channel7->CCR &= ~DMA_CCR_EN;
|
||||
i2cDMAr = I2C_DMA_READY;
|
||||
}
|
||||
50
F1:F103/deprecated/MLX90640/i2c.h
Normal file
50
F1:F103/deprecated/MLX90640/i2c.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2022 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef I2C_H__
|
||||
|
||||
#include <stm32f1.h>
|
||||
|
||||
typedef enum{
|
||||
I2C_OK = 0,
|
||||
I2C_LINEBUSY,
|
||||
I2C_TMOUT,
|
||||
I2C_NOADDR,
|
||||
I2C_NACK,
|
||||
I2C_HWPROBLEM,
|
||||
} i2c_status;
|
||||
|
||||
typedef enum{
|
||||
I2C_DMA_NOTINIT,
|
||||
I2C_DMA_RELAX,
|
||||
I2C_DMA_BUSY,
|
||||
I2C_DMA_READY
|
||||
} i2c_dma_status;
|
||||
|
||||
extern volatile i2c_dma_status i2cDMAr;
|
||||
|
||||
void i2c_setup(uint8_t withDMA);
|
||||
void i2c_set_addr7(uint8_t addr);
|
||||
i2c_status i2c_7bit_send(const uint8_t *data, int datalen, uint8_t stop);
|
||||
i2c_status i2c_7bit_receive_onebyte(uint8_t *data, uint8_t stop);
|
||||
i2c_status i2c_7bit_receive_twobytes(uint8_t *data);
|
||||
i2c_status i2c_7bit_receive(uint8_t *data, uint16_t nbytes);
|
||||
i2c_status i2c_7bit_receive_DMA(uint8_t *data, uint16_t nbytes);
|
||||
|
||||
#define I2C_H__
|
||||
#endif // I2C_H__
|
||||
70
F1:F103/deprecated/MLX90640/main.c
Normal file
70
F1:F103/deprecated/MLX90640/main.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2022 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "i2c.h"
|
||||
#include "hardware.h"
|
||||
#include "mlx90640.h"
|
||||
#include "proto.h"
|
||||
#include "strfunct.h"
|
||||
#include "usb.h"
|
||||
|
||||
volatile uint32_t Tms = 0;
|
||||
|
||||
/* Called when systick fires */
|
||||
void sys_tick_handler(void){
|
||||
++Tms;
|
||||
}
|
||||
|
||||
int main(void){
|
||||
uint32_t lastT = 0;
|
||||
sysreset();
|
||||
StartHSE();
|
||||
hw_setup();
|
||||
SysTick_Config(72000);
|
||||
|
||||
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
|
||||
|
||||
USBPU_OFF();
|
||||
USB_setup();
|
||||
#ifndef EBUG
|
||||
iwdg_setup();
|
||||
#endif
|
||||
USBPU_ON();
|
||||
i2c_setup(TRUE);
|
||||
i2c_set_addr7(MLX_DEFAULT_ADDR);
|
||||
|
||||
while(1){
|
||||
IWDG->KR = IWDG_REFRESH; // refresh watchdog
|
||||
if(lastT > Tms || Tms - lastT > 499){
|
||||
LED_blink(LED0);
|
||||
lastT = Tms;
|
||||
}
|
||||
usb_proc();
|
||||
char *txt, *ans;
|
||||
if((txt = get_USB())){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
ans = (char*)parse_cmd(txt);
|
||||
if(ans){
|
||||
addtobuf(ans);
|
||||
NL();
|
||||
}
|
||||
}
|
||||
mlx90640_process();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
578
F1:F103/deprecated/MLX90640/mlx90640.c
Normal file
578
F1:F103/deprecated/MLX90640/mlx90640.c
Normal file
@@ -0,0 +1,578 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2022 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include "hardware.h"
|
||||
#include "i2c.h"
|
||||
#include "mlx90640.h"
|
||||
#include "mlx90640_regs.h"
|
||||
#include "strfunct.h"
|
||||
|
||||
#ifdef EBUG
|
||||
extern volatile uint32_t Tms;
|
||||
#endif
|
||||
|
||||
mlx90640_state mlx_state = M_ERROR;
|
||||
|
||||
MLX90640_params params;
|
||||
|
||||
#if REG_CALIBRDATA_LEN > MLX_DMA_MAXLEN || MLX_PIXARRSZ > MLX_DMA_MAXLEN
|
||||
#error "MLX_DMA_MAXLEN should be >= REG_CALIBRDATA_LEN"
|
||||
#endif
|
||||
static uint16_t dataarray[MLX_DMA_MAXLEN]; // array for raw data from sensor
|
||||
static int portionlen = 0; // data length in `dataarray`
|
||||
float mlx_image[MLX_PIXNO]; // ready image
|
||||
|
||||
#define CREG_VAL(reg) dataarray[CREG_IDX(reg)]
|
||||
#define IMD_VAL(reg) dataarray[IMD_IDX(reg)]
|
||||
|
||||
static uint8_t simpleimage = 0; // ==1 not to calibrate T
|
||||
static uint8_t subpageno = 0; // subpage number
|
||||
|
||||
// reg_control values for subpage #0 and #1
|
||||
static const uint16_t reg_control_val[2] = {
|
||||
REG_CONTROL_CHESS | REG_CONTROL_RES18 | REG_CONTROL_REFR_2HZ | REG_CONTROL_SUBPSEL | REG_CONTROL_DATAHOLD | REG_CONTROL_SUBPEN,
|
||||
REG_CONTROL_CHESS | REG_CONTROL_RES18 | REG_CONTROL_REFR_2HZ | REG_CONTROL_SUBP1 | REG_CONTROL_SUBPSEL | REG_CONTROL_DATAHOLD | REG_CONTROL_SUBPEN
|
||||
};
|
||||
|
||||
// read register value
|
||||
int read_reg(uint16_t reg, uint16_t *val){
|
||||
reg = __REV16(reg);
|
||||
if(I2C_OK != i2c_7bit_send((uint8_t*)®, 2, 0)){
|
||||
DBG("Can't send address");
|
||||
return FALSE;
|
||||
}
|
||||
uint16_t d;
|
||||
i2c_status s = i2c_7bit_receive_twobytes((uint8_t*)&d);
|
||||
if(I2C_OK != s){
|
||||
#ifdef EBUG
|
||||
DBG("Can't get info, s=");
|
||||
printu(s); NL();
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
*val = __REV16(d);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// blocking read N uint16_t values starting from `reg`
|
||||
// @param reg - register to read
|
||||
// @param N (io) - amount of bytes to read / bytes read
|
||||
// @return `dataarray` or NULL if failed
|
||||
uint16_t *read_data(uint16_t reg, uint16_t *N){
|
||||
uint16_t n = *N;
|
||||
if(n < 1 || n > MLX_DMA_MAXLEN) return NULL;
|
||||
uint16_t i, *data = dataarray;
|
||||
#ifdef EBUG
|
||||
SEND("Tms="); printu(Tms); newline();
|
||||
#endif
|
||||
for(i = 0; i < n; ++i){
|
||||
if(!read_reg(reg++, data++)){
|
||||
DBG("can't read");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef EBUG
|
||||
SEND("Tms="); printu(Tms); newline();
|
||||
#endif
|
||||
*N = i;
|
||||
return dataarray;
|
||||
}
|
||||
|
||||
// write register value
|
||||
int write_reg(uint16_t reg, uint16_t val){
|
||||
// little endian -> big endian
|
||||
uint8_t _4bytes[4];
|
||||
_4bytes[0] = reg >> 8;
|
||||
_4bytes[1] = reg & 0xff;
|
||||
_4bytes[2] = val >> 8;
|
||||
_4bytes[3] = val & 0xff;
|
||||
if(I2C_OK != i2c_7bit_send(_4bytes, 4, 1)) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief read_data_dma - read big data buffer by DMA
|
||||
* @param reg - starting register number
|
||||
* @param N - amount of data (in 16-bit words)
|
||||
* @return FALSE if can't run operation
|
||||
*/
|
||||
int read_data_dma(uint16_t reg, int N){
|
||||
if(N < 1 || N > MLX_DMA_MAXLEN) return FALSE;
|
||||
/*uint8_t _2bytes[2];
|
||||
_2bytes[0] = reg >> 8; // big endian!
|
||||
_2bytes[1] = reg & 0xff;*/
|
||||
reg = __REV16(reg);
|
||||
portionlen = N;
|
||||
if(I2C_OK != i2c_7bit_send((uint8_t*)®, 2, 0)){
|
||||
DBG("DMA: can't send address");
|
||||
return FALSE;
|
||||
}
|
||||
if(I2C_OK != i2c_7bit_receive_DMA((uint8_t*)dataarray, N*2)) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Calculate parameters & values
|
||||
*****************************************************************************/
|
||||
// calculate Vdd from vddRAM register
|
||||
/*
|
||||
static float getVdd(uint16_t vddRAM){
|
||||
int16_t ram = (int16_t) vddRAM;
|
||||
float vdd = (float)ram - params.vdd25;
|
||||
return vdd / params.kVdd + 3.3f;
|
||||
}*/
|
||||
|
||||
// fill OCC/ACC row/col arrays
|
||||
static void occacc(int8_t *arr, int l, uint16_t *regstart){
|
||||
int n = l >> 2; // divide by 4
|
||||
int8_t *p = arr;
|
||||
for(int i = 0; i < n; ++i){
|
||||
register uint16_t val = *regstart++;
|
||||
*p++ = (val & 0x000F) >> 0;
|
||||
*p++ = (val & 0x00F0) >> 4;
|
||||
*p++ = (val & 0x0F00) >> 8;
|
||||
*p++ = (val ) >> 12;
|
||||
}
|
||||
for(int i = 0; i < l; ++i, ++arr){
|
||||
if(*arr > 0x07) *arr -= 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
// get all parameters' values from `dataarray`, return FALSE if something failed
|
||||
static int get_parameters(){
|
||||
#ifdef EBUG
|
||||
SEND("0 Tms="); printu(Tms); newline();
|
||||
#endif
|
||||
int8_t i8;
|
||||
int16_t i16;
|
||||
uint16_t *pu16;
|
||||
uint16_t val = CREG_VAL(REG_VDD);
|
||||
i8 = (int8_t) (val >> 8);
|
||||
params.kVdd = i8 << 5;
|
||||
if(params.kVdd == 0) return FALSE;
|
||||
i16 = val & 0xFF;
|
||||
params.vdd25 = ((i16 - 0x100) << 5) - (1<<13);
|
||||
val = CREG_VAL(REG_KVTPTAT);
|
||||
i16 = (val & 0xFC00) >> 10;
|
||||
if(i16 > 0x1F) i16 -= 0x40;
|
||||
params.KvPTAT = (float)i16 / (1<<12);
|
||||
i16 = (val & 0x03FF);
|
||||
if(i16 > 0x1FF) i16 -= 0x400;
|
||||
params.KtPTAT = (float)i16 / 8.f;
|
||||
params.vPTAT25 = (int16_t) CREG_VAL(REG_PTAT);
|
||||
val = CREG_VAL(REG_APTATOCCS) >> 12;
|
||||
params.alphaPTAT = val / 4.f + 8.f;
|
||||
params.gainEE = (int16_t)CREG_VAL(REG_GAIN);
|
||||
if(params.gainEE == 0) return FALSE;
|
||||
#ifdef EBUG
|
||||
SEND("1 Tms="); printu(Tms); newline();
|
||||
#endif
|
||||
int8_t occRow[MLX_H];
|
||||
int8_t occColumn[MLX_W];
|
||||
occacc(occRow, MLX_H, &CREG_VAL(REG_OCCROW14));
|
||||
occacc(occColumn, MLX_W, &CREG_VAL(REG_OCCCOL14));
|
||||
int8_t accRow[MLX_H];
|
||||
int8_t accColumn[MLX_W];
|
||||
occacc(accRow, MLX_H, &CREG_VAL(REG_ACCROW14));
|
||||
occacc(accColumn, MLX_W, &CREG_VAL(REG_ACCCOL14));
|
||||
val = CREG_VAL(REG_APTATOCCS);
|
||||
// need to do multiplication instead of bitshift, so:
|
||||
float occRemScale = 1<<(val&0x0F),
|
||||
occColumnScale = 1<<((val>>4)&0x0F),
|
||||
occRowScale = 1<<((val>>8)&0x0F);
|
||||
int16_t offavg = (int16_t) CREG_VAL(REG_OSAVG);
|
||||
// even/odd column/row numbers are for starting from 1, so for starting from 0 we chould swap them:
|
||||
// even - for 1,3,5,...; odd - for 0,2,4,... etc
|
||||
int8_t ktaavg[4];
|
||||
// 0 - odd row, odd col; 1 - odd row even col; 2 - even row, odd col; 3 - even row, even col
|
||||
val = CREG_VAL(REG_KTAAVGODDCOL);
|
||||
ktaavg[2] = (int8_t)(val & 0xFF); // odd col, even row -> col 0,2,..; row 1,3,..
|
||||
ktaavg[0] = (int8_t)(val >> 8);; // odd col, odd row -> col 0,2,..; row 0,2,..
|
||||
val = CREG_VAL(REG_KTAAVGEVENCOL);
|
||||
ktaavg[3] = (int8_t)(val & 0xFF); // even col, even row -> col 1,3,..; row 1,3,..
|
||||
ktaavg[1] = (int8_t)(val >> 8); // even col, odd row -> col 1,3,..; row 0,2,..
|
||||
// so index of ktaavg is 2*(row&1)+(col&1)
|
||||
val = CREG_VAL(REG_KTAVSCALE);
|
||||
uint8_t scale1 = ((val & 0xFF)>>4) + 8, scale2 = (val&0xF);
|
||||
if(scale1 == 0 || scale2 == 0) return FALSE;
|
||||
float mul = (float)(1<<scale2), div = (float)(1<<scale1); // kta_scales
|
||||
uint16_t a_r = CREG_VAL(REG_SENSIVITY); // alpha_ref
|
||||
val = CREG_VAL(REG_SCALEACC);
|
||||
float *a = params.alpha, diva = (float)(val >> 12);
|
||||
diva *= (float)(1<<30); // alpha_scale
|
||||
float accRowScale = 1<<((val & 0x0f00)>>8),
|
||||
accColumnScale = 1<<((val & 0x00f0)>>4),
|
||||
accRemScale = 1<<(val & 0x0f);
|
||||
pu16 = &CREG_VAL(REG_OFFAK1);
|
||||
float *kta = params.kta, *offset = params.offset;
|
||||
#ifdef EBUG
|
||||
SEND("2 Tms="); printu(Tms); newline();
|
||||
#endif
|
||||
for(int row = 0; row < MLX_H; ++row){
|
||||
int idx = (row&1)<<1;
|
||||
for(int col = 0; col < MLX_W; ++col){
|
||||
// offset
|
||||
register uint16_t rv = *pu16++;
|
||||
i16 = (rv & 0xFC00) >> 10;
|
||||
if(i16 > 0x1F) i16 -= 0x40;
|
||||
*offset++ = (float)offavg + (float)occRow[row]*occRowScale + (float)occColumn[col]*occColumnScale + (float)i16*occRemScale;
|
||||
// kta
|
||||
i16 = (rv & 0xF) >> 1;
|
||||
if(i16 > 0x03) i16 -= 0x08;
|
||||
*kta++ = (ktaavg[idx|(col&1)] + i16*mul) / div;
|
||||
// alpha
|
||||
i16 = (rv & 0x3F0) >> 4;
|
||||
if(i16 > 0x1F) i16 -= 0x40;
|
||||
float oft = (float)a_r + accRow[row]*accRowScale + accColumn[col]*accColumnScale +i16*accRemScale;
|
||||
*a++ = oft / diva;
|
||||
}
|
||||
}
|
||||
#ifdef EBUG
|
||||
SEND("3 Tms="); printu(Tms); newline();
|
||||
#endif
|
||||
scale1 = (CREG_VAL(REG_KTAVSCALE) >> 8) & 0xF; // kvscale
|
||||
div = (float)(1<<scale1);
|
||||
val = CREG_VAL(REG_KVAVG);
|
||||
i16 = val >> 12; if(i16 > 0x07) i16 -= 0x10;
|
||||
ktaavg[0] = i16; // odd col, odd row
|
||||
i16 = (val & 0xF0) >> 4; if(i16 > 0x07) i16 -= 0x10;
|
||||
ktaavg[1] = i16; // even col, odd row
|
||||
i16 = (val & 0x0F00) >> 8; if(i16 > 0x07) i16 -= 0x10;
|
||||
ktaavg[2] = i16; // odd col, even row
|
||||
i16 = val & 0x0F; if(i16 > 0x07) i16 -= 0x10;
|
||||
ktaavg[3] = i16; // even col, even row
|
||||
for(int i = 0; i < 4; ++i) params.kv[i] = ktaavg[i] / div;
|
||||
val = CREG_VAL(REG_CPOFF);
|
||||
params.cpOffset[0] = (val & 0x03ff);
|
||||
if(params.cpOffset[0] > 0x1ff) params.cpOffset[0] -= 0x400;
|
||||
params.cpOffset[1] = val >> 10;
|
||||
if(params.cpOffset[1] > 0x1f) params.cpOffset[1] -= 0x40;
|
||||
params.cpOffset[1] += params.cpOffset[0];
|
||||
val = ((CREG_VAL(REG_KTAVSCALE) & 0xF0) >> 4) + 8;
|
||||
i8 = (int8_t)(CREG_VAL(REG_KVTACP) & 0xFF);
|
||||
params.cpKta = (float)i8 / (1<<val);
|
||||
val = (CREG_VAL(REG_KTAVSCALE) & 0x0F00) >> 8;
|
||||
i16 = CREG_VAL(REG_KVTACP) >> 8;
|
||||
if(i16 > 0x7F) i16 -= 0x100;
|
||||
params.cpKv = (float)i16 / (1<<val);
|
||||
i16 = CREG_VAL(REG_KSTATGC) & 0xFF;
|
||||
if(i16 > 0x7F) i16 -= 0x100;
|
||||
params.tgc = (float)i16;
|
||||
params.tgc /= 32.;
|
||||
#ifdef EBUG
|
||||
SEND("4 Tms="); printu(Tms); newline();
|
||||
#endif
|
||||
val = (CREG_VAL(REG_SCALEACC)>>12); // alpha_scale_CP
|
||||
i16 = CREG_VAL(REG_ALPHA)>>10; // cp_P1_P0_ratio
|
||||
if(i16 > 0x1F) i16 -= 0x40;
|
||||
div = (float)(1<<val);
|
||||
div *= (float)(1<<27);
|
||||
params.cpAlpha[0] = (float)(CREG_VAL(REG_ALPHA) & 0x03FF) / div;
|
||||
div = (float)(1<<7);
|
||||
params.cpAlpha[1] = params.cpAlpha[0] * (1.f + (float)i16/div);
|
||||
i8 = (int8_t)(CREG_VAL(REG_KSTATGC) >> 8);
|
||||
params.KsTa = (float)i8/(1<<13);
|
||||
div = 1<<((CREG_VAL(REG_CT34) & 0x0F) + 8); // kstoscale
|
||||
val = CREG_VAL(REG_KSTO12);
|
||||
i8 = (int8_t)(val & 0xFF);
|
||||
params.ksTo[0] = 273.15f * i8 / div;
|
||||
i8 = (int8_t)(val >> 8);
|
||||
params.ksTo[1] = 273.15f * i8 / div;
|
||||
val = CREG_VAL(REG_KSTO34);
|
||||
i8 = (int8_t)(val & 0xFF);
|
||||
params.ksTo[2] = 273.15f * i8 / div;
|
||||
i8 = (int8_t)(val >> 8);
|
||||
params.ksTo[3] = 273.15f * i8 / div;
|
||||
params.CT[0] = 0.f; // 0degr - between ranges 1 and 2
|
||||
val = CREG_VAL(REG_CT34);
|
||||
mul = ((val & 0x3000)>>12)*10.f; // step
|
||||
params.CT[1] = ((val & 0xF0)>>4)*mul; // CT3 - between ranges 2 and 3
|
||||
params.CT[2] = ((val & 0x0F00) >> 8)*mul + params.CT[1]; // CT4 - between ranges 3 and 4
|
||||
params.alphacorr[0] = 1.f/(1.f + params.ksTo[0] * 40.f);
|
||||
params.alphacorr[1] = 1.f;
|
||||
params.alphacorr[2] = (1.f + params.ksTo[2] * params.CT[1]);
|
||||
params.alphacorr[3] = (1.f + params.ksTo[3] * (params.CT[2] - params.CT[1])) * params.alphacorr[2];
|
||||
// Don't forget to check 'outlier' flags for wide purpose
|
||||
#ifdef EBUG
|
||||
SEND("end Tms="); printu(Tms);
|
||||
NL();
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief process_subpage - calculate all parameters from `dataarray` into `mlx_image`
|
||||
*/
|
||||
static void process_subpage(){
|
||||
DBG("process_subpage()");
|
||||
SEND("Tms="); printu(Tms); newline();
|
||||
SEND("subpage="); printu(subpageno); newline();
|
||||
(void)subpageno; (void)simpleimage;
|
||||
for(int i = 0; i < MLX_W; ++i){
|
||||
printi((int8_t)dataarray[i]); bufputchar(' ');
|
||||
} newline();
|
||||
SEND("072a="); printuhex(IMD_VAL(REG_IVDDPIX));
|
||||
SEND("\n0720="); printuhex(IMD_VAL(REG_ITAPTAT));
|
||||
SEND("\n0700="); printuhex(IMD_VAL(REG_ITAVBE));
|
||||
SEND("\n070a="); printuhex(IMD_VAL(REG_IGAIN)); newline();
|
||||
int16_t i16a = (int16_t)IMD_VAL(REG_IVDDPIX);
|
||||
float dvdd = i16a - params.vdd25;
|
||||
dvdd = dvdd / params.kVdd;
|
||||
SEND("Vd="); float2str(dvdd+3.3f, 2); newline();
|
||||
i16a = (int16_t)IMD_VAL(REG_ITAPTAT);
|
||||
int16_t i16b = (int16_t)IMD_VAL(REG_ITAVBE);
|
||||
float dTa = (float)i16a / (i16a * params.alphaPTAT + i16b); // vptatart
|
||||
dTa *= (float)(1<<18);
|
||||
dTa = (dTa / (1 + params.KvPTAT*dvdd) - params.vPTAT25);
|
||||
dTa = dTa / params.KtPTAT; // without 25degr - Ta0
|
||||
SEND("Ta="); float2str(dTa+25., 2); newline();
|
||||
i16a = (int16_t)IMD_VAL(REG_IGAIN);
|
||||
float Kgain = params.gainEE / (float)i16a;
|
||||
SEND("Kgain="); float2str(Kgain, 2); newline();
|
||||
// now make first approximation to image
|
||||
uint16_t pixno = 0; // current pixel number - for indexing in parameters etc
|
||||
for(int row = 0; row < MLX_H; ++row){
|
||||
int idx = (row&1)<<1; // index for params.kv
|
||||
for(int col = 0; col < MLX_W; ++col, ++pixno){
|
||||
uint8_t sp = (row&1)^(col&1); // subpage of current pixel
|
||||
if(sp != subpageno) continue;
|
||||
register float curval = (float)((int16_t)dataarray[pixno]) * Kgain; // gain compensation
|
||||
curval -= params.offset[pixno] * (1.f + params.kta[pixno]*dTa) *
|
||||
(1.f + params.kv[idx|(col&1)]*dvdd); // add offset
|
||||
float IRcompens = curval; // IR_compensated
|
||||
curval -= params.cpOffset[subpageno] * (1.f - params.cpKta * dTa) *
|
||||
(1.f + params.cpKv * dvdd); // CP
|
||||
if(!simpleimage){
|
||||
curval = IRcompens - params.tgc * curval; // IR gradient compens
|
||||
float alphaComp = params.alpha[pixno] - params.tgc * params.cpAlpha[subpageno];
|
||||
alphaComp /= 1.f + params.KsTa * dTa;
|
||||
// calculate To for basic range
|
||||
float Tar = dTa + 273.15f + 25.f;
|
||||
Tar = Tar*Tar*Tar*Tar;
|
||||
float ac3 = alphaComp*alphaComp*alphaComp;
|
||||
float Sx = ac3*IRcompens + alphaComp*ac3*Tar;
|
||||
Sx = params.KsTa * sqrt(sqrt(Sx));
|
||||
float To = IRcompens / (alphaComp * (1.f - params.ksTo[1]) + Sx) + Tar;
|
||||
curval = sqrt(sqrt(To)) - 273.15; // To
|
||||
// TODO: extended
|
||||
}
|
||||
mlx_image[pixno] = curval;
|
||||
}
|
||||
}
|
||||
SEND("Tms="); printu(Tms); newline();
|
||||
NL();
|
||||
}
|
||||
|
||||
// start image acquiring for next subpage
|
||||
static int startima(){
|
||||
DBG("startima()");
|
||||
// write `overwrite` flag twice
|
||||
if(!write_reg(REG_CONTROL, reg_control_val[subpageno]) ||
|
||||
!write_reg(REG_STATUS, REG_STATUS_OVWEN) ||
|
||||
!write_reg(REG_STATUS, REG_STATUS_OVWEN)) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief parse_buffer - swap bytes in `dataarray` (after receiving or before transmitting data)
|
||||
*
|
||||
static void parse_buffer(){
|
||||
uint16_t *ptr = dataarray;
|
||||
DBG("parse_buffer()");
|
||||
for(uint16_t i = 0; i < portionlen; ++i, ++ptr){
|
||||
*ptr = __REV16(*ptr);
|
||||
#if 0
|
||||
printu(i);
|
||||
addtobuf(" ");
|
||||
printuhex(*ptr);
|
||||
newline();
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
sendbuf();
|
||||
#endif
|
||||
}*/
|
||||
|
||||
/**
|
||||
* @brief mlx90640_process - main finite-state machine
|
||||
*/
|
||||
void mlx90640_process(){
|
||||
#define chstate(s) do{errctr = 0; Tlast = Tms; mlx_state = s;}while(0)
|
||||
#define chkerr() do{if(++errctr > MLX_MAXERR_COUNT){chstate(M_ERROR); DBG("-> M_ERROR");}}while(0)
|
||||
#define chktmout() do{if(Tms - Tlast > MLX_TIMEOUT){chstate(M_ERROR); DBG("Timeout! -> M_ERROR"); }}while(0)
|
||||
static int errctr = 0;
|
||||
static uint32_t Tlast = 0;
|
||||
uint16_t reg, N;
|
||||
/*
|
||||
uint8_t gotdata = 0;
|
||||
if(i2cDMAr == I2C_DMA_READY){ // convert received data into little-endian
|
||||
i2cDMAr = I2C_DMA_RELAX;
|
||||
parse_buffer();
|
||||
gotdata = 1;
|
||||
}*/
|
||||
switch(mlx_state){
|
||||
case M_FIRSTSTART: // init working mode by request
|
||||
if(write_reg(REG_CONTROL, reg_control_val[0])
|
||||
&& read_reg(REG_CONTROL, ®)){
|
||||
SEND("REG_CTRL="); printuhex(reg); NL();
|
||||
if(read_reg(REG_STATUS, ®)){
|
||||
SEND("REG_STATUS="); printuhex(reg); NL();}
|
||||
/*
|
||||
#define PARTD 512
|
||||
if(read_data_dma(REG_CALIDATA, PARTD)){
|
||||
chstate(M_READCONF);
|
||||
DBG("-> M_READCONF");
|
||||
}else chkerr();
|
||||
*/
|
||||
N = REG_CALIDATA_LEN;
|
||||
if(read_data(REG_CALIDATA, &N)){
|
||||
chstate(M_READCONF);
|
||||
DBG("-> M_READCONF");
|
||||
}else chkerr();
|
||||
}else chkerr();
|
||||
break;
|
||||
case M_READCONF:
|
||||
//if(gotdata){ // calculate calibration parameters
|
||||
/* uint16_t *d = &dataarray[PARTD];
|
||||
for(uint16_t r = REG_CALIDATA+PARTD; r < REG_CALIDATA + REG_CALIDATA_LEN; ++r){
|
||||
if(!read_reg(r, d++)){
|
||||
chstate(M_FIRSTSTART);
|
||||
DBG("can't read all confdata -> M_FIRSTSTART");
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
if(get_parameters()){
|
||||
chstate(M_RELAX);
|
||||
DBG("-> M_RELAX");
|
||||
}else{ // error -> go to M_FIRSTSTART again
|
||||
chstate(M_FIRSTSTART);
|
||||
DBG("-> M_FIRSTSTART");
|
||||
}
|
||||
//}else chktmout();
|
||||
break;
|
||||
case M_STARTIMA:
|
||||
if(startima()){
|
||||
chstate(M_PROCESS);
|
||||
DBG("-> M_PROCESS");
|
||||
}else{
|
||||
chstate(M_ERROR);
|
||||
DBG("can't start subpage -> M_ERROR");
|
||||
}
|
||||
break;
|
||||
case M_PROCESS:
|
||||
if(read_reg(REG_STATUS, ®)){
|
||||
if(reg & REG_STATUS_NEWDATA){
|
||||
if(subpageno != (reg & REG_STATUS_SPNO)){
|
||||
chstate(M_ERROR);
|
||||
DBG("wrong subpage number -> M_ERROR");
|
||||
}else{ // all OK, run image reading
|
||||
write_reg(REG_STATUS, 0); // clear rdy bit
|
||||
/*
|
||||
if(read_data_dma(REG_IMAGEDATA, PARTD)){
|
||||
chstate(M_READOUT);
|
||||
DBG("-> M_READOUT");
|
||||
}else chkerr();
|
||||
*/
|
||||
N = MLX_PIXARRSZ;
|
||||
if(read_data(REG_IMAGEDATA, &N)){
|
||||
chstate(M_READOUT);
|
||||
DBG("-> M_READOUT");
|
||||
}else chkerr();
|
||||
}
|
||||
}else chktmout();
|
||||
}else chkerr();
|
||||
break;
|
||||
case M_READOUT:
|
||||
//if(gotdata){
|
||||
/* uint16_t *d = &dataarray[PARTD];
|
||||
for(uint16_t r = REG_IMAGEDATA+PARTD; r < REG_IMAGEDATA+MLX_PIXARRSZ; ++r){
|
||||
if(!read_reg(r, d++)){
|
||||
chstate(M_ERROR);
|
||||
DBG("can't read all confdata -> M_ERROR");
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
process_subpage();
|
||||
subpageno = !subpageno;
|
||||
DBG("Subpage ready");
|
||||
chstate(M_RELAX);
|
||||
/*
|
||||
if(++subpageno > 1){ // image ready
|
||||
subpageno = 0;
|
||||
chstate(M_RELAX);
|
||||
DBG("Image READY!");
|
||||
}else{
|
||||
chstate(M_STARTIMA);
|
||||
DBG("-> M_STARTIMA");
|
||||
}*/
|
||||
//}else chktmout();
|
||||
break;
|
||||
case M_POWERON:
|
||||
if(Tms - Tlast > MLX_POWON_WAIT){
|
||||
if(params.kVdd == 0){ // get all parameters
|
||||
chstate(M_FIRSTSTART);
|
||||
DBG("M_FIRSTSTART");
|
||||
}else{ // rewrite settings register
|
||||
if(write_reg(REG_CONTROL, reg_control_val[0])){
|
||||
chstate(M_RELAX);
|
||||
DBG("-> M_RELAX");
|
||||
}else chkerr();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case M_POWEROFF1:
|
||||
MLXPOW_OFF();
|
||||
chstate(M_POWEROFF);
|
||||
DBG("-> M_POWEROFF");
|
||||
break;
|
||||
case M_POWEROFF:
|
||||
if(Tms - Tlast > MLX_POWOFF_WAIT){
|
||||
MLXPOW_ON();
|
||||
chstate(M_POWERON);
|
||||
DBG("-> M_POWERON");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void mlx90640_restart(){
|
||||
DBG("restart");
|
||||
mlx_state = M_POWEROFF1;
|
||||
}
|
||||
|
||||
// if state of MLX allows, make an image else return error
|
||||
// @param simple ==1 for simplest image processing (without T calibration)
|
||||
int mlx90640_take_image(uint8_t simple){
|
||||
simpleimage = simple;
|
||||
if(mlx_state == M_ERROR){
|
||||
DBG("Restart I2C");
|
||||
i2c_setup(i2cDMAr != I2C_DMA_NOTINIT);
|
||||
} else if(mlx_state != M_RELAX) return FALSE;
|
||||
if(params.kVdd == 0){ // no parameters -> make first run
|
||||
mlx_state = M_FIRSTSTART;
|
||||
DBG("no params -> M_FIRSTSTART");
|
||||
return TRUE;
|
||||
}
|
||||
//subpageno = 0;
|
||||
mlx_state = M_STARTIMA;
|
||||
DBG("-> M_STARTIMA");
|
||||
return TRUE;
|
||||
}
|
||||
96
F1:F103/deprecated/MLX90640/mlx90640.h
Normal file
96
F1:F103/deprecated/MLX90640/mlx90640.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2022 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef MLX90640__
|
||||
#define MLX90640__
|
||||
|
||||
#include <stm32f1.h>
|
||||
|
||||
// timeout for reading operations, ms
|
||||
#define MLX_TIMEOUT 1000
|
||||
// counter of errors, when > max -> M_ERROR
|
||||
#define MLX_MAXERR_COUNT 10
|
||||
// wait after power off, ms
|
||||
#define MLX_POWOFF_WAIT 500
|
||||
// wait after power on, ms
|
||||
#define MLX_POWON_WAIT 2000
|
||||
|
||||
// amount of pixels
|
||||
#define MLX_W (32)
|
||||
#define MLX_H (24)
|
||||
#define MLX_PIXNO (MLX_W*MLX_H)
|
||||
// pixels + service data
|
||||
#define MLX_PIXARRSZ (MLX_PIXNO + 64)
|
||||
|
||||
typedef struct{
|
||||
int16_t kVdd;
|
||||
int16_t vdd25;
|
||||
float KvPTAT;
|
||||
float KtPTAT;
|
||||
int16_t vPTAT25;
|
||||
float alphaPTAT;
|
||||
int16_t gainEE;
|
||||
float tgc;
|
||||
float cpKv; // K_V_CP
|
||||
float cpKta; // K_Ta_CP
|
||||
float KsTa;
|
||||
float CT[3]; // range borders (0, 160, 320 degrC?)
|
||||
float ksTo[4]; // K_S_To for each range * 273.15
|
||||
float alphacorr[4]; // Alpha_corr for each range
|
||||
float alpha[MLX_PIXNO]; // full - with alpha_scale
|
||||
float offset[MLX_PIXNO];
|
||||
float kta[MLX_PIXNO]; // full K_ta - with scale1&2
|
||||
float kv[4]; // full - with scale; 0 - odd row, odd col; 1 - odd row even col; 2 - even row, odd col; 3 - even row, even col
|
||||
float cpAlpha[2]; // alpha_CP_subpage 0 and 1
|
||||
int16_t cpOffset[2];
|
||||
} MLX90640_params;
|
||||
|
||||
extern MLX90640_params params;
|
||||
|
||||
typedef enum{
|
||||
M_ERROR, // error: need to reboot sensor
|
||||
M_RELAX, // base state
|
||||
M_FIRSTSTART, // first start after power on
|
||||
M_READCONF, // read configuration data
|
||||
M_STARTIMA, // start image aquiring
|
||||
M_PROCESS, // process subpage - wait for image ready
|
||||
M_READOUT, // wait while subpage data be read
|
||||
M_POWERON, // wait for 100ms after power is on before -> firststart
|
||||
M_POWEROFF1, // turn off power
|
||||
M_POWEROFF, // wait for 500ms without power
|
||||
//
|
||||
M_STATES_AMOUNT // amount of states
|
||||
} mlx90640_state;
|
||||
|
||||
extern mlx90640_state mlx_state;
|
||||
extern float mlx_image[MLX_PIXNO];
|
||||
|
||||
// default I2C address
|
||||
#define MLX_DEFAULT_ADDR (0x33)
|
||||
// max datalength by one read (in 16-bit values)
|
||||
#define MLX_DMA_MAXLEN (832)
|
||||
|
||||
int read_reg(uint16_t reg, uint16_t *val);
|
||||
int write_reg(uint16_t reg, uint16_t val);
|
||||
uint16_t *read_data(uint16_t reg, uint16_t *N);
|
||||
int read_data_dma(uint16_t reg, int N);
|
||||
void mlx90640_process();
|
||||
int mlx90640_take_image(uint8_t simple);
|
||||
void mlx90640_restart();
|
||||
|
||||
#endif // MLX90640__
|
||||
82
F1:F103/deprecated/MLX90640/mlx90640_regs.h
Normal file
82
F1:F103/deprecated/MLX90640/mlx90640_regs.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2022 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef MLX90640_REGS_H__
|
||||
#define MLX90640_REGS_H__
|
||||
|
||||
#define REG_STATUS 0x8000
|
||||
#define REG_STATUS_OVWEN (1<<4)
|
||||
#define REG_STATUS_NEWDATA (1<<3)
|
||||
#define REG_STATUS_SPNO (1<<0)
|
||||
#define REG_STATUS_SPMASK (3<<0)
|
||||
#define REG_CONTROL 0x800D
|
||||
#define REG_CONTROL_CHESS (1<<12)
|
||||
#define REG_CONTROL_RES18 (2<<10)
|
||||
#define REG_CONTROL_RESMASK (3<<10)
|
||||
#define REG_CONTROL_REFR_2HZ (2<<7)
|
||||
#define REG_CONTROL_SUBP1 (1<<4)
|
||||
#define REG_CONTROL_SUBPMASK (3<<4)
|
||||
#define REG_CONTROL_SUBPSEL (1<<3)
|
||||
#define REG_CONTROL_DATAHOLD (1<<2)
|
||||
#define REG_CONTROL_SUBPEN (1<<0)
|
||||
|
||||
// calibration data start & len
|
||||
#define REG_CALIDATA 0x2410
|
||||
#define REG_CALIDATA_LEN 816
|
||||
|
||||
#define REG_APTATOCCS 0x2410
|
||||
#define REG_OSAVG 0x2411
|
||||
#define REG_OCCROW14 0x2412
|
||||
#define REG_OCCCOL14 0x2418
|
||||
#define REG_SCALEACC 0x2420
|
||||
#define REG_SENSIVITY 0x2421
|
||||
#define REG_ACCROW14 0x2422
|
||||
#define REG_ACCCOL14 0x2428
|
||||
#define REG_GAIN 0x2430
|
||||
#define REG_PTAT 0x2431
|
||||
#define REG_KVTPTAT 0x2432
|
||||
#define REG_VDD 0x2433
|
||||
#define REG_KVAVG 0x2434
|
||||
#define REG_ILCHESS 0x2435
|
||||
#define REG_KTAAVGODDCOL 0x2436
|
||||
#define REG_KTAAVGEVENCOL 0x2437
|
||||
#define REG_KTAVSCALE 0x2438
|
||||
#define REG_ALPHA 0x2439
|
||||
#define REG_CPOFF 0x243A
|
||||
#define REG_KVTACP 0x243B
|
||||
#define REG_KSTATGC 0x243C
|
||||
#define REG_KSTO12 0x243D
|
||||
#define REG_KSTO34 0x243E
|
||||
#define REG_CT34 0x243F
|
||||
#define REG_OFFAK1 0x2440
|
||||
// index of register in array (from REG_CALIDATA)
|
||||
#define CREG_IDX(addr) ((addr)-REG_CALIDATA)
|
||||
|
||||
#define REG_IMAGEDATA 0x0400
|
||||
#define REG_ITAVBE 0x0700
|
||||
#define REG_ICPSP0 0x0708
|
||||
#define REG_IGAIN 0x070A
|
||||
#define REG_ITAPTAT 0x0720
|
||||
#define REG_ICPSP1 0x0728
|
||||
#define REG_IVDDPIX 0x072A
|
||||
// indeg of register in array (from REG_IMAGEDATA)
|
||||
#define IMD_IDX(addr) ((addr)-REG_IMAGEDATA)
|
||||
|
||||
|
||||
#endif // MLX90640_REGS_H__
|
||||
243
F1:F103/deprecated/MLX90640/proto.c
Normal file
243
F1:F103/deprecated/MLX90640/proto.c
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2022 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "i2c.h"
|
||||
#include "mlx90640.h"
|
||||
#include "proto.h"
|
||||
#include "strfunct.h"
|
||||
#include "usb.h"
|
||||
#include "version.inc"
|
||||
|
||||
extern uint32_t Tms;
|
||||
|
||||
static const char* _states[M_STATES_AMOUNT] = {
|
||||
[M_ERROR] = "error",
|
||||
[M_RELAX] = "do nothing",
|
||||
[M_FIRSTSTART] = "first start",
|
||||
[M_READCONF] = "read config",
|
||||
[M_STARTIMA] = "start image",
|
||||
[M_PROCESS] = "process subframe",
|
||||
[M_READOUT] = "read subpage data",
|
||||
[M_POWERON] = "wait after power on",
|
||||
[M_POWEROFF1] = "turn power off",
|
||||
[M_POWEROFF] = "wait without power",
|
||||
};
|
||||
|
||||
// dump floating point array 24x32
|
||||
static void dumpfarr(float *arr){
|
||||
for(int row = 0; row < 24; ++row){
|
||||
for(int col = 0; col < 32; ++col){
|
||||
float2str(*arr++, 2); bufputchar(' ');
|
||||
}
|
||||
newline();
|
||||
}
|
||||
}
|
||||
|
||||
static void dumpparams(){
|
||||
SEND("\nkVdd="); printi(params.kVdd);
|
||||
SEND("\nvdd25="); printi(params.vdd25);
|
||||
SEND("\nKvPTAT="); float2str(params.KvPTAT, 4);
|
||||
SEND("\nKtPTAT="); float2str(params.KtPTAT, 4);
|
||||
SEND("\nvPTAT25="); printi(params.vPTAT25);
|
||||
SEND("\nalphaPTAT="); float2str(params.alphaPTAT, 2);
|
||||
SEND("\ngainEE="); printi(params.gainEE);
|
||||
SEND("\nPixel offset parameters:\n");
|
||||
float *offset = params.offset;
|
||||
for(int row = 0; row < 24; ++row){
|
||||
for(int col = 0; col < 32; ++col){
|
||||
float2str(*offset++, 2); bufputchar(' ');
|
||||
}
|
||||
newline();
|
||||
}
|
||||
SEND("K_talpha:\n");
|
||||
dumpfarr(params.kta);
|
||||
SEND("Kv: ");
|
||||
for(int i = 0; i < 4; ++i){
|
||||
float2str(params.kv[i], 2); bufputchar(' ');
|
||||
}
|
||||
SEND("\ncpOffset=");
|
||||
printi(params.cpOffset[0]); SEND(", "); printi(params.cpOffset[1]);
|
||||
SEND("\ncpKta="); float2str(params.cpKta, 2);
|
||||
SEND("\ncpKv="); float2str(params.cpKv, 2);
|
||||
SEND("\ntgc="); float2str(params.tgc, 2);
|
||||
SEND("\ncpALpha="); float2str(params.cpAlpha[0], 2);
|
||||
SEND(", "); float2str(params.cpAlpha[1], 2);
|
||||
SEND("\nKsTa="); float2str(params.KsTa, 2);
|
||||
SEND("\nAlpha:\n");
|
||||
dumpfarr(params.alpha);
|
||||
SEND("\nCT3="); float2str(params.CT[1], 2);
|
||||
SEND("\nCT4="); float2str(params.CT[2], 2);
|
||||
for(int i = 0; i < 4; ++i){
|
||||
SEND("\nKsTo"); bufputchar('0'+i); bufputchar('=');
|
||||
float2str(params.ksTo[i], 2);
|
||||
SEND("\nalphacorr"); bufputchar('0'+i); bufputchar('=');
|
||||
float2str(params.alphacorr[i], 2);
|
||||
}
|
||||
NL();
|
||||
}
|
||||
|
||||
static void dumpimage(){
|
||||
float *idata = mlx_image;
|
||||
for(int row = 0; row < MLX_H; ++row){
|
||||
for(int col = 0; col < MLX_W; ++col, ++idata){
|
||||
float2str(*idata,1); bufputchar(' ');
|
||||
}
|
||||
newline();
|
||||
}
|
||||
NL();
|
||||
}
|
||||
|
||||
const char *parse_cmd(char *buf){
|
||||
int32_t Num = 0;
|
||||
uint16_t r, d;
|
||||
uint16_t *data;
|
||||
const float pi = 3.1415927f, e = 2.7182818f;
|
||||
char *ptr, cmd = *buf++;
|
||||
switch(cmd){
|
||||
case 'a':
|
||||
if(buf != getnum(buf, &Num)){
|
||||
if(Num & 0x80) return "Enter 7bit address";
|
||||
i2c_set_addr7(Num);
|
||||
return "Changed";
|
||||
}else return "Wrong address";
|
||||
break;
|
||||
case 'd':
|
||||
if(buf != (ptr = getnum(buf, &Num))){
|
||||
r = Num;
|
||||
if(ptr != getnum(ptr, &Num)){
|
||||
if(Num < 1 || Num > MLX_DMA_MAXLEN) return "0<N<=832";
|
||||
if(!read_data_dma(r, Num)) return("Can't read");
|
||||
else return "OK";
|
||||
}else return "Need amount";
|
||||
}else return "Need reg";
|
||||
break;
|
||||
case 'E':
|
||||
case 'e':
|
||||
if(!mlx90640_take_image(cmd == 'e')) return "FAILED";
|
||||
else return "OK";
|
||||
break;
|
||||
case 'f':
|
||||
SEND("Float test: ");
|
||||
float2str(0.f, 2); addtobuf(", ");
|
||||
float2str(pi, 1); addtobuf(", ");
|
||||
float2str(-e, 2); addtobuf(", ");
|
||||
float2str(-pi, 3); addtobuf(", ");
|
||||
float2str(e, 4); addtobuf(", ");
|
||||
uint32_t uu = INF | 0x80000000;
|
||||
float *f = (float*)&uu;
|
||||
float2str(*f, 4); addtobuf(", ");
|
||||
uu = NAN;
|
||||
f = (float*)&uu;
|
||||
float2str(*f, 4);
|
||||
NL();
|
||||
return NULL;
|
||||
break;
|
||||
case 'g':
|
||||
if(buf != (ptr = getnum(buf, &Num))){
|
||||
r = Num;
|
||||
if(ptr != getnum(ptr, &Num)){
|
||||
if(Num < 1 || Num > MLX_DMA_MAXLEN) return "N from 0 to 832";
|
||||
uint16_t od = d = Num;
|
||||
if(!(data = read_data(r, &d))){
|
||||
SEND("Can't read\n");
|
||||
return NULL;
|
||||
}
|
||||
if(d != od){
|
||||
addtobuf("Got only ");
|
||||
printu(d);
|
||||
addtobuf(" values\n");
|
||||
}
|
||||
for(uint16_t i = 0; i < d; ++i){
|
||||
printuhex(r + i);
|
||||
addtobuf(" ");
|
||||
printuhex(data[i]);
|
||||
newline();
|
||||
}
|
||||
sendbuf();
|
||||
return NULL;
|
||||
}else return "Need amount";
|
||||
}else return "Need reg";
|
||||
break;
|
||||
case 'I':
|
||||
i2c_setup(TRUE);
|
||||
return "I2C restarted";
|
||||
break;
|
||||
case 'M':
|
||||
SEND("MLX state: "); SEND(_states[mlx_state]);
|
||||
SEND("\npower="); printu(MLXPOW_VAL()); NL();
|
||||
return NULL;
|
||||
break;
|
||||
case 'O':
|
||||
mlx90640_restart();
|
||||
return "Power off/on";
|
||||
break;
|
||||
case 'P':
|
||||
dumpparams();
|
||||
return NULL;
|
||||
break;
|
||||
case 'r':
|
||||
if(buf != (ptr = getnum(buf, &Num))){
|
||||
if(read_reg(Num, &d)){
|
||||
printuhex(d); NL();
|
||||
return NULL;
|
||||
}else return "Can't read";
|
||||
}else return "Need register address";
|
||||
break;
|
||||
case 'R':
|
||||
USB_sendstr("Soft reset\n");
|
||||
NVIC_SystemReset();
|
||||
break;
|
||||
case 'S':
|
||||
dumpimage();
|
||||
return NULL;
|
||||
break;
|
||||
case 'T':
|
||||
SEND("Tms="); printu(Tms); NL();
|
||||
return NULL;
|
||||
break;
|
||||
case 'w':
|
||||
if(buf == (ptr = getnum(buf, &Num))) return "Need register";
|
||||
r = Num;
|
||||
if(ptr == getnum(ptr, &Num)) return "Need data";
|
||||
if(write_reg(r, Num)) return "OK";
|
||||
else return "Failed";
|
||||
break;
|
||||
default: // help
|
||||
addtobuf(
|
||||
"MLX90640 build #" BUILD_NUMBER " @" BUILD_DATE "\n\n"
|
||||
"'a addr' - change MLX I2C address to `addr`\n"
|
||||
"'d reg N' - read registers starting from `reg` using DMA\n"
|
||||
"'Ee' - expose image: E - full, e - simple\n"
|
||||
"'f' - test float printf (0.00, 3.1, -2.72, -3.142, 2.7183, -INF, NAN)\n"
|
||||
"'g reg N' - read N registers starting from `reg`\n"
|
||||
"'I' - restart I2C\n"
|
||||
"'M' - MLX state\n"
|
||||
"'O' - turn On or restart MLX sensor\n"
|
||||
"'P' - dump params\n"
|
||||
"'r reg' - read `reg`\n"
|
||||
"'R' - software reset\n"
|
||||
"'S' - show image\n"
|
||||
"'T' - get Tms\n"
|
||||
"'w reg dword' - write `dword` to `reg`\n"
|
||||
);
|
||||
NL();
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
24
F1:F103/deprecated/MLX90640/proto.h
Normal file
24
F1:F103/deprecated/MLX90640/proto.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2022 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef PROTO_H__
|
||||
#define PROTO_H__
|
||||
|
||||
const char *parse_cmd(char *buf);
|
||||
|
||||
#endif // PROTO_H__
|
||||
276
F1:F103/deprecated/MLX90640/strfunct.c
Normal file
276
F1:F103/deprecated/MLX90640/strfunct.c
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2022 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hardware.h"
|
||||
#include "strfunct.h"
|
||||
#include "usb.h"
|
||||
|
||||
#include <string.h> // strlen
|
||||
|
||||
// usb getline
|
||||
char *get_USB(){
|
||||
static char tmpbuf[IBUFSZ+1], *curptr = tmpbuf;
|
||||
static int rest = IBUFSZ;
|
||||
uint8_t x = USB_receive((uint8_t*)curptr);
|
||||
curptr[x] = 0;
|
||||
if(!x) return NULL;
|
||||
if(curptr[x-1] == '\n'){
|
||||
curptr[x] = 0;
|
||||
curptr = tmpbuf;
|
||||
rest = IBUFSZ;
|
||||
return tmpbuf;
|
||||
}
|
||||
curptr += x; rest -= x;
|
||||
if(rest <= 63){ // buffer overflow
|
||||
curptr = tmpbuf;
|
||||
rest = IBUFSZ;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char buff[OBUFSZ+1], *bptr = buff;
|
||||
static uint16_t blen = 0;
|
||||
|
||||
void sendbuf(){
|
||||
if(blen == 0) return;
|
||||
*bptr = 0;
|
||||
USB_sendstr(buff);
|
||||
bptr = buff;
|
||||
blen = 0;
|
||||
}
|
||||
|
||||
void bufputchar(char ch){
|
||||
if(blen > OBUFSZ-1){
|
||||
sendbuf();
|
||||
}
|
||||
*bptr++ = ch;
|
||||
++blen;
|
||||
}
|
||||
|
||||
void addtobuf(const char *txt){
|
||||
if(!txt) return;
|
||||
while(*txt) bufputchar(*txt++);
|
||||
}
|
||||
|
||||
// print 32bit unsigned int
|
||||
void printu(uint32_t val){
|
||||
char buf[11], *bufptr = &buf[10];
|
||||
*bufptr = 0;
|
||||
if(!val){
|
||||
*(--bufptr) = '0';
|
||||
}else{
|
||||
while(val){
|
||||
register uint32_t o = val;
|
||||
val /= 10;
|
||||
*(--bufptr) = (o - 10*val) + '0';
|
||||
}
|
||||
}
|
||||
addtobuf(bufptr);
|
||||
}
|
||||
void printi(int32_t val){
|
||||
if(val < 0){
|
||||
val = -val;
|
||||
bufputchar('-');
|
||||
}
|
||||
printu((uint32_t)val);
|
||||
}
|
||||
|
||||
// print 32bit unsigned int as hex
|
||||
void printuhex(uint32_t val){
|
||||
addtobuf("0x");
|
||||
uint8_t *ptr = (uint8_t*)&val + 3;
|
||||
int i, j, z = 1;
|
||||
for(i = 0; i < 4; ++i, --ptr){
|
||||
if(*ptr == 0){ // omit leading zeros
|
||||
if(i == 3) z = 0;
|
||||
if(z) continue;
|
||||
}
|
||||
else z = 0;
|
||||
for(j = 1; j > -1; --j){
|
||||
uint8_t half = (*ptr >> (4*j)) & 0x0f;
|
||||
if(half < 10) bufputchar(half + '0');
|
||||
else bufputchar(half - 10 + 'a');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *omit_spaces(char *buf){
|
||||
while(*buf){
|
||||
if(*buf != ' ' && *buf != '\t') break;
|
||||
++buf;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
// THERE'S NO OVERFLOW PROTECTION IN NUMBER READ PROCEDURES!
|
||||
// read decimal number
|
||||
static char *getdec(const char *buf, int32_t *N){
|
||||
int32_t num = 0;
|
||||
int positive = TRUE;
|
||||
if(*buf == '-'){
|
||||
positive = FALSE;
|
||||
++buf;
|
||||
}
|
||||
while(*buf){
|
||||
char c = *buf;
|
||||
if(c < '0' || c > '9'){
|
||||
break;
|
||||
}
|
||||
num *= 10;
|
||||
num += c - '0';
|
||||
++buf;
|
||||
}
|
||||
*N = (positive) ? num : -num;
|
||||
return (char *)buf;
|
||||
}
|
||||
// read hexadecimal number (without 0x prefix!)
|
||||
static char *gethex(const char *buf, int32_t *N){
|
||||
uint32_t num = 0;
|
||||
while(*buf){
|
||||
char c = *buf;
|
||||
uint8_t M = 0;
|
||||
if(c >= '0' && c <= '9'){
|
||||
M = '0';
|
||||
}else if(c >= 'A' && c <= 'F'){
|
||||
M = 'A' - 10;
|
||||
}else if(c >= 'a' && c <= 'f'){
|
||||
M = 'a' - 10;
|
||||
}
|
||||
if(M){
|
||||
num <<= 4;
|
||||
num += c - M;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
++buf;
|
||||
}
|
||||
*N = (int32_t)num;
|
||||
return (char *)buf;
|
||||
}
|
||||
// read binary number (without 0b prefix!)
|
||||
static char *getbin(const char *buf, int32_t *N){
|
||||
uint32_t num = 0;
|
||||
while(*buf){
|
||||
char c = *buf;
|
||||
if(c < '0' || c > '1'){
|
||||
break;
|
||||
}
|
||||
num <<= 1;
|
||||
if(c == '1') num |= 1;
|
||||
++buf;
|
||||
}
|
||||
*N = (int32_t)num;
|
||||
return (char *)buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief getnum - read uint32_t from string (dec, hex or bin: 127, 0x7f, 0b1111111)
|
||||
* @param buf - buffer with number and so on
|
||||
* @param N - the number read
|
||||
* @return pointer to first non-number symbol in buf (if it is == buf, there's no number)
|
||||
*/
|
||||
char *getnum(char *txt, int32_t *N){
|
||||
txt = omit_spaces(txt);
|
||||
if(*txt == '0'){
|
||||
if(txt[1] == 'x' || txt[1] == 'X') return gethex(txt+2, N);
|
||||
if(txt[1] == 'b' || txt[1] == 'B') return getbin(txt+2, N);
|
||||
}
|
||||
return getdec(txt, N);
|
||||
}
|
||||
|
||||
// be careful: if pow10 would be bigger you should change str[] size!
|
||||
static const float pwr10[] = {1., 10., 100., 1000., 10000.};
|
||||
static const float rounds[] = {0.5, 0.05, 0.005, 0.0005, 0.00005};
|
||||
#define P10L (sizeof(pwr10)/sizeof(uint32_t) - 1)
|
||||
void float2str(float x, uint8_t prec){
|
||||
if(prec > P10L) prec = P10L;
|
||||
static char str[16] = {0}; // -117.5494E-36\0 - 14 symbols max!
|
||||
uint32_t *u = (uint32_t*)&x;
|
||||
/* if(*u && (*u == (*u & DENORM))){
|
||||
SEND("DENORM"); return;
|
||||
}*/
|
||||
switch(*u){
|
||||
case INF:
|
||||
SEND("INF");
|
||||
return;
|
||||
break;
|
||||
case MINF:
|
||||
SEND("-INF");
|
||||
return;
|
||||
break;
|
||||
case NAN:
|
||||
SEND("NAN");
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
char *s = str + 14; // go to end of buffer
|
||||
uint8_t minus = 0;
|
||||
if(x < 0){
|
||||
x = -x;
|
||||
minus = 1;
|
||||
}
|
||||
int pow = 0; // xxxEpow
|
||||
// now convert float to 1.xxxE3y
|
||||
while(x > 1000.f){
|
||||
x /= 1000.f;
|
||||
pow += 3;
|
||||
}
|
||||
if(x > 0.) while(x < 1.){
|
||||
x *= 1000.f;
|
||||
pow -= 3;
|
||||
}
|
||||
// print Eyy
|
||||
if(pow){
|
||||
uint8_t m = 0;
|
||||
if(pow < 0){pow = -pow; m = 1;}
|
||||
while(pow){
|
||||
register int p10 = pow/10;
|
||||
*s-- = '0' + (pow - 10*p10);
|
||||
pow = p10;
|
||||
}
|
||||
if(m) *s-- = '-';
|
||||
*s-- = 'E';
|
||||
}
|
||||
// now our number is in [1, 1000]
|
||||
uint32_t units;
|
||||
if(prec){
|
||||
units = (uint32_t) x;
|
||||
uint32_t decimals = (uint32_t)((x-units+rounds[prec])*pwr10[prec]);
|
||||
// print decimals
|
||||
while(prec){
|
||||
register int d10 = decimals / 10;
|
||||
*s-- = '0' + (decimals - 10*d10);
|
||||
decimals = d10;
|
||||
--prec;
|
||||
}
|
||||
// decimal point
|
||||
*s-- = '.';
|
||||
}else{ // without decimal part
|
||||
units = (uint32_t) (x + 0.5f);
|
||||
}
|
||||
// print main units
|
||||
if(units == 0) *s-- = '0';
|
||||
else while(units){
|
||||
register uint32_t u10 = units / 10;
|
||||
*s-- = '0' + (units - 10*u10);
|
||||
units = u10;
|
||||
}
|
||||
if(minus) *s-- = '-';
|
||||
addtobuf(s+1);
|
||||
}
|
||||
67
F1:F103/deprecated/MLX90640/strfunct.h
Normal file
67
F1:F103/deprecated/MLX90640/strfunct.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2022 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef STRFUNCT_H__
|
||||
#define STRFUNCT_H__
|
||||
|
||||
#include "stm32f1.h"
|
||||
|
||||
#ifndef DENORM
|
||||
#define DENORM (0x007FFFFF)
|
||||
#endif
|
||||
#ifndef NAN
|
||||
#define NAN (0x7FC00000)
|
||||
#endif
|
||||
#ifndef INF
|
||||
#define INF (0x7F800000)
|
||||
#endif
|
||||
#ifndef MINF
|
||||
#define MINF (0xFF800000)
|
||||
#endif
|
||||
|
||||
#define OBUFSZ (64)
|
||||
#define IBUFSZ (256)
|
||||
|
||||
// macro for static strings
|
||||
#define SEND(str) do{addtobuf(str);}while(0)
|
||||
|
||||
#ifdef EBUG
|
||||
#define x__(a) #a
|
||||
#define STR(a) x__(a)
|
||||
#define DBG(str) do{addtobuf(__FILE__ " (L" STR(__LINE__) "): " str); NL();}while(0)
|
||||
#else
|
||||
#define DBG(str)
|
||||
#endif
|
||||
|
||||
#define newline() do{bufputchar('\n');}while(0)
|
||||
// newline & send buffer
|
||||
#define NL() do{bufputchar('\n'); sendbuf();}while(0)
|
||||
|
||||
char *get_USB();
|
||||
void addtobuf(const char *txt);
|
||||
void bufputchar(char ch);
|
||||
void printu(uint32_t val);
|
||||
void printi(int32_t val);
|
||||
void printuhex(uint32_t val);
|
||||
void sendbuf();
|
||||
char *omit_spaces(char *buf);
|
||||
char *getnum(char *buf, int32_t *N);
|
||||
void float2str(float x, uint8_t prec);
|
||||
|
||||
#endif // STRFUNCT_H__
|
||||
168
F1:F103/deprecated/MLX90640/usb.c
Normal file
168
F1:F103/deprecated/MLX90640/usb.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2020 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "usb.h"
|
||||
#include "usb_lib.h"
|
||||
|
||||
static volatile uint8_t tx_succesfull = 1;
|
||||
static volatile uint8_t rxNE = 0;
|
||||
|
||||
// interrupt IN handler (never used?)
|
||||
static void EP1_Handler(){
|
||||
uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]);
|
||||
if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX
|
||||
else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX);
|
||||
// clear CTR
|
||||
epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX));
|
||||
USB->EPnR[1] = epstatus;
|
||||
}
|
||||
|
||||
// data IN/OUT handlers
|
||||
static void transmit_Handler(){ // EP3IN
|
||||
tx_succesfull = 1;
|
||||
uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[3]);
|
||||
// clear CTR keep DTOGs & STATs
|
||||
USB->EPnR[3] = (epstatus & ~(USB_EPnR_CTR_TX)); // clear TX ctr
|
||||
}
|
||||
|
||||
static void receive_Handler(){ // EP2OUT
|
||||
rxNE = 1;
|
||||
uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[2]);
|
||||
USB->EPnR[2] = (epstatus & ~(USB_EPnR_CTR_RX)); // clear RX ctr
|
||||
}
|
||||
|
||||
void USB_setup(){
|
||||
NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||
NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||
USB->CNTR = USB_CNTR_FRES; // Force USB Reset
|
||||
for(uint32_t ctr = 0; ctr < 72000; ++ctr) nop(); // wait >1ms
|
||||
//uint32_t ctr = 0;
|
||||
USB->CNTR = 0;
|
||||
USB->BTABLE = 0;
|
||||
USB->DADDR = 0;
|
||||
USB->ISTR = 0;
|
||||
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_WKUPM; // allow only wakeup & reset interrupts
|
||||
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||
}
|
||||
|
||||
static int usbwr(const uint8_t *buf, uint16_t l){
|
||||
uint32_t ctra = 1000000;
|
||||
while(--ctra && tx_succesfull == 0){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
}
|
||||
if(tx_succesfull == 0) return 1;
|
||||
tx_succesfull = 0;
|
||||
EP_Write(3, buf, l);
|
||||
/* ctra = 1000000;
|
||||
while(--ctra && tx_succesfull == 0){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
}
|
||||
if(tx_succesfull == 0){usbON = 0; return 1;} // usb is OFF?
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t usbbuff[USB_TXBUFSZ-1]; // temporary buffer (63 - to prevent need of ZLP)
|
||||
static uint8_t buflen = 0; // amount of symbols in usbbuff
|
||||
|
||||
// send next up to 63 bytes of data in usbbuff
|
||||
static void send_next(){
|
||||
if(!buflen || !tx_succesfull) return;
|
||||
tx_succesfull = 0;
|
||||
EP_Write(3, usbbuff, buflen);
|
||||
buflen = 0;
|
||||
}
|
||||
|
||||
// unblocking sending - just fill a buffer
|
||||
void USB_send(const uint8_t *buf, uint16_t len){
|
||||
if(!usbON || !len) return;
|
||||
if(len > USB_TXBUFSZ-1 - buflen){
|
||||
usbwr(usbbuff, buflen);
|
||||
buflen = 0;
|
||||
}
|
||||
if(len > USB_TXBUFSZ-1){
|
||||
USB_send_blk(buf, len);
|
||||
return;
|
||||
}
|
||||
while(len--) usbbuff[buflen++] = *buf++;
|
||||
}
|
||||
// send zero-terminated string
|
||||
void USB_sendstr(const char *str){
|
||||
uint16_t l = 0;
|
||||
const char *ptr = str;
|
||||
while(*ptr++) ++l;
|
||||
USB_send((uint8_t*)str, l);
|
||||
}
|
||||
|
||||
// blocking sending
|
||||
void USB_send_blk(const uint8_t *buf, uint16_t len){
|
||||
if(!usbON || !len) return; // USB disconnected
|
||||
if(buflen){
|
||||
usbwr(usbbuff, buflen);
|
||||
buflen = 0;
|
||||
}
|
||||
int needzlp = 0;
|
||||
while(len){
|
||||
if(len == USB_TXBUFSZ) needzlp = 1;
|
||||
uint16_t s = (len > USB_TXBUFSZ) ? USB_TXBUFSZ : len;
|
||||
if(usbwr(buf, s)) return;
|
||||
len -= s;
|
||||
buf += s;
|
||||
}
|
||||
if(needzlp){
|
||||
usbwr(NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_proc(){
|
||||
switch(USB_Dev.USB_Status){
|
||||
case USB_STATE_CONFIGURED:
|
||||
// make new BULK endpoint
|
||||
// Buffer have 1024 bytes, but last 256 we use for CAN bus (30.2 of RM: USB main features)
|
||||
EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit
|
||||
EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data
|
||||
EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data
|
||||
USB_Dev.USB_Status = USB_STATE_CONNECTED;
|
||||
break;
|
||||
case USB_STATE_DEFAULT:
|
||||
case USB_STATE_ADDRESSED:
|
||||
if(usbON){
|
||||
usbON = 0;
|
||||
}
|
||||
break;
|
||||
default: // USB_STATE_CONNECTED - send next data portion
|
||||
if(!usbON) return;
|
||||
send_next();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB_receive
|
||||
* @param buf (i) - buffer[64] for received data
|
||||
* @return amount of received bytes
|
||||
*/
|
||||
uint8_t USB_receive(uint8_t *buf){
|
||||
if(!usbON || !rxNE) return 0;
|
||||
uint8_t sz = EP_Read(2, (uint16_t*)buf);
|
||||
uint16_t epstatus = KEEP_DTOG(USB->EPnR[2]);
|
||||
// keep stat_tx & set ACK rx
|
||||
USB->EPnR[2] = (epstatus & ~(USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX;
|
||||
rxNE = 0;
|
||||
return sz;
|
||||
}
|
||||
34
F1:F103/deprecated/MLX90640/usb.h
Normal file
34
F1:F103/deprecated/MLX90640/usb.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2020 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef __USB_H__
|
||||
#define __USB_H__
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
#define BUFFSIZE (64)
|
||||
|
||||
void USB_setup();
|
||||
void usb_proc();
|
||||
void USB_send(const uint8_t *buf, uint16_t len);
|
||||
void USB_sendstr(const char *str);
|
||||
void USB_send_blk(const uint8_t *buf, uint16_t len);
|
||||
uint8_t USB_receive(uint8_t *buf);
|
||||
|
||||
#endif // __USB_H__
|
||||
102
F1:F103/deprecated/MLX90640/usb_defs.h
Normal file
102
F1:F103/deprecated/MLX90640/usb_defs.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2020 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef __USB_DEFS_H__
|
||||
#define __USB_DEFS_H__
|
||||
|
||||
#include <stm32f1.h>
|
||||
|
||||
// max endpoints number
|
||||
#define STM32ENDPOINTS 8
|
||||
/**
|
||||
* Buffers size definition
|
||||
**/
|
||||
#define USB_BTABLE_SIZE 512
|
||||
// first 64 bytes of USB_BTABLE are registers!
|
||||
//#define USB_EP0_BASEADDR 64
|
||||
// for USB FS EP0 buffers are from 8 to 64 bytes long (64 for PL2303)
|
||||
#define USB_EP0_BUFSZ 64
|
||||
// USB transmit buffer size (64 for PL2303)
|
||||
#define USB_TXBUFSZ 64
|
||||
// USB receive buffer size (64 for PL2303)
|
||||
#define USB_RXBUFSZ 64
|
||||
// EP1 - interrupt - buffer size
|
||||
#define USB_EP1BUFSZ 8
|
||||
|
||||
#define USB_BTABLE_BASE 0x40006000
|
||||
#define USB_BASE ((uint32_t)0x40005C00)
|
||||
#define USB ((USB_TypeDef *) USB_BASE)
|
||||
|
||||
#ifdef USB_BTABLE
|
||||
#undef USB_BTABLE
|
||||
#endif
|
||||
#define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE))
|
||||
#define USB_ISTR_EPID 0x0000000F
|
||||
#define USB_FNR_LSOF_0 0x00000800
|
||||
#define USB_FNR_lSOF_1 0x00001000
|
||||
#define USB_LPMCSR_BESL_0 0x00000010
|
||||
#define USB_LPMCSR_BESL_1 0x00000020
|
||||
#define USB_LPMCSR_BESL_2 0x00000040
|
||||
#define USB_LPMCSR_BESL_3 0x00000080
|
||||
#define USB_EPnR_CTR_RX 0x00008000
|
||||
#define USB_EPnR_DTOG_RX 0x00004000
|
||||
#define USB_EPnR_STAT_RX 0x00003000
|
||||
#define USB_EPnR_STAT_RX_0 0x00001000
|
||||
#define USB_EPnR_STAT_RX_1 0x00002000
|
||||
#define USB_EPnR_SETUP 0x00000800
|
||||
#define USB_EPnR_EP_TYPE 0x00000600
|
||||
#define USB_EPnR_EP_TYPE_0 0x00000200
|
||||
#define USB_EPnR_EP_TYPE_1 0x00000400
|
||||
#define USB_EPnR_EP_KIND 0x00000100
|
||||
#define USB_EPnR_CTR_TX 0x00000080
|
||||
#define USB_EPnR_DTOG_TX 0x00000040
|
||||
#define USB_EPnR_STAT_TX 0x00000030
|
||||
#define USB_EPnR_STAT_TX_0 0x00000010
|
||||
#define USB_EPnR_STAT_TX_1 0x00000020
|
||||
#define USB_EPnR_EA 0x0000000F
|
||||
#define USB_COUNTn_RX_BLSIZE 0x00008000
|
||||
#define USB_COUNTn_NUM_BLOCK 0x00007C00
|
||||
#define USB_COUNTn_RX 0x0000003F
|
||||
|
||||
#ifdef USB_TypeDef
|
||||
#define USB_TypeDef USB_TypeDef_custom
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
__IO uint32_t EPnR[STM32ENDPOINTS];
|
||||
__IO uint32_t RESERVED[STM32ENDPOINTS];
|
||||
__IO uint32_t CNTR;
|
||||
__IO uint32_t ISTR;
|
||||
__IO uint32_t FNR;
|
||||
__IO uint32_t DADDR;
|
||||
__IO uint32_t BTABLE;
|
||||
} USB_TypeDef;
|
||||
|
||||
typedef struct{
|
||||
__IO uint32_t USB_ADDR_TX;
|
||||
__IO uint32_t USB_COUNT_TX;
|
||||
__IO uint32_t USB_ADDR_RX;
|
||||
__IO uint32_t USB_COUNT_RX;
|
||||
} USB_EPDATA_TypeDef;
|
||||
|
||||
typedef struct{
|
||||
__IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS];
|
||||
} USB_BtableDef;
|
||||
|
||||
#endif // __USB_DEFS_H__
|
||||
476
F1:F103/deprecated/MLX90640/usb_lib.c
Normal file
476
F1:F103/deprecated/MLX90640/usb_lib.c
Normal file
@@ -0,0 +1,476 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2020 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "usb_lib.h"
|
||||
|
||||
ep_t endpoints[STM32ENDPOINTS];
|
||||
|
||||
usb_dev_t USB_Dev;
|
||||
static usb_LineCoding lineCoding = {115200, 0, 0, 8};
|
||||
static config_pack_t setup_packet;
|
||||
static uint8_t ep0databuf[EP0DATABUF_SIZE];
|
||||
static uint8_t ep0dbuflen = 0;
|
||||
|
||||
usb_LineCoding getLineCoding(){return lineCoding;}
|
||||
|
||||
uint8_t usbON = 0; // device disconnected from terminal
|
||||
|
||||
// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor
|
||||
#define bcdUSB_L 0x10
|
||||
#define bcdUSB_H 0x01
|
||||
#define bDeviceClass 0
|
||||
#define bDeviceSubClass 0
|
||||
#define bDeviceProtocol 0
|
||||
#define bNumConfigurations 1
|
||||
|
||||
static const uint8_t USB_DeviceDescriptor[] = {
|
||||
18, // bLength
|
||||
0x01, // bDescriptorType - Device descriptor
|
||||
bcdUSB_L, // bcdUSB_L - 1.10
|
||||
bcdUSB_H, // bcdUSB_H
|
||||
bDeviceClass, // bDeviceClass - USB_COMM
|
||||
bDeviceSubClass, // bDeviceSubClass
|
||||
bDeviceProtocol, // bDeviceProtocol
|
||||
USB_EP0_BUFSZ, // bMaxPacketSize
|
||||
0x7b, // idVendor_L PL2303: VID=0x067b, PID=0x2303
|
||||
0x06, // idVendor_H
|
||||
0x03, // idProduct_L
|
||||
0x23, // idProduct_H
|
||||
0x00, // bcdDevice_Ver_L
|
||||
0x03, // bcdDevice_Ver_H
|
||||
0x01, // iManufacturer
|
||||
0x02, // iProduct
|
||||
0x00, // iSerialNumber
|
||||
bNumConfigurations // bNumConfigurations
|
||||
};
|
||||
|
||||
static const uint8_t USB_DeviceQualifierDescriptor[] = {
|
||||
10, //bLength
|
||||
0x06, // bDescriptorType - Device qualifier
|
||||
bcdUSB_L, // bcdUSB_L
|
||||
bcdUSB_H, // bcdUSB_H
|
||||
bDeviceClass, // bDeviceClass
|
||||
bDeviceSubClass, // bDeviceSubClass
|
||||
bDeviceProtocol, // bDeviceProtocol
|
||||
USB_EP0_BUFSZ, // bMaxPacketSize0
|
||||
bNumConfigurations, // bNumConfigurations
|
||||
0x00 // Reserved
|
||||
};
|
||||
|
||||
static const uint8_t USB_ConfigDescriptor[] = {
|
||||
/*Configuration Descriptor*/
|
||||
0x09, /* bLength: Configuration Descriptor size */
|
||||
0x02, /* bDescriptorType: Configuration */
|
||||
39, /* wTotalLength:no of returned bytes */
|
||||
0x00,
|
||||
0x01, /* bNumInterfaces: 1 interface */
|
||||
0x01, /* bConfigurationValue: Configuration value */
|
||||
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
|
||||
0xa0, /* bmAttributes - Bus powered, Remote wakeup */
|
||||
0x32, /* MaxPower 100 mA */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*Interface Descriptor */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
0x04, /* bDescriptorType: Interface */
|
||||
0x00, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x03, /* bNumEndpoints: 3 endpoints used */
|
||||
0xff, /* bInterfaceClass */
|
||||
0x00, /* bInterfaceSubClass */
|
||||
0x00, /* bInterfaceProtocol */
|
||||
0x00, /* iInterface: */
|
||||
///////////////////////////////////////////////////
|
||||
/*Endpoint 1 Descriptor*/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
0x05, /* bDescriptorType: Endpoint */
|
||||
0x81, /* bEndpointAddress IN1 */
|
||||
0x03, /* bmAttributes: Interrupt */
|
||||
0x0a, /* wMaxPacketSize LO: */
|
||||
0x00, /* wMaxPacketSize HI: */
|
||||
0x01, /* bInterval: */
|
||||
|
||||
/*Endpoint OUT2 Descriptor*/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
0x05, /* bDescriptorType: Endpoint */
|
||||
0x02, /* bEndpointAddress: OUT2 */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
(USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
|
||||
(USB_RXBUFSZ >> 8),
|
||||
0x00, /* bInterval: ignore for Bulk transfer */
|
||||
|
||||
/*Endpoint IN3 Descriptor*/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
0x05, /* bDescriptorType: Endpoint */
|
||||
0x83, /* bEndpointAddress IN3 */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
(USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
|
||||
(USB_TXBUFSZ >> 8),
|
||||
0x00, /* bInterval: ignore for Bulk transfer */
|
||||
};
|
||||
|
||||
_USB_LANG_ID_(USB_StringLangDescriptor, LANG_US);
|
||||
// these descriptors are not used in PL2303 emulator!
|
||||
_USB_STRING_(USB_StringSerialDescriptor, u"0");
|
||||
_USB_STRING_(USB_StringManufacturingDescriptor, u"Prolific Technology Inc.");
|
||||
_USB_STRING_(USB_StringProdDescriptor, u"USB-Serial Controller");
|
||||
|
||||
/*
|
||||
* default handlers
|
||||
*/
|
||||
// SET_LINE_CODING
|
||||
void WEAK linecoding_handler(usb_LineCoding __attribute__((unused)) *lc){
|
||||
}
|
||||
|
||||
// SET_CONTROL_LINE_STATE
|
||||
void WEAK clstate_handler(uint16_t __attribute__((unused)) val){
|
||||
}
|
||||
|
||||
// SEND_BREAK
|
||||
void WEAK break_handler(){
|
||||
}
|
||||
|
||||
// handler of vendor requests
|
||||
void WEAK vendor_handler(config_pack_t *packet){
|
||||
if(packet->bmRequestType & 0x80){ // read
|
||||
uint8_t c;
|
||||
switch(packet->wValue){
|
||||
case 0x8484:
|
||||
c = 2;
|
||||
break;
|
||||
case 0x0080:
|
||||
c = 1;
|
||||
break;
|
||||
case 0x8686:
|
||||
c = 0xaa;
|
||||
break;
|
||||
default:
|
||||
c = 0;
|
||||
}
|
||||
EP_WriteIRQ(0, &c, 1);
|
||||
}else{ // write ZLP
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void wr0(const uint8_t *buf, uint16_t size){
|
||||
if(setup_packet.wLength < size) size = setup_packet.wLength; // shortened request
|
||||
if(size < endpoints[0].txbufsz){
|
||||
EP_WriteIRQ(0, buf, size);
|
||||
return;
|
||||
}
|
||||
while(size){
|
||||
uint16_t l = size;
|
||||
if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz;
|
||||
EP_WriteIRQ(0, buf, l);
|
||||
buf += l;
|
||||
size -= l;
|
||||
uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0;
|
||||
if(size || needzlp){ // send last data buffer
|
||||
uint16_t status = KEEP_DTOG(USB->EPnR[0]);
|
||||
// keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx
|
||||
USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX))
|
||||
^ USB_EPnR_STAT_TX;
|
||||
uint32_t ctr = 1000000;
|
||||
while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;};
|
||||
if((USB->ISTR & USB_ISTR_CTR) == 0){
|
||||
return;
|
||||
}
|
||||
if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void get_descriptor(){
|
||||
switch(setup_packet.wValue){
|
||||
case DEVICE_DESCRIPTOR:
|
||||
wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor));
|
||||
break;
|
||||
case CONFIGURATION_DESCRIPTOR:
|
||||
wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor));
|
||||
break;
|
||||
case STRING_LANG_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringLangDescriptor, STRING_LANG_DESCRIPTOR_SIZE_BYTE);
|
||||
break;
|
||||
case STRING_MAN_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringManufacturingDescriptor, USB_StringManufacturingDescriptor.bLength);
|
||||
break;
|
||||
case STRING_PROD_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringProdDescriptor, USB_StringProdDescriptor.bLength);
|
||||
break;
|
||||
case STRING_SN_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringSerialDescriptor, USB_StringSerialDescriptor.bLength);
|
||||
break;
|
||||
case DEVICE_QUALIFIER_DESCRIPTOR:
|
||||
wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured)
|
||||
static inline void std_d2h_req(){
|
||||
uint16_t status = 0; // bus powered
|
||||
switch(setup_packet.bRequest){
|
||||
case GET_DESCRIPTOR:
|
||||
get_descriptor();
|
||||
break;
|
||||
case GET_STATUS:
|
||||
EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered
|
||||
break;
|
||||
case GET_CONFIGURATION:
|
||||
EP_WriteIRQ(0, &configuration, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void std_h2d_req(){
|
||||
switch(setup_packet.bRequest){
|
||||
case SET_ADDRESS:
|
||||
// new address will be assigned later - after acknowlegement or request to host
|
||||
USB_Dev.USB_Addr = setup_packet.wValue;
|
||||
break;
|
||||
case SET_CONFIGURATION:
|
||||
// Now device configured
|
||||
USB_Dev.USB_Status = USB_STATE_CONFIGURED;
|
||||
configuration = setup_packet.wValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bmRequestType: 76543210
|
||||
7 direction: 0 - host->device, 1 - device->host
|
||||
65 type: 0 - standard, 1 - class, 2 - vendor
|
||||
4..0 getter: 0 - device, 1 - interface, 2 - endpoint, 3 - other
|
||||
*/
|
||||
/**
|
||||
* Endpoint0 (control) handler
|
||||
*/
|
||||
static void EP0_Handler(){
|
||||
uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications
|
||||
uint8_t reqtype = setup_packet.bmRequestType & 0x7f;
|
||||
uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0;
|
||||
int rxflag = RX_FLAG(epstatus);
|
||||
if(rxflag && SETUP_FLAG(epstatus)){
|
||||
switch(reqtype){
|
||||
case STANDARD_DEVICE_REQUEST_TYPE: // standard device request
|
||||
if(dev2host){
|
||||
std_d2h_req();
|
||||
}else{
|
||||
std_h2d_req();
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}
|
||||
break;
|
||||
case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request
|
||||
if(setup_packet.bRequest == CLEAR_FEATURE){
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}
|
||||
break;
|
||||
case VENDOR_REQUEST_TYPE:
|
||||
vendor_handler(&setup_packet);
|
||||
break;
|
||||
case CONTROL_REQUEST_TYPE:
|
||||
switch(setup_packet.bRequest){
|
||||
case GET_LINE_CODING:
|
||||
EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding));
|
||||
break;
|
||||
case SET_LINE_CODING: // omit this for next stage, when data will come
|
||||
break;
|
||||
case SET_CONTROL_LINE_STATE:
|
||||
usbON = 1;
|
||||
clstate_handler(setup_packet.wValue);
|
||||
break;
|
||||
case SEND_BREAK:
|
||||
usbON = 0;
|
||||
break_handler();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(setup_packet.bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement
|
||||
break;
|
||||
default:
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}
|
||||
}else if(rxflag){ // got data over EP0 or host acknowlegement
|
||||
if(endpoints[0].rx_cnt){
|
||||
if(setup_packet.bRequest == SET_LINE_CODING){
|
||||
linecoding_handler((usb_LineCoding*)ep0databuf);
|
||||
}
|
||||
}
|
||||
} else if(TX_FLAG(epstatus)){ // package transmitted
|
||||
// now we can change address after enumeration
|
||||
if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){
|
||||
USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr;
|
||||
// change state to ADRESSED
|
||||
USB_Dev.USB_Status = USB_STATE_ADDRESSED;
|
||||
}
|
||||
}
|
||||
epstatus = KEEP_DTOG(USB->EPnR[0]);
|
||||
if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP/data transmission
|
||||
else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged
|
||||
// keep DTOGs, clear CTR_RX,TX, set RX VALID
|
||||
USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX;
|
||||
}
|
||||
|
||||
static uint16_t lastaddr = LASTADDR_DEFAULT;
|
||||
/**
|
||||
* Endpoint initialisation
|
||||
* @param number - EP num (0...7)
|
||||
* @param type - EP type (EP_TYPE_BULK, EP_TYPE_CONTROL, EP_TYPE_ISO, EP_TYPE_INTERRUPT)
|
||||
* @param txsz - transmission buffer size @ USB/CAN buffer
|
||||
* @param rxsz - reception buffer size @ USB/CAN buffer
|
||||
* @param uint16_t (*func)(ep_t *ep) - EP handler function
|
||||
* @return 0 if all OK
|
||||
*/
|
||||
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)(ep_t ep)){
|
||||
if(number >= STM32ENDPOINTS) return 4; // out of configured amount
|
||||
if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large
|
||||
if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE) return 2; // out of btable
|
||||
USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA);
|
||||
USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1;
|
||||
if(rxsz & 1 || rxsz > 512) return 3; // wrong rx buffer size
|
||||
uint16_t countrx = 0;
|
||||
if(rxsz < 64) countrx = rxsz / 2;
|
||||
else{
|
||||
if(rxsz & 0x1f) return 3; // should be multiple of 32
|
||||
countrx = 31 + rxsz / 32;
|
||||
}
|
||||
USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr;
|
||||
endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr*2);
|
||||
endpoints[number].txbufsz = txsz;
|
||||
lastaddr += txsz;
|
||||
USB_BTABLE->EP[number].USB_COUNT_TX = 0;
|
||||
USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr;
|
||||
endpoints[number].rx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr*2);
|
||||
lastaddr += rxsz;
|
||||
USB_BTABLE->EP[number].USB_COUNT_RX = countrx << 10;
|
||||
endpoints[number].func = func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// standard IRQ handler
|
||||
void usb_lp_can_rx0_isr(){
|
||||
if(USB->ISTR & USB_ISTR_RESET){
|
||||
usbON = 0;
|
||||
// Reinit registers
|
||||
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
|
||||
USB->ISTR = 0;
|
||||
// Endpoint 0 - CONTROL
|
||||
// ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes!
|
||||
lastaddr = LASTADDR_DEFAULT;
|
||||
// clear address, leave only enable bit
|
||||
USB->DADDR = USB_DADDR_EF;
|
||||
USB_Dev.USB_Status = USB_STATE_DEFAULT;
|
||||
USB->ISTR = ~USB_ISTR_RESET;
|
||||
if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(USB->ISTR & USB_ISTR_CTR){
|
||||
// EP number
|
||||
uint8_t n = USB->ISTR & USB_ISTR_EPID;
|
||||
// copy status register
|
||||
uint16_t epstatus = USB->EPnR[n];
|
||||
// copy received bytes amount
|
||||
endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter
|
||||
// check direction
|
||||
if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit)
|
||||
if(n == 0){ // control endpoint
|
||||
if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack
|
||||
EP_Read(0, (uint16_t*)&setup_packet);
|
||||
ep0dbuflen = 0;
|
||||
// interrupt handler will be called later
|
||||
}else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf
|
||||
ep0dbuflen = endpoints[0].rx_cnt;
|
||||
EP_Read(0, (uint16_t*)&ep0databuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
// call EP handler
|
||||
if(endpoints[n].func) endpoints[n].func(endpoints[n]);
|
||||
}
|
||||
if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep
|
||||
usbON = 0;
|
||||
USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LP_MODE;
|
||||
USB->ISTR = ~USB_ISTR_SUSP;
|
||||
}
|
||||
if(USB->ISTR & USB_ISTR_WKUP){ // wakeup
|
||||
USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LP_MODE); // clear suspend flags
|
||||
USB->ISTR = ~USB_ISTR_WKUP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to EP buffer (called from IRQ handler)
|
||||
* @param number - EP number
|
||||
* @param *buf - array with data
|
||||
* @param size - its size
|
||||
*/
|
||||
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
|
||||
uint8_t i;
|
||||
if(size > endpoints[number].txbufsz) size = endpoints[number].txbufsz;
|
||||
uint16_t N2 = (size + 1) >> 1;
|
||||
// the buffer is 16-bit, so we should copy data as it would be uint16_t
|
||||
uint16_t *buf16 = (uint16_t *)buf;
|
||||
uint32_t *out = (uint32_t *)endpoints[number].tx_buf;
|
||||
for(i = 0; i < N2; ++i, ++out){
|
||||
*out = buf16[i];
|
||||
}
|
||||
USB_BTABLE->EP[number].USB_COUNT_TX = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to EP buffer (called outside IRQ handler)
|
||||
* @param number - EP number
|
||||
* @param *buf - array with data
|
||||
* @param size - its size
|
||||
*/
|
||||
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){
|
||||
EP_WriteIRQ(number, buf, size);
|
||||
uint16_t status = KEEP_DTOG(USB->EPnR[number]);
|
||||
// keep DTOGs, clear CTR_TX & set TX VALID to start transmission
|
||||
USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy data from EP buffer into user buffer area
|
||||
* @param *buf - user array for data
|
||||
* @return amount of data read
|
||||
*/
|
||||
int EP_Read(uint8_t number, uint16_t *buf){
|
||||
int sz = endpoints[number].rx_cnt;
|
||||
if(!sz) return 0;
|
||||
endpoints[number].rx_cnt = 0;
|
||||
int n = (sz + 1) >> 1;
|
||||
uint32_t *in = (uint32_t *)endpoints[number].rx_buf;
|
||||
if(n){
|
||||
for(int i = 0; i < n; ++i, ++in)
|
||||
buf[i] = *(uint16_t*)in;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
184
F1:F103/deprecated/MLX90640/usb_lib.h
Normal file
184
F1:F103/deprecated/MLX90640/usb_lib.h
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* This file is part of the MLX90640 project.
|
||||
* Copyright 2020 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef __USB_LIB_H__
|
||||
#define __USB_LIB_H__
|
||||
|
||||
#include <wchar.h>
|
||||
#include "usb_defs.h"
|
||||
|
||||
#define EP0DATABUF_SIZE (64)
|
||||
#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8)
|
||||
|
||||
// bmRequestType & 0x7f
|
||||
#define STANDARD_DEVICE_REQUEST_TYPE 0
|
||||
#define STANDARD_ENDPOINT_REQUEST_TYPE 2
|
||||
#define VENDOR_REQUEST_TYPE 0x40
|
||||
#define CONTROL_REQUEST_TYPE 0x21
|
||||
// bRequest, standard; for bmRequestType == 0x80
|
||||
#define GET_STATUS 0x00
|
||||
#define GET_DESCRIPTOR 0x06
|
||||
#define GET_CONFIGURATION 0x08
|
||||
// for bmRequestType == 0
|
||||
#define CLEAR_FEATURE 0x01
|
||||
#define SET_FEATURE 0x03 // unused
|
||||
#define SET_ADDRESS 0x05
|
||||
#define SET_DESCRIPTOR 0x07 // unused
|
||||
#define SET_CONFIGURATION 0x09
|
||||
// for bmRequestType == 0x81, 1 or 0xB2
|
||||
#define GET_INTERFACE 0x0A // unused
|
||||
#define SET_INTERFACE 0x0B // unused
|
||||
#define SYNC_FRAME 0x0C // unused
|
||||
#define VENDOR_REQUEST 0x01 // unused
|
||||
|
||||
// Class-Specific Control Requests
|
||||
#define SEND_ENCAPSULATED_COMMAND 0x00 // unused
|
||||
#define GET_ENCAPSULATED_RESPONSE 0x01 // unused
|
||||
#define SET_COMM_FEATURE 0x02 // unused
|
||||
#define GET_COMM_FEATURE 0x03 // unused
|
||||
#define CLEAR_COMM_FEATURE 0x04 // unused
|
||||
#define SET_LINE_CODING 0x20
|
||||
#define GET_LINE_CODING 0x21
|
||||
#define SET_CONTROL_LINE_STATE 0x22
|
||||
#define SEND_BREAK 0x23
|
||||
|
||||
// control line states
|
||||
#define CONTROL_DTR 0x01
|
||||
#define CONTROL_RTS 0x02
|
||||
|
||||
// wValue
|
||||
#define DEVICE_DESCRIPTOR 0x100
|
||||
#define CONFIGURATION_DESCRIPTOR 0x200
|
||||
#define STRING_LANG_DESCRIPTOR 0x300
|
||||
#define STRING_MAN_DESCRIPTOR 0x301
|
||||
#define STRING_PROD_DESCRIPTOR 0x302
|
||||
#define STRING_SN_DESCRIPTOR 0x303
|
||||
#define DEVICE_QUALIFIER_DESCRIPTOR 0x600
|
||||
|
||||
#define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX)
|
||||
#define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX)
|
||||
#define SETUP_FLAG(epstat) (epstat & USB_EPnR_SETUP)
|
||||
|
||||
// EPnR bits manipulation
|
||||
#define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
|
||||
#define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
|
||||
|
||||
// USB state: uninitialized, addressed, ready for use
|
||||
typedef enum{
|
||||
USB_STATE_DEFAULT,
|
||||
USB_STATE_ADDRESSED,
|
||||
USB_STATE_CONFIGURED,
|
||||
USB_STATE_CONNECTED
|
||||
} USB_state;
|
||||
|
||||
// EP types
|
||||
#define EP_TYPE_BULK 0x00
|
||||
#define EP_TYPE_CONTROL 0x01
|
||||
#define EP_TYPE_ISO 0x02
|
||||
#define EP_TYPE_INTERRUPT 0x03
|
||||
|
||||
#define LANG_US (uint16_t)0x0409
|
||||
|
||||
#define _USB_STRING_(name, str) \
|
||||
static const struct name \
|
||||
{ \
|
||||
uint8_t bLength; \
|
||||
uint8_t bDescriptorType; \
|
||||
uint16_t bString[(sizeof(str) - 2) / 2]; \
|
||||
\
|
||||
} \
|
||||
name = {sizeof(name), 0x03, str}
|
||||
|
||||
#define _USB_LANG_ID_(name, lng_id) \
|
||||
\
|
||||
static const struct name \
|
||||
{ \
|
||||
uint8_t bLength; \
|
||||
uint8_t bDescriptorType; \
|
||||
uint16_t bString; \
|
||||
\
|
||||
} \
|
||||
name = {0x04, 0x03, lng_id}
|
||||
#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4)
|
||||
|
||||
// EP0 configuration packet
|
||||
typedef struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} config_pack_t;
|
||||
|
||||
// endpoints state
|
||||
typedef struct{
|
||||
uint16_t *tx_buf; // transmission buffer address
|
||||
uint16_t txbufsz; // transmission buffer size
|
||||
uint16_t *rx_buf; // reception buffer address
|
||||
void (*func)(); // endpoint action function
|
||||
unsigned rx_cnt : 10; // received data counter
|
||||
} ep_t;
|
||||
|
||||
// USB status & its address
|
||||
typedef struct {
|
||||
uint8_t USB_Status;
|
||||
uint16_t USB_Addr;
|
||||
}usb_dev_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t dwDTERate;
|
||||
uint8_t bCharFormat;
|
||||
#define USB_CDC_1_STOP_BITS 0
|
||||
#define USB_CDC_1_5_STOP_BITS 1
|
||||
#define USB_CDC_2_STOP_BITS 2
|
||||
uint8_t bParityType;
|
||||
#define USB_CDC_NO_PARITY 0
|
||||
#define USB_CDC_ODD_PARITY 1
|
||||
#define USB_CDC_EVEN_PARITY 2
|
||||
#define USB_CDC_MARK_PARITY 3
|
||||
#define USB_CDC_SPACE_PARITY 4
|
||||
uint8_t bDataBits;
|
||||
} __attribute__ ((packed)) usb_LineCoding;
|
||||
|
||||
typedef struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bNotificationType;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} __attribute__ ((packed)) usb_cdc_notification;
|
||||
|
||||
extern ep_t endpoints[];
|
||||
extern usb_dev_t USB_Dev;
|
||||
extern uint8_t usbON;
|
||||
|
||||
void USB_Init();
|
||||
void USB_ResetState();
|
||||
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)());
|
||||
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size);
|
||||
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size);
|
||||
int EP_Read(uint8_t number, uint16_t *buf);
|
||||
usb_LineCoding getLineCoding();
|
||||
|
||||
void linecoding_handler(usb_LineCoding *lc);
|
||||
void clstate_handler(uint16_t val);
|
||||
void break_handler();
|
||||
void vendor_handler(config_pack_t *packet);
|
||||
|
||||
#endif // __USB_LIB_H__
|
||||
2
F1:F103/deprecated/MLX90640/version.inc
Normal file
2
F1:F103/deprecated/MLX90640/version.inc
Normal file
@@ -0,0 +1,2 @@
|
||||
#define BUILD_NUMBER "197"
|
||||
#define BUILD_DATE "2022-05-20"
|
||||
139
F1:F103/deprecated/PL2303/Makefile
Normal file
139
F1:F103/deprecated/PL2303/Makefile
Normal file
@@ -0,0 +1,139 @@
|
||||
BINARY = pl2303
|
||||
BOOTPORT ?= /dev/ttyUSB0
|
||||
BOOTSPEED ?= 115200
|
||||
# MCU FAMILY
|
||||
FAMILY ?= F1
|
||||
# MCU code
|
||||
MCU ?= F103x8
|
||||
# density (stm32f10x.h, lines 70-84)
|
||||
DENSITY ?= MD
|
||||
# change this linking script depending on particular MCU model,
|
||||
LDSCRIPT ?= stm32f103x8.ld
|
||||
# debug
|
||||
#DEFS = -DEBUG
|
||||
|
||||
INDEPENDENT_HEADERS=
|
||||
|
||||
FP_FLAGS ?= -msoft-float -mfloat-abi=soft
|
||||
ASM_FLAGS ?= -mthumb -mcpu=cortex-m3 -mfix-cortex-m3-ldrd
|
||||
ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS)
|
||||
|
||||
###############################################################################
|
||||
# Executables
|
||||
#PREFIX ?= arm-none-eabi
|
||||
# gcc from arm web site
|
||||
PREFIX ?= /opt/bin/arm-none-eabi
|
||||
TOOLCHLIB ?= /opt/arm-none-eabi/lib
|
||||
RM := rm -f
|
||||
RMDIR := rmdir
|
||||
CC := $(PREFIX)-gcc
|
||||
# don't replace ld with gcc: the binary size would be much greater!!
|
||||
LD := $(PREFIX)-ld
|
||||
AR := $(PREFIX)-ar
|
||||
AS := $(PREFIX)-as
|
||||
SIZE := $(PREFIX)-size
|
||||
OBJCOPY := $(PREFIX)-objcopy
|
||||
OBJDUMP := $(PREFIX)-objdump
|
||||
GDB := $(PREFIX)-gdb
|
||||
STFLASH := $(shell which st-flash)
|
||||
STBOOT := $(shell which stm32flash)
|
||||
DFUUTIL := $(shell which dfu-util)
|
||||
|
||||
###############################################################################
|
||||
# Source files
|
||||
OBJDIR = mk
|
||||
SRC := $(wildcard *.c)
|
||||
OBJS := $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o))
|
||||
STARTUP = $(OBJDIR)/startup.o
|
||||
OBJS += $(STARTUP)
|
||||
# dependencies: we need them to recompile files if their headers-dependencies changed
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
|
||||
INC_DIR ?= ../inc
|
||||
|
||||
INCLUDE := -I$(INC_DIR)/Fx -I$(INC_DIR)/cm
|
||||
LIB_DIR := $(INC_DIR)/ld
|
||||
|
||||
###############################################################################
|
||||
# C flags
|
||||
CFLAGS += -O2 -g -D__thumb2__=1 -MD
|
||||
CFLAGS += -Wall -Werror -Wextra -Wshadow
|
||||
CFLAGS += -fno-common -ffunction-sections -fdata-sections -fno-stack-protector
|
||||
CFLAGS += $(ARCH_FLAGS)
|
||||
|
||||
###############################################################################
|
||||
# Linker flags
|
||||
LDFLAGS += -nostartfiles --static -nostdlibs
|
||||
LDFLAGS += -L$(LIB_DIR) -L$(TOOLCHLIB)
|
||||
LDFLAGS += -T$(LDSCRIPT)
|
||||
|
||||
###############################################################################
|
||||
# Used libraries
|
||||
LDLIBS += -lc $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
|
||||
|
||||
DEFS += -DSTM32$(FAMILY) -DSTM32$(MCU) -DSTM32F10X_$(DENSITY)
|
||||
|
||||
ELF := $(OBJDIR)/$(BINARY).elf
|
||||
LIST := $(OBJDIR)/$(BINARY).list
|
||||
BIN := $(BINARY).bin
|
||||
HEX := $(BINARY).hex
|
||||
|
||||
all: bin list size
|
||||
|
||||
elf: $(ELF)
|
||||
bin: $(BIN)
|
||||
hex: $(HEX)
|
||||
list: $(LIST)
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(DEPS)
|
||||
endif
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir $(OBJDIR)
|
||||
|
||||
$(STARTUP): $(INC_DIR)/startup/vector.c
|
||||
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $<
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
@echo " CC $<"
|
||||
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $<
|
||||
|
||||
$(BIN): $(ELF)
|
||||
@echo " OBJCOPY $(BIN)"
|
||||
$(OBJCOPY) -Obinary $(ELF) $(BIN)
|
||||
|
||||
$(HEX): $(ELF)
|
||||
@echo " OBJCOPY $(HEX)"
|
||||
$(OBJCOPY) -Oihex $(ELF) $(HEX)
|
||||
|
||||
$(LIST): $(ELF)
|
||||
@echo " OBJDUMP $(LIST)"
|
||||
$(OBJDUMP) -S $(ELF) > $(LIST)
|
||||
|
||||
$(ELF): $(OBJDIR) $(OBJS)
|
||||
@echo " LD $(ELF)"
|
||||
$(LD) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(ELF)
|
||||
|
||||
size: $(ELF)
|
||||
$(SIZE) $(ELF)
|
||||
|
||||
clean:
|
||||
@echo " CLEAN"
|
||||
$(RM) $(OBJS) $(DEPS) $(ELF) $(HEX) $(LIST)
|
||||
@rmdir $(OBJDIR) 2>/dev/null || true
|
||||
|
||||
|
||||
flash: $(BIN)
|
||||
@echo " FLASH $(BIN)"
|
||||
$(STFLASH) write $(BIN) 0x8000000
|
||||
|
||||
boot: $(BIN)
|
||||
@echo " LOAD $(BIN) through bootloader"
|
||||
$(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN)
|
||||
|
||||
dfuboot: $(BIN)
|
||||
@echo " LOAD $(BIN) THROUGH DFU"
|
||||
$(DFUUTIL) -a0 -D $(BIN) -s 0x08000000
|
||||
|
||||
.PHONY: clean flash boot
|
||||
1
F1:F103/deprecated/PL2303/Readme
Normal file
1
F1:F103/deprecated/PL2303/Readme
Normal file
@@ -0,0 +1 @@
|
||||
Empty base for PL2303 emulation
|
||||
41
F1:F103/deprecated/PL2303/hardware.c
Normal file
41
F1:F103/deprecated/PL2303/hardware.c
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* hardware.c - hardware-dependent macros & functions
|
||||
*
|
||||
* Copyright 2018 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
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_IOPCEN | RCC_APB2ENR_AFIOEN;
|
||||
// turn off SWJ/JTAG
|
||||
// AFIO->MAPR = AFIO_MAPR_SWJ_CFG_DISABLE;
|
||||
// turn off USB pullup
|
||||
GPIOA->ODR = (1<<13); // turn off usb pullup & turn on pullups for buttons
|
||||
// Set led as opendrain output
|
||||
GPIOC->CRH |= CRH(13, CNF_ODOUTPUT|MODE_SLOW);
|
||||
// USB pullup (PA13) - opendrain output
|
||||
GPIOA->CRH = CRH(13, CNF_ODOUTPUT|MODE_SLOW);
|
||||
}
|
||||
|
||||
void hw_setup(){
|
||||
gpio_setup();
|
||||
}
|
||||
45
F1:F103/deprecated/PL2303/hardware.h
Normal file
45
F1:F103/deprecated/PL2303/hardware.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* hardware.h
|
||||
*
|
||||
* Copyright 2018 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 __HARDWARE_H__
|
||||
#define __HARDWARE_H__
|
||||
|
||||
#include "stm32f1.h"
|
||||
|
||||
// LED0 - PC13 (bluepill), blinking each second
|
||||
#define LED0_port GPIOC
|
||||
#define LED0_pin (1<<13)
|
||||
|
||||
// USB pullup (not present in bluepill) - PA13
|
||||
#define USBPU_port GPIOA
|
||||
#define USBPU_pin (1<<13)
|
||||
#define USBPU_ON() pin_clear(USBPU_port, USBPU_pin)
|
||||
#define USBPU_OFF() pin_set(USBPU_port, USBPU_pin)
|
||||
|
||||
#define LED_blink(x) pin_toggle(x ## _port, x ## _pin)
|
||||
#define LED_on(x) pin_clear(x ## _port, x ## _pin)
|
||||
#define LED_off(x) pin_set(x ## _port, x ## _pin)
|
||||
|
||||
void hw_setup();
|
||||
|
||||
#endif // __HARDWARE_H__
|
||||
172
F1:F103/deprecated/PL2303/main.c
Normal file
172
F1:F103/deprecated/PL2303/main.c
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* main.c
|
||||
*
|
||||
* Copyright 2017 Edward V. Emelianoff <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.
|
||||
*/
|
||||
|
||||
#include "hardware.h"
|
||||
#include "usart.h"
|
||||
#include "usb.h"
|
||||
#include "usb_lib.h"
|
||||
|
||||
volatile uint32_t Tms = 0;
|
||||
|
||||
/* Called when systick fires */
|
||||
void sys_tick_handler(void){
|
||||
++Tms;
|
||||
}
|
||||
|
||||
void iwdg_setup(){
|
||||
uint32_t tmout = 16000000;
|
||||
/* Enable the peripheral clock RTC */
|
||||
/* (1) Enable the LSI (40kHz) */
|
||||
/* (2) Wait while it is not ready */
|
||||
RCC->CSR |= RCC_CSR_LSION; /* (1) */
|
||||
while((RCC->CSR & RCC_CSR_LSIRDY) != RCC_CSR_LSIRDY){if(--tmout == 0) break;} /* (2) */
|
||||
/* Configure IWDG */
|
||||
/* (1) Activate IWDG (not needed if done in option bytes) */
|
||||
/* (2) Enable write access to IWDG registers */
|
||||
/* (3) Set prescaler by 64 (1.6ms for each tick) */
|
||||
/* (4) Set reload value to have a rollover each 2s */
|
||||
/* (5) Check if flags are reset */
|
||||
/* (6) Refresh counter */
|
||||
IWDG->KR = IWDG_START; /* (1) */
|
||||
IWDG->KR = IWDG_WRITE_ACCESS; /* (2) */
|
||||
IWDG->PR = IWDG_PR_PR_1; /* (3) */
|
||||
IWDG->RLR = 1250; /* (4) */
|
||||
tmout = 16000000;
|
||||
while(IWDG->SR){if(--tmout == 0) break;} /* (5) */
|
||||
IWDG->KR = IWDG_REFRESH; /* (6) */
|
||||
}
|
||||
|
||||
#define USND(str) do{USB_send((uint8_t*)str, sizeof(str)-1);}while(0)
|
||||
static const char *parse_cmd(const char *buf){
|
||||
if(buf[1] != '\n') return buf;
|
||||
switch(*buf){
|
||||
case 'p':
|
||||
pin_toggle(USBPU_port, USBPU_pin);
|
||||
USND("USB pullup is ");
|
||||
if(pin_read(USBPU_port, USBPU_pin)) USND("off\n");
|
||||
else USND("on\n");
|
||||
return NULL;
|
||||
break;
|
||||
case 'L':
|
||||
USND("Very long test string for USB (it's length is more than 64 bytes).\n"
|
||||
"This is another part of the string! Can you see all of this?\n");
|
||||
return "OK\n";
|
||||
break;
|
||||
case 'R':
|
||||
USND("Soft reset\n");
|
||||
NVIC_SystemReset();
|
||||
break;
|
||||
case 'S':
|
||||
USND("Test string for USB\n");
|
||||
return "OK\n";
|
||||
break;
|
||||
case 'W':
|
||||
USND("Wait for reboot\n");
|
||||
while(1){nop();};
|
||||
break;
|
||||
default: // help
|
||||
return
|
||||
"'p' - toggle USB pullup\n"
|
||||
"'L' - send long string over USB\n"
|
||||
"'R' - software reset\n"
|
||||
"'S' - send short string over USB\n"
|
||||
"'W' - test watchdog\n"
|
||||
;
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// usb getline
|
||||
char *get_USB(){
|
||||
static char tmpbuf[512], *curptr = tmpbuf;
|
||||
static int rest = 511;
|
||||
uint8_t x = USB_receive((uint8_t*)curptr);
|
||||
curptr[x] = 0;
|
||||
if(!x) return NULL;
|
||||
if(curptr[x-1] == '\n'){
|
||||
#ifdef EBUG
|
||||
DBG("fullline");
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
SEND(tmpbuf);
|
||||
transmit_tbuf();
|
||||
#endif
|
||||
curptr = tmpbuf;
|
||||
rest = 511;
|
||||
return tmpbuf;
|
||||
}
|
||||
curptr += x; rest -= x;
|
||||
if(rest <= 0){ // buffer overflow
|
||||
curptr = tmpbuf;
|
||||
rest = 511;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(void){
|
||||
uint32_t lastT = 0;
|
||||
sysreset();
|
||||
StartHSE();
|
||||
hw_setup();
|
||||
SysTick_Config(72000);
|
||||
|
||||
usart_setup();
|
||||
DBG("Start");
|
||||
if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured
|
||||
SEND("WDGRESET=1"); newline();
|
||||
}
|
||||
if(RCC->CSR & RCC_CSR_SFTRSTF){ // software reset occured
|
||||
SEND("SOFTRESET=1"); newline();
|
||||
}
|
||||
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
|
||||
|
||||
USBPU_OFF();
|
||||
USB_setup();
|
||||
iwdg_setup();
|
||||
USBPU_ON();
|
||||
|
||||
while (1){
|
||||
IWDG->KR = IWDG_REFRESH; // refresh watchdog
|
||||
if(lastT > Tms || Tms - lastT > 499){
|
||||
LED_blink(LED0);
|
||||
lastT = Tms;
|
||||
USND("tick\n");
|
||||
transmit_tbuf();
|
||||
}
|
||||
usb_proc();
|
||||
char *txt, *ans;
|
||||
if((txt = get_USB())){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
#ifdef EBUG
|
||||
SEND("Got data: ");
|
||||
SEND(txt); newline();
|
||||
transmit_tbuf();
|
||||
#endif
|
||||
ans = (char*)parse_cmd(txt);
|
||||
if(ans){
|
||||
uint16_t l = 0; char *p = ans;
|
||||
while(*p++) l++;
|
||||
USB_send((uint8_t*)ans, l);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
BIN
F1:F103/deprecated/PL2303/pl2303.bin
Executable file
BIN
F1:F103/deprecated/PL2303/pl2303.bin
Executable file
Binary file not shown.
267
F1:F103/deprecated/PL2303/usart.c
Normal file
267
F1:F103/deprecated/PL2303/usart.c
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* usart.c
|
||||
*
|
||||
* Copyright 2018 Edward V. Emelianoff <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.
|
||||
*/
|
||||
#include "stm32f1.h"
|
||||
#include "usart.h"
|
||||
#include "usb.h"
|
||||
|
||||
extern volatile uint32_t Tms;
|
||||
static volatile int idatalen[2] = {0,0}; // received data line length (including '\n')
|
||||
static volatile int odatalen[2] = {0,0};
|
||||
|
||||
static int dlen = 0; // length of data (including '\n') in current buffer
|
||||
|
||||
int linerdy = 0, // received data ready
|
||||
bufovr = 0, // input buffer overfull
|
||||
txrdy = 1 // transmission done
|
||||
;
|
||||
|
||||
static int rbufno = 0, tbufno = 0; // current rbuf/tbuf numbers
|
||||
static uint8_t rbuf[2][UARTBUFSZI], tbuf[2][UARTBUFSZO]; // receive & transmit buffers
|
||||
static uint8_t *recvdata = NULL;
|
||||
|
||||
/**
|
||||
* return length of received data (without trailing zero)
|
||||
*/
|
||||
uint16_t usart_get(uint8_t **line){
|
||||
if(!line) return 0;
|
||||
*line = NULL;
|
||||
if(bufovr){
|
||||
bufovr = 0;
|
||||
linerdy = 0;
|
||||
return 0;
|
||||
}
|
||||
if(!linerdy) return 0;
|
||||
USART1->CR1 &= ~USART_CR1_RXNEIE; // disallow Rx IRQ
|
||||
dlen = idatalen[rbufno];
|
||||
recvdata = rbuf[rbufno];
|
||||
// prepare other buffer
|
||||
rbufno = !rbufno;
|
||||
idatalen[rbufno] = 0;
|
||||
recvdata[dlen] = 0;
|
||||
*line = recvdata;
|
||||
linerdy = 0;
|
||||
USART1->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ
|
||||
return dlen;
|
||||
}
|
||||
|
||||
// transmit current tbuf and swap buffers
|
||||
int transmit_tbuf(){
|
||||
uint32_t tmout = 7200;
|
||||
while(!txrdy){ // wait for previos buffer transmission
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(--tmout == 0){
|
||||
//DMA1_Channel4->CCR &= ~DMA_CCR_EN;
|
||||
//txrdy = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
int l = odatalen[tbufno];
|
||||
if(!l){
|
||||
return 0;
|
||||
}
|
||||
DMA1_Channel4->CCR &= ~DMA_CCR_EN;
|
||||
DMA1_Channel4->CMAR = (uint32_t) tbuf[tbufno]; // mem
|
||||
DMA1_Channel4->CNDTR = l;
|
||||
tbufno = !tbufno;
|
||||
odatalen[tbufno] = 0;
|
||||
txrdy = 0;
|
||||
DMA1_Channel4->CCR |= DMA_CCR_EN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usart_putchar(const char ch){
|
||||
tbuf[tbufno][odatalen[tbufno]++] = ch;
|
||||
if(odatalen[tbufno] >= UARTBUFSZO){
|
||||
while(transmit_tbuf()) IWDG->KR = IWDG_REFRESH;
|
||||
}
|
||||
}
|
||||
|
||||
void usart_send(const char *str){
|
||||
if(!str) return;
|
||||
while(*str){
|
||||
tbuf[tbufno][odatalen[tbufno]++] = *str++;
|
||||
if(odatalen[tbufno] >= UARTBUFSZO){
|
||||
while(transmit_tbuf()) IWDG->KR = IWDG_REFRESH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief usart_senddata - the same as usart_send, but with given length
|
||||
*/
|
||||
void usart_senddata(const uint8_t *str, uint16_t len){
|
||||
while(len--){
|
||||
tbuf[tbufno][odatalen[tbufno]++] = *str++;
|
||||
if(odatalen[tbufno] >= UARTBUFSZO){
|
||||
while(transmit_tbuf()) IWDG->KR = IWDG_REFRESH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void newline(){
|
||||
usart_putchar('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* USART speed: baudrate = Fck/(USARTDIV)
|
||||
* USARTDIV stored in USART->BRR
|
||||
*
|
||||
* for 72MHz USARTDIV=72000/f(kboud); so for 115200 USARTDIV=72000/115.2=625 -> BRR=0x271
|
||||
* 9600: BRR = 7500 (0x1D4C)
|
||||
*/
|
||||
|
||||
void usart_setup(){
|
||||
uint32_t tmout = 16000000;
|
||||
// PA9 - Tx, PA10 - Rx
|
||||
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_AFIOEN;
|
||||
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
|
||||
GPIOA->CRH = CRH(9, CNF_AFPP|MODE_NORMAL) | CRH(10, CNF_FLINPUT|MODE_INPUT);
|
||||
|
||||
// USART1 Tx DMA - Channel4 (Rx - channel 5)
|
||||
DMA1_Channel4->CPAR = (uint32_t) &USART1->DR; // periph
|
||||
DMA1_Channel4->CCR |= DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // 8bit, mem++, mem->per, transcompl irq
|
||||
// Tx CNDTR set @ each transmission due to data size
|
||||
NVIC_SetPriority(DMA1_Channel4_IRQn, 3);
|
||||
NVIC_EnableIRQ(DMA1_Channel4_IRQn);
|
||||
NVIC_SetPriority(USART1_IRQn, 0);
|
||||
// setup usart1
|
||||
USART1->BRR = 72000000 / 115200;
|
||||
//USART1->BRR = 24; // 3000000
|
||||
USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART
|
||||
while(!(USART1->SR & USART_SR_TC)){ // polling idle frame Transmission
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(--tmout == 0) break;
|
||||
}
|
||||
USART1->SR = 0; // clear flags
|
||||
USART1->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ
|
||||
USART1->CR3 = USART_CR3_DMAT; // enable DMA Tx
|
||||
NVIC_EnableIRQ(USART1_IRQn);
|
||||
}
|
||||
|
||||
|
||||
void usart1_isr(){
|
||||
#ifdef CHECK_TMOUT
|
||||
static uint32_t tmout = 0;
|
||||
#endif
|
||||
if(USART1->SR & USART_SR_RXNE){ // RX not emty - receive next char
|
||||
#ifdef CHECK_TMOUT
|
||||
if(tmout && Tms >= tmout){ // set overflow flag
|
||||
bufovr = 1;
|
||||
idatalen[rbufno] = 0;
|
||||
}
|
||||
tmout = Tms + TIMEOUT_MS;
|
||||
if(!tmout) tmout = 1; // prevent 0
|
||||
#endif
|
||||
uint8_t rb = USART1->DR;
|
||||
if(idatalen[rbufno] < UARTBUFSZI){ // put next char into buf
|
||||
rbuf[rbufno][idatalen[rbufno]++] = rb;
|
||||
linerdy = 1; // ready for reading
|
||||
#ifdef CHECK_TMOUT
|
||||
// clear timeout at line end
|
||||
tmout = 0;
|
||||
#endif
|
||||
}else{ // buffer overrun
|
||||
bufovr = 1;
|
||||
idatalen[rbufno] = 0;
|
||||
#ifdef CHECK_TMOUT
|
||||
tmout = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// print 32bit unsigned int
|
||||
void printu(uint32_t val){
|
||||
char bufa[11], bufb[10];
|
||||
int l = 0, bpos = 0;
|
||||
if(!val){
|
||||
bufa[0] = '0';
|
||||
l = 1;
|
||||
}else{
|
||||
while(val){
|
||||
bufb[l++] = val % 10 + '0';
|
||||
val /= 10;
|
||||
}
|
||||
int i;
|
||||
bpos += l;
|
||||
for(i = 0; i < l; ++i){
|
||||
bufa[--bpos] = bufb[i];
|
||||
}
|
||||
}
|
||||
bufa[l + bpos] = 0;
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
usart_send(bufa);
|
||||
}
|
||||
|
||||
// print 32bit unsigned int as hex
|
||||
void printuhex(uint32_t val){
|
||||
usart_send("0x");
|
||||
uint8_t *ptr = (uint8_t*)&val + 3;
|
||||
int i, j;
|
||||
for(i = 0; i < 4; ++i, --ptr){
|
||||
for(j = 1; j > -1; --j){
|
||||
register uint8_t half = (*ptr >> (4*j)) & 0x0f;
|
||||
if(half < 10) usart_putchar(half + '0');
|
||||
else usart_putchar(half - 10 + 'a');
|
||||
}
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
}
|
||||
}
|
||||
/*
|
||||
// dump memory buffer
|
||||
void hexdump(const uint8_t *arr, uint16_t len){
|
||||
for(uint16_t l = 0; l < len; ++l, ++arr){
|
||||
for(int16_t j = 1; j > -1; --j){
|
||||
register uint8_t half = (*arr >> (4*j)) & 0x0f;
|
||||
if(half < 10) usart_putchar(half + '0');
|
||||
else usart_putchar(half - 10 + 'a');
|
||||
}
|
||||
if(l % 16 == 15) usart_putchar('\n');
|
||||
else if(l & 1) usart_putchar(' ');
|
||||
}
|
||||
}
|
||||
*/
|
||||
void dma1_channel4_isr(){
|
||||
DMA1->IFCR = DMA_IFCR_CTCIF4; // clear TC flag
|
||||
txrdy = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
#if USARTNUM == 2
|
||||
void dma1_channel4_5_isr(){
|
||||
if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx
|
||||
DMA1->IFCR |= DMA_IFCR_CTCIF4; // clear TC flag
|
||||
txrdy = 1;
|
||||
}
|
||||
}
|
||||
// USART1
|
||||
#elif USARTNUM == 1
|
||||
void dma1_channel2_3_isr(){
|
||||
if(DMA1->ISR & DMA_ISR_TCIF2){ // Tx
|
||||
DMA1->IFCR |= DMA_IFCR_CTCIF2; // clear TC flag
|
||||
txrdy = 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "Not implemented"
|
||||
#endif
|
||||
*/
|
||||
67
F1:F103/deprecated/PL2303/usart.h
Normal file
67
F1:F103/deprecated/PL2303/usart.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* usart.h
|
||||
*
|
||||
* Copyright 2018 Edward V. Emelianoff <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 __USART_H__
|
||||
#define __USART_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// input and output buffers size
|
||||
#define UARTBUFSZI (64)
|
||||
#define UARTBUFSZO (64)
|
||||
// timeout between data bytes
|
||||
#ifndef TIMEOUT_MS
|
||||
#define TIMEOUT_MS (1500)
|
||||
#endif
|
||||
|
||||
// macro for static strings
|
||||
#define SEND(str) usart_send(str)
|
||||
#define _s(s) #s
|
||||
#define STR(s) _s(s)
|
||||
|
||||
#ifdef EBUG
|
||||
#define DBG(str) do{SEND(__FILE__ " (L" STR(__LINE__) "): " str); newline();}while(0)
|
||||
#define HERE() do{SEND(STR(__LINE__)); usart_putchar('\n');}while(0)
|
||||
#define MSG(str) do{SEND(str); usart_putchar('\n');}while(0)
|
||||
#else
|
||||
#define MSG(str)
|
||||
#define HERE()
|
||||
#define DBG(str)
|
||||
#endif
|
||||
|
||||
#define usartrx() (linerdy)
|
||||
#define usartovr() (bufovr)
|
||||
|
||||
extern int linerdy, bufovr, txrdy;
|
||||
|
||||
int transmit_tbuf();
|
||||
void usart_setup();
|
||||
uint16_t usart_get(uint8_t **line);
|
||||
void usart_send(const char *str);
|
||||
void usart_senddata(const uint8_t *str, uint16_t len);
|
||||
void newline();
|
||||
void usart_putchar(const char ch);
|
||||
void printu(uint32_t val);
|
||||
void printuhex(uint32_t val);
|
||||
void hexdump(const uint8_t *arr, uint16_t len);
|
||||
|
||||
#endif // __USART_H__
|
||||
167
F1:F103/deprecated/PL2303/usb.c
Normal file
167
F1:F103/deprecated/PL2303/usb.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb.c - base functions for different USB types
|
||||
*
|
||||
* Copyright 2018 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.
|
||||
*
|
||||
*/
|
||||
#include "usart.h"
|
||||
#include "usb.h"
|
||||
#include "usb_lib.h"
|
||||
|
||||
static volatile uint8_t tx_succesfull = 1;
|
||||
static volatile uint8_t rxNE = 0;
|
||||
|
||||
// interrupt IN handler (never used?)
|
||||
static void EP1_Handler(){
|
||||
uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]);
|
||||
if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX
|
||||
else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX);
|
||||
// clear CTR
|
||||
epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX));
|
||||
USB->EPnR[1] = epstatus;
|
||||
}
|
||||
|
||||
// data IN/OUT handlers
|
||||
static void transmit_Handler(){ // EP3IN
|
||||
tx_succesfull = 1;
|
||||
uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[3]);
|
||||
// clear CTR keep DTOGs & STATs
|
||||
USB->EPnR[3] = (epstatus & ~(USB_EPnR_CTR_TX)); // clear TX ctr
|
||||
}
|
||||
|
||||
static void receive_Handler(){ // EP2OUT
|
||||
rxNE = 1;
|
||||
uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[2]);
|
||||
USB->EPnR[2] = (epstatus & ~(USB_EPnR_CTR_RX)); // clear RX ctr
|
||||
DBG("RXh");
|
||||
}
|
||||
|
||||
void USB_setup(){
|
||||
NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||
NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||
USB->CNTR = USB_CNTR_FRES; // Force USB Reset
|
||||
for(uint32_t ctr = 0; ctr < 72000; ++ctr) nop(); // wait >1ms
|
||||
//uint32_t ctr = 0;
|
||||
USB->CNTR = 0;
|
||||
USB->BTABLE = 0;
|
||||
USB->DADDR = 0;
|
||||
USB->ISTR = 0;
|
||||
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_WKUPM; // allow only wakeup & reset interrupts
|
||||
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||
}
|
||||
|
||||
static int usbwr(const uint8_t *buf, uint16_t l){
|
||||
uint32_t ctra = 1000000;
|
||||
while(--ctra && tx_succesfull == 0){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
}
|
||||
tx_succesfull = 0;
|
||||
EP_Write(3, buf, l);
|
||||
ctra = 1000000;
|
||||
while(--ctra && tx_succesfull == 0){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
}
|
||||
if(tx_succesfull == 0){usbON = 0; return 1;} // usb is OFF?
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t usbbuff[USB_TXBUFSZ-1]; // temporary buffer (63 - to prevent need of ZLP)
|
||||
static uint8_t buflen = 0; // amount of symbols in usbbuff
|
||||
|
||||
// send next up to 63 bytes of data in usbbuff
|
||||
static void send_next(){
|
||||
if(!buflen || !tx_succesfull) return;
|
||||
tx_succesfull = 0;
|
||||
EP_Write(3, usbbuff, buflen);
|
||||
buflen = 0;
|
||||
}
|
||||
|
||||
// unblocking sending - just fill a buffer
|
||||
void USB_send(const uint8_t *buf, uint16_t len){
|
||||
if(!usbON || !len) return;
|
||||
if(len > USB_TXBUFSZ-1 - buflen){
|
||||
usbwr(usbbuff, buflen);
|
||||
buflen = 0;
|
||||
}
|
||||
if(len > USB_TXBUFSZ-1){
|
||||
USB_send_blk(buf, len);
|
||||
return;
|
||||
}
|
||||
while(len--) usbbuff[buflen++] = *buf++;
|
||||
}
|
||||
|
||||
// blocking sending
|
||||
void USB_send_blk(const uint8_t *buf, uint16_t len){
|
||||
if(!usbON || !len) return; // USB disconnected
|
||||
if(buflen){
|
||||
usbwr(usbbuff, buflen);
|
||||
buflen = 0;
|
||||
}
|
||||
int needzlp = 0;
|
||||
while(len){
|
||||
if(len == USB_TXBUFSZ) needzlp = 1;
|
||||
uint16_t s = (len > USB_TXBUFSZ) ? USB_TXBUFSZ : len;
|
||||
if(usbwr(buf, s)) return;
|
||||
len -= s;
|
||||
buf += s;
|
||||
}
|
||||
if(needzlp){
|
||||
usbwr(NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_proc(){
|
||||
switch(USB_Dev.USB_Status){
|
||||
case USB_STATE_CONFIGURED:
|
||||
// make new BULK endpoint
|
||||
// Buffer have 1024 bytes, but last 256 we use for CAN bus (30.2 of RM: USB main features)
|
||||
EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit
|
||||
EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data
|
||||
EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data
|
||||
USB_Dev.USB_Status = USB_STATE_CONNECTED;
|
||||
break;
|
||||
case USB_STATE_DEFAULT:
|
||||
case USB_STATE_ADDRESSED:
|
||||
if(usbON){
|
||||
usbON = 0;
|
||||
}
|
||||
break;
|
||||
default: // USB_STATE_CONNECTED - send next data portion
|
||||
if(!usbON) return;
|
||||
send_next();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB_receive
|
||||
* @param buf (i) - buffer[64] for received data
|
||||
* @return amount of received bytes
|
||||
*/
|
||||
uint8_t USB_receive(uint8_t *buf){
|
||||
if(!usbON || !rxNE) return 0;
|
||||
DBG("Get data");
|
||||
SEND((char*)buf); newline();
|
||||
uint8_t sz = EP_Read(2, (uint16_t*)buf);
|
||||
uint16_t epstatus = KEEP_DTOG(USB->EPnR[2]);
|
||||
// keep stat_tx & set ACK rx
|
||||
USB->EPnR[2] = (epstatus & ~(USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX;
|
||||
rxNE = 0;
|
||||
return sz;
|
||||
}
|
||||
37
F1:F103/deprecated/PL2303/usb.h
Normal file
37
F1:F103/deprecated/PL2303/usb.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb.h
|
||||
*
|
||||
* Copyright 2018 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 __USB_H__
|
||||
#define __USB_H__
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
#define BUFFSIZE (64)
|
||||
|
||||
void USB_setup();
|
||||
void usb_proc();
|
||||
void USB_send(const uint8_t *buf, uint16_t len);
|
||||
void USB_send_blk(const uint8_t *buf, uint16_t len);
|
||||
uint8_t USB_receive(uint8_t *buf);
|
||||
|
||||
#endif // __USB_H__
|
||||
107
F1:F103/deprecated/PL2303/usb_defs.h
Normal file
107
F1:F103/deprecated/PL2303/usb_defs.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb_defs.h
|
||||
*
|
||||
* Copyright 2018 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 __USB_DEFS_H__
|
||||
#define __USB_DEFS_H__
|
||||
|
||||
#include <stm32f1.h>
|
||||
|
||||
// max endpoints number
|
||||
#define STM32ENDPOINTS 8
|
||||
/**
|
||||
* Buffers size definition
|
||||
**/
|
||||
#define USB_BTABLE_SIZE 512
|
||||
// first 64 bytes of USB_BTABLE are registers!
|
||||
//#define USB_EP0_BASEADDR 64
|
||||
// for USB FS EP0 buffers are from 8 to 64 bytes long (64 for PL2303)
|
||||
#define USB_EP0_BUFSZ 64
|
||||
// USB transmit buffer size (64 for PL2303)
|
||||
#define USB_TXBUFSZ 64
|
||||
// USB receive buffer size (64 for PL2303)
|
||||
#define USB_RXBUFSZ 64
|
||||
// EP1 - interrupt - buffer size
|
||||
#define USB_EP1BUFSZ 8
|
||||
|
||||
#define USB_BTABLE_BASE 0x40006000
|
||||
#define USB_BASE ((uint32_t)0x40005C00)
|
||||
#define USB ((USB_TypeDef *) USB_BASE)
|
||||
|
||||
#ifdef USB_BTABLE
|
||||
#undef USB_BTABLE
|
||||
#endif
|
||||
#define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE))
|
||||
#define USB_ISTR_EPID 0x0000000F
|
||||
#define USB_FNR_LSOF_0 0x00000800
|
||||
#define USB_FNR_lSOF_1 0x00001000
|
||||
#define USB_LPMCSR_BESL_0 0x00000010
|
||||
#define USB_LPMCSR_BESL_1 0x00000020
|
||||
#define USB_LPMCSR_BESL_2 0x00000040
|
||||
#define USB_LPMCSR_BESL_3 0x00000080
|
||||
#define USB_EPnR_CTR_RX 0x00008000
|
||||
#define USB_EPnR_DTOG_RX 0x00004000
|
||||
#define USB_EPnR_STAT_RX 0x00003000
|
||||
#define USB_EPnR_STAT_RX_0 0x00001000
|
||||
#define USB_EPnR_STAT_RX_1 0x00002000
|
||||
#define USB_EPnR_SETUP 0x00000800
|
||||
#define USB_EPnR_EP_TYPE 0x00000600
|
||||
#define USB_EPnR_EP_TYPE_0 0x00000200
|
||||
#define USB_EPnR_EP_TYPE_1 0x00000400
|
||||
#define USB_EPnR_EP_KIND 0x00000100
|
||||
#define USB_EPnR_CTR_TX 0x00000080
|
||||
#define USB_EPnR_DTOG_TX 0x00000040
|
||||
#define USB_EPnR_STAT_TX 0x00000030
|
||||
#define USB_EPnR_STAT_TX_0 0x00000010
|
||||
#define USB_EPnR_STAT_TX_1 0x00000020
|
||||
#define USB_EPnR_EA 0x0000000F
|
||||
#define USB_COUNTn_RX_BLSIZE 0x00008000
|
||||
#define USB_COUNTn_NUM_BLOCK 0x00007C00
|
||||
#define USB_COUNTn_RX 0x0000003F
|
||||
|
||||
#ifdef USB_TypeDef
|
||||
#define USB_TypeDef USB_TypeDef_custom
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
__IO uint32_t EPnR[STM32ENDPOINTS];
|
||||
__IO uint32_t RESERVED[STM32ENDPOINTS];
|
||||
__IO uint32_t CNTR;
|
||||
__IO uint32_t ISTR;
|
||||
__IO uint32_t FNR;
|
||||
__IO uint32_t DADDR;
|
||||
__IO uint32_t BTABLE;
|
||||
} USB_TypeDef;
|
||||
|
||||
typedef struct{
|
||||
__IO uint32_t USB_ADDR_TX;
|
||||
__IO uint32_t USB_COUNT_TX;
|
||||
__IO uint32_t USB_ADDR_RX;
|
||||
__IO uint32_t USB_COUNT_RX;
|
||||
} USB_EPDATA_TypeDef;
|
||||
|
||||
typedef struct{
|
||||
__IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS];
|
||||
} USB_BtableDef;
|
||||
|
||||
#endif // __USB_DEFS_H__
|
||||
481
F1:F103/deprecated/PL2303/usb_lib.c
Normal file
481
F1:F103/deprecated/PL2303/usb_lib.c
Normal file
@@ -0,0 +1,481 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb_lib.c
|
||||
*
|
||||
* Copyright 2018 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "usb_lib.h"
|
||||
|
||||
ep_t endpoints[STM32ENDPOINTS];
|
||||
|
||||
usb_dev_t USB_Dev;
|
||||
static usb_LineCoding lineCoding = {115200, 0, 0, 8};
|
||||
static config_pack_t setup_packet;
|
||||
static uint8_t ep0databuf[EP0DATABUF_SIZE];
|
||||
static uint8_t ep0dbuflen = 0;
|
||||
|
||||
usb_LineCoding getLineCoding(){return lineCoding;}
|
||||
|
||||
uint8_t usbON = 0; // device disconnected from terminal
|
||||
|
||||
// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor
|
||||
#define bcdUSB_L 0x10
|
||||
#define bcdUSB_H 0x01
|
||||
#define bDeviceClass 0
|
||||
#define bDeviceSubClass 0
|
||||
#define bDeviceProtocol 0
|
||||
#define bNumConfigurations 1
|
||||
|
||||
static const uint8_t USB_DeviceDescriptor[] = {
|
||||
18, // bLength
|
||||
0x01, // bDescriptorType - Device descriptor
|
||||
bcdUSB_L, // bcdUSB_L - 1.10
|
||||
bcdUSB_H, // bcdUSB_H
|
||||
bDeviceClass, // bDeviceClass - USB_COMM
|
||||
bDeviceSubClass, // bDeviceSubClass
|
||||
bDeviceProtocol, // bDeviceProtocol
|
||||
USB_EP0_BUFSZ, // bMaxPacketSize
|
||||
0x7b, // idVendor_L PL2303: VID=0x067b, PID=0x2303
|
||||
0x06, // idVendor_H
|
||||
0x03, // idProduct_L
|
||||
0x23, // idProduct_H
|
||||
0x00, // bcdDevice_Ver_L
|
||||
0x03, // bcdDevice_Ver_H
|
||||
0x01, // iManufacturer
|
||||
0x02, // iProduct
|
||||
0x00, // iSerialNumber
|
||||
bNumConfigurations // bNumConfigurations
|
||||
};
|
||||
|
||||
static const uint8_t USB_DeviceQualifierDescriptor[] = {
|
||||
10, //bLength
|
||||
0x06, // bDescriptorType - Device qualifier
|
||||
bcdUSB_L, // bcdUSB_L
|
||||
bcdUSB_H, // bcdUSB_H
|
||||
bDeviceClass, // bDeviceClass
|
||||
bDeviceSubClass, // bDeviceSubClass
|
||||
bDeviceProtocol, // bDeviceProtocol
|
||||
USB_EP0_BUFSZ, // bMaxPacketSize0
|
||||
bNumConfigurations, // bNumConfigurations
|
||||
0x00 // Reserved
|
||||
};
|
||||
|
||||
static const uint8_t USB_ConfigDescriptor[] = {
|
||||
/*Configuration Descriptor*/
|
||||
0x09, /* bLength: Configuration Descriptor size */
|
||||
0x02, /* bDescriptorType: Configuration */
|
||||
39, /* wTotalLength:no of returned bytes */
|
||||
0x00,
|
||||
0x01, /* bNumInterfaces: 1 interface */
|
||||
0x01, /* bConfigurationValue: Configuration value */
|
||||
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
|
||||
0xa0, /* bmAttributes - Bus powered, Remote wakeup */
|
||||
0x32, /* MaxPower 100 mA */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*Interface Descriptor */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
0x04, /* bDescriptorType: Interface */
|
||||
0x00, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x03, /* bNumEndpoints: 3 endpoints used */
|
||||
0xff, /* bInterfaceClass */
|
||||
0x00, /* bInterfaceSubClass */
|
||||
0x00, /* bInterfaceProtocol */
|
||||
0x00, /* iInterface: */
|
||||
///////////////////////////////////////////////////
|
||||
/*Endpoint 1 Descriptor*/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
0x05, /* bDescriptorType: Endpoint */
|
||||
0x81, /* bEndpointAddress IN1 */
|
||||
0x03, /* bmAttributes: Interrupt */
|
||||
0x0a, /* wMaxPacketSize LO: */
|
||||
0x00, /* wMaxPacketSize HI: */
|
||||
0x01, /* bInterval: */
|
||||
|
||||
/*Endpoint OUT2 Descriptor*/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
0x05, /* bDescriptorType: Endpoint */
|
||||
0x02, /* bEndpointAddress: OUT2 */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
(USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
|
||||
(USB_RXBUFSZ >> 8),
|
||||
0x00, /* bInterval: ignore for Bulk transfer */
|
||||
|
||||
/*Endpoint IN3 Descriptor*/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
0x05, /* bDescriptorType: Endpoint */
|
||||
0x83, /* bEndpointAddress IN3 */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
(USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
|
||||
(USB_TXBUFSZ >> 8),
|
||||
0x00, /* bInterval: ignore for Bulk transfer */
|
||||
};
|
||||
|
||||
_USB_LANG_ID_(USB_StringLangDescriptor, LANG_US);
|
||||
// these descriptors are not used in PL2303 emulator!
|
||||
_USB_STRING_(USB_StringSerialDescriptor, u"0");
|
||||
_USB_STRING_(USB_StringManufacturingDescriptor, u"Prolific Technology Inc.");
|
||||
_USB_STRING_(USB_StringProdDescriptor, u"USB-Serial Controller");
|
||||
|
||||
/*
|
||||
* default handlers
|
||||
*/
|
||||
// SET_LINE_CODING
|
||||
void WEAK linecoding_handler(usb_LineCoding __attribute__((unused)) *lc){
|
||||
}
|
||||
|
||||
// SET_CONTROL_LINE_STATE
|
||||
void WEAK clstate_handler(uint16_t __attribute__((unused)) val){
|
||||
}
|
||||
|
||||
// SEND_BREAK
|
||||
void WEAK break_handler(){
|
||||
}
|
||||
|
||||
// handler of vendor requests
|
||||
void WEAK vendor_handler(config_pack_t *packet){
|
||||
if(packet->bmRequestType & 0x80){ // read
|
||||
uint8_t c;
|
||||
switch(packet->wValue){
|
||||
case 0x8484:
|
||||
c = 2;
|
||||
break;
|
||||
case 0x0080:
|
||||
c = 1;
|
||||
break;
|
||||
case 0x8686:
|
||||
c = 0xaa;
|
||||
break;
|
||||
default:
|
||||
c = 0;
|
||||
}
|
||||
EP_WriteIRQ(0, &c, 1);
|
||||
}else{ // write ZLP
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void wr0(const uint8_t *buf, uint16_t size){
|
||||
if(setup_packet.wLength < size) size = setup_packet.wLength; // shortened request
|
||||
if(size < endpoints[0].txbufsz){
|
||||
EP_WriteIRQ(0, buf, size);
|
||||
return;
|
||||
}
|
||||
while(size){
|
||||
uint16_t l = size;
|
||||
if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz;
|
||||
EP_WriteIRQ(0, buf, l);
|
||||
buf += l;
|
||||
size -= l;
|
||||
uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0;
|
||||
if(size || needzlp){ // send last data buffer
|
||||
uint16_t status = KEEP_DTOG(USB->EPnR[0]);
|
||||
// keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx
|
||||
USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX))
|
||||
^ USB_EPnR_STAT_TX;
|
||||
uint32_t ctr = 1000000;
|
||||
while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;};
|
||||
if((USB->ISTR & USB_ISTR_CTR) == 0){
|
||||
return;
|
||||
}
|
||||
if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void get_descriptor(){
|
||||
switch(setup_packet.wValue){
|
||||
case DEVICE_DESCRIPTOR:
|
||||
wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor));
|
||||
break;
|
||||
case CONFIGURATION_DESCRIPTOR:
|
||||
wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor));
|
||||
break;
|
||||
case STRING_LANG_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringLangDescriptor, STRING_LANG_DESCRIPTOR_SIZE_BYTE);
|
||||
break;
|
||||
case STRING_MAN_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringManufacturingDescriptor, USB_StringManufacturingDescriptor.bLength);
|
||||
break;
|
||||
case STRING_PROD_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringProdDescriptor, USB_StringProdDescriptor.bLength);
|
||||
break;
|
||||
case STRING_SN_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringSerialDescriptor, USB_StringSerialDescriptor.bLength);
|
||||
break;
|
||||
case DEVICE_QUALIFIER_DESCRIPTOR:
|
||||
wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured)
|
||||
static inline void std_d2h_req(){
|
||||
uint16_t status = 0; // bus powered
|
||||
switch(setup_packet.bRequest){
|
||||
case GET_DESCRIPTOR:
|
||||
get_descriptor();
|
||||
break;
|
||||
case GET_STATUS:
|
||||
EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered
|
||||
break;
|
||||
case GET_CONFIGURATION:
|
||||
EP_WriteIRQ(0, &configuration, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void std_h2d_req(){
|
||||
switch(setup_packet.bRequest){
|
||||
case SET_ADDRESS:
|
||||
// new address will be assigned later - after acknowlegement or request to host
|
||||
USB_Dev.USB_Addr = setup_packet.wValue;
|
||||
break;
|
||||
case SET_CONFIGURATION:
|
||||
// Now device configured
|
||||
USB_Dev.USB_Status = USB_STATE_CONFIGURED;
|
||||
configuration = setup_packet.wValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bmRequestType: 76543210
|
||||
7 direction: 0 - host->device, 1 - device->host
|
||||
65 type: 0 - standard, 1 - class, 2 - vendor
|
||||
4..0 getter: 0 - device, 1 - interface, 2 - endpoint, 3 - other
|
||||
*/
|
||||
/**
|
||||
* Endpoint0 (control) handler
|
||||
*/
|
||||
static void EP0_Handler(){
|
||||
uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications
|
||||
uint8_t reqtype = setup_packet.bmRequestType & 0x7f;
|
||||
uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0;
|
||||
int rxflag = RX_FLAG(epstatus);
|
||||
if(rxflag && SETUP_FLAG(epstatus)){
|
||||
switch(reqtype){
|
||||
case STANDARD_DEVICE_REQUEST_TYPE: // standard device request
|
||||
if(dev2host){
|
||||
std_d2h_req();
|
||||
}else{
|
||||
std_h2d_req();
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}
|
||||
break;
|
||||
case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request
|
||||
if(setup_packet.bRequest == CLEAR_FEATURE){
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}
|
||||
break;
|
||||
case VENDOR_REQUEST_TYPE:
|
||||
vendor_handler(&setup_packet);
|
||||
break;
|
||||
case CONTROL_REQUEST_TYPE:
|
||||
switch(setup_packet.bRequest){
|
||||
case GET_LINE_CODING:
|
||||
EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding));
|
||||
break;
|
||||
case SET_LINE_CODING: // omit this for next stage, when data will come
|
||||
break;
|
||||
case SET_CONTROL_LINE_STATE:
|
||||
usbON = 1;
|
||||
clstate_handler(setup_packet.wValue);
|
||||
break;
|
||||
case SEND_BREAK:
|
||||
usbON = 0;
|
||||
break_handler();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(setup_packet.bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement
|
||||
break;
|
||||
default:
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}
|
||||
}else if(rxflag){ // got data over EP0 or host acknowlegement
|
||||
if(endpoints[0].rx_cnt){
|
||||
if(setup_packet.bRequest == SET_LINE_CODING){
|
||||
linecoding_handler((usb_LineCoding*)ep0databuf);
|
||||
}
|
||||
}
|
||||
} else if(TX_FLAG(epstatus)){ // package transmitted
|
||||
// now we can change address after enumeration
|
||||
if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){
|
||||
USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr;
|
||||
// change state to ADRESSED
|
||||
USB_Dev.USB_Status = USB_STATE_ADDRESSED;
|
||||
}
|
||||
}
|
||||
epstatus = KEEP_DTOG(USB->EPnR[0]);
|
||||
if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP/data transmission
|
||||
else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged
|
||||
// keep DTOGs, clear CTR_RX,TX, set RX VALID
|
||||
USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX;
|
||||
}
|
||||
|
||||
static uint16_t lastaddr = LASTADDR_DEFAULT;
|
||||
/**
|
||||
* Endpoint initialisation
|
||||
* @param number - EP num (0...7)
|
||||
* @param type - EP type (EP_TYPE_BULK, EP_TYPE_CONTROL, EP_TYPE_ISO, EP_TYPE_INTERRUPT)
|
||||
* @param txsz - transmission buffer size @ USB/CAN buffer
|
||||
* @param rxsz - reception buffer size @ USB/CAN buffer
|
||||
* @param uint16_t (*func)(ep_t *ep) - EP handler function
|
||||
* @return 0 if all OK
|
||||
*/
|
||||
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)(ep_t ep)){
|
||||
if(number >= STM32ENDPOINTS) return 4; // out of configured amount
|
||||
if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large
|
||||
if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE) return 2; // out of btable
|
||||
USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA);
|
||||
USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1;
|
||||
if(rxsz & 1 || rxsz > 512) return 3; // wrong rx buffer size
|
||||
uint16_t countrx = 0;
|
||||
if(rxsz < 64) countrx = rxsz / 2;
|
||||
else{
|
||||
if(rxsz & 0x1f) return 3; // should be multiple of 32
|
||||
countrx = 31 + rxsz / 32;
|
||||
}
|
||||
USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr;
|
||||
endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr*2);
|
||||
endpoints[number].txbufsz = txsz;
|
||||
lastaddr += txsz;
|
||||
USB_BTABLE->EP[number].USB_COUNT_TX = 0;
|
||||
USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr;
|
||||
endpoints[number].rx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr*2);
|
||||
lastaddr += rxsz;
|
||||
USB_BTABLE->EP[number].USB_COUNT_RX = countrx << 10;
|
||||
endpoints[number].func = func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// standard IRQ handler
|
||||
void usb_lp_can_rx0_isr(){
|
||||
if(USB->ISTR & USB_ISTR_RESET){
|
||||
usbON = 0;
|
||||
// Reinit registers
|
||||
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
|
||||
USB->ISTR = 0;
|
||||
// Endpoint 0 - CONTROL
|
||||
// ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes!
|
||||
lastaddr = LASTADDR_DEFAULT;
|
||||
// clear address, leave only enable bit
|
||||
USB->DADDR = USB_DADDR_EF;
|
||||
USB_Dev.USB_Status = USB_STATE_DEFAULT;
|
||||
USB->ISTR = ~USB_ISTR_RESET;
|
||||
if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(USB->ISTR & USB_ISTR_CTR){
|
||||
// EP number
|
||||
uint8_t n = USB->ISTR & USB_ISTR_EPID;
|
||||
// copy status register
|
||||
uint16_t epstatus = USB->EPnR[n];
|
||||
// copy received bytes amount
|
||||
endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter
|
||||
// check direction
|
||||
if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit)
|
||||
if(n == 0){ // control endpoint
|
||||
if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack
|
||||
EP_Read(0, (uint16_t*)&setup_packet);
|
||||
ep0dbuflen = 0;
|
||||
// interrupt handler will be called later
|
||||
}else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf
|
||||
ep0dbuflen = endpoints[0].rx_cnt;
|
||||
EP_Read(0, (uint16_t*)&ep0databuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
// call EP handler
|
||||
if(endpoints[n].func) endpoints[n].func(endpoints[n]);
|
||||
}
|
||||
if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep
|
||||
usbON = 0;
|
||||
USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LP_MODE;
|
||||
USB->ISTR = ~USB_ISTR_SUSP;
|
||||
}
|
||||
if(USB->ISTR & USB_ISTR_WKUP){ // wakeup
|
||||
USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LP_MODE); // clear suspend flags
|
||||
USB->ISTR = ~USB_ISTR_WKUP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to EP buffer (called from IRQ handler)
|
||||
* @param number - EP number
|
||||
* @param *buf - array with data
|
||||
* @param size - its size
|
||||
*/
|
||||
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
|
||||
uint8_t i;
|
||||
if(size > endpoints[number].txbufsz) size = endpoints[number].txbufsz;
|
||||
uint16_t N2 = (size + 1) >> 1;
|
||||
// the buffer is 16-bit, so we should copy data as it would be uint16_t
|
||||
uint16_t *buf16 = (uint16_t *)buf;
|
||||
uint32_t *out = (uint32_t *)endpoints[number].tx_buf;
|
||||
for(i = 0; i < N2; ++i, ++out){
|
||||
*out = buf16[i];
|
||||
}
|
||||
USB_BTABLE->EP[number].USB_COUNT_TX = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to EP buffer (called outside IRQ handler)
|
||||
* @param number - EP number
|
||||
* @param *buf - array with data
|
||||
* @param size - its size
|
||||
*/
|
||||
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){
|
||||
EP_WriteIRQ(number, buf, size);
|
||||
uint16_t status = KEEP_DTOG(USB->EPnR[number]);
|
||||
// keep DTOGs, clear CTR_TX & set TX VALID to start transmission
|
||||
USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy data from EP buffer into user buffer area
|
||||
* @param *buf - user array for data
|
||||
* @return amount of data read
|
||||
*/
|
||||
int EP_Read(uint8_t number, uint16_t *buf){
|
||||
int sz = endpoints[number].rx_cnt;
|
||||
if(!sz) return 0;
|
||||
endpoints[number].rx_cnt = 0;
|
||||
int n = (sz + 1) >> 1;
|
||||
uint32_t *in = (uint32_t *)endpoints[number].rx_buf;
|
||||
if(n){
|
||||
for(int i = 0; i < n; ++i, ++in)
|
||||
buf[i] = *(uint16_t*)in;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
189
F1:F103/deprecated/PL2303/usb_lib.h
Normal file
189
F1:F103/deprecated/PL2303/usb_lib.h
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb_lib.h
|
||||
*
|
||||
* Copyright 2018 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 __USB_LIB_H__
|
||||
#define __USB_LIB_H__
|
||||
|
||||
#include <wchar.h>
|
||||
#include "usb_defs.h"
|
||||
|
||||
#define EP0DATABUF_SIZE (64)
|
||||
#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8)
|
||||
|
||||
// bmRequestType & 0x7f
|
||||
#define STANDARD_DEVICE_REQUEST_TYPE 0
|
||||
#define STANDARD_ENDPOINT_REQUEST_TYPE 2
|
||||
#define VENDOR_REQUEST_TYPE 0x40
|
||||
#define CONTROL_REQUEST_TYPE 0x21
|
||||
// bRequest, standard; for bmRequestType == 0x80
|
||||
#define GET_STATUS 0x00
|
||||
#define GET_DESCRIPTOR 0x06
|
||||
#define GET_CONFIGURATION 0x08
|
||||
// for bmRequestType == 0
|
||||
#define CLEAR_FEATURE 0x01
|
||||
#define SET_FEATURE 0x03 // unused
|
||||
#define SET_ADDRESS 0x05
|
||||
#define SET_DESCRIPTOR 0x07 // unused
|
||||
#define SET_CONFIGURATION 0x09
|
||||
// for bmRequestType == 0x81, 1 or 0xB2
|
||||
#define GET_INTERFACE 0x0A // unused
|
||||
#define SET_INTERFACE 0x0B // unused
|
||||
#define SYNC_FRAME 0x0C // unused
|
||||
#define VENDOR_REQUEST 0x01 // unused
|
||||
|
||||
// Class-Specific Control Requests
|
||||
#define SEND_ENCAPSULATED_COMMAND 0x00 // unused
|
||||
#define GET_ENCAPSULATED_RESPONSE 0x01 // unused
|
||||
#define SET_COMM_FEATURE 0x02 // unused
|
||||
#define GET_COMM_FEATURE 0x03 // unused
|
||||
#define CLEAR_COMM_FEATURE 0x04 // unused
|
||||
#define SET_LINE_CODING 0x20
|
||||
#define GET_LINE_CODING 0x21
|
||||
#define SET_CONTROL_LINE_STATE 0x22
|
||||
#define SEND_BREAK 0x23
|
||||
|
||||
// control line states
|
||||
#define CONTROL_DTR 0x01
|
||||
#define CONTROL_RTS 0x02
|
||||
|
||||
// wValue
|
||||
#define DEVICE_DESCRIPTOR 0x100
|
||||
#define CONFIGURATION_DESCRIPTOR 0x200
|
||||
#define STRING_LANG_DESCRIPTOR 0x300
|
||||
#define STRING_MAN_DESCRIPTOR 0x301
|
||||
#define STRING_PROD_DESCRIPTOR 0x302
|
||||
#define STRING_SN_DESCRIPTOR 0x303
|
||||
#define DEVICE_QUALIFIER_DESCRIPTOR 0x600
|
||||
|
||||
#define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX)
|
||||
#define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX)
|
||||
#define SETUP_FLAG(epstat) (epstat & USB_EPnR_SETUP)
|
||||
|
||||
// EPnR bits manipulation
|
||||
#define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
|
||||
#define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
|
||||
|
||||
// USB state: uninitialized, addressed, ready for use
|
||||
typedef enum{
|
||||
USB_STATE_DEFAULT,
|
||||
USB_STATE_ADDRESSED,
|
||||
USB_STATE_CONFIGURED,
|
||||
USB_STATE_CONNECTED
|
||||
} USB_state;
|
||||
|
||||
// EP types
|
||||
#define EP_TYPE_BULK 0x00
|
||||
#define EP_TYPE_CONTROL 0x01
|
||||
#define EP_TYPE_ISO 0x02
|
||||
#define EP_TYPE_INTERRUPT 0x03
|
||||
|
||||
#define LANG_US (uint16_t)0x0409
|
||||
|
||||
#define _USB_STRING_(name, str) \
|
||||
static const struct name \
|
||||
{ \
|
||||
uint8_t bLength; \
|
||||
uint8_t bDescriptorType; \
|
||||
uint16_t bString[(sizeof(str) - 2) / 2]; \
|
||||
\
|
||||
} \
|
||||
name = {sizeof(name), 0x03, str}
|
||||
|
||||
#define _USB_LANG_ID_(name, lng_id) \
|
||||
\
|
||||
static const struct name \
|
||||
{ \
|
||||
uint8_t bLength; \
|
||||
uint8_t bDescriptorType; \
|
||||
uint16_t bString; \
|
||||
\
|
||||
} \
|
||||
name = {0x04, 0x03, lng_id}
|
||||
#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4)
|
||||
|
||||
// EP0 configuration packet
|
||||
typedef struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} config_pack_t;
|
||||
|
||||
// endpoints state
|
||||
typedef struct{
|
||||
uint16_t *tx_buf; // transmission buffer address
|
||||
uint16_t txbufsz; // transmission buffer size
|
||||
uint16_t *rx_buf; // reception buffer address
|
||||
void (*func)(); // endpoint action function
|
||||
unsigned rx_cnt : 10; // received data counter
|
||||
} ep_t;
|
||||
|
||||
// USB status & its address
|
||||
typedef struct {
|
||||
uint8_t USB_Status;
|
||||
uint16_t USB_Addr;
|
||||
}usb_dev_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t dwDTERate;
|
||||
uint8_t bCharFormat;
|
||||
#define USB_CDC_1_STOP_BITS 0
|
||||
#define USB_CDC_1_5_STOP_BITS 1
|
||||
#define USB_CDC_2_STOP_BITS 2
|
||||
uint8_t bParityType;
|
||||
#define USB_CDC_NO_PARITY 0
|
||||
#define USB_CDC_ODD_PARITY 1
|
||||
#define USB_CDC_EVEN_PARITY 2
|
||||
#define USB_CDC_MARK_PARITY 3
|
||||
#define USB_CDC_SPACE_PARITY 4
|
||||
uint8_t bDataBits;
|
||||
} __attribute__ ((packed)) usb_LineCoding;
|
||||
|
||||
typedef struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bNotificationType;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} __attribute__ ((packed)) usb_cdc_notification;
|
||||
|
||||
extern ep_t endpoints[];
|
||||
extern usb_dev_t USB_Dev;
|
||||
extern uint8_t usbON;
|
||||
|
||||
void USB_Init();
|
||||
void USB_ResetState();
|
||||
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)());
|
||||
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size);
|
||||
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size);
|
||||
int EP_Read(uint8_t number, uint16_t *buf);
|
||||
usb_LineCoding getLineCoding();
|
||||
|
||||
void linecoding_handler(usb_LineCoding *lc);
|
||||
void clstate_handler(uint16_t val);
|
||||
void break_handler();
|
||||
void vendor_handler(config_pack_t *packet);
|
||||
|
||||
#endif // __USB_LIB_H__
|
||||
7
F1:F103/deprecated/Readme.md
Normal file
7
F1:F103/deprecated/Readme.md
Normal file
@@ -0,0 +1,7 @@
|
||||
- **CDC_ACM** - simplest CDC-ACM snippet (*deprecated*)
|
||||
- **chronometer** - first version of chronometer for bike/auto/moto competitions
|
||||
- **chronometer_v2** - chrono-2
|
||||
- **MLX90640** - test of MLX90640 (*deprecated* as can't calculate so many sqrt's on STM32F103)
|
||||
- **PL2303** - based PL2303 emulation (*deprecated*)
|
||||
- **pl2303_snippet** - (*deprecated*)
|
||||
- **pl2303_snippet_naked** - (*deprecated*)
|
||||
179
F1:F103/deprecated/chronometer/GPS.c
Normal file
179
F1:F103/deprecated/chronometer/GPS.c
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* GPS.c
|
||||
*
|
||||
* Copyright 2015 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.
|
||||
*/
|
||||
|
||||
#include "GPS.h"
|
||||
#include "hardware.h"
|
||||
#include "time.h"
|
||||
#include "usart.h"
|
||||
#include "str.h"
|
||||
#include "usb.h"
|
||||
#include <string.h> // memcpy
|
||||
|
||||
#define GPS_send_string(str) do{usart_send(GPS_USART, str);}while(0)
|
||||
|
||||
gps_status GPS_status = GPS_NOTFOUND;
|
||||
int need2startseq = 1;
|
||||
|
||||
static uint8_t hex(uint8_t n){
|
||||
return ((n < 10) ? (n+'0') : (n+'A'-10));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check checksum
|
||||
*/
|
||||
static int checksum_true(const char *buf){
|
||||
char *eol;
|
||||
uint8_t checksum = 0, cs[3];
|
||||
if(*buf != '$' || !(eol = getchr(buf, '*'))){
|
||||
return 0;
|
||||
}
|
||||
while(++buf != eol)
|
||||
checksum ^= (uint8_t)*buf;
|
||||
++buf;
|
||||
cs[0] = hex(checksum >> 4);
|
||||
cs[1] = hex(checksum & 0x0f);
|
||||
if(buf[0] == cs[0] && buf[1] == cs[1])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_chksum(uint8_t chs){
|
||||
usart_putchar(GPS_USART, hex(chs >> 4));
|
||||
usart_putchar(GPS_USART, hex(chs & 0x0f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate checksum & write message to port
|
||||
* @param buf - command to write (without leading $ and trailing *)
|
||||
* return 0 if fails
|
||||
*/
|
||||
static void write_with_checksum(const char *buf){
|
||||
/*
|
||||
for(int i = 0; i < 10000; ++i){
|
||||
char *txt = NULL;
|
||||
if(usartrx(GPS_USART)){
|
||||
usart_getline(GPS_USART, &txt);
|
||||
DBG("Old data");
|
||||
GPS_parse_answer(txt);
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
uint8_t checksum = 0;
|
||||
usart_putchar(GPS_USART, '$');
|
||||
GPS_send_string(buf);
|
||||
do{
|
||||
checksum ^= *buf++;
|
||||
}while(*buf);
|
||||
usart_putchar(GPS_USART, '*');
|
||||
send_chksum(checksum);
|
||||
newline(GPS_USART);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MTK fields format:
|
||||
* $PMTKxxx,yyy,zzz*2E
|
||||
* P - proprietary, MTK - always this, xxx - packet type, yyy,zzz - packet data
|
||||
* Packet types:
|
||||
* 220 - PMTK_SET_POS_FIX, data - position fix interval (msec, > 200)
|
||||
* 255 - PMTK_SET_SYNC_PPS_NMEA - turn on/off (def - off) PPS, data = 0/1 -> "$PMTK255,1" turn ON
|
||||
* 285 - PMTK_SET_PPS_CONFIG - set PPS configuration, data fields:
|
||||
* 1st - 0-disable, 1-after 1st fix, 2-3D only, 3-2D/3D only, 4-always
|
||||
* 2nd - 2..998 - pulse width
|
||||
* 314 - PMTK_API_SET_NMEA_OUTPUT - set output messages, N== N fixes per output,
|
||||
* order of messages: GLL,RMC,VTG,GGA,GSA,GSV,GRS,GST, only RMC per every pos fix:
|
||||
* $PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
* 386 - PMTK_API_SET_STATIC_NAV_THD speed threshold (m/s) for static navigation
|
||||
* $PMTK386,1.5
|
||||
* ;
|
||||
*/
|
||||
|
||||
/**
|
||||
* Send starting sequences (get only RMC messages)
|
||||
*/
|
||||
void GPS_send_start_seq(){
|
||||
DBG("Send start seq");
|
||||
// turn ON PPS:
|
||||
write_with_checksum("PMTK255,1");
|
||||
// set pulse width to 10ms with working after 1st fix
|
||||
write_with_checksum("PMTK285,1,10");
|
||||
// set only RMC:
|
||||
write_with_checksum("PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0");
|
||||
// set static speed threshold
|
||||
write_with_checksum("PMTK386,1.5");
|
||||
need2startseq = 0;
|
||||
}
|
||||
|
||||
// send "full cold start" command to clear all almanach & location data
|
||||
void GPS_send_FullColdStart(){
|
||||
write_with_checksum("PMTK104");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse answer from GPS module
|
||||
*
|
||||
* Recommended minimum specific GPS/Transit data
|
||||
* $GPRMC,hhmmss.sss,status,latitude,N,longitude,E,spd,cog,ddmmyy,mv,mvE,mode*cs
|
||||
* 1 = UTC of position fix
|
||||
* 2 = Data status (V=valid, A=invalid)
|
||||
* 3 = Latitude (ddmm.mmmm)
|
||||
* 4 = N or S
|
||||
* 5 = Longitude (dddmm.mmmm)
|
||||
* 6 = E or W
|
||||
* 7 = Speed over ground in knots
|
||||
* 8 = Cource over ground in degrees
|
||||
* 9 = UT date (ddmmyy)
|
||||
* 10 = Magnetic variation degrees (Easterly var. subtracts from true course)
|
||||
* 11 = E or W
|
||||
* 12 = Mode: N(bad), E(approx), A(auto), D(diff)
|
||||
* 213457.00,A,4340.59415,N,04127.47560,E,2.494,,290615,,,A*7B
|
||||
*/
|
||||
void GPS_parse_answer(const char *buf){
|
||||
char *ptr;
|
||||
if(buf[1] == 'P') return; // answers to proprietary messages
|
||||
if(cmpstr(buf+3, "RMC", 3)){ // not RMC message
|
||||
//need2startseq = 1;
|
||||
return;
|
||||
}
|
||||
if(!checksum_true(buf)){
|
||||
return; // wrong checksum
|
||||
}
|
||||
if(showGPSstr){
|
||||
showGPSstr = 0;
|
||||
sendstring(buf);
|
||||
}
|
||||
buf += 7; // skip header
|
||||
if(*buf == ','){ // time unknown
|
||||
GPS_status = GPS_WAIT;
|
||||
return;
|
||||
}
|
||||
ptr = getchr(buf, ',');
|
||||
if(!ptr ) return;
|
||||
*ptr++ = 0;
|
||||
if(*ptr == 'A'){
|
||||
GPS_status = GPS_VALID;
|
||||
set_time(buf);
|
||||
}else{
|
||||
uint8_t goth = (buf[0]-'0')*10 + buf[1]-'0';
|
||||
if(current_time.H != goth) set_time(buf); // set time once per hour even if it's not valid
|
||||
GPS_status = GPS_NOT_VALID;
|
||||
}
|
||||
}
|
||||
43
F1:F103/deprecated/chronometer/GPS.h
Normal file
43
F1:F103/deprecated/chronometer/GPS.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* GPS.h
|
||||
*
|
||||
* Copyright 2015 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 __GPS_H__
|
||||
#define __GPS_H__
|
||||
|
||||
#include "stm32f1.h"
|
||||
|
||||
extern int need2startseq;
|
||||
|
||||
typedef enum{
|
||||
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;
|
||||
|
||||
extern gps_status GPS_status;
|
||||
|
||||
void GPS_parse_answer(const char *string);
|
||||
void GPS_send_start_seq();
|
||||
void GPS_send_FullColdStart();
|
||||
|
||||
#endif // __GPS_H__
|
||||
159
F1:F103/deprecated/chronometer/Makefile
Normal file
159
F1:F103/deprecated/chronometer/Makefile
Normal file
@@ -0,0 +1,159 @@
|
||||
# make debug adds -DEBUG -Werror
|
||||
# make ADDEFS="additional defs"
|
||||
BINARY = chrono
|
||||
BOOTPORT ?= /dev/ttyUSB0
|
||||
BOOTSPEED ?= 115200
|
||||
# MCU FAMILY
|
||||
FAMILY ?= F1
|
||||
# MCU code
|
||||
MCU ?= F103x8
|
||||
# density (stm32f10x.h, lines 70-84)
|
||||
DENSITY ?= MD
|
||||
# change this linking script depending on particular MCU model,
|
||||
LDSCRIPT ?= stm32F103xB.ld
|
||||
DEFS = ${ADDEFS} -DVERSION=\"0.1.0\"
|
||||
TARGET := RELEASE
|
||||
# proxy GPS output over USART1
|
||||
#DEFS += -DUSART1PROXY
|
||||
|
||||
FP_FLAGS ?= -msoft-float -mfloat-abi=soft
|
||||
ASM_FLAGS ?= -mthumb -mcpu=cortex-m3 -mfix-cortex-m3-ldrd
|
||||
ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS)
|
||||
|
||||
###############################################################################
|
||||
# Executables
|
||||
#PREFIX ?= arm-none-eabi
|
||||
# gcc from arm web site
|
||||
PREFIX ?= /opt/bin/arm-none-eabi
|
||||
TOOLCHLIB ?= /opt/arm-none-eabi/lib
|
||||
RM := rm -f
|
||||
RMDIR := rmdir
|
||||
CC := $(PREFIX)-gcc
|
||||
# don't replace ld with gcc: the binary size would be much greater!!
|
||||
LD := $(PREFIX)-ld
|
||||
AR := $(PREFIX)-ar
|
||||
AS := $(PREFIX)-as
|
||||
SIZE := $(PREFIX)-size
|
||||
OBJCOPY := $(PREFIX)-objcopy
|
||||
OBJDUMP := $(PREFIX)-objdump
|
||||
GDB := $(PREFIX)-gdb
|
||||
STFLASH := $(shell which st-flash)
|
||||
STBOOT := $(shell which stm32flash)
|
||||
DFUUTIL := $(shell which dfu-util)
|
||||
|
||||
###############################################################################
|
||||
# Source files
|
||||
OBJDIR = mk
|
||||
SRC := $(wildcard *.c)
|
||||
OBJS := $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o))
|
||||
STARTUP = $(OBJDIR)/startup.o
|
||||
OBJS += $(STARTUP)
|
||||
# dependencies: we need them to recompile files if their headers-dependencies changed
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
|
||||
INC_DIR ?= ../inc
|
||||
|
||||
INCLUDE := -I$(INC_DIR)/Fx -I$(INC_DIR)/cm
|
||||
LIB_DIR := $(INC_DIR)/ld
|
||||
|
||||
###############################################################################
|
||||
# C flags
|
||||
CFLAGS += -O2 -g -D__thumb2__=1 -MD
|
||||
CFLAGS += -Wall -Wextra -Wshadow
|
||||
CFLAGS += -fno-common -ffunction-sections -fdata-sections -fno-stack-protector
|
||||
CFLAGS += $(ARCH_FLAGS)
|
||||
|
||||
###############################################################################
|
||||
# Linker flags
|
||||
LDFLAGS += --static -nostartfiles -nostdlibs
|
||||
LDFLAGS += -L$(LIB_DIR) -L$(TOOLCHLIB)
|
||||
LDFLAGS += -T$(LDSCRIPT)
|
||||
|
||||
###############################################################################
|
||||
# Used libraries
|
||||
LDLIBS += -lc $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
|
||||
|
||||
DEFS += -DSTM32$(FAMILY) -DSTM32$(MCU) -DSTM32F10X_$(DENSITY)
|
||||
|
||||
ELF := $(OBJDIR)/$(BINARY).elf
|
||||
LIST := $(OBJDIR)/$(BINARY).list
|
||||
BIN := $(BINARY).bin
|
||||
HEX := $(BINARY).hex
|
||||
|
||||
all: $(OBJDIR)/RELEASE bin list size
|
||||
release: all
|
||||
|
||||
debug: CFLAGS += -DEBUG -Werror
|
||||
debug: $(OBJDIR)/DEBUG bin list size
|
||||
|
||||
$(OBJDIR)/DEBUG:
|
||||
@rm -rf $(OBJDIR)
|
||||
@mkdir $(OBJDIR)
|
||||
@> $(OBJDIR)/DEBUG
|
||||
@echo "TARGET: DEBUG"
|
||||
echo "CFLAGS += -DEBUG -Werror" > $(OBJDIR)/CFLAGS
|
||||
$(OBJDIR)/RELEASE:
|
||||
@rm -rf $(OBJDIR)
|
||||
@mkdir $(OBJDIR)
|
||||
@> $(OBJDIR)/RELEASE
|
||||
@echo "TARGET: RELEASE"
|
||||
echo "" > $(OBJDIR)/CFLAGS
|
||||
|
||||
elf: $(ELF)
|
||||
bin: $(BIN)
|
||||
hex: $(HEX)
|
||||
list: $(LIST)
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(DEPS)
|
||||
-include $(OBJDIR)/CFLAGS
|
||||
endif
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir $(OBJDIR)
|
||||
|
||||
$(STARTUP): $(INC_DIR)/startup/vector.c
|
||||
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $<
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
@echo " CC $<"
|
||||
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $<
|
||||
|
||||
$(BIN): $(ELF)
|
||||
@echo " OBJCOPY $(BIN)"
|
||||
$(OBJCOPY) -Obinary $(ELF) $(BIN)
|
||||
|
||||
$(HEX): $(ELF)
|
||||
@echo " OBJCOPY $(HEX)"
|
||||
$(OBJCOPY) -Oihex $(ELF) $(HEX)
|
||||
|
||||
$(LIST): $(ELF)
|
||||
@echo " OBJDUMP $(LIST)"
|
||||
$(OBJDUMP) -S $(ELF) > $(LIST)
|
||||
|
||||
$(ELF): $(OBJDIR) $(OBJS) $(LDSCRIPT)
|
||||
@echo " LD $(ELF)"
|
||||
$(LD) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(ELF)
|
||||
|
||||
size: $(ELF)
|
||||
$(SIZE) $(ELF)
|
||||
|
||||
clean:
|
||||
@echo " CLEAN"
|
||||
@$(RM) $(HEX)
|
||||
@$(RM) -rf $(OBJDIR) 2>/dev/null || true
|
||||
|
||||
|
||||
flash: $(BIN)
|
||||
@echo " FLASH $(BIN)"
|
||||
$(STFLASH) --reset write $(BIN) 0x8000000
|
||||
|
||||
boot: $(BIN)
|
||||
@echo " LOAD $(BIN) through bootloader"
|
||||
$(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN)
|
||||
|
||||
dfuboot: $(BIN)
|
||||
@echo " LOAD $(BIN) THROUGH DFU"
|
||||
$(DFUUTIL) -a0 -D $(BIN) -s 0x08000000
|
||||
|
||||
.PHONY: clean flash boot
|
||||
33
F1:F103/deprecated/chronometer/Readme.md
Normal file
33
F1:F103/deprecated/chronometer/Readme.md
Normal file
@@ -0,0 +1,33 @@
|
||||
Chronometer for downhill competitions
|
||||
=====================================
|
||||
|
||||
## Pinout
|
||||
|
||||
- PA11/12 - USB
|
||||
- PA9(Tx),PA10 (debug mode) - USART1 - debug console
|
||||
- PA2(Tx), PA3 - USART2 - GPS
|
||||
- PB10(Tx), PB11 - USART3 - LIDAR - TRIG3
|
||||
|
||||
- PA1 - PPS signal from GPS (EXTI)
|
||||
|
||||
- PA4 - TRIG2 - 12V trigger (EXTI)
|
||||
- PA13 - TRIG0 - button0 (EXTI)
|
||||
- PA14 - TRIG1 - button1/laser/etc (EXTI)
|
||||
- PA15 - USB pullup
|
||||
|
||||
- PB8, PB9 - onboard LEDs (0/1)
|
||||
|
||||
- PC13 - buzzer
|
||||
|
||||
## LEDS
|
||||
|
||||
- LED0 - shining when there's no PPS signal, fades for 0.25s on PPS
|
||||
- LED1 - don't shines if no GPS found, shines when time not valid, blinks when time valid
|
||||
|
||||
### Not implemented yet:
|
||||
|
||||
- PA5,6,7 (SCK, MISO, MOSI) - SPI
|
||||
- PB0 - TRIG4 - ADC channel 8
|
||||
- PB6/7 (SCL, SDA) - I2C
|
||||
|
||||
|
||||
123
F1:F103/deprecated/chronometer/Readme_rus.txt
Normal file
123
F1:F103/deprecated/chronometer/Readme_rus.txt
Normal file
@@ -0,0 +1,123 @@
|
||||
Дополнено выводом времени на LED screen.
|
||||
|
||||
!!! инвертировать USB_PU
|
||||
|
||||
|
||||
****** Распиновка ******
|
||||
|
||||
=== Интерфейсы I/O ===
|
||||
- PA11/12 - USB
|
||||
- PA9(Tx), PA10(Rx) - USART1 - консоль отладки / прокси RMC-сообщений GPS (опт. - bluetooth).
|
||||
- PA2(Tx), PA3(Rx) - USART2 - подключение GPS-приемника.
|
||||
- PB10(Tx), PB11(Rx) - USART3 - подключение лидара или другой консоли.
|
||||
|
||||
=== Остальные порты ===
|
||||
- PA1 - PPS сигнал от GPS; сюда можно подключать любой дополнительный высокоомный вход напрямую.
|
||||
- PB0 - TRIG0 - (замыкать на землю).
|
||||
- PB1 - TRIG1 - подключен к 12В.
|
||||
- PB3 - TRIG2 - (замыкать на землю).
|
||||
- PA15 - подтяжка USB.
|
||||
- PA8 - (еще не реализовано) - bluetooth "state"
|
||||
- PB8, PB9 - индикаторные светодиоды (LED1, LED0 соответственно).
|
||||
- PC13 - пищалка.
|
||||
|
||||
=== Светодиоды ===
|
||||
- LED0 - при отсутствии сигнала PPS просто горит, если PPS появляется - мигает (затухает на 0.25с на каждый сигнал).
|
||||
- LED1 - индикатор GPS: не горит, если приемник не обнаружен; горит постоянно, если неуверенный прием времени
|
||||
(буква "V" во второй позиции RMC-сообщения); мигает при уверенном приеме (буква "A" во второй позиции).
|
||||
Судя по эксперименту, даже через час после пропадания сигнала точность определения события - не хуже 1мс. Сам GPS-приемник выдает
|
||||
PPS даже при отсутствии спутников - лишь бы он успел "подхватить" точное время и начать генерировать pps. Начинать работу можно сразу,
|
||||
как только замигает LED0.
|
||||
|
||||
|
||||
****** Триггеры ******
|
||||
К TRIG0/TRIG2 подключается кнопка, педаль, иной створ, замыкающий контакты. Никакого внешнего напряжения здесь быть не должно!
|
||||
К TRIG1 нужно подключать 12-вольтный сигнал, ток не меньше 10мА. Если створ имеет открытый коллектор, то выход створа подключается
|
||||
к минусу TRIG2, а к плюсу подключается 12В с источника питания.
|
||||
|
||||
Иногда бывают ложные срабатывания триггеров TRIG0..TRIG2, связанные с мощными источниками искр (зажигание, искрящиеся обмотки и т.п.).
|
||||
В случае таких ложных срабатываний рекомендуется заземлить катод источника питания хронометра.
|
||||
|
||||
При подключении внешней кнопки желательно, чтобы она имела нормально замкнутые контакты - это предотвратит ложные срабатывания из-за электромагнитных помех.
|
||||
|
||||
|
||||
****** Подключение ******
|
||||
Хронометр эмулирует "китайский" преобразователь PL2303.
|
||||
|
||||
К выходам PA9/PA10 можно подключить преобразователь USART<>USB или накинуть их напрямую на ноги Rx/Tx "малинки" (не забыв соединить
|
||||
земли хронометра и малинки): PA9(Tx) соединить с Rx, PA10(Rx) - с Tx. Этот USART проксирует RMC-сообщения GPS-приемника (уже после
|
||||
обработки микроконтроллером, поэтому если МК выключен, а приемник включен, сигнала все равно не будет).
|
||||
|
||||
Для подключения PPS сигнала к "малинке" выведен соответствующий разъем.
|
||||
|
||||
|
||||
****** Конфигурация ******
|
||||
Хронометр конфигурируется через USB. Ввод команд не сопровождается эхом (чтобы удобней было работать из внешних программ), поэтому
|
||||
для удобства можно тексты команд копировать из окна текстового редактора.
|
||||
Чтобы увидеть подсказку, достаточно отправить любую строку, начинающуюся с вопросительного знака. Появится справка:
|
||||
|
||||
adcmax - max ADC value treshold for trigger
|
||||
adcmin - min -//- (triggered when ADval>min & <max
|
||||
adcval - get ADC value
|
||||
buzzerS - turn buzzer ON/OFF
|
||||
distmin - min distance threshold (cm)
|
||||
distmax - max distance threshold (cm)
|
||||
gpsrestart - send Full Cold Restart to GPS
|
||||
gpsstring - current GPS data string
|
||||
ledsS - turn leds on/off (1/0)
|
||||
mcutemp - MCU temperature
|
||||
pullupNS - triggers pullups state (N - trigger No, S - 0/1 for off/on)
|
||||
showconf - show current configuration
|
||||
time - print time
|
||||
store - store new configuration in flash
|
||||
triglevelNS - working trigger N level S
|
||||
trigpauseNP - pause (P, ms) after trigger N shots
|
||||
trigtimeN - show last trigger N time
|
||||
vdd - Vdd value
|
||||
|
||||
Из нужного здесь:
|
||||
- gpsrestart - перезапуск GPS (если вдруг начнет глючить - у меня такого не случалось), делает "холодный" рестарт. Команда
|
||||
проверялась лишь на прототипе.
|
||||
- gpsstring - вывод очередного сообщения от GPS. Если все нормально, то появится строка RMC вроде
|
||||
$GPRMC,124001.000,A,4340.9369,N,04127.5034,E,0.00,33.26,150819,,,A*5C
|
||||
- pullupNS - включить или выключить внутренние верхние подтяжки для триггеров 0..3 (особо не нужно, т.к. подтяжки слабые, и если
|
||||
будет нужна подтяжка, лучше сделать сильную внешнюю).
|
||||
- showconf - отображение текущей конфигурации, например:
|
||||
CONFIG:
|
||||
DISTMIN=50
|
||||
DISTMAX=1000
|
||||
ADCMIN=1024
|
||||
ADCMAX=3072
|
||||
PULLUPS=255
|
||||
TRIGLVL=0
|
||||
TRIGPAUSE={400, 400, 400, 300, 300}
|
||||
ENDCONFIG
|
||||
|
||||
пункты конфигурации: DISTMIN/DISTMAX относятся к лидару, ADCMIN/ADCMAX ко входу АЦП, PULLUPS - состояние подтяжек
|
||||
(каждый бит, начиная с младшего - состояние соответствующей подтяжки; 0 - не активна, 1 - активна).
|
||||
TRIGLVL - конфигурация уровней срабатывания, каждый бит, начиная с младшего (всего три младших бита, как и в PULLUPS),
|
||||
равен нулю, если для соответствующего триггера срабатывание при перепаде 1->0, равен единице, если при
|
||||
перепаде 0->1.
|
||||
TRIGPAUSE - пауза между срабатываниями триггера: если после срабатывания произойдет следующее событие за интервал, меньший
|
||||
данного, это событие учитываться не будет.
|
||||
- time - отображает текущее время так, как оно бы отобразилось при срабатывании триггера, например,
|
||||
55725.961 (15:28:45)
|
||||
ВРЕМЯ ИЗМЕРЯЕТСЯ В UTC!!! Первое число - количество секунд и миллисекунд с начала суток по UTC, в скобках
|
||||
указывается человекочитаемое время.
|
||||
- store - сохранить новую конфигурацию во флеш-памяти МК.
|
||||
- triglevelNS - рабочий уровень триггера. Здесь N - номер триггера (0..2), S - уровень (0/1). Скажем, чтобы триггер 0 срабатывал
|
||||
при перепаде 1->0, нужно написать команду
|
||||
triglevel00
|
||||
а чтобы триггер 2 срабатывал при перепаде 0->1,
|
||||
triglevel21
|
||||
- trigpauseNP - задать паузу для триггера N, пауза в миллисекундах. Если написать 0, паузы не будет и каждое срабатывание
|
||||
будет вызывать соответствующее сообщение. Эта пауза нужнад для защиты от "звона" и нескольких срабатываний на "дырках"
|
||||
в объекте. Меньше 50мс лучше не делать.
|
||||
- trigtimeN - отображение последнего времени срабатывания триггера N, например, на запрос trigtime0, может быть выведено:
|
||||
TRIG0=45212.930 (12:33:32)
|
||||
Если срабатываний с момента включения не было, выведутся нули:
|
||||
TRIG4=0.000 (00:00:00)
|
||||
|
||||
После изменения конфигурации и ее сохранения необходимо нажатием на reset или отключением/включением питания перезагрузить МК,
|
||||
т.к. некоторые параметры активируются лишь при старте.
|
||||
|
||||
72
F1:F103/deprecated/chronometer/adc.c
Normal file
72
F1:F103/deprecated/chronometer/adc.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is part of the chronometer project.
|
||||
* Copyright 2018 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adc.h"
|
||||
#include "flash.h"
|
||||
#include "hardware.h"
|
||||
|
||||
/**
|
||||
* @brief ADC_array - array for ADC channels with median filtering:
|
||||
* 0 - Rvar
|
||||
* 1 - internal Tsens
|
||||
* 2 - Vref
|
||||
*/
|
||||
uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9];
|
||||
|
||||
/**
|
||||
* @brief getADCval - calculate median value for `nch` channel
|
||||
* @param nch - number of channel
|
||||
* @return
|
||||
*/
|
||||
uint16_t getADCval(int nch){
|
||||
int i, addr = nch;
|
||||
register uint16_t temp;
|
||||
#define PIX_SORT(a,b) do{ if ((a)>(b)) PIX_SWAP((a),(b)); }while(0)
|
||||
#define PIX_SWAP(a,b) do{ temp=(a);(a)=(b);(b)=temp; }while(0)
|
||||
uint16_t p[9];
|
||||
for(i = 0; i < 9; ++i, addr += NUMBER_OF_ADC_CHANNELS) // first we should prepare array for optmed
|
||||
p[i] = ADC_array[addr];
|
||||
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
|
||||
PIX_SORT(p[0], p[1]) ; PIX_SORT(p[3], p[4]) ; PIX_SORT(p[6], p[7]) ;
|
||||
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
|
||||
PIX_SORT(p[0], p[3]) ; PIX_SORT(p[5], p[8]) ; PIX_SORT(p[4], p[7]) ;
|
||||
PIX_SORT(p[3], p[6]) ; PIX_SORT(p[1], p[4]) ; PIX_SORT(p[2], p[5]) ;
|
||||
PIX_SORT(p[4], p[7]) ; PIX_SORT(p[4], p[2]) ; PIX_SORT(p[6], p[4]) ;
|
||||
PIX_SORT(p[4], p[2]) ;
|
||||
return p[4];
|
||||
#undef PIX_SORT
|
||||
#undef PIX_SWAP
|
||||
}
|
||||
|
||||
// return MCU temperature (degrees of celsius * 10)
|
||||
int32_t getMCUtemp(){
|
||||
// Temp = (V25 - Vsense)/Avg_Slope + 25
|
||||
// V_25 = 1.45V, Slope = 4.3e-3
|
||||
uint32_t Vsense = getVdd() * getADCval(ADC_TMCU_CHANNEL);
|
||||
int32_t temperature = 593920 - (int32_t)Vsense; // 593920 == 145*4096
|
||||
temperature /= 172; // == /(4096*10*4.3e-3), 10 - to convert from *100 to *10
|
||||
temperature += 250;
|
||||
return(temperature);
|
||||
}
|
||||
|
||||
// return Vdd * 100 (V)
|
||||
uint32_t getVdd(){
|
||||
uint32_t vdd = 120 * 4096; // 1.2V
|
||||
vdd /= getADCval(ADC_VDD_CHANNEL);
|
||||
return vdd;
|
||||
}
|
||||
32
F1:F103/deprecated/chronometer/adc.h
Normal file
32
F1:F103/deprecated/chronometer/adc.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of the chronometer project.
|
||||
* Copyright 2018 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef ADC_H
|
||||
#define ADC_H
|
||||
#include "stm32f1.h"
|
||||
|
||||
// interval of trigger's shot (>min && <max), maybe negative
|
||||
#define ADC_MIN_VAL (1024)
|
||||
#define ADC_MAX_VAL (3072)
|
||||
// 2*ADC_THRESHOLD = hysteresis width
|
||||
#define ADC_THRESHOLD (50)
|
||||
|
||||
extern uint16_t ADC_array[];
|
||||
int32_t getMCUtemp();
|
||||
uint32_t getVdd();
|
||||
uint16_t getADCval(int nch);
|
||||
#endif // ADC_H
|
||||
BIN
F1:F103/deprecated/chronometer/chrono.bin
Normal file
BIN
F1:F103/deprecated/chronometer/chrono.bin
Normal file
Binary file not shown.
318
F1:F103/deprecated/chronometer/flash.c
Normal file
318
F1:F103/deprecated/chronometer/flash.c
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* 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 "adc.h"
|
||||
#include "flash.h"
|
||||
#include "lidar.h"
|
||||
#include "str.h"
|
||||
#include "usart.h" // DBG
|
||||
#include "usb.h" // printout
|
||||
#include <string.h> // memcpy
|
||||
|
||||
// max amount of records stored: Config & Logs
|
||||
uint32_t maxCnum = FLASH_BLOCK_SIZE / sizeof(user_conf);
|
||||
uint32_t maxLnum = FLASH_BLOCK_SIZE / sizeof(user_conf);
|
||||
|
||||
// common structure for all datatypes stored
|
||||
/*typedef struct {
|
||||
uint16_t userconf_sz;
|
||||
} flash_storage;*/
|
||||
|
||||
#define USERCONF_INITIALIZER { \
|
||||
.userconf_sz = sizeof(user_conf) \
|
||||
,.dist_min = LIDAR_MIN_DIST \
|
||||
,.dist_max = LIDAR_MAX_DIST \
|
||||
,.trigstate = 0 \
|
||||
,.trigpause = {400, 400, 400, 300} \
|
||||
,.USART_speed = USART1_DEFAULT_SPEED \
|
||||
,.LIDAR_speed = LIDAR_DEFAULT_SPEED \
|
||||
,.defflags = 0 \
|
||||
,.NLfreeWarn = 100 \
|
||||
}
|
||||
|
||||
// change to placement
|
||||
/*
|
||||
__attribute__ ((section(".logs"))) const uint32_t *logsstart;
|
||||
__attribute__ ((section(".myvars"))) const user_conf *Flash_Data;
|
||||
*/
|
||||
|
||||
static int erase_flash(const void*, const void*);
|
||||
static int write2flash(const void*, const void*, uint32_t);
|
||||
|
||||
const user_conf *Flash_Data = (const user_conf *)&__varsstart;
|
||||
const event_log *logsstart = (event_log*) &__logsstart;
|
||||
TODO("Add to event_log a comment - up to 8 chars")
|
||||
|
||||
user_conf the_conf = USERCONF_INITIALIZER;
|
||||
|
||||
static int currentconfidx = -1; // index of current configuration
|
||||
static int currentlogidx = -1; // index of current logs record
|
||||
|
||||
/**
|
||||
* @brief binarySearch - binary search in flash for last non-empty cell
|
||||
* any struct searched should have its sizeof() @ the first field!!!
|
||||
* @param l - left index
|
||||
* @param r - right index (should be @1 less than last index!)
|
||||
* @param start - starting address
|
||||
* @param stor_size - size of structure to search
|
||||
* @return index of non-empty cell or -1
|
||||
*/
|
||||
static int binarySearch(int r, const uint8_t *start, int stor_size){
|
||||
int l = 0;
|
||||
while(r >= l){
|
||||
int mid = l + (r - l) / 2;
|
||||
const uint8_t *s = start + mid * stor_size;
|
||||
if(*((const uint16_t*)s) == stor_size){
|
||||
if(*((const uint16_t*)(s + stor_size)) == 0xffff){
|
||||
return mid;
|
||||
}else{ // element is to the right
|
||||
l = mid + 1;
|
||||
}
|
||||
}else{ // element is to the left
|
||||
r = mid - 1;
|
||||
}
|
||||
}
|
||||
return -1; // not found
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief flashstorage_init - initialization of user conf & logs storage
|
||||
* run in once @ start
|
||||
*/
|
||||
void flashstorage_init(){
|
||||
maxCnum = ((uint32_t)&_varslen) / sizeof(user_conf);
|
||||
//SEND("maxCnum="); printu(1, maxCnum);
|
||||
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
|
||||
uint32_t flsz = FLASH_SIZE * 1024; // size in bytes
|
||||
flsz -= (uint32_t)logsstart - FLASH_BASE;
|
||||
maxLnum = flsz / sizeof(event_log);
|
||||
//SEND("\nmaxLnum="); printu(1, maxLnum);
|
||||
}
|
||||
// -1 if there's no data at all & flash is clear; maxnum-1 if flash is full
|
||||
currentconfidx = binarySearch((int)maxCnum-2, (const uint8_t*)Flash_Data, sizeof(user_conf));
|
||||
if(currentconfidx > -1){
|
||||
memcpy(&the_conf, &Flash_Data[currentconfidx], sizeof(user_conf));
|
||||
}
|
||||
currentlogidx = binarySearch((int)maxLnum-2, (const uint8_t*)logsstart, sizeof(event_log));
|
||||
}
|
||||
|
||||
// store new configuration
|
||||
// @return 0 if all OK
|
||||
int store_userconf(){
|
||||
// maxnum - 3 means that there always should be at least one empty record after last data
|
||||
// for binarySearch() checking that there's nothing more after it!
|
||||
if(currentconfidx > (int)maxCnum - 3){ // there's no more place
|
||||
currentconfidx = 0;
|
||||
DBG("Need to erase flash!");
|
||||
if(erase_flash(Flash_Data, logsstart)) return 1;
|
||||
}else ++currentconfidx; // take next data position (0 - within first run after firmware flashing)
|
||||
return write2flash((const void*)&Flash_Data[currentconfidx], &the_conf, sizeof(the_conf));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief store_log - save log record L into flash memory
|
||||
* @param L - event log (or NULL to delete flash)
|
||||
* @return 0 if all OK
|
||||
*/
|
||||
int store_log(event_log *L){
|
||||
if(!L){
|
||||
currentlogidx = -1;
|
||||
return erase_flash(logsstart, NULL);
|
||||
}
|
||||
if(currentlogidx > (int)maxLnum - 3){ // there's no more place
|
||||
/*currentlogidx = 0;
|
||||
DBG("Need to erase flash!");
|
||||
if(erase_flash(logsstart, NULL)) return 1;*/
|
||||
// prevent automatic logs erasing!
|
||||
sendstring("\n\nERROR!\nCan't save logs: delete old manually!!!\n");
|
||||
return 1;
|
||||
}else ++currentlogidx; // take next data position (0 - within first run after firmware flashing)
|
||||
// put warning if there's little space
|
||||
if(currentlogidx + the_conf.NLfreeWarn > (int)maxLnum - 3){
|
||||
uint32_t nfree = maxLnum - 2 - (uint32_t)currentlogidx;
|
||||
sendstring("\n\nWARNING!\nCan store only ");
|
||||
sendstring(u2str(nfree));
|
||||
sendstring(" logs!\n\n");
|
||||
}
|
||||
return write2flash(&logsstart[currentlogidx], L, sizeof(event_log));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief dump_log - dump N log records
|
||||
* @param start - first record to show (if start<0, then first=last+start)
|
||||
* @param Nlogs - amount of logs to show (if Nlogs<=0, then show all logs)
|
||||
* @return 0 if all OK, 1 if there's no logs in flash
|
||||
*/
|
||||
int dump_log(int start, int Nlogs){
|
||||
if(currentlogidx < 0) return 1;
|
||||
if(start < 0){
|
||||
start += currentlogidx + 1;
|
||||
if(start < 0) start = 0;
|
||||
}
|
||||
if(start > currentlogidx) return 1;
|
||||
int nlast;
|
||||
if(Nlogs > 0){
|
||||
nlast = start + Nlogs - 1;
|
||||
if(nlast > currentlogidx) nlast = currentlogidx;
|
||||
}else nlast = currentlogidx;
|
||||
++nlast;
|
||||
const event_log *l = logsstart + start;
|
||||
for(int i = start; i < nlast; ++i, ++l){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
sendstring(get_trigger_shot(i, l));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write2flash(const void *start, const void *wrdata, uint32_t stor_size){
|
||||
int ret = 0;
|
||||
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){
|
||||
DBG("Can't remove write protection");
|
||||
return 1; // write protection
|
||||
}
|
||||
FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; // clear all flags
|
||||
FLASH->CR |= FLASH_CR_PG;
|
||||
const uint16_t *data = (const uint16_t*) wrdata;
|
||||
volatile uint16_t *address = (volatile uint16_t*) start;
|
||||
uint32_t i, count = (stor_size + 1) / 2;
|
||||
for (i = 0; i < count; ++i){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
*(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
|
||||
DBG("FLASH_SR_PGERR");
|
||||
break;
|
||||
}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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief erase_flash - erase N pages of flash memory
|
||||
* @param start - first address
|
||||
* @param end - last address (or NULL if need to erase all flash remaining)
|
||||
* @return 0 if succeed
|
||||
*/
|
||||
static int erase_flash(const void *start, const void *end){
|
||||
int ret = 0;
|
||||
uint32_t nblocks = 1, flsz = 0;
|
||||
if(!end){ // erase all remaining
|
||||
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
|
||||
flsz = FLASH_SIZE * 1024; // size in bytes
|
||||
flsz -= (uint32_t)start - FLASH_BASE;
|
||||
}
|
||||
}else{ // erase a part
|
||||
flsz = (uint32_t)end - (uint32_t)start;
|
||||
}
|
||||
nblocks = flsz / FLASH_BLOCK_SIZE;
|
||||
if(nblocks == 0 || nblocks >= FLASH_SIZE) return 1;
|
||||
for(uint32_t i = 0; i < nblocks; ++i){
|
||||
#ifdef EBUG
|
||||
SEND("Try to erase page #"); printu(1,i); newline(1);
|
||||
#endif
|
||||
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) */
|
||||
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);
|
||||
SEND("\ndist_min="); printu(1, the_conf.dist_min);
|
||||
SEND("\ndist_max="); printu(1, the_conf.dist_max);
|
||||
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){
|
||||
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(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
SEND("Curr idx: "); printu(1, currentconfidx); newline(1);
|
||||
}
|
||||
|
||||
#endif
|
||||
88
F1:F103/deprecated/chronometer/flash.h
Normal file
88
F1:F103/deprecated/chronometer/flash.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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>
|
||||
#include "hardware.h"
|
||||
|
||||
#define FLASH_BLOCK_SIZE (1024)
|
||||
#define FLASH_SIZE_REG ((uint32_t)0x1FFFF7E0)
|
||||
#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG)
|
||||
|
||||
/*
|
||||
* struct to save user configurations
|
||||
*/
|
||||
typedef struct __attribute__((packed, aligned(4))){
|
||||
uint16_t userconf_sz; // "magick number"
|
||||
uint16_t NLfreeWarn; // warn user when there's less free log records than NLfreeWarn
|
||||
uint8_t trigstate; // level in `triggered` state
|
||||
uint8_t defflags; // default flags
|
||||
uint16_t dist_min; // minimal distance for LIDAR
|
||||
uint16_t dist_max; // maximal -//-
|
||||
uint32_t USART_speed; // USART1 speed (115200 by default)
|
||||
uint32_t LIDAR_speed; // USART3 speed (115200 by default)
|
||||
uint16_t trigpause[TRIGGERS_AMOUNT]; // pause (ms) for false shots
|
||||
} user_conf;
|
||||
|
||||
// values for user_conf.defflags:
|
||||
// save events in flash
|
||||
#define FLAG_SAVE_EVENTS (1 << 0)
|
||||
// strings ends with "\r\n" instead of normal "\n"
|
||||
#define FLAG_STRENDRN (1 << 1)
|
||||
// proxy GPS messages over USART1
|
||||
#define FLAG_GPSPROXY (1 << 2)
|
||||
// USART3 works as regular TTY instead of LIDAR
|
||||
#define FLAG_NOLIDAR (1 << 3)
|
||||
|
||||
/*
|
||||
* struct to save events logs
|
||||
*/
|
||||
typedef struct __attribute__((packed, aligned(4))){
|
||||
uint16_t elog_sz;
|
||||
uint8_t trigno;
|
||||
trigtime shottime;
|
||||
int16_t triglen;
|
||||
uint16_t lidar_dist;
|
||||
} event_log;
|
||||
|
||||
extern user_conf the_conf;
|
||||
extern const user_conf *Flash_Data;
|
||||
extern const event_log *logsstart;
|
||||
extern uint32_t maxCnum, maxLnum;
|
||||
// data from ld-file
|
||||
extern uint32_t _varslen, __varsstart, __logsstart;
|
||||
|
||||
|
||||
void flashstorage_init();
|
||||
int store_userconf();
|
||||
int store_log(event_log *L);
|
||||
int dump_log(int start, int Nlogs);
|
||||
|
||||
#ifdef EBUG
|
||||
void dump_userconf();
|
||||
void addNrecs(int N);
|
||||
#endif
|
||||
|
||||
#endif // __FLASH_H__
|
||||
248
F1:F103/deprecated/chronometer/hardware.c
Normal file
248
F1:F103/deprecated/chronometer/hardware.c
Normal file
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* hardware.c - hardware-dependent macros & functions
|
||||
*
|
||||
* Copyright 2018 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "adc.h"
|
||||
#include "flash.h"
|
||||
#include "hardware.h"
|
||||
#include "lidar.h"
|
||||
#include "str.h"
|
||||
#include "time.h"
|
||||
#include "usart.h"
|
||||
|
||||
#include <string.h> // memcpy
|
||||
|
||||
uint8_t buzzer_on = 1; // buzzer ON by default
|
||||
uint8_t LEDSon = 1; // LEDS are working
|
||||
// ports of triggers
|
||||
static GPIO_TypeDef *trigport[DIGTRIG_AMOUNT] = {GPIOA, GPIOA, GPIOA};
|
||||
// pins of triggers: PA13, PA14, PA4
|
||||
static uint16_t trigpin[DIGTRIG_AMOUNT] = {1<<13, 1<<14, 1<<4};
|
||||
// value of pin in `triggered` state
|
||||
static uint8_t trigstate[DIGTRIG_AMOUNT];
|
||||
// time of triggers shot
|
||||
trigtime shottime[TRIGGERS_AMOUNT];
|
||||
// Tms value when they shot
|
||||
uint32_t shotms[TRIGGERS_AMOUNT];
|
||||
// trigger length (-1 if > MAX_TRIG_LEN)
|
||||
int16_t triglen[TRIGGERS_AMOUNT];
|
||||
// if trigger[N] shots, the bit N will be 1
|
||||
uint8_t trigger_shot = 0;
|
||||
|
||||
static inline void gpio_setup(){
|
||||
BUZZER_OFF(); // turn off buzzer @start
|
||||
LED_on(); // turn ON LED0 @start
|
||||
LED1_off(); // turn off LED1 @start
|
||||
USBPU_OFF(); // turn off USB pullup @start
|
||||
// Enable clocks to the GPIO subsystems (PB for ADC), turn on AFIO clocking enable EXTI & so on
|
||||
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, PA15 - USB pullup
|
||||
GPIOA->ODR = (1<<1)|(1<<15);
|
||||
// buzzer (PC13): pushpull output
|
||||
GPIOC->CRH = CRH(13, CNF_PPOUTPUT|MODE_SLOW);
|
||||
// Set leds (PB8/9) 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 USB pullup (PA15) - opendrain output
|
||||
GPIOA->CRH = CRH(15, CNF_ODOUTPUT|MODE_SLOW);
|
||||
// Trigger 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; // mask PA1
|
||||
// interrupt on pulse front: buttons - 1->0, PPS - 0->1
|
||||
EXTI->RTSR = EXTI_RTSR_TR1; // rising trigger for PPS
|
||||
// PA4/PA13/PA14 - triggers
|
||||
for(int i = 0; i < DIGTRIG_AMOUNT; ++i){
|
||||
uint16_t pin = trigpin[i];
|
||||
// fill trigstate array
|
||||
uint8_t trgs = (the_conf.trigstate & (1<<i)) ? 1 : 0;
|
||||
trigstate[i] = trgs;
|
||||
trigport[i]->ODR |= pin; // turn on pullups
|
||||
EXTI->IMR |= pin;
|
||||
if(trgs){ // triggered @1 -> rising interrupt
|
||||
EXTI->RTSR |= pin;
|
||||
}else{ // falling interrupt
|
||||
EXTI->FTSR |= pin;
|
||||
}
|
||||
}
|
||||
NVIC_EnableIRQ(EXTI4_IRQn);
|
||||
NVIC_EnableIRQ(EXTI15_10_IRQn);
|
||||
NVIC_EnableIRQ(EXTI1_IRQn); // enable PPS interrupt
|
||||
}
|
||||
|
||||
static inline void adc_setup(){
|
||||
GPIOB->CRL |= CRL(0, CNF_ANALOG|MODE_INPUT);
|
||||
uint32_t ctr = 0;
|
||||
// Enable clocking
|
||||
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
|
||||
RCC->CFGR &= ~(RCC_CFGR_ADCPRE);
|
||||
RCC->CFGR |= RCC_CFGR_ADCPRE_DIV8; // ADC clock = RCC / 8
|
||||
// sampling time - 239.5 cycles for channels 16 and 17
|
||||
ADC1->SMPR1 = ADC_SMPR1_SMP16 | ADC_SMPR1_SMP17;
|
||||
// we have three conversions in group -> ADC1->SQR1[L] = 2, order: 16->17
|
||||
// Tsens == 16, Vdd == 17
|
||||
ADC1->SQR3 = (16<<0) | (17<<5);
|
||||
ADC1->SQR1 = ADC_SQR1_L_0; // 2 conversions
|
||||
ADC1->CR1 |= ADC_CR1_SCAN; // scan mode
|
||||
// DMA configuration
|
||||
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
|
||||
DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR));
|
||||
DMA1_Channel1->CMAR = (uint32_t)(ADC_array);
|
||||
DMA1_Channel1->CNDTR = NUMBER_OF_ADC_CHANNELS * 9;
|
||||
DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0
|
||||
| DMA_CCR_CIRC | DMA_CCR_PL | DMA_CCR_EN;
|
||||
// continuous mode & DMA; enable vref & Tsens; wake up ADC
|
||||
ADC1->CR2 |= ADC_CR2_DMA | ADC_CR2_TSVREFE | ADC_CR2_CONT | ADC_CR2_ADON;
|
||||
// wait for Tstab - at least 1us
|
||||
while(++ctr < 0xff) nop();
|
||||
// calibration
|
||||
ADC1->CR2 |= ADC_CR2_RSTCAL;
|
||||
ctr = 0; while((ADC1->CR2 & ADC_CR2_RSTCAL) && ++ctr < 0xfffff);
|
||||
ADC1->CR2 |= ADC_CR2_CAL;
|
||||
ctr = 0; while((ADC1->CR2 & ADC_CR2_CAL) && ++ctr < 0xfffff);
|
||||
// turn ON ADC
|
||||
ADC1->CR2 |= ADC_CR2_ADON;
|
||||
}
|
||||
|
||||
void hw_setup(){
|
||||
gpio_setup();
|
||||
adc_setup();
|
||||
}
|
||||
|
||||
static trigtime trgtm;
|
||||
void savetrigtime(){
|
||||
trgtm.millis = Timer;
|
||||
memcpy(&trgtm.Time, ¤t_time, sizeof(curtime));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief fillshotms - save trigger shot time
|
||||
* @param i - trigger number
|
||||
*/
|
||||
void fillshotms(int i){
|
||||
if(i < 0 || i >= TRIGGERS_AMOUNT) return;
|
||||
if(Tms - shotms[i] > (uint32_t)the_conf.trigpause[i] || i == LIDAR_TRIGGER){
|
||||
memcpy(&shottime[i], &trgtm, sizeof(trigtime));
|
||||
shotms[i] = Tms;
|
||||
trigger_shot |= 1<<i;
|
||||
BUZZER_ON();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief fillunshotms - calculate trigger length time
|
||||
*/
|
||||
void fillunshotms(){
|
||||
if(!trigger_shot) return;
|
||||
uint8_t X = 1;
|
||||
for(int i = 0; i < TRIGGERS_AMOUNT; ++i, X<<=1){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
// check whether trigger is OFF but shot recently
|
||||
if(trigger_shot & X){
|
||||
uint32_t len = Tms - shotms[i];
|
||||
uint8_t rdy = 0;
|
||||
if(len > MAX_TRIG_LEN){
|
||||
triglen[i] = -1;
|
||||
rdy = 1;
|
||||
}else triglen[i] = (int16_t) len;
|
||||
if(i == LIDAR_TRIGGER){
|
||||
if(!parse_lidar_data(NULL)) rdy = 1;
|
||||
}else{
|
||||
uint8_t pinval = (trigport[i]->IDR & trigpin[i]) ? 1 : 0;
|
||||
if(pinval != trigstate[i]) rdy = 1; // trigger is OFF
|
||||
}
|
||||
if(rdy){
|
||||
if(i != LIDAR_TRIGGER) shotms[i] = Tms;
|
||||
show_trigger_shot(X);
|
||||
trigger_shot &= ~X;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void exti1_isr(){ // PPS - PA1
|
||||
systick_correction();
|
||||
LED_off(); // turn off LED0 @ each PPS
|
||||
EXTI->PR = EXTI_PR_PR1;
|
||||
}
|
||||
|
||||
void exti4_isr(){ // PA4 - trigger[2]
|
||||
savetrigtime();
|
||||
fillshotms(2);
|
||||
EXTI->PR = EXTI_PR_PR4;
|
||||
}
|
||||
|
||||
void exti15_10_isr(){ // PA13 - trigger[0], PA14 - trigger[1]
|
||||
savetrigtime();
|
||||
if(EXTI->PR & EXTI_PR_PR13){
|
||||
fillshotms(0);
|
||||
EXTI->PR = EXTI_PR_PR13;
|
||||
}
|
||||
if(EXTI->PR & EXTI_PR_PR14){
|
||||
fillshotms(1);
|
||||
EXTI->PR = EXTI_PR_PR14;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EBUG
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
#endif
|
||||
|
||||
void chk_buzzer(){
|
||||
static uint32_t Ton = 0; // Time of first buzzer check
|
||||
if(!BUZZER_GET()) return; // buzzer if OFF
|
||||
if(!trigger_shot){ // should we turn off buzzer?
|
||||
uint8_t notrg = 1;
|
||||
for(int i = 0; i < DIGTRIG_AMOUNT; ++i){
|
||||
uint8_t curval = (trigport[i]->IDR & trigpin[i]) ? 1 : 0;
|
||||
if(curval == trigstate[i]){
|
||||
notrg = 0; // cheep while digital trigger is ON
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(notrg){ // turn off buzzer when there's no trigger events & timeout came
|
||||
if(Tms - Ton < BUZZER_CHEEP_TIME) return;
|
||||
Ton = 0;
|
||||
BUZZER_OFF();
|
||||
}
|
||||
}else{ // buzzer is ON - check timer
|
||||
if(Ton == 0){
|
||||
Ton = Tms;
|
||||
if(!Ton) Ton = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
116
F1:F103/deprecated/chronometer/hardware.h
Normal file
116
F1:F103/deprecated/chronometer/hardware.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* hardware.h
|
||||
*
|
||||
* Copyright 2018 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 __HARDWARE_H__
|
||||
#define __HARDWARE_H__
|
||||
|
||||
#include "stm32f1.h"
|
||||
#include "time.h"
|
||||
|
||||
#ifdef EBUG
|
||||
#define DO_PRAGMA(x) _Pragma (#x)
|
||||
#define TODO(x) DO_PRAGMA(message #x)
|
||||
#else
|
||||
#define TODO(x)
|
||||
#endif
|
||||
|
||||
// only 2 ADC channels used: Tmcu and Vdd
|
||||
#define NUMBER_OF_ADC_CHANNELS (2)
|
||||
#define ADC_TMCU_CHANNEL (0)
|
||||
#define ADC_VDD_CHANNEL (1)
|
||||
|
||||
// onboard LEDs - PB8/PB9
|
||||
#define LED0_port GPIOB
|
||||
#define LED0_pin (1<<9)
|
||||
#define LED1_port GPIOB
|
||||
#define LED1_pin (1<<8)
|
||||
|
||||
// buzzer (1 - active) - PC13
|
||||
extern uint8_t buzzer_on;
|
||||
#define BUZZER_port GPIOC
|
||||
#define BUZZER_pin (1<<13)
|
||||
#define BUZZER_ON() do{if(buzzer_on)pin_set(BUZZER_port, BUZZER_pin);}while(0)
|
||||
#define BUZZER_OFF() pin_clear(BUZZER_port, BUZZER_pin)
|
||||
#define BUZZER_GET() (pin_read(BUZZER_port, BUZZER_pin))
|
||||
// minimal time to buzzer to cheep (ms)
|
||||
#define BUZZER_CHEEP_TIME 500
|
||||
|
||||
// PPS pin - PA1
|
||||
#define PPS_port GPIOA
|
||||
#define PPS_pin (1<<1)
|
||||
|
||||
// PPS and triggers state
|
||||
// amount of triggers, should be less than 9; 4 - 0..2 - switches, 3 - LIDAR
|
||||
#define TRIGGERS_AMOUNT 4
|
||||
// number of LIDAR trigger
|
||||
#define LIDAR_TRIGGER 3
|
||||
// amount of digital triggers (on interrupts)
|
||||
#define DIGTRIG_AMOUNT 3
|
||||
// max length of trigger event (ms)
|
||||
#define MAX_TRIG_LEN 1000
|
||||
|
||||
#ifdef EBUG
|
||||
uint8_t gettrig(uint8_t N);
|
||||
#endif
|
||||
void fillshotms(int i);
|
||||
void fillunshotms();
|
||||
void savetrigtime();
|
||||
#define GET_PPS() ((GPIOA->IDR & (1<<1)) ? 1 : 0)
|
||||
|
||||
// USB pullup - PA15
|
||||
#define USBPU_port GPIOA
|
||||
#define USBPU_pin (1<<15)
|
||||
#define USBPU_ON() pin_clear(USBPU_port, USBPU_pin)
|
||||
#define USBPU_OFF() pin_set(USBPU_port, USBPU_pin)
|
||||
|
||||
#define LED_blink() do{if(LEDSon)pin_toggle(LED0_port, LED0_pin);}while(0)
|
||||
#define LED_on() do{if(LEDSon)pin_clear(LED0_port, LED0_pin);}while(0)
|
||||
#define LED_off() do{pin_set(LED0_port, LED0_pin);}while(0)
|
||||
#define LED1_blink() do{if(LEDSon)pin_toggle(LED1_port, LED1_pin);}while(0)
|
||||
#define LED1_on() do{if(LEDSon)pin_clear(LED1_port, LED1_pin);}while(0)
|
||||
#define LED1_off() do{pin_set(LED1_port, LED1_pin);}while(0)
|
||||
|
||||
// GPS USART == USART2, LIDAR USART == USART3
|
||||
#define GPS_USART (2)
|
||||
#define LIDAR_USART (3)
|
||||
|
||||
typedef struct{
|
||||
uint32_t millis;
|
||||
curtime Time;
|
||||
} trigtime;
|
||||
|
||||
// turn on/off LEDs:
|
||||
extern uint8_t LEDSon;
|
||||
// time of triggers shot
|
||||
extern trigtime shottime[TRIGGERS_AMOUNT];
|
||||
// length (in ms) of trigger event (-1 if > MAX_TRIG_LEN
|
||||
extern int16_t triglen[TRIGGERS_AMOUNT];
|
||||
// if trigger[N] shots, the bit N will be 1
|
||||
extern uint8_t trigger_shot;
|
||||
// Tms value when they shot
|
||||
extern uint32_t shotms[TRIGGERS_AMOUNT];
|
||||
|
||||
void chk_buzzer();
|
||||
void hw_setup();
|
||||
|
||||
#endif // __HARDWARE_H__
|
||||
81
F1:F103/deprecated/chronometer/lidar.c
Normal file
81
F1:F103/deprecated/chronometer/lidar.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This file is part of the chronometer project.
|
||||
* Copyright 2019 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "flash.h"
|
||||
#include "lidar.h"
|
||||
#include "usart.h"
|
||||
|
||||
uint16_t last_lidar_dist = 0;
|
||||
uint16_t last_lidar_stren = 0;
|
||||
uint16_t lidar_triggered_dist = 0;
|
||||
|
||||
extern uint32_t shotms[];
|
||||
|
||||
/**
|
||||
* @brief parse_lidar_data - parsing of string from lidar
|
||||
* @param txt - the string or NULL (if you want just check trigger state)
|
||||
* @return trigger state
|
||||
*/
|
||||
uint8_t parse_lidar_data(char *txt){
|
||||
static uint8_t triggered = 0;
|
||||
if(!txt){
|
||||
// clear trigger state after timeout -> need to monitor lidar
|
||||
uint32_t len = Tms - shotms[LIDAR_TRIGGER];
|
||||
//if(len > MAX_TRIG_LEN || len > (uint32_t)the_conf.trigpause[LIDAR_TRIGGER]){
|
||||
if(len > MAX_TRIG_LEN){
|
||||
triggered = 0;
|
||||
DBG("MAX time gone, untrigger!");
|
||||
}
|
||||
return triggered;
|
||||
}
|
||||
last_lidar_dist = txt[2] | (txt[3] << 8);
|
||||
last_lidar_stren = txt[4] | (txt[5] << 8);
|
||||
if(last_lidar_stren < LIDAR_LOWER_STREN) return 0; // weak signal
|
||||
if(!lidar_triggered_dist){ // first run
|
||||
lidar_triggered_dist = last_lidar_dist;
|
||||
return 0;
|
||||
}
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(triggered){ // check if body gone
|
||||
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=");
|
||||
printu(1, last_lidar_dist);
|
||||
SEND(" signal=");
|
||||
printu(1, last_lidar_stren);
|
||||
newline(1);
|
||||
#endif
|
||||
}
|
||||
}else{
|
||||
if(last_lidar_dist > the_conf.dist_min && last_lidar_dist < the_conf.dist_max){
|
||||
savetrigtime();
|
||||
triggered = 1;
|
||||
lidar_triggered_dist = last_lidar_dist;
|
||||
fillshotms(LIDAR_TRIGGER);
|
||||
#ifdef EBUG
|
||||
SEND("Triggered! distance=");
|
||||
printu(1, last_lidar_dist);
|
||||
SEND(" signal=");
|
||||
printu(1, last_lidar_stren);
|
||||
newline(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return triggered;
|
||||
}
|
||||
39
F1:F103/deprecated/chronometer/lidar.h
Normal file
39
F1:F103/deprecated/chronometer/lidar.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of the chronometer project.
|
||||
* Copyright 2019 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef LIDAR_H__
|
||||
#define LIDAR_H__
|
||||
#include <stm32f1.h>
|
||||
|
||||
#define LIDAR_FRAME_LEN (9)
|
||||
// frame header
|
||||
#define LIDAR_FRAME_HEADER (0x59)
|
||||
// lower strength limit
|
||||
#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;
|
||||
|
||||
uint8_t parse_lidar_data(char *txt);
|
||||
|
||||
#endif // LIDAR_H__
|
||||
364
F1:F103/deprecated/chronometer/main.c
Normal file
364
F1:F103/deprecated/chronometer/main.c
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* main.c
|
||||
*
|
||||
* Copyright 2017 Edward V. Emelianoff <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.
|
||||
*/
|
||||
|
||||
#include "adc.h"
|
||||
#include "GPS.h"
|
||||
#include "flash.h"
|
||||
#include "hardware.h"
|
||||
#include "lidar.h"
|
||||
#include "str.h"
|
||||
#include "time.h"
|
||||
#include "usart.h"
|
||||
#include "usb.h"
|
||||
#include "usb_lib.h"
|
||||
|
||||
#ifndef VERSION
|
||||
#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 pseudo-milliseconds counter
|
||||
if(++Timer == 1000){ // increment milliseconds counter
|
||||
time_increment();
|
||||
}
|
||||
}
|
||||
|
||||
void iwdg_setup(){
|
||||
uint32_t tmout = 16000000;
|
||||
/* Enable the peripheral clock RTC */
|
||||
/* (1) Enable the LSI (40kHz) */
|
||||
/* (2) Wait while it is not ready */
|
||||
RCC->CSR |= RCC_CSR_LSION; /* (1) */
|
||||
while((RCC->CSR & RCC_CSR_LSIRDY) != RCC_CSR_LSIRDY){if(--tmout == 0) break;} /* (2) */
|
||||
/* Configure IWDG */
|
||||
/* (1) Activate IWDG (not needed if done in option bytes) */
|
||||
/* (2) Enable write access to IWDG registers */
|
||||
/* (3) Set prescaler by 64 (1.6ms for each tick) */
|
||||
/* (4) Set reload value to have a rollover each 2s */
|
||||
/* (5) Check if flags are reset */
|
||||
/* (6) Refresh counter */
|
||||
IWDG->KR = IWDG_START; /* (1) */
|
||||
IWDG->KR = IWDG_WRITE_ACCESS; /* (2) */
|
||||
IWDG->PR = IWDG_PR_PR_1; /* (3) */
|
||||
IWDG->RLR = 1250; /* (4) */
|
||||
tmout = 16000000;
|
||||
while(IWDG->SR){if(--tmout == 0) break;} /* (5) */
|
||||
IWDG->KR = IWDG_REFRESH; /* (6) */
|
||||
}
|
||||
|
||||
#if 0
|
||||
char *parse_cmd(char *buf){
|
||||
int32_t N;
|
||||
static char btns[] = "BTN0=0, BTN1=0, BTN2=0, PPS=0\n";
|
||||
event_log l = {.elog_sz = sizeof(event_log), .trigno = 2};
|
||||
switch(*buf){
|
||||
case '0':
|
||||
LED1_off(); // LED1 off @dbg
|
||||
break;
|
||||
case '1':
|
||||
LED1_on(); // LED1 on @dbg
|
||||
break;
|
||||
case 'a':
|
||||
l.shottime.Time = current_time;
|
||||
l.shottime.millis = Timer;
|
||||
l.triglen = getADCval(1);
|
||||
if(store_log(&l)) SEND("Error storing");
|
||||
else SEND("Store OK");
|
||||
newline(1);
|
||||
break;
|
||||
case 'b':
|
||||
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':
|
||||
DBG("Send cold start");
|
||||
GPS_send_FullColdStart();
|
||||
break;
|
||||
case 'C':
|
||||
if(getnum(&buf[1], &N)){
|
||||
SEND("Need a number!\n");
|
||||
}else{
|
||||
addNrecs(N);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
dump_userconf();
|
||||
break;
|
||||
case 'D':
|
||||
if(dump_log(0, -1)) DBG("Error dumping log: empty?");
|
||||
break;
|
||||
case 'p':
|
||||
pin_toggle(USBPU_port, USBPU_pin);
|
||||
SEND("USB pullup is ");
|
||||
if(pin_read(USBPU_port, USBPU_pin)) SEND("off");
|
||||
else SEND("on");
|
||||
newline(1);
|
||||
break;
|
||||
case 'G':
|
||||
SEND("LIDAR_DIST=");
|
||||
printu(1, last_lidar_dist);
|
||||
SEND(", LIDAR_STREN=");
|
||||
printu(1, last_lidar_stren);
|
||||
newline(1);
|
||||
break;
|
||||
case 'L':
|
||||
sendstring("Very long test string for USB (it's length is more than 64 bytes).\n"
|
||||
"This is another part of the string! Can you see all of this?\n");
|
||||
return "Long test sent\n";
|
||||
break;
|
||||
case 'R':
|
||||
sendstring("Soft reset\n");
|
||||
SEND("Soft reset\n");
|
||||
NVIC_SystemReset();
|
||||
break;
|
||||
case 'S':
|
||||
sendstring("Test string for USB\n");
|
||||
return "Short test sent\n";
|
||||
break;
|
||||
case 'T':
|
||||
SEND(get_time(¤t_time, get_millis()));
|
||||
break;
|
||||
case 'W':
|
||||
sendstring("Wait for reboot\n");
|
||||
SEND("Wait for reboot\n");
|
||||
while(1){nop();}
|
||||
break;
|
||||
default: // help
|
||||
if(buf[1] != '\n') return buf;
|
||||
return
|
||||
"0/1 - turn on/off LED1\n"
|
||||
"'a' - add test log record\n"
|
||||
"'b' - get buttons's state\n"
|
||||
"'c' - send cold start\n"
|
||||
"'d' - dump current user conf\n"
|
||||
"'D' - dump log\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"
|
||||
"'S' - send short string over USB\n"
|
||||
"'T' - show current GPS time\n"
|
||||
"'W' - test watchdog\n"
|
||||
;
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define USBBUF 63
|
||||
// usb getline
|
||||
static char *get_USB(){
|
||||
static char tmpbuf[USBBUF+1], *curptr = tmpbuf;
|
||||
static int rest = USBBUF;
|
||||
int x = USB_receive(curptr, rest);
|
||||
if(!x) return NULL;
|
||||
curptr[x] = 0;
|
||||
if(x == 1 && *curptr == 0x7f){ // backspace
|
||||
if(curptr > tmpbuf){
|
||||
--curptr;
|
||||
USB_send("\b \b");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
USB_send(curptr); // echo
|
||||
if(curptr[x-1] == '\n'){ // || curptr[x-1] == '\r'){
|
||||
curptr = tmpbuf;
|
||||
rest = USBBUF;
|
||||
// omit empty lines
|
||||
if(tmpbuf[0] == '\n') return NULL;
|
||||
// and wrong empty lines
|
||||
if(tmpbuf[0] == '\r' && tmpbuf[1] == '\n') return NULL;
|
||||
return tmpbuf;
|
||||
}
|
||||
curptr += x; rest -= x;
|
||||
if(rest <= 0){ // buffer overflow
|
||||
sendstring("\nUSB buffer overflow!\n");
|
||||
curptr = tmpbuf;
|
||||
rest = USBBUF;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void linecoding_handler(usb_LineCoding __attribute__((unused)) *lc){ // get/set line coding
|
||||
#ifdef EBUG
|
||||
SEND("Change speed to ");
|
||||
printu(1, lc->dwDTERate);
|
||||
newline(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static volatile uint8_t USBconn = 0;
|
||||
uint8_t USB_connected = 0; // need for usb.c
|
||||
void clstate_handler(uint16_t __attribute__((unused)) val){ // lesser bits of val: RTS|DTR
|
||||
USBconn = 1; // if == 1 -> send welcome message
|
||||
USB_connected = 1;
|
||||
#if 0
|
||||
if(val & 2){
|
||||
DBG("RTS set");
|
||||
sendstring("RTS set\n");
|
||||
}
|
||||
if(val & 1){
|
||||
DBG("DTR set");
|
||||
sendstring("DTR set\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void break_handler(){ // client disconnected
|
||||
DBG("Disconnected");
|
||||
USB_connected = 0;
|
||||
}
|
||||
|
||||
int main(void){
|
||||
uint32_t lastT = 0;
|
||||
sysreset();
|
||||
StartHSE();
|
||||
SysTick_Config(SYSTICK_DEFCONF); // function SysTick_Config decrements argument!
|
||||
// read data stored in flash - before all pins/ports setup!!!
|
||||
flashstorage_init();
|
||||
// !!! hw_setup() should be the first in setup stage
|
||||
hw_setup();
|
||||
USB_setup();
|
||||
USBPU_ON();
|
||||
#ifdef EBUG
|
||||
SEND("This is chronometer version " VERSION ".\n");
|
||||
if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured
|
||||
SEND("WDGRESET=1\n");
|
||||
}
|
||||
if(RCC->CSR & RCC_CSR_SFTRSTF){ // software reset occured
|
||||
SEND("SOFTRESET=1\n");
|
||||
}
|
||||
#endif
|
||||
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
|
||||
usarts_setup(); // setup usarts after reading configuration
|
||||
iwdg_setup();
|
||||
|
||||
while (1){
|
||||
IWDG->KR = IWDG_REFRESH; // refresh watchdog
|
||||
if(Timer > 499) LED_on(); // turn ON LED0 over 0.25s after PPS pulse
|
||||
if(USBconn && Tms > 100){ // USB connection
|
||||
USBconn = 0;
|
||||
sendstring("Chronometer version " VERSION ".\n");
|
||||
}
|
||||
// check if triggers that was recently shot are off now
|
||||
fillunshotms();
|
||||
if(Tms - lastT > 499){
|
||||
if(need2startseq) GPS_send_start_seq();
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
switch(GPS_status){
|
||||
case GPS_VALID:
|
||||
LED1_blink(); // blink LED1 @ VALID time
|
||||
break;
|
||||
case GPS_NOT_VALID:
|
||||
LED1_on(); // shine LED1 @ NON-VALID time
|
||||
break;
|
||||
default:
|
||||
LED1_off(); // turn off LED1 if GPS not found or time unknown
|
||||
}
|
||||
lastT = Tms;
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
transmit_tbuf(1); // non-blocking transmission of data from UART buffer every 0.5s
|
||||
transmit_tbuf(GPS_USART);
|
||||
transmit_tbuf(LIDAR_USART);
|
||||
#ifdef EBUG
|
||||
static int32_t oldctr = 0;
|
||||
if(timecntr && timecntr != oldctr){
|
||||
oldctr = timecntr;
|
||||
SEND("ticksdiff=");
|
||||
if(ticksdiff < 0){
|
||||
SEND("-");
|
||||
printu(1, -ticksdiff);
|
||||
}else printu(1, ticksdiff);
|
||||
SEND(", timecntr=");
|
||||
printu(1, timecntr);
|
||||
SEND("\nlast_corr_time=");
|
||||
printu(1, last_corr_time);
|
||||
SEND(", Tms=");
|
||||
printu(1, Tms1);
|
||||
SEND("\nTimer=");
|
||||
printu(1, timerval);
|
||||
SEND(", LOAD=");
|
||||
printu(1, SysTick->LOAD);
|
||||
usart_putchar(1, '\n');
|
||||
newline(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
usb_proc();
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
int r = 0;
|
||||
char *txt = NULL;
|
||||
if((txt = get_USB())){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
parse_CMD(txt);
|
||||
}
|
||||
if(usartrx(1)){ // usart1 received data, store it in buffer
|
||||
r = usart_getline(1, &txt);
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(r){
|
||||
txt[r] = 0;
|
||||
if(the_conf.defflags & FLAG_GPSPROXY){
|
||||
usart_send(GPS_USART, txt);
|
||||
}else{ // UART1 is additive serial/bluetooth console
|
||||
usart_send(1, txt);
|
||||
if(*txt != '\n'){
|
||||
parse_CMD(txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(usartrx(GPS_USART)){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
r = usart_getline(GPS_USART, &txt);
|
||||
if(r){
|
||||
txt[r] = 0;
|
||||
if(the_conf.defflags & FLAG_GPSPROXY) usart_send(1, txt);
|
||||
GPS_parse_answer(txt);
|
||||
}
|
||||
}
|
||||
if(usartrx(LIDAR_USART)){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
r = usart_getline(LIDAR_USART, &txt);
|
||||
if(r){
|
||||
if(the_conf.defflags & FLAG_NOLIDAR){
|
||||
usart_send(LIDAR_USART, txt);
|
||||
if(*txt != '\n'){
|
||||
parse_CMD(txt);
|
||||
}
|
||||
}else
|
||||
parse_lidar_data(txt);
|
||||
}
|
||||
}
|
||||
chk_buzzer(); // should we turn off buzzer?
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
109
F1:F103/deprecated/chronometer/stm32F103xB.ld
Normal file
109
F1:F103/deprecated/chronometer/stm32F103xB.ld
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
********************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2017 Andrea Loi *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a *
|
||||
* copy of this software and associated documentation files (the "Software"), *
|
||||
* to deal in the Software without restriction, including without limitation *
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
|
||||
* and/or sell copies of the Software, and to permit persons to whom the *
|
||||
* Software is furnished to do so, subject to the following conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included *
|
||||
* in all copies or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
|
||||
* DEALINGS IN THE SOFTWARE. *
|
||||
* *
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
MEMORY
|
||||
{
|
||||
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
|
||||
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* DON'T EDIT THIS FILE UNLESS YOU KNOW WHAT YOU'RE DOING! */
|
||||
/******************************************************************************/
|
||||
|
||||
/* _isrvectors_tend = 0x00000150; - different for different series */
|
||||
|
||||
ENTRY(reset_handler)
|
||||
|
||||
SECTIONS {
|
||||
.vector_table 0x08000000 :
|
||||
{
|
||||
_sisrvectors = .;
|
||||
KEEP(*(.vector_table))
|
||||
/* ASSERT(. == _isrvectors_tend, "The vector table needs to be 84 elements long!"); */
|
||||
_eisrvectors = .;
|
||||
} >rom
|
||||
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_stext = .;
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
} >rom
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} >rom
|
||||
|
||||
.ARM : {
|
||||
*(.ARM.exidx*)
|
||||
} >rom
|
||||
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .;
|
||||
*(.data*)
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} >ram AT >rom
|
||||
|
||||
.myvars :
|
||||
{
|
||||
. = ALIGN(1024);
|
||||
__varsstart = ABSOLUTE(.);
|
||||
KEEP(*(.myvars));
|
||||
. = . + 2000;
|
||||
. = ALIGN(1024);
|
||||
__varsend = ABSOLUTE(.);
|
||||
} > rom
|
||||
|
||||
.logs :
|
||||
{
|
||||
. = ALIGN(1024);
|
||||
__logsstart = ABSOLUTE(.);
|
||||
KEEP(*(.logs))
|
||||
} > rom
|
||||
|
||||
_ldata = LOADADDR(.data);
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sbss = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
} >ram
|
||||
}
|
||||
|
||||
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
|
||||
PROVIDE(_varslen = __varsend - __varsstart);
|
||||
597
F1:F103/deprecated/chronometer/str.c
Normal file
597
F1:F103/deprecated/chronometer/str.c
Normal file
@@ -0,0 +1,597 @@
|
||||
/*
|
||||
* This file is part of the chronometer project.
|
||||
* Copyright 2019 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Commands parser
|
||||
|
||||
#include "adc.h"
|
||||
#include "GPS.h"
|
||||
#include "lidar.h"
|
||||
#include "str.h"
|
||||
#include "time.h"
|
||||
#include "usart.h"
|
||||
#include "usb.h"
|
||||
|
||||
// flag to show new GPS message over USB
|
||||
uint8_t showGPSstr = 0;
|
||||
|
||||
extern uint32_t shotms[];
|
||||
|
||||
/**
|
||||
* @brief cmpstr - the same as strncmp
|
||||
* @param s1,s2 - strings to compare
|
||||
* @param n - max symbols amount + 1 (!!!!)
|
||||
* @return 0 if strings equal or 1/-1
|
||||
*/
|
||||
int cmpstr(const char *s1, const char *s2, int n){
|
||||
int ret = 0;
|
||||
while(--n){
|
||||
ret = *s1 - *s2;
|
||||
if(ret == 0 && *s1 && *s2){
|
||||
++s1; ++s2;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief getchr - analog of strchr
|
||||
* @param str - string to search
|
||||
* @param symbol - searching symbol
|
||||
* @return pointer to symbol found or NULL
|
||||
*/
|
||||
char *getchr(const char *str, char symbol){
|
||||
do{
|
||||
if(*str == symbol) return (char*)str;
|
||||
}while(*(++str));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define sendu(x) do{sendstring(u2str(x));}while(0)
|
||||
|
||||
/*
|
||||
static void sendi(int32_t I){
|
||||
if(I < 0){
|
||||
sendchar('-');
|
||||
I = -I;
|
||||
}
|
||||
sendstring(u2str((uint32_t)I));
|
||||
}*/
|
||||
|
||||
// echo '1' if true or '0' if false
|
||||
static void checkflag(uint8_t f){
|
||||
if(f) sendchar('1');
|
||||
else sendchar('0');
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief showuserconf - show configuration over USB
|
||||
*/
|
||||
static void showuserconf(){
|
||||
sendstring("DISTMIN="); sendu(the_conf.dist_min);
|
||||
sendstring("\nDISTMAX="); sendu(the_conf.dist_max);
|
||||
sendstring("\nTRIGLVL="); sendu(the_conf.trigstate);
|
||||
sendstring("\nTRIGPAUSE={");
|
||||
for(int i = 0; i < TRIGGERS_AMOUNT; ++i){
|
||||
if(i) sendstring(", ");
|
||||
sendu(the_conf.trigpause[i]);
|
||||
}
|
||||
sendstring("}\nUSART1SPD="); sendu(the_conf.USART_speed);
|
||||
sendstring("\nLIDARSPD="); sendu(the_conf.LIDAR_speed);
|
||||
sendstring("\nNFREE=");
|
||||
sendu(the_conf.NLfreeWarn);
|
||||
sendstring("\nSTREND=");
|
||||
if(the_conf.defflags & FLAG_STRENDRN) sendstring("RN");
|
||||
else sendchar('N');
|
||||
uint8_t f = the_conf.defflags;
|
||||
sendstring("\nSAVE_EVENTS=");
|
||||
checkflag(f & FLAG_SAVE_EVENTS);
|
||||
sendstring("\nGPSPROXY=");
|
||||
checkflag(f & FLAG_GPSPROXY);
|
||||
sendstring("\nLIDAR=");
|
||||
checkflag(!(f & FLAG_NOLIDAR));
|
||||
sendstring("\n"); // <-- sendstring @ the end to initialize data transmission
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief parse_USBCMD - parsing of string buffer got by USB
|
||||
* @param cmd - buffer with commands
|
||||
* @return 0 if got command, 1 if command not recognized
|
||||
*/
|
||||
void parse_CMD(char *cmd){
|
||||
char *oldcmd = cmd;
|
||||
#define CMP(a,b) cmpstr(a, b, sizeof(b))
|
||||
#define GETNUM(x) do{if(getnum(cmd+sizeof(x)-1, &N)) goto bad_number;}while(0)
|
||||
static uint8_t conf_modified = 0;
|
||||
uint8_t succeed = 0;
|
||||
int32_t N;
|
||||
if(!cmd || !*cmd) return;
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(*cmd == '?' || CMP(cmd, "help") == 0){ // help
|
||||
sendstring("Commands:\n"
|
||||
CMD_BUZZER "S - turn buzzer ON/OFF\n"
|
||||
CMD_CURDIST " - show current LIDAR distance\n"
|
||||
CMD_DELLOGS " - delete logs from flash memory\n"
|
||||
CMD_DISTMIN " - min distance threshold (cm)\n"
|
||||
CMD_DISTMAX " - max distance threshold (cm)\n"
|
||||
CMD_DUMP "N - dump 20 last stored events (no x), all (x<1) or x\n"
|
||||
CMD_FLASH " - FLASH info\n"
|
||||
CMD_GPSPROXY "S - GPS proxy over USART1 on/off\n"
|
||||
CMD_GPSRESTART " - send Full Cold Restart to GPS\n"
|
||||
CMD_GPSSTAT " - get GPS status\n"
|
||||
CMD_GPSSTR " - current GPS data string\n"
|
||||
CMD_LEDS "S - turn leds on/off (1/0)\n"
|
||||
CMD_LIDAR "S - switch between LIDAR (1) or command TTY (0)\n"
|
||||
CMD_LIDARSPEED "N - set LIDAR speed to N\n"
|
||||
CMD_GETMCUTEMP " - MCU temperature\n"
|
||||
CMD_NFREE " - warn when free logs space less than this number (0 - not warn)\n"
|
||||
CMD_RESET " - reset MCU\n"
|
||||
CMD_SAVEEVTS "S - save/don't save (1/0) trigger events into flash\n"
|
||||
CMD_SHOWCONF " - show current configuration\n"
|
||||
CMD_STORECONF " - store new configuration in flash\n"
|
||||
CMD_STREND "C - string ends with \\n (C=n) or \\r\\n (C=r)\n"
|
||||
CMD_PRINTTIME " - print current time\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"
|
||||
CMD_USARTSPD "N - set USART1 speed to N\n"
|
||||
CMD_GETVDD " - Vdd value\n"
|
||||
);
|
||||
}else if(CMP(cmd, CMD_PRINTTIME) == 0){ // print current time
|
||||
sendstring(get_time(¤t_time, get_millis()));
|
||||
sendstring("\n");
|
||||
}else if(CMP(cmd, CMD_DISTMIN) == 0){ // set low LIDAR limit
|
||||
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 high LIDAR limit
|
||||
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 in flash
|
||||
if(conf_modified){
|
||||
if(store_userconf()){
|
||||
sendstring("Error: can't save data!\n");
|
||||
}else{
|
||||
conf_modified = 0;
|
||||
succeed = 1;
|
||||
}
|
||||
}
|
||||
}else if(CMP(cmd, CMD_GPSSTR) == 0){ // show GPS status string
|
||||
showGPSstr = 1;
|
||||
}else if(CMP(cmd, CMD_TRIGLVL) == 0){ // trigger levels: 0->1 or 1->0
|
||||
cmd += sizeof(CMD_TRIGLVL) - 1;
|
||||
uint8_t Nt = (uint8_t)(*cmd++ - '0');
|
||||
if(Nt > TRIGGERS_AMOUNT - 1) goto bad_number;
|
||||
uint8_t state = (uint8_t)(*cmd -'0');
|
||||
if(state > 1) goto bad_number;
|
||||
uint8_t oldval = the_conf.trigstate;
|
||||
if(!state) the_conf.trigstate = oldval & ~(1<<Nt);
|
||||
else the_conf.trigstate = (uint8_t)(oldval | (1<<Nt));
|
||||
if(oldval != the_conf.trigstate) conf_modified = 1;
|
||||
succeed = 1;
|
||||
}else if(CMP(cmd, CMD_SHOWCONF) == 0){ // print current configuration
|
||||
showuserconf();
|
||||
}else if(CMP(cmd, CMD_TRGPAUSE) == 0){ // pause after Nth trigger
|
||||
cmd += sizeof(CMD_TRGPAUSE) - 1;
|
||||
uint8_t Nt = (uint8_t)(*cmd++ - '0');
|
||||
if(Nt > 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] != (uint16_t)N){
|
||||
conf_modified = 1;
|
||||
the_conf.trigpause[Nt] = (uint16_t)N;
|
||||
}
|
||||
succeed = 1;
|
||||
}else if(CMP(cmd, CMD_TRGTIME) == 0){ // last trigger time
|
||||
cmd += sizeof(CMD_TRGTIME) - 1;
|
||||
uint8_t Nt = (uint8_t)(*cmd++ - '0');
|
||||
if(Nt > TRIGGERS_AMOUNT - 1) goto bad_number;
|
||||
show_trigger_shot((uint8_t)(1<<Nt));
|
||||
}else if(CMP(cmd, CMD_GETVDD) == 0){ // Vdd
|
||||
sendstring("VDD=");
|
||||
uint32_t vdd = getVdd();
|
||||
sendu(vdd/100);
|
||||
vdd %= 100;
|
||||
if(vdd < 10) sendstring(".0");
|
||||
else sendstring(".");
|
||||
sendu(vdd);
|
||||
sendstring("\n");
|
||||
}else if(CMP(cmd, CMD_GETMCUTEMP) == 0){ // ~Tmcu
|
||||
int32_t t = getMCUtemp();
|
||||
sendstring("MCUTEMP=");
|
||||
if(t < 0){
|
||||
t = -t;
|
||||
sendstring("-");
|
||||
}
|
||||
sendu(t/10);
|
||||
sendstring(".");
|
||||
sendu(t%10);
|
||||
sendstring("\n");
|
||||
}else if(CMP(cmd, CMD_LEDS) == 0){ // turn LEDs on/off
|
||||
uint8_t Nt = (uint8_t)(cmd[sizeof(CMD_LEDS) - 1] - '0');
|
||||
if(Nt > 1) goto bad_number;
|
||||
sendstring("LEDS=");
|
||||
if(Nt){
|
||||
LEDSon = 1;
|
||||
sendstring("ON\n");
|
||||
}else{
|
||||
LED_off(); // turn off LEDS
|
||||
LED1_off(); // by user request
|
||||
LEDSon = 0;
|
||||
sendstring("OFF\n");
|
||||
}
|
||||
}else if(CMP(cmd, CMD_GPSRESTART) == 0){ // restart GPS
|
||||
sendstring("Send full cold restart to GPS\n");
|
||||
GPS_send_FullColdStart();
|
||||
}else if(CMP(cmd, CMD_BUZZER) == 0){
|
||||
uint8_t Nt = (uint8_t)(cmd[sizeof(CMD_BUZZER) - 1] - '0');
|
||||
if(Nt > 1) goto bad_number;
|
||||
sendstring("BUZZER=");
|
||||
if(Nt){
|
||||
buzzer_on = 1;
|
||||
sendstring("ON\n");
|
||||
}else{
|
||||
buzzer_on = 0;
|
||||
sendstring("OFF\n");
|
||||
}
|
||||
}else if(CMP(cmd, CMD_GPSSTAT) == 0){ // GPS status
|
||||
sendstring("GPS status: ");
|
||||
const char *str = "unknown";
|
||||
switch(GPS_status){
|
||||
case GPS_NOTFOUND:
|
||||
str = "not found";
|
||||
break;
|
||||
case GPS_WAIT:
|
||||
str = "waiting";
|
||||
break;
|
||||
case GPS_NOT_VALID:
|
||||
str = "no satellites";
|
||||
break;
|
||||
case GPS_VALID:
|
||||
str = "valid time";
|
||||
break;
|
||||
}
|
||||
sendstring(str);
|
||||
if(Tms - last_corr_time < 1500)
|
||||
sendstring(", PPS working\n");
|
||||
else
|
||||
sendstring(", no PPS\n");
|
||||
}else if(CMP(cmd, CMD_USARTSPD) == 0){ // USART speed
|
||||
GETNUM(CMD_USARTSPD);
|
||||
if(N < 400 || N > 3000000) goto bad_number;
|
||||
if(the_conf.USART_speed != (uint32_t)N){
|
||||
the_conf.USART_speed = (uint32_t)N;
|
||||
conf_modified = 1;
|
||||
}
|
||||
succeed = 1;
|
||||
}else if(CMP(cmd, CMD_LIDARSPEED) == 0){ // LIDAR speed
|
||||
GETNUM(CMD_LIDARSPEED);
|
||||
if(N < 400 || N > 3000000) goto bad_number;
|
||||
if(the_conf.LIDAR_speed != (uint32_t)N){
|
||||
the_conf.LIDAR_speed = (uint32_t)N;
|
||||
conf_modified = 1;
|
||||
}
|
||||
succeed = 1;
|
||||
}else if(CMP(cmd, CMD_RESET) == 0){ // Reset MCU
|
||||
sendstring("Soft reset\n");
|
||||
NVIC_SystemReset();
|
||||
}else if(CMP(cmd, CMD_STREND) == 0){ // string ends in '\n' or "\r\n"
|
||||
char c = cmd[sizeof(CMD_STREND) - 1];
|
||||
succeed = 1;
|
||||
if(c == 'n' || c == 'N'){
|
||||
if(the_conf.defflags & FLAG_STRENDRN){
|
||||
conf_modified = 1;
|
||||
the_conf.defflags &= ~FLAG_STRENDRN;
|
||||
}
|
||||
}else if(c == 'r' || c == 'R'){
|
||||
if(!(the_conf.defflags & FLAG_STRENDRN)){
|
||||
conf_modified = 1;
|
||||
the_conf.defflags |= FLAG_STRENDRN;
|
||||
}
|
||||
}else{
|
||||
succeed = 0;
|
||||
sendstring("Bad letter, should be 'n' or 'r'\n");
|
||||
}
|
||||
}else if(CMP(cmd, CMD_FLASH) == 0){ // show flash size
|
||||
sendstring("FLASHSIZE=");
|
||||
sendu(FLASH_SIZE);
|
||||
sendstring("kB\nFLASH_BASE=");
|
||||
sendstring(u2hex(FLASH_BASE));
|
||||
sendstring("\nFlash_Data=");
|
||||
sendstring(u2hex((uint32_t)Flash_Data));
|
||||
sendstring("\nvarslen=");
|
||||
sendu((uint32_t)&_varslen);
|
||||
sendstring("\nCONFsize=");
|
||||
sendu(sizeof(user_conf));
|
||||
sendstring("\nNconf_records=");
|
||||
sendu(maxCnum - 1);
|
||||
sendstring("\nlogsstart=");
|
||||
sendstring(u2hex((uint32_t)logsstart));
|
||||
sendstring("\nLOGsize=");
|
||||
sendu(sizeof(event_log));
|
||||
sendstring("\nNlogs_records=");
|
||||
sendu(maxLnum - 1);
|
||||
sendstring("\n");
|
||||
}else if(CMP(cmd, CMD_SAVEEVTS) == 0){ // save all events
|
||||
if('0' == cmd[sizeof(CMD_SAVEEVTS) - 1]){
|
||||
if(the_conf.defflags & FLAG_SAVE_EVENTS){
|
||||
conf_modified = 1;
|
||||
the_conf.defflags &= ~FLAG_SAVE_EVENTS;
|
||||
}
|
||||
}else{
|
||||
if(!(the_conf.defflags & FLAG_SAVE_EVENTS)){
|
||||
conf_modified = 1;
|
||||
the_conf.defflags |= FLAG_SAVE_EVENTS;
|
||||
}
|
||||
}
|
||||
succeed = 1;
|
||||
}else if(CMP(cmd, CMD_DUMP) == 0){ // dump N last events
|
||||
if(getnum(cmd+sizeof(CMD_DUMP)-1, &N)) N = -20; // default - without N
|
||||
else N = -N;
|
||||
if(N > 0) N = 0;
|
||||
if(dump_log(N, -1)) sendstring("Event log empty!\n");
|
||||
}else if(CMP(cmd, CMD_NFREE) == 0){ // warn if there's less than N free cells for logs in flash
|
||||
GETNUM(CMD_NFREE);
|
||||
if(N < 0 || N > 0xffff) goto bad_number;
|
||||
if(the_conf.NLfreeWarn != (uint16_t)N){
|
||||
conf_modified = 1;
|
||||
the_conf.NLfreeWarn = (uint16_t)N;
|
||||
}
|
||||
succeed = 1;
|
||||
}else if(CMP(cmd, CMD_DELLOGS) == 0){ // delete all logs
|
||||
if(store_log(NULL)) sendstring("Error during erasing flash\n");
|
||||
else sendstring("All logs erased\n");
|
||||
}else if(CMP(cmd, CMD_GPSPROXY) == 0){ // proxy GPS data over USART1
|
||||
if(cmd[sizeof(CMD_GPSPROXY) - 1] == '0'){
|
||||
if(the_conf.defflags & FLAG_GPSPROXY){
|
||||
conf_modified = 1;
|
||||
the_conf.defflags &= ~FLAG_GPSPROXY;
|
||||
}
|
||||
}else{
|
||||
if(!(the_conf.defflags & FLAG_GPSPROXY)){
|
||||
conf_modified = 1;
|
||||
the_conf.defflags |= FLAG_GPSPROXY;
|
||||
}
|
||||
}
|
||||
succeed = 1;
|
||||
}else if(CMP(cmd, CMD_CURDIST) == 0){ // current LIDAR distance
|
||||
sendstring("DIST=");
|
||||
sendu(last_lidar_dist);
|
||||
sendstring("\nSTREN=");
|
||||
sendu(last_lidar_stren);
|
||||
sendstring("\nTRIGDIST=");
|
||||
sendu(lidar_triggered_dist);
|
||||
sendstring("\nTms=");
|
||||
sendu(Tms);
|
||||
sendstring("\nshotms=");
|
||||
sendu(shotms[LIDAR_TRIGGER]);
|
||||
sendstring("\n");
|
||||
}else if(CMP(cmd, CMD_LIDAR) == 0){ // turn LIDAR on/off
|
||||
if(cmd[sizeof(CMD_LIDAR) - 1] == '0'){
|
||||
if(!(the_conf.defflags & FLAG_NOLIDAR)){
|
||||
conf_modified = 1;
|
||||
the_conf.defflags |= FLAG_NOLIDAR;
|
||||
}
|
||||
}else{
|
||||
if(the_conf.defflags & FLAG_NOLIDAR){
|
||||
conf_modified = 1;
|
||||
the_conf.defflags &= ~FLAG_NOLIDAR;
|
||||
}
|
||||
}
|
||||
succeed = 1;
|
||||
}else{
|
||||
sendstring("Bad command: ");
|
||||
sendstring(oldcmd);
|
||||
sendstring("\n");
|
||||
return;
|
||||
}
|
||||
/*else if(CMP(cmd, CMD_) == 0){
|
||||
;
|
||||
}*/
|
||||
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(succeed) sendstring("Success!\n");
|
||||
return;
|
||||
bad_number:
|
||||
sendstring("Error: bad number!\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get_trigger_shot - print on USB message about last trigger shot time
|
||||
* @param number - number of event (if > -1)
|
||||
* @param logdata - record from event log
|
||||
* @return string with data
|
||||
*/
|
||||
char *get_trigger_shot(int number, const event_log *logdata){
|
||||
static char buf[64];
|
||||
char *bptr = buf;
|
||||
if(number > -1){
|
||||
bptr = strcp(bptr, u2str(number));
|
||||
bptr = strcp(bptr, ": ");
|
||||
}
|
||||
if(logdata->trigno == LIDAR_TRIGGER){
|
||||
bptr = strcp(bptr, "LIDAR, dist=");
|
||||
bptr = strcp(bptr, u2str(logdata->lidar_dist));
|
||||
bptr = strcp(bptr, ", TRIG" STR(LIDAR_TRIGGER));
|
||||
}else{
|
||||
bptr = strcp(bptr, "TRIG");
|
||||
*bptr++ = '0' + logdata->trigno;
|
||||
}
|
||||
*bptr++ = '=';
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
bptr = strcp(bptr, get_time(&logdata->shottime.Time, logdata->shottime.millis));
|
||||
bptr = strcp(bptr, ", len=");
|
||||
if(logdata->triglen < 0) bptr = strcp(bptr, ">1s");
|
||||
else bptr = strcp(bptr, u2str((uint32_t) logdata->triglen));
|
||||
*bptr++ = '\n'; *bptr++ = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief show_trigger_shot printout @ USB data with all triggers shot recently (+ save it in flash)
|
||||
* @param tshot - each bit consists information about trigger
|
||||
*/
|
||||
void show_trigger_shot(uint8_t tshot){
|
||||
uint8_t X = 1;
|
||||
for(uint8_t i = 0; i < TRIGGERS_AMOUNT && tshot; ++i, X <<= 1){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(tshot & X) tshot &= ~X;
|
||||
else continue;
|
||||
event_log l;
|
||||
l.elog_sz = sizeof(event_log);
|
||||
l.trigno = i;
|
||||
if(i == LIDAR_TRIGGER) l.lidar_dist = lidar_triggered_dist;
|
||||
l.shottime = shottime[i];
|
||||
l.triglen = triglen[i];
|
||||
sendstring(get_trigger_shot(-1, &l));
|
||||
if(the_conf.defflags & FLAG_SAVE_EVENTS){
|
||||
if(store_log(&l)) sendstring("\n\nError saving event!\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief strln == strlen
|
||||
* @param s - string
|
||||
* @return length
|
||||
*/
|
||||
int strln(const char *s){
|
||||
int i = 0;
|
||||
while(*s++) ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief strcp - strcpy (be carefull: it doesn't checks destination length!)
|
||||
* @param dst - destination
|
||||
* @param src - source
|
||||
* @return pointer to '\0' @ dst`s end
|
||||
*/
|
||||
char *strcp(char* dst, const char *src){
|
||||
int l = strln(src);
|
||||
if(l < 1) return dst;
|
||||
while((*dst++ = *src++));
|
||||
return dst - 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;
|
||||
}
|
||||
|
||||
static char strbuf[11];
|
||||
// return string buffer (strbuf) with val
|
||||
char *u2str(uint32_t val){
|
||||
char *bufptr = &strbuf[10];
|
||||
*bufptr = 0;
|
||||
if(!val){
|
||||
*(--bufptr) = '0';
|
||||
}else{
|
||||
while(val){
|
||||
*(--bufptr) = val % 10 + '0';
|
||||
val /= 10;
|
||||
}
|
||||
}
|
||||
return bufptr;
|
||||
}
|
||||
|
||||
// return strbuf filled with hex
|
||||
char *u2hex(uint32_t val){
|
||||
char *bufptr = strbuf;
|
||||
*bufptr++ = '0';
|
||||
*bufptr++ = 'x';
|
||||
uint8_t *ptr = (uint8_t*)&val + 3;
|
||||
int i, j;
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
for(i = 0; i < 4; ++i, --ptr){
|
||||
for(j = 1; j > -1; --j){
|
||||
register uint8_t half = (*ptr >> (4*j)) & 0x0f;
|
||||
if(half < 10) *bufptr++ = half + '0';
|
||||
else *bufptr++ = half - 10 + 'a';
|
||||
}
|
||||
}
|
||||
*bufptr = 0;
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
static char localbuffer[LOCBUFSZ];
|
||||
static uint8_t bufidx = 0;
|
||||
static void transmitlocbuf(){
|
||||
localbuffer[bufidx] = 0;
|
||||
USB_send(localbuffer);
|
||||
if(!(the_conf.defflags & FLAG_GPSPROXY)){ // USART1 isn't a GPS proxy
|
||||
usart_send(1, localbuffer);
|
||||
transmit_tbuf(1);
|
||||
}
|
||||
if(the_conf.defflags & FLAG_NOLIDAR){ // USART3 isn't a LIDAR
|
||||
usart_send(LIDAR_USART, localbuffer);
|
||||
transmit_tbuf(LIDAR_USART);
|
||||
}
|
||||
bufidx = 0;
|
||||
}
|
||||
// add char to buf
|
||||
void sendchar(char ch){
|
||||
localbuffer[bufidx++] = ch;
|
||||
if(bufidx >= LOCBUFSZ-1) transmitlocbuf();
|
||||
}
|
||||
/**
|
||||
* @brief addtobuf - add to local buffer any zero-terminated substring
|
||||
* @param str - string to add
|
||||
* it sends data to USB and (due to setup) USART1 when buffer will be full or when meet '\n' at the end of str
|
||||
*/
|
||||
void sendstring(const char *str){
|
||||
while(*str) sendchar(*str++);
|
||||
if(str[-1] == '\n') transmitlocbuf();
|
||||
}
|
||||
73
F1:F103/deprecated/chronometer/str.h
Normal file
73
F1:F103/deprecated/chronometer/str.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of the chronometer project.
|
||||
* Copyright 2019 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef STR_H__
|
||||
#define STR_H__
|
||||
|
||||
#include "stm32f1.h"
|
||||
#include "flash.h"
|
||||
#include "hardware.h"
|
||||
|
||||
// local buffer size (chars)
|
||||
#define LOCBUFSZ 128
|
||||
|
||||
// TTY commands
|
||||
#define CMD_BUZZER "buzzer"
|
||||
#define CMD_CURDIST "curdist"
|
||||
#define CMD_DELLOGS "deletelogs"
|
||||
#define CMD_DISTMAX "distmax"
|
||||
#define CMD_DISTMIN "distmin"
|
||||
#define CMD_DUMP "dump"
|
||||
#define CMD_FLASH "flash"
|
||||
#define CMD_GETMCUTEMP "mcutemp"
|
||||
#define CMD_GETVDD "vdd"
|
||||
#define CMD_GPSPROXY "gpsproxy"
|
||||
#define CMD_GPSRESTART "gpsrestart"
|
||||
#define CMD_GPSSTAT "gpsstat"
|
||||
#define CMD_GPSSTR "gpsstring"
|
||||
#define CMD_LEDS "leds"
|
||||
#define CMD_LIDAR "lidar"
|
||||
#define CMD_LIDARSPEED "lidspd"
|
||||
#define CMD_NFREE "nfree"
|
||||
#define CMD_PRINTTIME "time"
|
||||
#define CMD_RESET "reset"
|
||||
#define CMD_SAVEEVTS "se"
|
||||
#define CMD_SHOWCONF "showconf"
|
||||
#define CMD_STORECONF "store"
|
||||
#define CMD_STREND "strend"
|
||||
#define CMD_TRGPAUSE "trigpause"
|
||||
#define CMD_TRGTIME "trigtime"
|
||||
#define CMD_TRIGLVL "triglevel"
|
||||
#define CMD_USARTSPD "usartspd"
|
||||
|
||||
extern uint8_t showGPSstr;
|
||||
|
||||
int getnum(const char *buf, int32_t *N);
|
||||
char *u2str(uint32_t val);
|
||||
char *u2hex(uint32_t val);
|
||||
|
||||
int strln(const char *s);
|
||||
char *strcp(char* dst, const char *src);
|
||||
int cmpstr(const char *s1, const char *s2, int n);
|
||||
char *getchr(const char *str, char symbol);
|
||||
void parse_CMD(char *cmd);
|
||||
char *get_trigger_shot(int number, const event_log *logdata);
|
||||
void show_trigger_shot(uint8_t trigger_shot);
|
||||
void sendstring(const char *str);
|
||||
void sendchar(char ch);
|
||||
#endif // STR_H__
|
||||
194
F1:F103/deprecated/chronometer/time.c
Normal file
194
F1:F103/deprecated/chronometer/time.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* This file is part of the chronometer project.
|
||||
* Copyright 2019 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "GPS.h"
|
||||
#include "time.h"
|
||||
#ifdef EBUG
|
||||
#include "usart.h"
|
||||
#endif
|
||||
#include "usb.h"
|
||||
#include <string.h>
|
||||
|
||||
volatile uint32_t Timer; // milliseconds counter
|
||||
curtime current_time = TMNOTINI;
|
||||
|
||||
// convert two-digit decimal string into number
|
||||
static inline uint8_t atou(const char *b){
|
||||
return (uint8_t)((b[0]-'0')*10 + b[1]-'0');
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set_time - set current time from GPS data
|
||||
* @param buf - buffer with time data (HHMMSS)
|
||||
*/
|
||||
void set_time(const char *buf){
|
||||
uint8_t H = atou(buf);// + TIMEZONE_GMT_PLUS;
|
||||
if(H > 23) H -= 24;
|
||||
current_time.H = H;
|
||||
current_time.M = atou(&buf[2]);
|
||||
current_time.S = atou(&buf[4]);
|
||||
/*
|
||||
#ifdef EBUG
|
||||
SEND("set_time, Tms: "); printu(1, Tms);
|
||||
SEND("; Timer: "); printu(1, Timer);
|
||||
newline(1);
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *puttwo(uint8_t N, char *buf){
|
||||
if(N < 10){
|
||||
*buf++ = '0';
|
||||
}else{
|
||||
*buf++ = N/10 + '0';
|
||||
N %= 10;
|
||||
}
|
||||
*buf++ = (char)(N + '0');
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ms2str - fill buffer str with milliseconds ms
|
||||
* @param str (io) - pointer to buffer
|
||||
* @param T - milliseconds
|
||||
*/
|
||||
static void ms2str(char **str, uint32_t T){
|
||||
char *bptr = *str;
|
||||
*bptr++ = '.';
|
||||
if(T > 99){
|
||||
*bptr++ = (char)(T/100 + '0');
|
||||
T %= 100;
|
||||
}else *bptr++ = '0';
|
||||
if(T > 9){
|
||||
*bptr++ = (char)(T/10 + '0');
|
||||
T %= 10;
|
||||
}else *bptr++ = '0';
|
||||
*bptr++ = (char)(T + '0');
|
||||
*str = bptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* print time: Tm - time structure, T - milliseconds
|
||||
*/
|
||||
char *get_time(const curtime *Tm, uint32_t T){
|
||||
static char buf[64];
|
||||
char *bstart = &buf[5], *bptr = bstart;
|
||||
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';
|
||||
while(S){
|
||||
*(--bstart) = S%10 + '0';
|
||||
S /= 10;
|
||||
}
|
||||
// now bstart is buffer starting index; bptr points to decimal point
|
||||
ms2str(&bptr, T);
|
||||
// put current time in HH:MM:SS format into buf
|
||||
*bptr++ = ' '; *bptr++ = '(';
|
||||
bptr = puttwo(Tm->H, bptr); *bptr++ = ':';
|
||||
bptr = puttwo(Tm->M, bptr); *bptr++ = ':';
|
||||
bptr = puttwo(Tm->S, bptr);
|
||||
ms2str(&bptr, T);
|
||||
*bptr++ = ')';
|
||||
if(GPS_status == GPS_NOTFOUND){
|
||||
strcpy(bptr, " GPS not found");
|
||||
bptr += 14;
|
||||
}
|
||||
*bptr = 0;
|
||||
return bstart;
|
||||
}
|
||||
|
||||
|
||||
#ifdef EBUG
|
||||
uint32_t timerval, Tms1;
|
||||
int32_t timecntr=0, ticksdiff=0;
|
||||
#else
|
||||
static int32_t timecntr=0, ticksdiff=0;
|
||||
#endif
|
||||
uint32_t last_corr_time = 0;
|
||||
|
||||
/**
|
||||
* @brief systick_correction
|
||||
* Makes correction of system timer
|
||||
* The default frequency of timer is 1kHz - 72000 clocks per interrupt
|
||||
* So we check how much ticks there was for last one second - between PPS interrupts
|
||||
* Their amount equal to M = `Timer` value x (SysTick->LOAD+1) + (SysTick->LOAD+1 - SysTick->VAL)
|
||||
* if `Timer` is very small, add 1000 to its value.
|
||||
* We need 1000xN ticks instead of M
|
||||
* if L = LOAD+1, then
|
||||
* M = Timer*L + L - VAL; newL = L + D = M/1000
|
||||
* 1000*D = M - 1000*L = L(Timer+1-1000) - VAL ->
|
||||
* D = [L*(Timer-999) - VAL]/1000
|
||||
* So correction equal to
|
||||
* [ (SysTick->LOAD + 1) * (Timer - 999) - SysTick->VAL ] / 1000
|
||||
*/
|
||||
void systick_correction(){
|
||||
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // stop systick for a while
|
||||
int32_t systick_val = (int32_t)SysTick->VAL, L = (int32_t)SysTick->LOAD + 1;
|
||||
uint32_t timer_val = Timer;
|
||||
#ifdef EBUG
|
||||
timerval = Timer;
|
||||
Tms1 = Tms;
|
||||
#endif
|
||||
Timer = 0;
|
||||
SysTick->VAL = SysTick->LOAD;
|
||||
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // start it again
|
||||
// if(systick_val != SysTick->LOAD) ++Tms;
|
||||
if(timer_val > 500) time_increment(); // counter greater than 500 -> need to increment time
|
||||
if(last_corr_time){
|
||||
uint32_t Tdiff = Tms - last_corr_time;
|
||||
if(Tdiff < 1500 && Tdiff > 700){ // there was perevious PPS signal ~1s ago
|
||||
int32_t D = L * ((int32_t)(Tms - 1000 - last_corr_time)) + ((int32_t)SysTick->LOAD - systick_val); // amount of spare ticks
|
||||
++timecntr;
|
||||
ticksdiff += D;
|
||||
uint32_t ticksabs = (ticksdiff < 0) ? (uint32_t)-ticksdiff : (uint32_t)ticksdiff;
|
||||
// 30000 == 30 seconds * 1000 interrupts per second
|
||||
if(ticksabs > 30000 && timecntr > 10){ // need correction (not more often than each 10s)
|
||||
ticksdiff /= timecntr * 1000; // correction per one interrupt
|
||||
SysTick->LOAD = (uint32_t)(ticksdiff + (int32_t)SysTick->LOAD);
|
||||
timecntr = 0;
|
||||
ticksdiff = 0;
|
||||
#ifdef EBUG
|
||||
SEND("Correction\n");
|
||||
#endif
|
||||
}
|
||||
}else{
|
||||
timecntr = 0;
|
||||
ticksdiff = 0;
|
||||
}
|
||||
}
|
||||
last_corr_time = Tms;
|
||||
}
|
||||
|
||||
65
F1:F103/deprecated/chronometer/time.h
Normal file
65
F1:F103/deprecated/chronometer/time.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This file is part of the chronometer project.
|
||||
* Copyright 2019 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef TIME_H__
|
||||
#define TIME_H__
|
||||
|
||||
#include <stm32f1.h>
|
||||
|
||||
// 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)
|
||||
|
||||
// debounce delay: .4s
|
||||
#define TRIGGER_DELAY (400)
|
||||
|
||||
#define TMNOTINI {25,61,61}
|
||||
|
||||
// current milliseconds
|
||||
#define get_millis() (Timer)
|
||||
|
||||
typedef struct{
|
||||
uint8_t H;
|
||||
uint8_t M;
|
||||
uint8_t S;
|
||||
} curtime;
|
||||
|
||||
#ifdef EBUG
|
||||
extern int32_t ticksdiff, timecntr;
|
||||
extern uint32_t timerval, Tms1;
|
||||
#endif
|
||||
extern volatile uint32_t Tms;
|
||||
extern volatile uint32_t Timer;
|
||||
extern curtime current_time;
|
||||
extern uint32_t last_corr_time;
|
||||
|
||||
extern curtime trigger_time[];
|
||||
extern uint32_t trigger_ms[];
|
||||
|
||||
extern volatile int need_sync;
|
||||
|
||||
char *get_time(const curtime *T, uint32_t m);
|
||||
void set_time(const char *buf);
|
||||
void time_increment();
|
||||
void systick_correction();
|
||||
|
||||
#endif // TIME_H__
|
||||
309
F1:F103/deprecated/chronometer/usart.c
Normal file
309
F1:F103/deprecated/chronometer/usart.c
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* This file is part of the chronometer project.
|
||||
* Copyright 2019 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "stm32f1.h"
|
||||
#include "flash.h"
|
||||
#include "lidar.h"
|
||||
#include "str.h"
|
||||
#include "usart.h"
|
||||
|
||||
extern volatile uint32_t Tms;
|
||||
static volatile uint8_t idatalen[4][2] = {{0}}; // received data line length (including '\n')
|
||||
static volatile uint8_t odatalen[4][2] = {{0}};
|
||||
|
||||
static volatile uint8_t dlen[4] = {0}; // length of data (including '\n') in current buffer
|
||||
|
||||
volatile uint8_t linerdy[4] = {0}, // received data ready
|
||||
bufovr[4] = {0}, // input buffer overfull
|
||||
txrdy[4] = {0,1,1,1} // transmission done
|
||||
;
|
||||
|
||||
|
||||
static uint8_t rbufno[4] = {0}, tbufno[4] = {0}; // current rbuf/tbuf numbers
|
||||
static char rbuf[4][2][UARTBUFSZ], tbuf[4][2][UARTBUFSZ]; // receive & transmit buffers
|
||||
static char *recvdata[4] = {0};
|
||||
|
||||
/**
|
||||
* return length of received data (without trailing zero)
|
||||
*/
|
||||
int usart_getline(int n, char **line){
|
||||
if(bufovr[n]){
|
||||
bufovr[n] = 0;
|
||||
linerdy[n] = 0;
|
||||
return 0;
|
||||
}
|
||||
*line = recvdata[n];
|
||||
linerdy[n] = 0;
|
||||
return dlen[n];
|
||||
}
|
||||
|
||||
// transmit current tbuf and swap buffers
|
||||
void transmit_tbuf(uint8_t n){
|
||||
DMA_Channel_TypeDef *DMA;
|
||||
switch(n){ // also check if n wrong
|
||||
case 1:
|
||||
DMA = DMA1_Channel4;
|
||||
break;
|
||||
case 2:
|
||||
DMA = DMA1_Channel7;
|
||||
break;
|
||||
case 3:
|
||||
DMA = DMA1_Channel2;
|
||||
break;
|
||||
default: return;
|
||||
}
|
||||
uint32_t tmout = 72000;
|
||||
while(!txrdy[n]){if(--tmout == 0) return;} // wait for previos buffer transmission
|
||||
register uint32_t l = odatalen[n][tbufno[n]];
|
||||
if(!l) return;
|
||||
txrdy[n] = 0;
|
||||
odatalen[n][tbufno[n]] = 0;
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
DMA->CCR &= ~DMA_CCR_EN;
|
||||
DMA->CMAR = (uint32_t) tbuf[n][tbufno[n]]; // mem
|
||||
DMA->CNDTR = l;
|
||||
DMA->CCR |= DMA_CCR_EN;
|
||||
tbufno[n] = !tbufno[n];
|
||||
}
|
||||
|
||||
void usart_putchar(uint8_t n, char ch){
|
||||
if(!n || n > USART_LAST+1) return;
|
||||
for(int i = 0; odatalen[n][tbufno[n]] == UARTBUFSZ && i < 1024; ++i) transmit_tbuf(n);
|
||||
tbuf[n][tbufno[n]][odatalen[n][tbufno[n]]++] = ch;
|
||||
}
|
||||
|
||||
void usart_send(uint8_t n, const char *str){
|
||||
if(!n || n > USART_LAST+1) return;
|
||||
uint32_t x = 512;
|
||||
while(*str && --x){
|
||||
if(odatalen[n][tbufno[n]] == UARTBUFSZ){
|
||||
transmit_tbuf(n);
|
||||
continue;
|
||||
}
|
||||
tbuf[n][tbufno[n]][odatalen[n][tbufno[n]]++] = *str++;
|
||||
}
|
||||
}
|
||||
|
||||
// send newline ("\r" or "\r\n") and transmit whole buffer
|
||||
// for GPS_USART endline always is "\r\n"
|
||||
// @param n - USART number
|
||||
void newline(uint8_t n){
|
||||
if((the_conf.defflags & FLAG_STRENDRN) || n == GPS_USART) usart_putchar(n, '\r');
|
||||
usart_putchar(n, '\n');
|
||||
transmit_tbuf(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* USART speed: baudrate = Fck/(USARTDIV)
|
||||
* USARTDIV stored in USART->BRR
|
||||
*
|
||||
* for 72MHz USARTDIV=72000/f(kboud); so for 115200 USARTDIV=72000/115.2=625 -> BRR=0x271
|
||||
* 9600: BRR = 7500 (0x1D4C)
|
||||
*/
|
||||
static void usart_setup(uint8_t n, uint16_t BRR){
|
||||
DMA_Channel_TypeDef *DMA;
|
||||
IRQn_Type DMAirqN, USARTirqN;
|
||||
USART_TypeDef *USART;
|
||||
switch(n){
|
||||
case 1:
|
||||
// USART1 Tx DMA - Channel4 (Rx - channel 5)
|
||||
DMA = DMA1_Channel4;
|
||||
DMAirqN = DMA1_Channel4_IRQn;
|
||||
USARTirqN = USART1_IRQn;
|
||||
// PA9 - Tx, PA10 - Rx
|
||||
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN;
|
||||
GPIOA->CRH |= CRH(9, CNF_AFPP|MODE_NORMAL) | CRH(10, CNF_FLINPUT|MODE_INPUT);
|
||||
USART = USART1;
|
||||
break;
|
||||
case 2:
|
||||
// USART2 Tx DMA - Channel7
|
||||
DMA = DMA1_Channel7;
|
||||
DMAirqN = DMA1_Channel7_IRQn;
|
||||
USARTirqN = USART2_IRQn;
|
||||
// PA2 - Tx, PA3 - Rx
|
||||
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
|
||||
GPIOA->CRL |= CRL(2, CNF_AFPP|MODE_NORMAL) | CRL(3, CNF_FLINPUT|MODE_INPUT);
|
||||
USART = USART2;
|
||||
break;
|
||||
case 3:
|
||||
// USART3 Tx DMA - Channel2
|
||||
DMA = DMA1_Channel2;
|
||||
DMAirqN = DMA1_Channel2_IRQn;
|
||||
USARTirqN = USART3_IRQn;
|
||||
// PB10 - Tx, PB11 - Rx
|
||||
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
|
||||
GPIOB->CRH |= CRH(10, CNF_AFPP|MODE_NORMAL) | CRH(11, CNF_FLINPUT|MODE_INPUT);
|
||||
USART = USART3;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
DMA->CPAR = (uint32_t) &USART->DR; // periph
|
||||
DMA->CCR |= DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // 8bit, mem++, mem->per, transcompl irq
|
||||
// setup usart(n)
|
||||
USART->BRR = BRR;
|
||||
USART->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART
|
||||
uint32_t tmout = 16000000;
|
||||
while(!(USART->SR & USART_SR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission
|
||||
USART->SR = 0; // clear flags
|
||||
USART->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ
|
||||
USART->CR3 = USART_CR3_DMAT; // enable DMA Tx
|
||||
// Tx CNDTR set @ each transmission due to data size
|
||||
NVIC_SetPriority(DMAirqN, n);
|
||||
NVIC_EnableIRQ(DMAirqN);
|
||||
NVIC_SetPriority(USARTirqN, n);
|
||||
NVIC_EnableIRQ(USARTirqN);
|
||||
}
|
||||
|
||||
void usarts_setup(){
|
||||
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
|
||||
usart_setup(1, 72000000 / the_conf.USART_speed); // debug console or GPS proxy
|
||||
usart_setup(GPS_USART, 36000000 / GPS_DEFAULT_SPEED); // GPS
|
||||
usart_setup(LIDAR_USART, 36000000 / the_conf.LIDAR_speed); // LIDAR
|
||||
}
|
||||
|
||||
|
||||
static void usart_isr(uint8_t n, USART_TypeDef *USART){
|
||||
#ifdef CHECK_TMOUT
|
||||
static uint32_t tmout[n] = 0;
|
||||
#endif
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(USART->SR & USART_SR_RXNE){ // RX not emty - receive next char
|
||||
#ifdef CHECK_TMOUT
|
||||
if(tmout[n] && Tms >= tmout[n]){ // set overflow flag
|
||||
bufovr[n] = 1;
|
||||
idatalen[n][rbufno[n]] = 0;
|
||||
}
|
||||
tmout[n] = Tms + TIMEOUT_MS;
|
||||
if(!tmout[n]) tmout[n] = 1; // prevent 0
|
||||
#endif
|
||||
char rb = (char)USART->DR;
|
||||
if(idatalen[n][rbufno[n]] < UARTBUFSZ){ // put next char into buf
|
||||
if(rb != '\r') rbuf[n][rbufno[n]][idatalen[n][rbufno[n]]++] = rb; // omit '\r'
|
||||
if(rb == '\n'){ // got newline - line ready
|
||||
linerdy[n] = 1;
|
||||
dlen[n] = idatalen[n][rbufno[n]];
|
||||
rbuf[n][rbufno[n]][dlen[n]] = 0;
|
||||
recvdata[n] = rbuf[n][rbufno[n]];
|
||||
// prepare other buffer
|
||||
rbufno[n] = !rbufno[n];
|
||||
idatalen[n][rbufno[n]] = 0;
|
||||
#ifdef CHECK_TMOUT
|
||||
// clear timeout at line end
|
||||
tmout[n] = 0;
|
||||
#endif
|
||||
}
|
||||
}else{ // buffer overrun
|
||||
bufovr[n] = 1;
|
||||
idatalen[n][rbufno[n]] = 0;
|
||||
#ifdef CHECK_TMOUT
|
||||
tmout[n] = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void usart1_isr(){
|
||||
usart_isr(1, USART1);
|
||||
}
|
||||
|
||||
// GPS_USART
|
||||
void usart2_isr(){
|
||||
usart_isr(2, USART2);
|
||||
}
|
||||
|
||||
// LIDAR_USART
|
||||
void usart3_isr(){
|
||||
if(the_conf.defflags & FLAG_NOLIDAR){ // regular TTY
|
||||
usart_isr(3, USART3);
|
||||
return;
|
||||
}
|
||||
// LIDAR - check for different things
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(USART3->SR & USART_SR_RXNE){ // RX not emty - receive next char
|
||||
char rb = (char)USART3->DR;
|
||||
uint8_t L = idatalen[3][rbufno[3]];
|
||||
if(rb != LIDAR_FRAME_HEADER && (L == 0 || L == 1)){ // bad starting sequence
|
||||
idatalen[3][rbufno[3]] = 0;
|
||||
return;
|
||||
}
|
||||
if(L < LIDAR_FRAME_LEN){ // put next char into buf
|
||||
rbuf[3][rbufno[3]][idatalen[3][rbufno[3]]++] = rb;
|
||||
if(L == LIDAR_FRAME_LEN-1){ // got LIDAR_FRAME_LEN bytes - line ready
|
||||
linerdy[3] = 1;
|
||||
dlen[3] = idatalen[3][rbufno[3]];
|
||||
recvdata[3] = rbuf[3][rbufno[3]];
|
||||
// prepare other buffer
|
||||
rbufno[3] = !rbufno[3];
|
||||
idatalen[3][rbufno[3]] = 0;
|
||||
}
|
||||
}else{ // buffer overrun
|
||||
idatalen[3][rbufno[3]] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print 32bit unsigned int
|
||||
void printu(uint8_t n, uint32_t val){
|
||||
usart_send(n, u2str(val));
|
||||
}
|
||||
|
||||
// print 32bit unsigned int as hex
|
||||
void printuhex(uint8_t n, uint32_t val){
|
||||
usart_send(n, u2hex(val));
|
||||
}
|
||||
|
||||
#ifdef EBUG
|
||||
// dump memory buffer
|
||||
void hexdump(uint8_t *arr, uint16_t len){
|
||||
for(uint16_t l = 0; l < len; ++l, ++arr){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
for(int16_t j = 1; j > -1; --j){
|
||||
register uint8_t half = (*arr >> (4*j)) & 0x0f;
|
||||
if(half < 10) usart_putchar(1, half + '0');
|
||||
else usart_putchar(1, half - 10 + 'a');
|
||||
}
|
||||
if(l % 16 == 15) usart_putchar(1, '\n');
|
||||
else if((l & 3) == 3) usart_putchar(1, ' ');
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void dma1_channel4_isr(){ // USART1
|
||||
if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx
|
||||
DMA1->IFCR = DMA_IFCR_CTCIF4; // clear TC flag
|
||||
txrdy[1] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void dma1_channel7_isr(){ // USART2
|
||||
if(DMA1->ISR & DMA_ISR_TCIF7){ // Tx
|
||||
DMA1->IFCR = DMA_IFCR_CTCIF7; // clear TC flag
|
||||
txrdy[2] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void dma1_channel2_isr(){ // USART3
|
||||
if(DMA1->ISR & DMA_ISR_TCIF2){ // Tx
|
||||
DMA1->IFCR = DMA_IFCR_CTCIF2; // clear TC flag
|
||||
txrdy[3] = 1;
|
||||
}
|
||||
}
|
||||
73
F1:F103/deprecated/chronometer/usart.h
Normal file
73
F1:F103/deprecated/chronometer/usart.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of the chronometer project.
|
||||
* Copyright 2019 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef __USART_H__
|
||||
#define __USART_H__
|
||||
|
||||
#include <stm32f1.h>
|
||||
|
||||
// input and output buffers size (should be less than 256!!!)
|
||||
#define UARTBUFSZ (128)
|
||||
// timeout between data bytes
|
||||
#ifndef TIMEOUT_MS
|
||||
#define TIMEOUT_MS (1500)
|
||||
#endif
|
||||
|
||||
// number of last USART used
|
||||
#define USART_LAST 3
|
||||
|
||||
// USART1 default speed
|
||||
#define USART1_DEFAULT_SPEED (115200)
|
||||
// LIDAR default speed
|
||||
#define LIDAR_DEFAULT_SPEED (115200)
|
||||
// GPS default speed
|
||||
#define GPS_DEFAULT_SPEED (9600)
|
||||
|
||||
#define STR_HELPER(s) #s
|
||||
#define STR(s) STR_HELPER(s)
|
||||
|
||||
#ifdef EBUG
|
||||
#define SEND(str) usart_send(1, str)
|
||||
#define MSG(str) do{SEND(__FILE__ " (L" STR(__LINE__) "): " str);}while(0)
|
||||
#define DBG(str) do{SEND(str); newline(1); }while(0)
|
||||
#else
|
||||
#define SEND(str)
|
||||
#define MSG(str)
|
||||
#define DBG(str)
|
||||
#endif
|
||||
|
||||
#define usartrx(n) (linerdy[n])
|
||||
#define usartovr(n) (bufovr[n])
|
||||
|
||||
extern volatile uint8_t linerdy[], bufovr[], txrdy[];
|
||||
|
||||
void transmit_tbuf(uint8_t n);
|
||||
void usarts_setup();
|
||||
int usart_getline(int n, char **line);
|
||||
void usart_send(uint8_t n, const char *str);
|
||||
void usart_putchar(uint8_t n, char ch);
|
||||
void printu(uint8_t n, uint32_t val);
|
||||
void printuhex(uint8_t n, uint32_t val);
|
||||
void newline(uint8_t n);
|
||||
|
||||
#ifdef EBUG
|
||||
void hexdump(uint8_t *arr, uint16_t len);
|
||||
#endif
|
||||
|
||||
#endif // __USART_H__
|
||||
213
F1:F103/deprecated/chronometer/usb.c
Normal file
213
F1:F103/deprecated/chronometer/usb.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb.c - base functions for different USB types
|
||||
*
|
||||
* Copyright 2018 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.
|
||||
*
|
||||
*/
|
||||
#include "flash.h"
|
||||
#include "usb.h"
|
||||
#include "usb_lib.h"
|
||||
#include "usart.h"
|
||||
|
||||
// incoming buffer size
|
||||
#define IDATASZ (256)
|
||||
static uint8_t incoming_data[IDATASZ];
|
||||
static uint8_t ovfl = 0;
|
||||
static uint16_t idatalen = 0;
|
||||
static volatile uint8_t tx_succesfull = 0;
|
||||
static int8_t usbON = 0; // ==1 when USB fully configured
|
||||
|
||||
// interrupt IN handler (never used?)
|
||||
static uint16_t EP1_Handler(ep_t ep){
|
||||
if (ep.rx_flag){
|
||||
ep.status = SET_VALID_TX(ep.status);
|
||||
ep.status = KEEP_STAT_RX(ep.status);
|
||||
}else if (ep.tx_flag){
|
||||
ep.status = SET_VALID_RX(ep.status);
|
||||
ep.status = SET_STALL_TX(ep.status);
|
||||
}
|
||||
return ep.status;
|
||||
}
|
||||
|
||||
// data IN/OUT handler
|
||||
static uint16_t EP23_Handler(ep_t ep){
|
||||
if(ep.rx_flag){
|
||||
int rd = ep.rx_cnt, rest = IDATASZ - idatalen;
|
||||
if(rd){
|
||||
if(rd <= rest){
|
||||
idatalen += EP_Read(2, (uint16_t*)&incoming_data[idatalen]);
|
||||
ovfl = 0;
|
||||
}else{
|
||||
ep.status = SET_NAK_RX(ep.status);
|
||||
ovfl = 1;
|
||||
return ep.status;
|
||||
}
|
||||
}
|
||||
// end of transaction: clear DTOGs
|
||||
ep.status = CLEAR_DTOG_RX(ep.status);
|
||||
ep.status = CLEAR_DTOG_TX(ep.status);
|
||||
ep.status = SET_STALL_TX(ep.status);
|
||||
}else if (ep.tx_flag){
|
||||
ep.status = KEEP_STAT_TX(ep.status);
|
||||
tx_succesfull = 1;
|
||||
}
|
||||
ep.status = SET_VALID_RX(ep.status);
|
||||
return ep.status;
|
||||
}
|
||||
|
||||
void USB_setup(){
|
||||
NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||
NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||
USB->CNTR = USB_CNTR_FRES; // Force USB Reset
|
||||
for(uint32_t ctr = 0; ctr < 72000; ++ctr) nop(); // wait >1ms
|
||||
//uint32_t ctr = 0;
|
||||
USB->CNTR = 0;
|
||||
USB->BTABLE = 0;
|
||||
USB->DADDR = 0;
|
||||
USB->ISTR = 0;
|
||||
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_WKUPM; // allow only wakeup & reset interrupts
|
||||
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||
NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn );
|
||||
}
|
||||
|
||||
void usb_proc(){
|
||||
if(USB_GetState() == USB_CONFIGURE_STATE){ // USB configured - activate other endpoints
|
||||
if(!usbON){ // endpoints not activated
|
||||
// make new BULK endpoint
|
||||
// Buffer have 1024 bytes, but last 256 we use for CAN bus (30.2 of RM: USB main features)
|
||||
EP_Init(1, EP_TYPE_INTERRUPT, 10, 0, EP1_Handler); // IN1 - transmit
|
||||
EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, EP23_Handler); // OUT2 - receive data
|
||||
EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, EP23_Handler); // IN3 - transmit data
|
||||
usbON = 1;
|
||||
}
|
||||
}else{
|
||||
usbON = 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern uint8_t USB_connected;
|
||||
void USB_send(const char *buf){
|
||||
if(!USB_configured()){
|
||||
DBG("USB not configured");
|
||||
return;
|
||||
}
|
||||
if(!USB_connected) return; // no connection -> no need to send data into nothing
|
||||
char tmpbuf[USB_TXBUFSZ];
|
||||
uint16_t l = 0, ctr = 0;
|
||||
const char *p = buf;
|
||||
while(*p++) ++l;
|
||||
while(l){
|
||||
uint16_t proc = 0, s = (l > USB_TXBUFSZ - 1) ? USB_TXBUFSZ - 1: l;
|
||||
for(int i = 0; i < s; ++i, ++proc){
|
||||
char c = buf[ctr+proc];
|
||||
if(c == '\n' && the_conf.defflags & FLAG_STRENDRN){ // add '\r' before '\n'
|
||||
tmpbuf[i++] = '\r';
|
||||
if(i == s) ++s;
|
||||
}
|
||||
if(c == 0x1B) tmpbuf[i] = 'E'; // ESC
|
||||
else if(c == 0x7F) tmpbuf[i] = 'B'; // Backspace
|
||||
else tmpbuf[i] = c;
|
||||
}
|
||||
tx_succesfull = 0;
|
||||
EP_Write(3, (uint8_t*)tmpbuf, s);
|
||||
uint32_t ctra = 1000000;
|
||||
while(--ctra && tx_succesfull == 0);
|
||||
l -= proc;
|
||||
ctr += proc;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB_receive
|
||||
* @param buf (i) - buffer for received data
|
||||
* @param bufsize - its size
|
||||
* @return amount of received bytes
|
||||
*/
|
||||
int USB_receive(char *buf, int bufsize){
|
||||
if(!bufsize || !idatalen) return 0;
|
||||
USB->CNTR = 0;
|
||||
int sz = (idatalen > bufsize) ? bufsize : idatalen, rest = idatalen - sz;
|
||||
for(int i = 0; i < sz; ++i) buf[i] = incoming_data[i];
|
||||
if(rest > 0){
|
||||
uint8_t *ptr = &incoming_data[sz];
|
||||
for(int i = 0; i < rest; ++i) incoming_data[i] = *ptr++;
|
||||
//memmove(incoming_data, &incoming_data[sz], rest); - hardfault on memcpy&memmove
|
||||
idatalen = rest;
|
||||
}else idatalen = 0;
|
||||
if(ovfl){
|
||||
EP23_Handler(endpoints[2]);
|
||||
uint16_t epstatus = USB->EPnR[2];
|
||||
epstatus = CLEAR_DTOG_RX(epstatus);
|
||||
epstatus = SET_VALID_RX(epstatus);
|
||||
USB->EPnR[2] = epstatus;
|
||||
}
|
||||
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
|
||||
return sz;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB_configured
|
||||
* @return 1 if USB is in configured state
|
||||
*/
|
||||
int USB_configured(){
|
||||
return usbON;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* default handlers
|
||||
*
|
||||
// SET_LINE_CODING
|
||||
void WEAK linecoding_handler(usb_LineCoding __attribute__((unused)) *lc){
|
||||
DBG("WEAK LH");
|
||||
}
|
||||
|
||||
// SET_CONTROL_LINE_STATE
|
||||
void WEAK clstate_handler(uint16_t __attribute__((unused)) val){
|
||||
DBG("WEAK CLSH");
|
||||
}
|
||||
|
||||
// SEND_BREAK
|
||||
void WEAK break_handler(){
|
||||
DBG("WEAK BH");
|
||||
}*/
|
||||
|
||||
// handler of vendor requests
|
||||
void WEAK vendor_handler(config_pack_t *packet){
|
||||
if(packet->bmRequestType & 0x80){ // read
|
||||
uint8_t c;
|
||||
switch(packet->wValue){
|
||||
case 0x8484:
|
||||
c = 2;
|
||||
break;
|
||||
case 0x0080:
|
||||
c = 1;
|
||||
break;
|
||||
case 0x8686:
|
||||
c = 0xaa;
|
||||
break;
|
||||
default:
|
||||
c = 0;
|
||||
}
|
||||
EP_WriteIRQ(0, &c, 1);
|
||||
}else{ // write ZLP
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}
|
||||
}
|
||||
37
F1:F103/deprecated/chronometer/usb.h
Normal file
37
F1:F103/deprecated/chronometer/usb.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb.h
|
||||
*
|
||||
* Copyright 2018 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 __USB_H__
|
||||
#define __USB_H__
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
#define BUFFSIZE (64)
|
||||
|
||||
void USB_setup();
|
||||
void usb_proc();
|
||||
void USB_send(const char *buf);
|
||||
int USB_receive(char *buf, int bufsize);
|
||||
int USB_configured();
|
||||
|
||||
#endif // __USB_H__
|
||||
117
F1:F103/deprecated/chronometer/usb_defs.h
Normal file
117
F1:F103/deprecated/chronometer/usb_defs.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb_defs.h
|
||||
*
|
||||
* Copyright 2018 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 __USB_DEFS_H__
|
||||
#define __USB_DEFS_H__
|
||||
|
||||
#include <stm32f1.h>
|
||||
|
||||
// max endpoints number
|
||||
#define STM32ENDPOINTS 8
|
||||
/**
|
||||
* Buffers size definition
|
||||
**/
|
||||
#define USB_BTABLE_SIZE 512
|
||||
// first 64 bytes of USB_BTABLE are registers!
|
||||
//#define USB_EP0_BASEADDR 64
|
||||
// for USB FS EP0 buffers are from 8 to 64 bytes long (64 for PL2303)
|
||||
#define USB_EP0_BUFSZ 64
|
||||
// USB transmit buffer size (64 for PL2303)
|
||||
#define USB_TXBUFSZ 64
|
||||
// USB receive buffer size (64 for PL2303)
|
||||
#define USB_RXBUFSZ 64
|
||||
|
||||
#define USB_BTABLE_BASE 0x40006000
|
||||
#define USB_BASE ((uint32_t)0x40005C00)
|
||||
#define USB ((USB_TypeDef *) USB_BASE)
|
||||
|
||||
#ifdef USB_BTABLE
|
||||
#undef USB_BTABLE
|
||||
#endif
|
||||
#define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE))
|
||||
#define USB_ISTR_EPID 0x0000000F
|
||||
#define USB_FNR_LSOF_0 0x00000800
|
||||
#define USB_FNR_lSOF_1 0x00001000
|
||||
#define USB_LPMCSR_BESL_0 0x00000010
|
||||
#define USB_LPMCSR_BESL_1 0x00000020
|
||||
#define USB_LPMCSR_BESL_2 0x00000040
|
||||
#define USB_LPMCSR_BESL_3 0x00000080
|
||||
#define USB_EPnR_CTR_RX 0x00008000
|
||||
#define USB_EPnR_DTOG_RX 0x00004000
|
||||
#define USB_EPnR_STAT_RX 0x00003000
|
||||
#define USB_EPnR_STAT_RX_0 0x00001000
|
||||
#define USB_EPnR_STAT_RX_1 0x00002000
|
||||
#define USB_EPnR_SETUP 0x00000800
|
||||
#define USB_EPnR_EP_TYPE 0x00000600
|
||||
#define USB_EPnR_EP_TYPE_0 0x00000200
|
||||
#define USB_EPnR_EP_TYPE_1 0x00000400
|
||||
#define USB_EPnR_EP_KIND 0x00000100
|
||||
#define USB_EPnR_CTR_TX 0x00000080
|
||||
#define USB_EPnR_DTOG_TX 0x00000040
|
||||
#define USB_EPnR_STAT_TX 0x00000030
|
||||
#define USB_EPnR_STAT_TX_0 0x00000010
|
||||
#define USB_EPnR_STAT_TX_1 0x00000020
|
||||
#define USB_EPnR_EA 0x0000000F
|
||||
#define USB_COUNTn_RX_BLSIZE 0x00008000
|
||||
#define USB_COUNTn_NUM_BLOCK 0x00007C00
|
||||
#define USB_COUNTn_RX 0x0000003F
|
||||
|
||||
#ifdef USB_TypeDef
|
||||
#define USB_TypeDef USB_TypeDef_custom
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
__IO uint32_t EPnR[STM32ENDPOINTS];
|
||||
__IO uint32_t RESERVED[STM32ENDPOINTS];
|
||||
__IO uint32_t CNTR;
|
||||
__IO uint32_t ISTR;
|
||||
__IO uint32_t FNR;
|
||||
__IO uint32_t DADDR;
|
||||
__IO uint32_t BTABLE;
|
||||
} USB_TypeDef;
|
||||
|
||||
/*
|
||||
typedef struct{
|
||||
__IO uint16_t USB_ADDR_TX;
|
||||
__IO uint16_t res1;
|
||||
__IO uint16_t USB_COUNT_TX;
|
||||
__IO uint16_t res2;
|
||||
__IO uint16_t USB_ADDR_RX;
|
||||
__IO uint16_t res3;
|
||||
__IO uint16_t USB_COUNT_RX;
|
||||
__IO uint16_t res4;
|
||||
} USB_EPDATA_TypeDef;*/
|
||||
|
||||
typedef struct{
|
||||
__IO uint32_t USB_ADDR_TX;
|
||||
__IO uint32_t USB_COUNT_TX;
|
||||
__IO uint32_t USB_ADDR_RX;
|
||||
__IO uint32_t USB_COUNT_RX;
|
||||
} USB_EPDATA_TypeDef;
|
||||
|
||||
typedef struct{
|
||||
__IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS];
|
||||
} USB_BtableDef;
|
||||
|
||||
#endif // __USB_DEFS_H__
|
||||
488
F1:F103/deprecated/chronometer/usb_lib.c
Normal file
488
F1:F103/deprecated/chronometer/usb_lib.c
Normal file
@@ -0,0 +1,488 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb_lib.c
|
||||
*
|
||||
* Copyright 2018 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "usb_lib.h"
|
||||
#include "usart.h"
|
||||
|
||||
ep_t endpoints[STM32ENDPOINTS];
|
||||
|
||||
static usb_dev_t USB_Dev;
|
||||
static usb_LineCoding lineCoding = {115200, 0, 0, 8};
|
||||
static config_pack_t setup_packet;
|
||||
static uint8_t ep0databuf[EP0DATABUF_SIZE];
|
||||
static uint8_t ep0dbuflen = 0;
|
||||
|
||||
usb_LineCoding getLineCoding(){return lineCoding;}
|
||||
|
||||
// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor
|
||||
#define bcdUSB_L 0x10
|
||||
#define bcdUSB_H 0x01
|
||||
#define bDeviceClass 0
|
||||
#define bDeviceSubClass 0
|
||||
#define bDeviceProtocol 0
|
||||
#define bNumConfigurations 1
|
||||
|
||||
static const uint8_t USB_DeviceDescriptor[] = {
|
||||
18, // bLength
|
||||
0x01, // bDescriptorType - Device descriptor
|
||||
bcdUSB_L, // bcdUSB_L - 1.10
|
||||
bcdUSB_H, // bcdUSB_H
|
||||
bDeviceClass, // bDeviceClass - USB_COMM
|
||||
bDeviceSubClass, // bDeviceSubClass
|
||||
bDeviceProtocol, // bDeviceProtocol
|
||||
USB_EP0_BUFSZ, // bMaxPacketSize
|
||||
0x7b, // idVendor_L PL2303: VID=0x067b, PID=0x2303
|
||||
0x06, // idVendor_H
|
||||
0x03, // idProduct_L
|
||||
0x23, // idProduct_H
|
||||
0x00, // bcdDevice_Ver_L
|
||||
0x03, // bcdDevice_Ver_H
|
||||
0x01, // iManufacturer
|
||||
0x02, // iProduct
|
||||
0x00, // iSerialNumber
|
||||
bNumConfigurations // bNumConfigurations
|
||||
};
|
||||
|
||||
static const uint8_t USB_DeviceQualifierDescriptor[] = {
|
||||
10, //bLength
|
||||
0x06, // bDescriptorType - Device qualifier
|
||||
bcdUSB_L, // bcdUSB_L
|
||||
bcdUSB_H, // bcdUSB_H
|
||||
bDeviceClass, // bDeviceClass
|
||||
bDeviceSubClass, // bDeviceSubClass
|
||||
bDeviceProtocol, // bDeviceProtocol
|
||||
USB_EP0_BUFSZ, // bMaxPacketSize0
|
||||
bNumConfigurations, // bNumConfigurations
|
||||
0x00 // Reserved
|
||||
};
|
||||
|
||||
static const uint8_t USB_ConfigDescriptor[] = {
|
||||
/*Configuration Descriptor*/
|
||||
0x09, /* bLength: Configuration Descriptor size */
|
||||
0x02, /* bDescriptorType: Configuration */
|
||||
39, /* wTotalLength:no of returned bytes */
|
||||
0x00,
|
||||
0x01, /* bNumInterfaces: 1 interface */
|
||||
0x01, /* bConfigurationValue: Configuration value */
|
||||
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
|
||||
0xa0, /* bmAttributes - Bus powered, Remote wakeup */
|
||||
0x32, /* MaxPower 100 mA */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*Interface Descriptor */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
0x04, /* bDescriptorType: Interface */
|
||||
0x00, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x03, /* bNumEndpoints: 3 endpoints used */
|
||||
0xff, /* bInterfaceClass */
|
||||
0x00, /* bInterfaceSubClass */
|
||||
0x00, /* bInterfaceProtocol */
|
||||
0x00, /* iInterface: */
|
||||
///////////////////////////////////////////////////
|
||||
/*Endpoint 1 Descriptor*/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
0x05, /* bDescriptorType: Endpoint */
|
||||
0x81, /* bEndpointAddress IN1 */
|
||||
0x03, /* bmAttributes: Interrupt */
|
||||
0x0a, /* wMaxPacketSize LO: */
|
||||
0x00, /* wMaxPacketSize HI: */
|
||||
0x01, /* bInterval: */
|
||||
|
||||
/*Endpoint OUT2 Descriptor*/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
0x05, /* bDescriptorType: Endpoint */
|
||||
0x02, /* bEndpointAddress: OUT2 */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
(USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
|
||||
(USB_RXBUFSZ >> 8),
|
||||
0x00, /* bInterval: ignore for Bulk transfer */
|
||||
|
||||
/*Endpoint IN3 Descriptor*/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
0x05, /* bDescriptorType: Endpoint */
|
||||
0x83, /* bEndpointAddress IN3 */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
(USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
|
||||
(USB_TXBUFSZ >> 8),
|
||||
0x00, /* bInterval: ignore for Bulk transfer */
|
||||
};
|
||||
|
||||
_USB_LANG_ID_(USB_StringLangDescriptor, LANG_US);
|
||||
// these descriptors are not used in PL2303 emulator!
|
||||
_USB_STRING_(USB_StringSerialDescriptor, u"0");
|
||||
_USB_STRING_(USB_StringManufacturingDescriptor, u"Prolific Technology Inc.");
|
||||
_USB_STRING_(USB_StringProdDescriptor, u"USB-Serial Controller");
|
||||
|
||||
static void wr0(const uint8_t *buf, uint16_t size){
|
||||
if(setup_packet.wLength < size) size = setup_packet.wLength;
|
||||
EP_WriteIRQ(0, buf, size);
|
||||
}
|
||||
|
||||
static inline void get_descriptor(){
|
||||
switch(setup_packet.wValue){
|
||||
case DEVICE_DESCRIPTOR:
|
||||
wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor));
|
||||
break;
|
||||
case CONFIGURATION_DESCRIPTOR:
|
||||
wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor));
|
||||
break;
|
||||
case STRING_LANG_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringLangDescriptor, STRING_LANG_DESCRIPTOR_SIZE_BYTE);
|
||||
break;
|
||||
case STRING_MAN_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringManufacturingDescriptor, USB_StringManufacturingDescriptor.bLength);
|
||||
break;
|
||||
case STRING_PROD_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringProdDescriptor, USB_StringProdDescriptor.bLength);
|
||||
break;
|
||||
case STRING_SN_DESCRIPTOR:
|
||||
wr0((const uint8_t *)&USB_StringSerialDescriptor, USB_StringSerialDescriptor.bLength);
|
||||
break;
|
||||
case DEVICE_QUALIFIER_DESCRIPTOR:
|
||||
wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured)
|
||||
static inline void std_d2h_req(){
|
||||
uint16_t status = 0; // bus powered
|
||||
switch(setup_packet.bRequest){
|
||||
case GET_DESCRIPTOR:
|
||||
get_descriptor();
|
||||
break;
|
||||
case GET_STATUS:
|
||||
EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered
|
||||
break;
|
||||
case GET_CONFIGURATION:
|
||||
EP_WriteIRQ(0, &configuration, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void std_h2d_req(){
|
||||
switch(setup_packet.bRequest){
|
||||
case SET_ADDRESS:
|
||||
// new address will be assigned later - after acknowlegement or request to host
|
||||
USB_Dev.USB_Addr = setup_packet.wValue;
|
||||
break;
|
||||
case SET_CONFIGURATION:
|
||||
// Now device configured
|
||||
USB_Dev.USB_Status = USB_CONFIGURE_STATE;
|
||||
configuration = setup_packet.wValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bmRequestType: 76543210
|
||||
7 direction: 0 - host->device, 1 - device->host
|
||||
65 type: 0 - standard, 1 - class, 2 - vendor
|
||||
4..0 getter: 0 - device, 1 - interface, 2 - endpoint, 3 - other
|
||||
*/
|
||||
/**
|
||||
* Endpoint0 (control) handler
|
||||
* @param ep - endpoint state
|
||||
* @return data written to EP0R
|
||||
*/
|
||||
static uint16_t EP0_Handler(ep_t ep){
|
||||
uint16_t epstatus = ep.status; // EP0R on input -> return this value after modifications
|
||||
uint8_t reqtype = setup_packet.bmRequestType & 0x7f;
|
||||
uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0;
|
||||
if ((ep.rx_flag) && (ep.setup_flag)){
|
||||
switch(reqtype){
|
||||
case STANDARD_DEVICE_REQUEST_TYPE: // standard device request
|
||||
if(dev2host){
|
||||
std_d2h_req();
|
||||
}else{
|
||||
std_h2d_req();
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
}
|
||||
//epstatus = SET_NAK_RX(epstatus);
|
||||
//epstatus = SET_VALID_TX(epstatus);
|
||||
break;
|
||||
case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request
|
||||
if(setup_packet.bRequest == CLEAR_FEATURE){
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
//epstatus = SET_NAK_RX(epstatus);
|
||||
//epstatus = SET_VALID_TX(epstatus);
|
||||
}
|
||||
break;
|
||||
case VENDOR_REQUEST_TYPE:
|
||||
vendor_handler(&setup_packet);
|
||||
//epstatus = SET_NAK_RX(epstatus);
|
||||
//epstatus = SET_VALID_TX(epstatus);
|
||||
break;
|
||||
case CONTROL_REQUEST_TYPE:
|
||||
switch(setup_packet.bRequest){
|
||||
case GET_LINE_CODING:
|
||||
EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding));
|
||||
break;
|
||||
case SET_LINE_CODING: // omit this for next stage, when data will come
|
||||
break;
|
||||
case SET_CONTROL_LINE_STATE:
|
||||
clstate_handler(setup_packet.wValue);
|
||||
break;
|
||||
case SEND_BREAK:
|
||||
break_handler();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// SET_CONTROL_LINE_STATE don't work! Need something to fix the BUG!
|
||||
//if(!dev2host)
|
||||
if(setup_packet.bRequest != GET_LINE_CODING)
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement
|
||||
//epstatus = SET_VALID_RX(epstatus);
|
||||
//epstatus = SET_VALID_TX(epstatus);
|
||||
break;
|
||||
default:
|
||||
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
//epstatus = SET_NAK_RX(epstatus);
|
||||
//epstatus = SET_VALID_TX(epstatus);
|
||||
}
|
||||
}else if (ep.rx_flag){ // got data over EP0 or host acknowlegement
|
||||
if(ep.rx_cnt){
|
||||
//EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||
if(setup_packet.bRequest == SET_LINE_CODING){
|
||||
linecoding_handler((usb_LineCoding*)ep0databuf);
|
||||
}
|
||||
}
|
||||
// wait for new data from host
|
||||
//epstatus = SET_VALID_RX(epstatus);
|
||||
//epstatus = SET_VALID_TX(epstatus);
|
||||
} else if (ep.tx_flag){ // package transmitted
|
||||
// now we can change address after enumeration
|
||||
if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){
|
||||
USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr;
|
||||
// change state to ADRESSED
|
||||
USB_Dev.USB_Status = USB_ADRESSED_STATE;
|
||||
}
|
||||
// end of transaction
|
||||
epstatus = CLEAR_DTOG_RX(epstatus);
|
||||
epstatus = CLEAR_DTOG_TX(epstatus);
|
||||
//epstatus = SET_VALID_RX(epstatus);
|
||||
//epstatus = SET_VALID_TX(epstatus);
|
||||
}
|
||||
epstatus = SET_VALID_RX(epstatus);
|
||||
epstatus = SET_VALID_TX(epstatus);
|
||||
return epstatus;
|
||||
}
|
||||
|
||||
static uint16_t lastaddr = LASTADDR_DEFAULT;
|
||||
/**
|
||||
* Endpoint initialisation
|
||||
* @param number - EP num (0...7)
|
||||
* @param type - EP type (EP_TYPE_BULK, EP_TYPE_CONTROL, EP_TYPE_ISO, EP_TYPE_INTERRUPT)
|
||||
* @param txsz - transmission buffer size @ USB/CAN buffer
|
||||
* @param rxsz - reception buffer size @ USB/CAN buffer
|
||||
* @param uint16_t (*func)(ep_t *ep) - EP handler function
|
||||
* @return 0 if all OK
|
||||
*/
|
||||
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep)){
|
||||
if(number >= STM32ENDPOINTS) return 4; // out of configured amount
|
||||
if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large
|
||||
if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE) return 2; // out of btable
|
||||
USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA);
|
||||
USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1;
|
||||
if(rxsz & 1 || rxsz > 512) return 3; // wrong rx buffer size
|
||||
uint16_t countrx = 0;
|
||||
if(rxsz < 64) countrx = rxsz / 2;
|
||||
else{
|
||||
if(rxsz & 0x1f) return 3; // should be multiple of 32
|
||||
countrx = 31 + rxsz / 32;
|
||||
}
|
||||
USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr;
|
||||
endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr*2);
|
||||
lastaddr += txsz;
|
||||
USB_BTABLE->EP[number].USB_COUNT_TX = 0;
|
||||
USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr;
|
||||
endpoints[number].rx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr*2);
|
||||
lastaddr += rxsz;
|
||||
USB_BTABLE->EP[number].USB_COUNT_RX = countrx << 10;
|
||||
endpoints[number].func = func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//extern int8_t dump;
|
||||
// standard IRQ handler
|
||||
void usb_isr(){
|
||||
if (USB->ISTR & USB_ISTR_RESET){
|
||||
// Reinit registers
|
||||
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
|
||||
USB->ISTR = 0;
|
||||
// Endpoint 0 - CONTROL
|
||||
// ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes!
|
||||
lastaddr = LASTADDR_DEFAULT;
|
||||
if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler)){
|
||||
DBG("Err init EP0");
|
||||
}
|
||||
// clear address, leave only enable bit
|
||||
USB->DADDR = USB_DADDR_EF;
|
||||
// state is default - wait for enumeration
|
||||
USB_Dev.USB_Status = USB_DEFAULT_STATE;
|
||||
}
|
||||
if(USB->ISTR & USB_ISTR_CTR){
|
||||
// EP number
|
||||
uint8_t n = USB->ISTR & USB_ISTR_EPID;
|
||||
// copy status register
|
||||
uint16_t epstatus = USB->EPnR[n];
|
||||
// dump = 1;
|
||||
// Calculate flags
|
||||
endpoints[n].rx_flag = (epstatus & USB_EPnR_CTR_RX) ? 1 : 0;
|
||||
endpoints[n].setup_flag = (epstatus & USB_EPnR_SETUP) ? 1 : 0;
|
||||
endpoints[n].tx_flag = (epstatus & USB_EPnR_CTR_TX) ? 1 : 0;
|
||||
// copy received bytes amount
|
||||
endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter
|
||||
// check direction
|
||||
if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit)
|
||||
if(n == 0){ // control endpoint
|
||||
if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack
|
||||
EP_Read(0, (uint16_t*)&setup_packet);
|
||||
ep0dbuflen = 0;
|
||||
// interrupt handler will be called later
|
||||
}else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf
|
||||
ep0dbuflen = endpoints[0].rx_cnt;
|
||||
EP_Read(0, (uint16_t*)&ep0databuf);
|
||||
}
|
||||
}
|
||||
}else{ // IN interrupt - transmit data, only CTR_TX == 1
|
||||
// enumeration end could be here (if EP0)
|
||||
}
|
||||
// prepare status field for EP handler
|
||||
endpoints[n].status = epstatus;
|
||||
// call EP handler (even if it will change EPnR, it should return new status)
|
||||
epstatus = endpoints[n].func(endpoints[n]);
|
||||
// keep DTOG state
|
||||
epstatus = KEEP_DTOG_TX(epstatus);
|
||||
epstatus = KEEP_DTOG_RX(epstatus);
|
||||
// clear all RX/TX flags
|
||||
epstatus = CLEAR_CTR_RX(epstatus);
|
||||
epstatus = CLEAR_CTR_TX(epstatus);
|
||||
// refresh EPnR
|
||||
USB->EPnR[n] = epstatus;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (USB->ISTR & USB_ISTR_PMAOVR) {
|
||||
MSG("PMAOVR\n");
|
||||
// Handle PMAOVR status
|
||||
}
|
||||
if (USB->ISTR & USB_ISTR_SUSP) {
|
||||
MSG("SUSP\n");
|
||||
if (USB->DADDR & 0x7f) {
|
||||
USB->DADDR = 0;
|
||||
USB->CNTR &= ~ 0x800;
|
||||
}
|
||||
}
|
||||
if (USB->ISTR & USB_ISTR_ERR) {
|
||||
MSG("ERR\n");
|
||||
// Handle Error
|
||||
}
|
||||
if (USB->ISTR & USB_ISTR_WKUP) {
|
||||
MSG("WKUP\n");
|
||||
// Handle Wakeup
|
||||
}
|
||||
if (USB->ISTR & USB_ISTR_SOF) {
|
||||
MSG("SOF\n");
|
||||
// Handle SOF
|
||||
}
|
||||
if (USB->ISTR & USB_ISTR_ESOF) {
|
||||
MSG("ESOF\n");
|
||||
// Handle ESOF
|
||||
}
|
||||
USB->ISTR = 0;
|
||||
*/
|
||||
|
||||
void usb_lp_can_rx0_isr(){
|
||||
usb_isr();
|
||||
}
|
||||
|
||||
void usb_hp_can_tx_isr(){
|
||||
usb_isr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to EP buffer (called from IRQ handler)
|
||||
* @param number - EP number
|
||||
* @param *buf - array with data
|
||||
* @param size - its size
|
||||
*/
|
||||
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
|
||||
uint8_t i;
|
||||
if(size > USB_TXBUFSZ) size = USB_TXBUFSZ;
|
||||
uint16_t N2 = (size + 1) >> 1;
|
||||
// the buffer is 16-bit, so we should copy data as it would be uint16_t
|
||||
uint16_t *buf16 = (uint16_t *)buf;
|
||||
uint32_t *out = (uint32_t *)endpoints[number].tx_buf;
|
||||
for(i = 0; i < N2; ++i, ++out){
|
||||
*out = buf16[i];
|
||||
}
|
||||
USB_BTABLE->EP[number].USB_COUNT_TX = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to EP buffer (called outside IRQ handler)
|
||||
* @param number - EP number
|
||||
* @param *buf - array with data
|
||||
* @param size - its size
|
||||
*/
|
||||
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){
|
||||
uint16_t status = USB->EPnR[number];
|
||||
EP_WriteIRQ(number, buf, size);
|
||||
status = SET_NAK_RX(status);
|
||||
status = SET_VALID_TX(status);
|
||||
status = KEEP_DTOG_TX(status);
|
||||
status = KEEP_DTOG_RX(status);
|
||||
USB->EPnR[number] = status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy data from EP buffer into user buffer area
|
||||
* @param *buf - user array for data
|
||||
* @return amount of data read
|
||||
*/
|
||||
int EP_Read(uint8_t number, uint16_t *buf){
|
||||
int n = (endpoints[number].rx_cnt + 1) >> 1;
|
||||
uint32_t *in = (uint32_t *)endpoints[number].rx_buf;
|
||||
if(n){
|
||||
for(int i = 0; i < n; ++i, ++in)
|
||||
buf[i] = *(uint16_t*)in;
|
||||
}
|
||||
return endpoints[number].rx_cnt;
|
||||
}
|
||||
|
||||
// USB status
|
||||
uint8_t USB_GetState(){
|
||||
return USB_Dev.USB_Status;
|
||||
}
|
||||
202
F1:F103/deprecated/chronometer/usb_lib.h
Normal file
202
F1:F103/deprecated/chronometer/usb_lib.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* usb_lib.h
|
||||
*
|
||||
* Copyright 2018 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 __USB_LIB_H__
|
||||
#define __USB_LIB_H__
|
||||
|
||||
#include <wchar.h>
|
||||
#include "usb_defs.h"
|
||||
|
||||
#define EP0DATABUF_SIZE (64)
|
||||
#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8)
|
||||
|
||||
// Max EP amount (EP0 + other used)
|
||||
//#define ENDPOINTS_NUM 4
|
||||
// bmRequestType & 0x7f
|
||||
#define STANDARD_DEVICE_REQUEST_TYPE 0
|
||||
#define STANDARD_ENDPOINT_REQUEST_TYPE 2
|
||||
#define VENDOR_REQUEST_TYPE 0x40
|
||||
#define CONTROL_REQUEST_TYPE 0x21
|
||||
// bRequest, standard; for bmRequestType == 0x80
|
||||
#define GET_STATUS 0x00
|
||||
#define GET_DESCRIPTOR 0x06
|
||||
#define GET_CONFIGURATION 0x08
|
||||
// for bmRequestType == 0
|
||||
#define CLEAR_FEATURE 0x01
|
||||
#define SET_FEATURE 0x03 // unused
|
||||
#define SET_ADDRESS 0x05
|
||||
#define SET_DESCRIPTOR 0x07 // unused
|
||||
#define SET_CONFIGURATION 0x09
|
||||
// for bmRequestType == 0x81, 1 or 0xB2
|
||||
#define GET_INTERFACE 0x0A // unused
|
||||
#define SET_INTERFACE 0x0B // unused
|
||||
#define SYNC_FRAME 0x0C // unused
|
||||
#define VENDOR_REQUEST 0x01 // unused
|
||||
|
||||
// Class-Specific Control Requests
|
||||
#define SEND_ENCAPSULATED_COMMAND 0x00 // unused
|
||||
#define GET_ENCAPSULATED_RESPONSE 0x01 // unused
|
||||
#define SET_COMM_FEATURE 0x02 // unused
|
||||
#define GET_COMM_FEATURE 0x03 // unused
|
||||
#define CLEAR_COMM_FEATURE 0x04 // unused
|
||||
#define SET_LINE_CODING 0x20
|
||||
#define GET_LINE_CODING 0x21
|
||||
#define SET_CONTROL_LINE_STATE 0x22
|
||||
#define SEND_BREAK 0x23
|
||||
|
||||
// control line states
|
||||
#define CONTROL_DTR 0x01
|
||||
#define CONTROL_RTS 0x02
|
||||
|
||||
// wValue
|
||||
#define DEVICE_DESCRIPTOR 0x100
|
||||
#define CONFIGURATION_DESCRIPTOR 0x200
|
||||
#define STRING_LANG_DESCRIPTOR 0x300
|
||||
#define STRING_MAN_DESCRIPTOR 0x301
|
||||
#define STRING_PROD_DESCRIPTOR 0x302
|
||||
#define STRING_SN_DESCRIPTOR 0x303
|
||||
#define DEVICE_QUALIFIER_DESCRIPTOR 0x600
|
||||
|
||||
// EPnR bits manipulation
|
||||
#define CLEAR_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? R : (R & (~USB_EPnR_DTOG_RX))
|
||||
#define SET_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? (R & (~USB_EPnR_DTOG_RX)) : R
|
||||
#define TOGGLE_DTOG_RX(R) (R | USB_EPnR_DTOG_RX)
|
||||
#define KEEP_DTOG_RX(R) (R & (~USB_EPnR_DTOG_RX))
|
||||
#define CLEAR_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? R : (R & (~USB_EPnR_DTOG_TX))
|
||||
#define SET_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? (R & (~USB_EPnR_DTOG_TX)) : R
|
||||
#define TOGGLE_DTOG_TX(R) (R | USB_EPnR_DTOG_TX)
|
||||
#define KEEP_DTOG_TX(R) (R & (~USB_EPnR_DTOG_TX))
|
||||
#define SET_VALID_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX) | (R & (~USB_EPnR_STAT_RX))
|
||||
#define SET_NAK_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_1) | (R & (~USB_EPnR_STAT_RX))
|
||||
#define SET_STALL_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_0) | (R & (~USB_EPnR_STAT_RX))
|
||||
#define KEEP_STAT_RX(R) (R & (~USB_EPnR_STAT_RX))
|
||||
#define SET_VALID_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX) | (R & (~USB_EPnR_STAT_TX))
|
||||
#define SET_NAK_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_1) | (R & (~USB_EPnR_STAT_TX))
|
||||
#define SET_STALL_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_0) | (R & (~USB_EPnR_STAT_TX))
|
||||
#define KEEP_STAT_TX(R) (R & (~USB_EPnR_STAT_TX))
|
||||
#define CLEAR_CTR_RX(R) (R & (~USB_EPnR_CTR_RX))
|
||||
#define CLEAR_CTR_TX(R) (R & (~USB_EPnR_CTR_TX))
|
||||
#define CLEAR_CTR_RX_TX(R) (R & (~(USB_EPnR_CTR_TX | USB_EPnR_CTR_RX)))
|
||||
|
||||
// USB state: uninitialized, addressed, ready for use
|
||||
#define USB_DEFAULT_STATE 0
|
||||
#define USB_ADRESSED_STATE 1
|
||||
#define USB_CONFIGURE_STATE 2
|
||||
|
||||
// EP types
|
||||
#define EP_TYPE_BULK 0x00
|
||||
#define EP_TYPE_CONTROL 0x01
|
||||
#define EP_TYPE_ISO 0x02
|
||||
#define EP_TYPE_INTERRUPT 0x03
|
||||
|
||||
#define LANG_US (uint16_t)0x0409
|
||||
|
||||
#define _USB_STRING_(name, str) \
|
||||
static const struct name \
|
||||
{ \
|
||||
uint8_t bLength; \
|
||||
uint8_t bDescriptorType; \
|
||||
uint16_t bString[(sizeof(str) - 2) / 2]; \
|
||||
\
|
||||
} \
|
||||
name = {sizeof(name), 0x03, str}
|
||||
|
||||
#define _USB_LANG_ID_(name, lng_id) \
|
||||
\
|
||||
static const struct name \
|
||||
{ \
|
||||
uint8_t bLength; \
|
||||
uint8_t bDescriptorType; \
|
||||
uint16_t bString; \
|
||||
\
|
||||
} \
|
||||
name = {0x04, 0x03, lng_id}
|
||||
#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4)
|
||||
|
||||
// EP0 configuration packet
|
||||
typedef struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} config_pack_t;
|
||||
|
||||
// endpoints state
|
||||
typedef struct __ep_t{
|
||||
uint16_t *tx_buf; // transmission buffer address
|
||||
uint16_t *rx_buf; // reception buffer address
|
||||
uint16_t (*func)(); // endpoint action function
|
||||
uint16_t status; // status flags
|
||||
unsigned rx_cnt : 10; // received data counter
|
||||
unsigned tx_flag : 1; // transmission flag
|
||||
unsigned rx_flag : 1; // reception flag
|
||||
unsigned setup_flag : 1; // this is setup packet (only for EP0)
|
||||
} ep_t;
|
||||
|
||||
// USB status & its address
|
||||
typedef struct {
|
||||
uint8_t USB_Status;
|
||||
uint16_t USB_Addr;
|
||||
}usb_dev_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t dwDTERate;
|
||||
uint8_t bCharFormat;
|
||||
#define USB_CDC_1_STOP_BITS 0
|
||||
#define USB_CDC_1_5_STOP_BITS 1
|
||||
#define USB_CDC_2_STOP_BITS 2
|
||||
uint8_t bParityType;
|
||||
#define USB_CDC_NO_PARITY 0
|
||||
#define USB_CDC_ODD_PARITY 1
|
||||
#define USB_CDC_EVEN_PARITY 2
|
||||
#define USB_CDC_MARK_PARITY 3
|
||||
#define USB_CDC_SPACE_PARITY 4
|
||||
uint8_t bDataBits;
|
||||
} __attribute__ ((packed)) usb_LineCoding;
|
||||
|
||||
typedef struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bNotificationType;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} __attribute__ ((packed)) usb_cdc_notification;
|
||||
|
||||
extern ep_t endpoints[];
|
||||
|
||||
void USB_Init();
|
||||
uint8_t USB_GetState();
|
||||
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep));
|
||||
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size);
|
||||
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size);
|
||||
int EP_Read(uint8_t number, uint16_t *buf);
|
||||
usb_LineCoding getLineCoding();
|
||||
|
||||
void WEAK linecoding_handler(usb_LineCoding *lc);
|
||||
void WEAK clstate_handler(uint16_t val);
|
||||
void WEAK break_handler();
|
||||
void WEAK vendor_handler(config_pack_t *packet);
|
||||
|
||||
#endif // __USB_LIB_H__
|
||||
4
F1:F103/deprecated/chronometer_v2/Difference
Normal file
4
F1:F103/deprecated/chronometer_v2/Difference
Normal file
@@ -0,0 +1,4 @@
|
||||
Difference from previous version:
|
||||
- new code (some bugs fixed)
|
||||
- backspace (in USB input) used
|
||||
- USART3 (LIDAR) can be used as command TTY
|
||||
179
F1:F103/deprecated/chronometer_v2/GPS.c
Normal file
179
F1:F103/deprecated/chronometer_v2/GPS.c
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* GPS.c
|
||||
*
|
||||
* Copyright 2015 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.
|
||||
*/
|
||||
|
||||
#include "GPS.h"
|
||||
#include "hardware.h"
|
||||
#include "time.h"
|
||||
#include "usart.h"
|
||||
#include "str.h"
|
||||
#include "usb.h"
|
||||
#include <string.h> // memcpy
|
||||
|
||||
#define GPS_send_string(str) do{usart_send(GPS_USART, str);}while(0)
|
||||
|
||||
gps_status GPS_status = GPS_NOTFOUND;
|
||||
int need2startseq = 1;
|
||||
|
||||
static uint8_t hex(uint8_t n){
|
||||
return ((n < 10) ? (n+'0') : (n+'A'-10));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check checksum
|
||||
*/
|
||||
static int checksum_true(const char *buf){
|
||||
char *eol;
|
||||
uint8_t checksum = 0, cs[3];
|
||||
if(*buf != '$' || !(eol = getchr(buf, '*'))){
|
||||
return 0;
|
||||
}
|
||||
while(++buf != eol)
|
||||
checksum ^= (uint8_t)*buf;
|
||||
++buf;
|
||||
cs[0] = hex(checksum >> 4);
|
||||
cs[1] = hex(checksum & 0x0f);
|
||||
if(buf[0] == cs[0] && buf[1] == cs[1])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_chksum(uint8_t chs){
|
||||
usart_putchar(GPS_USART, hex(chs >> 4));
|
||||
usart_putchar(GPS_USART, hex(chs & 0x0f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate checksum & write message to port
|
||||
* @param buf - command to write (without leading $ and trailing *)
|
||||
* return 0 if fails
|
||||
*/
|
||||
static void write_with_checksum(const char *buf){
|
||||
/*
|
||||
for(int i = 0; i < 10000; ++i){
|
||||
char *txt = NULL;
|
||||
if(usartrx(GPS_USART)){
|
||||
usart_getline(GPS_USART, &txt);
|
||||
DBG("Old data");
|
||||
GPS_parse_answer(txt);
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
uint8_t checksum = 0;
|
||||
usart_putchar(GPS_USART, '$');
|
||||
GPS_send_string(buf);
|
||||
do{
|
||||
checksum ^= *buf++;
|
||||
}while(*buf);
|
||||
usart_putchar(GPS_USART, '*');
|
||||
send_chksum(checksum);
|
||||
newline(GPS_USART);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MTK fields format:
|
||||
* $PMTKxxx,yyy,zzz*2E
|
||||
* P - proprietary, MTK - always this, xxx - packet type, yyy,zzz - packet data
|
||||
* Packet types:
|
||||
* 220 - PMTK_SET_POS_FIX, data - position fix interval (msec, > 200)
|
||||
* 255 - PMTK_SET_SYNC_PPS_NMEA - turn on/off (def - off) PPS, data = 0/1 -> "$PMTK255,1" turn ON
|
||||
* 285 - PMTK_SET_PPS_CONFIG - set PPS configuration, data fields:
|
||||
* 1st - 0-disable, 1-after 1st fix, 2-3D only, 3-2D/3D only, 4-always
|
||||
* 2nd - 2..998 - pulse width
|
||||
* 314 - PMTK_API_SET_NMEA_OUTPUT - set output messages, N== N fixes per output,
|
||||
* order of messages: GLL,RMC,VTG,GGA,GSA,GSV,GRS,GST, only RMC per every pos fix:
|
||||
* $PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
* 386 - PMTK_API_SET_STATIC_NAV_THD speed threshold (m/s) for static navigation
|
||||
* $PMTK386,1.5
|
||||
* ;
|
||||
*/
|
||||
|
||||
/**
|
||||
* Send starting sequences (get only RMC messages)
|
||||
*/
|
||||
void GPS_send_start_seq(){
|
||||
DBG("Send start seq");
|
||||
// turn ON PPS:
|
||||
write_with_checksum("PMTK255,1");
|
||||
// set pulse width to 10ms with working after 1st fix
|
||||
write_with_checksum("PMTK285,1,10");
|
||||
// set only RMC:
|
||||
write_with_checksum("PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0");
|
||||
// set static speed threshold
|
||||
write_with_checksum("PMTK386,1.5");
|
||||
need2startseq = 0;
|
||||
}
|
||||
|
||||
// send "full cold start" command to clear all almanach & location data
|
||||
void GPS_send_FullColdStart(){
|
||||
write_with_checksum("PMTK104");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse answer from GPS module
|
||||
*
|
||||
* Recommended minimum specific GPS/Transit data
|
||||
* $GPRMC,hhmmss.sss,status,latitude,N,longitude,E,spd,cog,ddmmyy,mv,mvE,mode*cs
|
||||
* 1 = UTC of position fix
|
||||
* 2 = Data status (V=valid, A=invalid)
|
||||
* 3 = Latitude (ddmm.mmmm)
|
||||
* 4 = N or S
|
||||
* 5 = Longitude (dddmm.mmmm)
|
||||
* 6 = E or W
|
||||
* 7 = Speed over ground in knots
|
||||
* 8 = Cource over ground in degrees
|
||||
* 9 = UT date (ddmmyy)
|
||||
* 10 = Magnetic variation degrees (Easterly var. subtracts from true course)
|
||||
* 11 = E or W
|
||||
* 12 = Mode: N(bad), E(approx), A(auto), D(diff)
|
||||
* 213457.00,A,4340.59415,N,04127.47560,E,2.494,,290615,,,A*7B
|
||||
*/
|
||||
void GPS_parse_answer(const char *buf){
|
||||
char *ptr;
|
||||
if(buf[1] == 'P') return; // answers to proprietary messages
|
||||
if(cmpstr(buf+3, "RMC", 3)){ // not RMC message
|
||||
//need2startseq = 1;
|
||||
return;
|
||||
}
|
||||
if(!checksum_true(buf)){
|
||||
return; // wrong checksum
|
||||
}
|
||||
if(showGPSstr){
|
||||
showGPSstr = 0;
|
||||
sendstring(buf);
|
||||
}
|
||||
buf += 7; // skip header
|
||||
if(*buf == ','){ // time unknown
|
||||
GPS_status = GPS_WAIT;
|
||||
return;
|
||||
}
|
||||
ptr = getchr(buf, ',');
|
||||
if(!ptr ) return;
|
||||
*ptr++ = 0;
|
||||
if(*ptr == 'A'){
|
||||
GPS_status = GPS_VALID;
|
||||
set_time(buf);
|
||||
}else{
|
||||
uint8_t goth = (buf[0]-'0')*10 + buf[1]-'0';
|
||||
if(current_time.H != goth) set_time(buf); // set time once per hour even if it's not valid
|
||||
GPS_status = GPS_NOT_VALID;
|
||||
}
|
||||
}
|
||||
43
F1:F103/deprecated/chronometer_v2/GPS.h
Normal file
43
F1:F103/deprecated/chronometer_v2/GPS.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* GPS.h
|
||||
*
|
||||
* Copyright 2015 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 __GPS_H__
|
||||
#define __GPS_H__
|
||||
|
||||
#include "stm32f1.h"
|
||||
|
||||
extern int need2startseq;
|
||||
|
||||
typedef enum{
|
||||
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;
|
||||
|
||||
extern gps_status GPS_status;
|
||||
|
||||
void GPS_parse_answer(const char *string);
|
||||
void GPS_send_start_seq();
|
||||
void GPS_send_FullColdStart();
|
||||
|
||||
#endif // __GPS_H__
|
||||
159
F1:F103/deprecated/chronometer_v2/Makefile
Normal file
159
F1:F103/deprecated/chronometer_v2/Makefile
Normal file
@@ -0,0 +1,159 @@
|
||||
# make debug adds -DEBUG -Werror
|
||||
# make ADDEFS="additional defs"
|
||||
BINARY = chrono
|
||||
BOOTPORT ?= /dev/ttyUSB0
|
||||
BOOTSPEED ?= 115200
|
||||
# MCU FAMILY
|
||||
FAMILY ?= F1
|
||||
# MCU code
|
||||
MCU ?= F103x8
|
||||
# density (stm32f10x.h, lines 70-84)
|
||||
DENSITY ?= MD
|
||||
# change this linking script depending on particular MCU model,
|
||||
LDSCRIPT ?= stm32F103xB.ld
|
||||
DEFS = ${ADDEFS} -DVERSION=\"0.1.0\"
|
||||
TARGET := RELEASE
|
||||
# proxy GPS output over USART1
|
||||
#DEFS += -DUSART1PROXY
|
||||
|
||||
FP_FLAGS ?= -msoft-float -mfloat-abi=soft
|
||||
ASM_FLAGS ?= -mthumb -mcpu=cortex-m3 -mfix-cortex-m3-ldrd
|
||||
ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS)
|
||||
|
||||
###############################################################################
|
||||
# Executables
|
||||
#PREFIX ?= arm-none-eabi
|
||||
# gcc from arm web site
|
||||
PREFIX ?= /opt/bin/arm-none-eabi
|
||||
TOOLCHLIB ?= /opt/arm-none-eabi/lib
|
||||
RM := rm -f
|
||||
RMDIR := rmdir
|
||||
CC := $(PREFIX)-gcc
|
||||
# don't replace ld with gcc: the binary size would be much greater!!
|
||||
LD := $(PREFIX)-ld
|
||||
AR := $(PREFIX)-ar
|
||||
AS := $(PREFIX)-as
|
||||
SIZE := $(PREFIX)-size
|
||||
OBJCOPY := $(PREFIX)-objcopy
|
||||
OBJDUMP := $(PREFIX)-objdump
|
||||
GDB := $(PREFIX)-gdb
|
||||
STFLASH := $(shell which st-flash)
|
||||
STBOOT := $(shell which stm32flash)
|
||||
DFUUTIL := $(shell which dfu-util)
|
||||
|
||||
###############################################################################
|
||||
# Source files
|
||||
OBJDIR = mk
|
||||
SRC := $(wildcard *.c)
|
||||
OBJS := $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o))
|
||||
STARTUP = $(OBJDIR)/startup.o
|
||||
OBJS += $(STARTUP)
|
||||
# dependencies: we need them to recompile files if their headers-dependencies changed
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
|
||||
INC_DIR ?= ../inc
|
||||
|
||||
INCLUDE := -I$(INC_DIR)/Fx -I$(INC_DIR)/cm
|
||||
LIB_DIR := $(INC_DIR)/ld
|
||||
|
||||
###############################################################################
|
||||
# C flags
|
||||
CFLAGS += -O2 -g -D__thumb2__=1 -MD
|
||||
CFLAGS += -Wall -Wextra -Wshadow
|
||||
CFLAGS += -fno-common -ffunction-sections -fdata-sections -fno-stack-protector
|
||||
CFLAGS += $(ARCH_FLAGS)
|
||||
|
||||
###############################################################################
|
||||
# Linker flags
|
||||
LDFLAGS += --static -nostartfiles -nostdlibs
|
||||
LDFLAGS += -L$(LIB_DIR) -L$(TOOLCHLIB)
|
||||
LDFLAGS += -T$(LDSCRIPT)
|
||||
|
||||
###############################################################################
|
||||
# Used libraries
|
||||
LDLIBS += -lc $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
|
||||
|
||||
DEFS += -DSTM32$(FAMILY) -DSTM32$(MCU) -DSTM32F10X_$(DENSITY)
|
||||
|
||||
ELF := $(OBJDIR)/$(BINARY).elf
|
||||
LIST := $(OBJDIR)/$(BINARY).list
|
||||
BIN := $(BINARY).bin
|
||||
HEX := $(BINARY).hex
|
||||
|
||||
all: $(OBJDIR)/RELEASE bin list size
|
||||
release: all
|
||||
|
||||
debug: CFLAGS += -DEBUG -Werror
|
||||
debug: $(OBJDIR)/DEBUG bin list size
|
||||
|
||||
$(OBJDIR)/DEBUG:
|
||||
@rm -rf $(OBJDIR)
|
||||
@mkdir $(OBJDIR)
|
||||
@> $(OBJDIR)/DEBUG
|
||||
@echo "TARGET: DEBUG"
|
||||
echo "CFLAGS += -DEBUG -Werror" > $(OBJDIR)/CFLAGS
|
||||
$(OBJDIR)/RELEASE:
|
||||
@rm -rf $(OBJDIR)
|
||||
@mkdir $(OBJDIR)
|
||||
@> $(OBJDIR)/RELEASE
|
||||
@echo "TARGET: RELEASE"
|
||||
echo "" > $(OBJDIR)/CFLAGS
|
||||
|
||||
elf: $(ELF)
|
||||
bin: $(BIN)
|
||||
hex: $(HEX)
|
||||
list: $(LIST)
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(DEPS)
|
||||
-include $(OBJDIR)/CFLAGS
|
||||
endif
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir $(OBJDIR)
|
||||
|
||||
$(STARTUP): $(INC_DIR)/startup/vector.c
|
||||
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $<
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
@echo " CC $<"
|
||||
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $<
|
||||
|
||||
$(BIN): $(ELF)
|
||||
@echo " OBJCOPY $(BIN)"
|
||||
$(OBJCOPY) -Obinary $(ELF) $(BIN)
|
||||
|
||||
$(HEX): $(ELF)
|
||||
@echo " OBJCOPY $(HEX)"
|
||||
$(OBJCOPY) -Oihex $(ELF) $(HEX)
|
||||
|
||||
$(LIST): $(ELF)
|
||||
@echo " OBJDUMP $(LIST)"
|
||||
$(OBJDUMP) -S $(ELF) > $(LIST)
|
||||
|
||||
$(ELF): $(OBJDIR) $(OBJS) $(LDSCRIPT)
|
||||
@echo " LD $(ELF)"
|
||||
$(LD) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(ELF)
|
||||
|
||||
size: $(ELF)
|
||||
$(SIZE) $(ELF)
|
||||
|
||||
clean:
|
||||
@echo " CLEAN"
|
||||
@$(RM) $(HEX)
|
||||
@$(RM) -rf $(OBJDIR) 2>/dev/null || true
|
||||
|
||||
|
||||
flash: $(BIN)
|
||||
@echo " FLASH $(BIN)"
|
||||
$(STFLASH) --reset write $(BIN) 0x8000000
|
||||
|
||||
boot: $(BIN)
|
||||
@echo " LOAD $(BIN) through bootloader"
|
||||
$(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN)
|
||||
|
||||
dfuboot: $(BIN)
|
||||
@echo " LOAD $(BIN) THROUGH DFU"
|
||||
$(DFUUTIL) -a0 -D $(BIN) -s 0x08000000
|
||||
|
||||
.PHONY: clean flash boot
|
||||
42
F1:F103/deprecated/chronometer_v2/Readme.md
Normal file
42
F1:F103/deprecated/chronometer_v2/Readme.md
Normal file
@@ -0,0 +1,42 @@
|
||||
Chronometer for downhill competitions
|
||||
=====================================
|
||||
|
||||
The binary have two models: DEBUG (make debug) and RELEASE (make release or just make).
|
||||
DEBUGGing model use USART1 as debugging console, showing many messages.
|
||||
|
||||
When typing commands you can fix them using backspace key. ESC-sequences don't work.
|
||||
|
||||
## Pinout
|
||||
|
||||
### Interfaces
|
||||
|
||||
- PA11/12 -- USB
|
||||
- PA9(Tx), PA10 (Rx) -- USART1 (debug console / Bluetooth / GPS proxy)
|
||||
- PA2(Tx), PA3 -- USART2 (GPS)
|
||||
- PB10(Tx), PB11 -- USART3 (LIDAR / console)
|
||||
|
||||
- PA13/14 - SWDIO
|
||||
|
||||
### Other
|
||||
|
||||
- PA1 -- PPS signal from GPS (EXTI)
|
||||
- PA8 -- Bluetooth "State" pin (not implemented yet)
|
||||
- PA15 -- USB pullup
|
||||
|
||||
- PB0/1 -- TRIG0/1
|
||||
- PB3 -- TRIG2
|
||||
- PB8, PB9 -- onboard LEDs (PB8 - LED1, PB9 - LED0)
|
||||
|
||||
- PC13 -- buzzer
|
||||
|
||||
### LED screen:
|
||||
|
||||
- PA5,6,7 (SCK, MISO, MOSI) -- SPI for LED screen: PA5/7 - SCK/MOSI, PA6 - SCLK/nOE (connected together)
|
||||
- PB6/7 -- A/B for LED screen
|
||||
|
||||
## LEDS
|
||||
|
||||
- LED0 -- shining when there's no PPS signal, fades for 0.25s on PPS
|
||||
- LED1 -- don't shines if no GPS found, shines when time not valid, blinks when time valid
|
||||
|
||||
|
||||
123
F1:F103/deprecated/chronometer_v2/Readme_rus.txt
Normal file
123
F1:F103/deprecated/chronometer_v2/Readme_rus.txt
Normal file
@@ -0,0 +1,123 @@
|
||||
Дополнено выводом времени на LED screen.
|
||||
|
||||
!!! инвертировать USB_PU
|
||||
|
||||
|
||||
****** Распиновка ******
|
||||
|
||||
=== Интерфейсы I/O ===
|
||||
- PA11/12 - USB
|
||||
- PA9(Tx), PA10(Rx) - USART1 - консоль отладки / прокси RMC-сообщений GPS (опт. - bluetooth).
|
||||
- PA2(Tx), PA3(Rx) - USART2 - подключение GPS-приемника.
|
||||
- PB10(Tx), PB11(Rx) - USART3 - подключение лидара или другой консоли.
|
||||
|
||||
=== Остальные порты ===
|
||||
- PA1 - PPS сигнал от GPS; сюда можно подключать любой дополнительный высокоомный вход напрямую.
|
||||
- PB0 - TRIG0 - (замыкать на землю).
|
||||
- PB1 - TRIG1 - подключен к 12В.
|
||||
- PB3 - TRIG2 - (замыкать на землю).
|
||||
- PA15 - подтяжка USB.
|
||||
- PA8 - (еще не реализовано) - bluetooth "state"
|
||||
- PB8, PB9 - индикаторные светодиоды (LED1, LED0 соответственно).
|
||||
- PC13 - пищалка.
|
||||
|
||||
=== Светодиоды ===
|
||||
- LED0 - при отсутствии сигнала PPS просто горит, если PPS появляется - мигает (затухает на 0.25с на каждый сигнал).
|
||||
- LED1 - индикатор GPS: не горит, если приемник не обнаружен; горит постоянно, если неуверенный прием времени
|
||||
(буква "V" во второй позиции RMC-сообщения); мигает при уверенном приеме (буква "A" во второй позиции).
|
||||
Судя по эксперименту, даже через час после пропадания сигнала точность определения события - не хуже 1мс. Сам GPS-приемник выдает
|
||||
PPS даже при отсутствии спутников - лишь бы он успел "подхватить" точное время и начать генерировать pps. Начинать работу можно сразу,
|
||||
как только замигает LED0.
|
||||
|
||||
|
||||
****** Триггеры ******
|
||||
К TRIG0/TRIG2 подключается кнопка, педаль, иной створ, замыкающий контакты. Никакого внешнего напряжения здесь быть не должно!
|
||||
К TRIG1 нужно подключать 12-вольтный сигнал, ток не меньше 10мА. Если створ имеет открытый коллектор, то выход створа подключается
|
||||
к минусу TRIG2, а к плюсу подключается 12В с источника питания.
|
||||
|
||||
Иногда бывают ложные срабатывания триггеров TRIG0..TRIG2, связанные с мощными источниками искр (зажигание, искрящиеся обмотки и т.п.).
|
||||
В случае таких ложных срабатываний рекомендуется заземлить катод источника питания хронометра.
|
||||
|
||||
При подключении внешней кнопки желательно, чтобы она имела нормально замкнутые контакты - это предотвратит ложные срабатывания из-за электромагнитных помех.
|
||||
|
||||
|
||||
****** Подключение ******
|
||||
Хронометр эмулирует "китайский" преобразователь PL2303.
|
||||
|
||||
К выходам PA9/PA10 можно подключить преобразователь USART<>USB или накинуть их напрямую на ноги Rx/Tx "малинки" (не забыв соединить
|
||||
земли хронометра и малинки): PA9(Tx) соединить с Rx, PA10(Rx) - с Tx. Этот USART проксирует RMC-сообщения GPS-приемника (уже после
|
||||
обработки микроконтроллером, поэтому если МК выключен, а приемник включен, сигнала все равно не будет).
|
||||
|
||||
Для подключения PPS сигнала к "малинке" выведен соответствующий разъем.
|
||||
|
||||
|
||||
****** Конфигурация ******
|
||||
Хронометр конфигурируется через USB. Ввод команд не сопровождается эхом (чтобы удобней было работать из внешних программ), поэтому
|
||||
для удобства можно тексты команд копировать из окна текстового редактора.
|
||||
Чтобы увидеть подсказку, достаточно отправить любую строку, начинающуюся с вопросительного знака. Появится справка:
|
||||
|
||||
adcmax - max ADC value treshold for trigger
|
||||
adcmin - min -//- (triggered when ADval>min & <max
|
||||
adcval - get ADC value
|
||||
buzzerS - turn buzzer ON/OFF
|
||||
distmin - min distance threshold (cm)
|
||||
distmax - max distance threshold (cm)
|
||||
gpsrestart - send Full Cold Restart to GPS
|
||||
gpsstring - current GPS data string
|
||||
ledsS - turn leds on/off (1/0)
|
||||
mcutemp - MCU temperature
|
||||
pullupNS - triggers pullups state (N - trigger No, S - 0/1 for off/on)
|
||||
showconf - show current configuration
|
||||
time - print time
|
||||
store - store new configuration in flash
|
||||
triglevelNS - working trigger N level S
|
||||
trigpauseNP - pause (P, ms) after trigger N shots
|
||||
trigtimeN - show last trigger N time
|
||||
vdd - Vdd value
|
||||
|
||||
Из нужного здесь:
|
||||
- gpsrestart - перезапуск GPS (если вдруг начнет глючить - у меня такого не случалось), делает "холодный" рестарт. Команда
|
||||
проверялась лишь на прототипе.
|
||||
- gpsstring - вывод очередного сообщения от GPS. Если все нормально, то появится строка RMC вроде
|
||||
$GPRMC,124001.000,A,4340.9369,N,04127.5034,E,0.00,33.26,150819,,,A*5C
|
||||
- pullupNS - включить или выключить внутренние верхние подтяжки для триггеров 0..3 (особо не нужно, т.к. подтяжки слабые, и если
|
||||
будет нужна подтяжка, лучше сделать сильную внешнюю).
|
||||
- showconf - отображение текущей конфигурации, например:
|
||||
CONFIG:
|
||||
DISTMIN=50
|
||||
DISTMAX=1000
|
||||
ADCMIN=1024
|
||||
ADCMAX=3072
|
||||
PULLUPS=255
|
||||
TRIGLVL=0
|
||||
TRIGPAUSE={400, 400, 400, 300, 300}
|
||||
ENDCONFIG
|
||||
|
||||
пункты конфигурации: DISTMIN/DISTMAX относятся к лидару, ADCMIN/ADCMAX ко входу АЦП, PULLUPS - состояние подтяжек
|
||||
(каждый бит, начиная с младшего - состояние соответствующей подтяжки; 0 - не активна, 1 - активна).
|
||||
TRIGLVL - конфигурация уровней срабатывания, каждый бит, начиная с младшего (всего три младших бита, как и в PULLUPS),
|
||||
равен нулю, если для соответствующего триггера срабатывание при перепаде 1->0, равен единице, если при
|
||||
перепаде 0->1.
|
||||
TRIGPAUSE - пауза между срабатываниями триггера: если после срабатывания произойдет следующее событие за интервал, меньший
|
||||
данного, это событие учитываться не будет.
|
||||
- time - отображает текущее время так, как оно бы отобразилось при срабатывании триггера, например,
|
||||
55725.961 (15:28:45)
|
||||
ВРЕМЯ ИЗМЕРЯЕТСЯ В UTC!!! Первое число - количество секунд и миллисекунд с начала суток по UTC, в скобках
|
||||
указывается человекочитаемое время.
|
||||
- store - сохранить новую конфигурацию во флеш-памяти МК.
|
||||
- triglevelNS - рабочий уровень триггера. Здесь N - номер триггера (0..2), S - уровень (0/1). Скажем, чтобы триггер 0 срабатывал
|
||||
при перепаде 1->0, нужно написать команду
|
||||
triglevel00
|
||||
а чтобы триггер 2 срабатывал при перепаде 0->1,
|
||||
triglevel21
|
||||
- trigpauseNP - задать паузу для триггера N, пауза в миллисекундах. Если написать 0, паузы не будет и каждое срабатывание
|
||||
будет вызывать соответствующее сообщение. Эта пауза нужнад для защиты от "звона" и нескольких срабатываний на "дырках"
|
||||
в объекте. Меньше 50мс лучше не делать.
|
||||
- trigtimeN - отображение последнего времени срабатывания триггера N, например, на запрос trigtime0, может быть выведено:
|
||||
TRIG0=45212.930 (12:33:32)
|
||||
Если срабатываний с момента включения не было, выведутся нули:
|
||||
TRIG4=0.000 (00:00:00)
|
||||
|
||||
После изменения конфигурации и ее сохранения необходимо нажатием на reset или отключением/включением питания перезагрузить МК,
|
||||
т.к. некоторые параметры активируются лишь при старте.
|
||||
|
||||
72
F1:F103/deprecated/chronometer_v2/adc.c
Normal file
72
F1:F103/deprecated/chronometer_v2/adc.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is part of the chronometer project.
|
||||
* Copyright 2018 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adc.h"
|
||||
#include "flash.h"
|
||||
#include "hardware.h"
|
||||
|
||||
/**
|
||||
* @brief ADC_array - array for ADC channels with median filtering:
|
||||
* 0 - Rvar
|
||||
* 1 - internal Tsens
|
||||
* 2 - Vref
|
||||
*/
|
||||
uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9];
|
||||
|
||||
/**
|
||||
* @brief getADCval - calculate median value for `nch` channel
|
||||
* @param nch - number of channel
|
||||
* @return
|
||||
*/
|
||||
uint16_t getADCval(int nch){
|
||||
int i, addr = nch;
|
||||
register uint16_t temp;
|
||||
#define PIX_SORT(a,b) do{ if ((a)>(b)) PIX_SWAP((a),(b)); }while(0)
|
||||
#define PIX_SWAP(a,b) do{ temp=(a);(a)=(b);(b)=temp; }while(0)
|
||||
uint16_t p[9];
|
||||
for(i = 0; i < 9; ++i, addr += NUMBER_OF_ADC_CHANNELS) // first we should prepare array for optmed
|
||||
p[i] = ADC_array[addr];
|
||||
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
|
||||
PIX_SORT(p[0], p[1]) ; PIX_SORT(p[3], p[4]) ; PIX_SORT(p[6], p[7]) ;
|
||||
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
|
||||
PIX_SORT(p[0], p[3]) ; PIX_SORT(p[5], p[8]) ; PIX_SORT(p[4], p[7]) ;
|
||||
PIX_SORT(p[3], p[6]) ; PIX_SORT(p[1], p[4]) ; PIX_SORT(p[2], p[5]) ;
|
||||
PIX_SORT(p[4], p[7]) ; PIX_SORT(p[4], p[2]) ; PIX_SORT(p[6], p[4]) ;
|
||||
PIX_SORT(p[4], p[2]) ;
|
||||
return p[4];
|
||||
#undef PIX_SORT
|
||||
#undef PIX_SWAP
|
||||
}
|
||||
|
||||
// return MCU temperature (degrees of celsius * 10)
|
||||
int32_t getMCUtemp(){
|
||||
// Temp = (V25 - Vsense)/Avg_Slope + 25
|
||||
// V_25 = 1.45V, Slope = 4.3e-3
|
||||
uint32_t Vsense = getVdd() * getADCval(ADC_TMCU_CHANNEL);
|
||||
int32_t temperature = 593920 - (int32_t)Vsense; // 593920 == 145*4096
|
||||
temperature /= 172; // == /(4096*10*4.3e-3), 10 - to convert from *100 to *10
|
||||
temperature += 250;
|
||||
return(temperature);
|
||||
}
|
||||
|
||||
// return Vdd * 100 (V)
|
||||
uint32_t getVdd(){
|
||||
uint32_t vdd = 120 * 4096; // 1.2V
|
||||
vdd /= getADCval(ADC_VDD_CHANNEL);
|
||||
return vdd;
|
||||
}
|
||||
32
F1:F103/deprecated/chronometer_v2/adc.h
Normal file
32
F1:F103/deprecated/chronometer_v2/adc.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of the chronometer project.
|
||||
* Copyright 2018 Edward V. Emelianov <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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef ADC_H
|
||||
#define ADC_H
|
||||
#include "stm32f1.h"
|
||||
|
||||
// interval of trigger's shot (>min && <max), maybe negative
|
||||
#define ADC_MIN_VAL (1024)
|
||||
#define ADC_MAX_VAL (3072)
|
||||
// 2*ADC_THRESHOLD = hysteresis width
|
||||
#define ADC_THRESHOLD (50)
|
||||
|
||||
extern uint16_t ADC_array[];
|
||||
int32_t getMCUtemp();
|
||||
uint32_t getVdd();
|
||||
uint16_t getADCval(int nch);
|
||||
#endif // ADC_H
|
||||
BIN
F1:F103/deprecated/chronometer_v2/chrono.bin
Executable file
BIN
F1:F103/deprecated/chronometer_v2/chrono.bin
Executable file
Binary file not shown.
318
F1:F103/deprecated/chronometer_v2/flash.c
Normal file
318
F1:F103/deprecated/chronometer_v2/flash.c
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* 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 "adc.h"
|
||||
#include "flash.h"
|
||||
#include "lidar.h"
|
||||
#include "str.h"
|
||||
#include "usart.h" // DBG
|
||||
#include "usb.h" // printout
|
||||
#include <string.h> // memcpy
|
||||
|
||||
// max amount of records stored: Config & Logs
|
||||
uint32_t maxCnum = FLASH_BLOCK_SIZE / sizeof(user_conf);
|
||||
uint32_t maxLnum = FLASH_BLOCK_SIZE / sizeof(user_conf);
|
||||
|
||||
// common structure for all datatypes stored
|
||||
/*typedef struct {
|
||||
uint16_t userconf_sz;
|
||||
} flash_storage;*/
|
||||
|
||||
#define USERCONF_INITIALIZER { \
|
||||
.userconf_sz = sizeof(user_conf) \
|
||||
,.dist_min = LIDAR_MIN_DIST \
|
||||
,.dist_max = LIDAR_MAX_DIST \
|
||||
,.trigstate = 0 \
|
||||
,.trigpause = {400, 400, 400, 300} \
|
||||
,.USART_speed = USART1_DEFAULT_SPEED \
|
||||
,.LIDAR_speed = LIDAR_DEFAULT_SPEED \
|
||||
,.defflags = 0 \
|
||||
,.NLfreeWarn = 100 \
|
||||
}
|
||||
|
||||
// change to placement
|
||||
/*
|
||||
__attribute__ ((section(".logs"))) const uint32_t *logsstart;
|
||||
__attribute__ ((section(".myvars"))) const user_conf *Flash_Data;
|
||||
*/
|
||||
|
||||
static int erase_flash(const void*, const void*);
|
||||
static int write2flash(const void*, const void*, uint32_t);
|
||||
|
||||
const user_conf *Flash_Data = (const user_conf *)&__varsstart;
|
||||
const event_log *logsstart = (event_log*) &__logsstart;
|
||||
TODO("Add to event_log a comment - up to 8 chars")
|
||||
|
||||
user_conf the_conf = USERCONF_INITIALIZER;
|
||||
|
||||
static int currentconfidx = -1; // index of current configuration
|
||||
static int currentlogidx = -1; // index of current logs record
|
||||
|
||||
/**
|
||||
* @brief binarySearch - binary search in flash for last non-empty cell
|
||||
* any struct searched should have its sizeof() @ the first field!!!
|
||||
* @param l - left index
|
||||
* @param r - right index (should be @1 less than last index!)
|
||||
* @param start - starting address
|
||||
* @param stor_size - size of structure to search
|
||||
* @return index of non-empty cell or -1
|
||||
*/
|
||||
static int binarySearch(int r, const uint8_t *start, int stor_size){
|
||||
int l = 0;
|
||||
while(r >= l){
|
||||
int mid = l + (r - l) / 2;
|
||||
const uint8_t *s = start + mid * stor_size;
|
||||
if(*((const uint16_t*)s) == stor_size){
|
||||
if(*((const uint16_t*)(s + stor_size)) == 0xffff){
|
||||
return mid;
|
||||
}else{ // element is to the right
|
||||
l = mid + 1;
|
||||
}
|
||||
}else{ // element is to the left
|
||||
r = mid - 1;
|
||||
}
|
||||
}
|
||||
return -1; // not found
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief flashstorage_init - initialization of user conf & logs storage
|
||||
* run in once @ start
|
||||
*/
|
||||
void flashstorage_init(){
|
||||
maxCnum = ((uint32_t)&_varslen) / sizeof(user_conf);
|
||||
//SEND("maxCnum="); printu(1, maxCnum);
|
||||
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
|
||||
uint32_t flsz = FLASH_SIZE * 1024; // size in bytes
|
||||
flsz -= (uint32_t)logsstart - FLASH_BASE;
|
||||
maxLnum = flsz / sizeof(event_log);
|
||||
//SEND("\nmaxLnum="); printu(1, maxLnum);
|
||||
}
|
||||
// -1 if there's no data at all & flash is clear; maxnum-1 if flash is full
|
||||
currentconfidx = binarySearch((int)maxCnum-2, (const uint8_t*)Flash_Data, sizeof(user_conf));
|
||||
if(currentconfidx > -1){
|
||||
memcpy(&the_conf, &Flash_Data[currentconfidx], sizeof(user_conf));
|
||||
}
|
||||
currentlogidx = binarySearch((int)maxLnum-2, (const uint8_t*)logsstart, sizeof(event_log));
|
||||
}
|
||||
|
||||
// store new configuration
|
||||
// @return 0 if all OK
|
||||
int store_userconf(){
|
||||
// maxnum - 3 means that there always should be at least one empty record after last data
|
||||
// for binarySearch() checking that there's nothing more after it!
|
||||
if(currentconfidx > (int)maxCnum - 3){ // there's no more place
|
||||
currentconfidx = 0;
|
||||
DBG("Need to erase flash!");
|
||||
if(erase_flash(Flash_Data, logsstart)) return 1;
|
||||
}else ++currentconfidx; // take next data position (0 - within first run after firmware flashing)
|
||||
return write2flash((const void*)&Flash_Data[currentconfidx], &the_conf, sizeof(the_conf));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief store_log - save log record L into flash memory
|
||||
* @param L - event log (or NULL to delete flash)
|
||||
* @return 0 if all OK
|
||||
*/
|
||||
int store_log(event_log *L){
|
||||
if(!L){
|
||||
currentlogidx = -1;
|
||||
return erase_flash(logsstart, NULL);
|
||||
}
|
||||
if(currentlogidx > (int)maxLnum - 3){ // there's no more place
|
||||
/*currentlogidx = 0;
|
||||
DBG("Need to erase flash!");
|
||||
if(erase_flash(logsstart, NULL)) return 1;*/
|
||||
// prevent automatic logs erasing!
|
||||
sendstring("\n\nERROR!\nCan't save logs: delete old manually!!!\n");
|
||||
return 1;
|
||||
}else ++currentlogidx; // take next data position (0 - within first run after firmware flashing)
|
||||
// put warning if there's little space
|
||||
if(currentlogidx + the_conf.NLfreeWarn > (int)maxLnum - 3){
|
||||
uint32_t nfree = maxLnum - 2 - (uint32_t)currentlogidx;
|
||||
sendstring("\n\nWARNING!\nCan store only ");
|
||||
sendstring(u2str(nfree));
|
||||
sendstring(" logs!\n\n");
|
||||
}
|
||||
return write2flash(&logsstart[currentlogidx], L, sizeof(event_log));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief dump_log - dump N log records
|
||||
* @param start - first record to show (if start<0, then first=last+start)
|
||||
* @param Nlogs - amount of logs to show (if Nlogs<=0, then show all logs)
|
||||
* @return 0 if all OK, 1 if there's no logs in flash
|
||||
*/
|
||||
int dump_log(int start, int Nlogs){
|
||||
if(currentlogidx < 0) return 1;
|
||||
if(start < 0){
|
||||
start += currentlogidx + 1;
|
||||
if(start < 0) start = 0;
|
||||
}
|
||||
if(start > currentlogidx) return 1;
|
||||
int nlast;
|
||||
if(Nlogs > 0){
|
||||
nlast = start + Nlogs - 1;
|
||||
if(nlast > currentlogidx) nlast = currentlogidx;
|
||||
}else nlast = currentlogidx;
|
||||
++nlast;
|
||||
const event_log *l = logsstart + start;
|
||||
for(int i = start; i < nlast; ++i, ++l){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
sendstring(get_trigger_shot(i, l));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write2flash(const void *start, const void *wrdata, uint32_t stor_size){
|
||||
int ret = 0;
|
||||
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){
|
||||
DBG("Can't remove write protection");
|
||||
return 1; // write protection
|
||||
}
|
||||
FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; // clear all flags
|
||||
FLASH->CR |= FLASH_CR_PG;
|
||||
const uint16_t *data = (const uint16_t*) wrdata;
|
||||
volatile uint16_t *address = (volatile uint16_t*) start;
|
||||
uint32_t i, count = (stor_size + 1) / 2;
|
||||
for (i = 0; i < count; ++i){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
*(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
|
||||
DBG("FLASH_SR_PGERR");
|
||||
break;
|
||||
}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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief erase_flash - erase N pages of flash memory
|
||||
* @param start - first address
|
||||
* @param end - last address (or NULL if need to erase all flash remaining)
|
||||
* @return 0 if succeed
|
||||
*/
|
||||
static int erase_flash(const void *start, const void *end){
|
||||
int ret = 0;
|
||||
uint32_t nblocks = 1, flsz = 0;
|
||||
if(!end){ // erase all remaining
|
||||
if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){
|
||||
flsz = FLASH_SIZE * 1024; // size in bytes
|
||||
flsz -= (uint32_t)start - FLASH_BASE;
|
||||
}
|
||||
}else{ // erase a part
|
||||
flsz = (uint32_t)end - (uint32_t)start;
|
||||
}
|
||||
nblocks = flsz / FLASH_BLOCK_SIZE;
|
||||
if(nblocks == 0 || nblocks >= FLASH_SIZE) return 1;
|
||||
for(uint32_t i = 0; i < nblocks; ++i){
|
||||
#ifdef EBUG
|
||||
SEND("Try to erase page #"); printu(1,i); newline(1);
|
||||
#endif
|
||||
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) */
|
||||
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);
|
||||
SEND("\ndist_min="); printu(1, the_conf.dist_min);
|
||||
SEND("\ndist_max="); printu(1, the_conf.dist_max);
|
||||
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){
|
||||
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(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
SEND("Curr idx: "); printu(1, currentconfidx); newline(1);
|
||||
}
|
||||
|
||||
#endif
|
||||
88
F1:F103/deprecated/chronometer_v2/flash.h
Normal file
88
F1:F103/deprecated/chronometer_v2/flash.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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>
|
||||
#include "hardware.h"
|
||||
|
||||
#define FLASH_BLOCK_SIZE (1024)
|
||||
#define FLASH_SIZE_REG ((uint32_t)0x1FFFF7E0)
|
||||
#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG)
|
||||
|
||||
/*
|
||||
* struct to save user configurations
|
||||
*/
|
||||
typedef struct __attribute__((packed, aligned(4))){
|
||||
uint16_t userconf_sz; // "magick number"
|
||||
uint16_t NLfreeWarn; // warn user when there's less free log records than NLfreeWarn
|
||||
uint8_t trigstate; // level in `triggered` state
|
||||
uint8_t defflags; // default flags
|
||||
uint16_t dist_min; // minimal distance for LIDAR
|
||||
uint16_t dist_max; // maximal -//-
|
||||
uint32_t USART_speed; // USART1 speed (115200 by default)
|
||||
uint32_t LIDAR_speed; // USART3 speed (115200 by default)
|
||||
uint16_t trigpause[TRIGGERS_AMOUNT]; // pause (ms) for false shots
|
||||
} user_conf;
|
||||
|
||||
// values for user_conf.defflags:
|
||||
// save events in flash
|
||||
#define FLAG_SAVE_EVENTS (1 << 0)
|
||||
// strings ends with "\r\n" instead of normal "\n"
|
||||
#define FLAG_STRENDRN (1 << 1)
|
||||
// proxy GPS messages over USART1
|
||||
#define FLAG_GPSPROXY (1 << 2)
|
||||
// USART3 works as regular TTY instead of LIDAR
|
||||
#define FLAG_NOLIDAR (1 << 3)
|
||||
|
||||
/*
|
||||
* struct to save events logs
|
||||
*/
|
||||
typedef struct __attribute__((packed, aligned(4))){
|
||||
uint16_t elog_sz;
|
||||
uint8_t trigno;
|
||||
trigtime shottime;
|
||||
int16_t triglen;
|
||||
uint16_t lidar_dist;
|
||||
} event_log;
|
||||
|
||||
extern user_conf the_conf;
|
||||
extern const user_conf *Flash_Data;
|
||||
extern const event_log *logsstart;
|
||||
extern uint32_t maxCnum, maxLnum;
|
||||
// data from ld-file
|
||||
extern uint32_t _varslen, __varsstart, __logsstart;
|
||||
|
||||
|
||||
void flashstorage_init();
|
||||
int store_userconf();
|
||||
int store_log(event_log *L);
|
||||
int dump_log(int start, int Nlogs);
|
||||
|
||||
#ifdef EBUG
|
||||
void dump_userconf();
|
||||
void addNrecs(int N);
|
||||
#endif
|
||||
|
||||
#endif // __FLASH_H__
|
||||
266
F1:F103/deprecated/chronometer_v2/hardware.c
Normal file
266
F1:F103/deprecated/chronometer_v2/hardware.c
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* hardware.c - hardware-dependent macros & functions
|
||||
*
|
||||
* Copyright 2018 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "adc.h"
|
||||
#include "hardware.h"
|
||||
#include "flash.h"
|
||||
#include "lidar.h"
|
||||
#include "str.h"
|
||||
#include "time.h"
|
||||
#include "usart.h"
|
||||
|
||||
#include <string.h> // memcpy
|
||||
|
||||
uint8_t buzzer_on = 1; // buzzer ON by default
|
||||
uint8_t LEDSon = 1; // LEDS are working
|
||||
// ports of triggers: PB0, PB1, PB3
|
||||
static GPIO_TypeDef *trigport[DIGTRIG_AMOUNT] = {GPIOB, GPIOB, GPIOB};
|
||||
// pins of triggers: 0, 1, 3
|
||||
static uint16_t trigpin[DIGTRIG_AMOUNT] = {1<<0, 1<<1, 1<<3};
|
||||
// value of pin in `triggered` state
|
||||
static uint8_t trigstate[DIGTRIG_AMOUNT];
|
||||
// time of triggers shot
|
||||
trigtime shottime[TRIGGERS_AMOUNT];
|
||||
// Tms value when they shot
|
||||
uint32_t shotms[TRIGGERS_AMOUNT];
|
||||
// trigger length (-1 if > MAX_TRIG_LEN)
|
||||
int16_t triglen[TRIGGERS_AMOUNT];
|
||||
// if trigger[N] shots, the bit N will be 1
|
||||
uint8_t trigger_shot = 0;
|
||||
|
||||
static inline void gpio_setup(){
|
||||
BUZZER_OFF(); // turn off buzzer @start
|
||||
LED_on(); // turn ON LED0 @start
|
||||
LED1_off(); // turn off LED1 @start
|
||||
USBPU_OFF(); // turn off USB pullup @start
|
||||
// Enable clocks to the GPIO subsystems (PB for ADC), turn on AFIO clocking enable EXTI & so on
|
||||
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN;
|
||||
// turn off JTAG (PA15, PB3)
|
||||
AFIO->MAPR = AFIO_MAPR_SWJ_CFG_JTAGDISABLE;
|
||||
// AFIO->MAPR = AFIO_MAPR_SWJ_CFG_DISABLE;
|
||||
// pullups: PA1 - PPS, PA15 - USB pullup
|
||||
GPIOA->ODR = (1<<1)|(1<<15);
|
||||
// PPS pin (PA1) - input with weak pullup
|
||||
GPIOA->CRL = CRL(1, CNF_PUDINPUT|MODE_INPUT);
|
||||
EXTI->IMR = EXTI_IMR_MR1; // mask PA1
|
||||
// interrupt on pulse front: buttons - 1->0, PPS - 0->1
|
||||
EXTI->RTSR = EXTI_RTSR_TR1; // rising trigger for PPS
|
||||
NVIC_EnableIRQ(EXTI1_IRQn); // enable PPS interrupt
|
||||
// Set USB pullup (PA15) - opendrain output
|
||||
GPIOA->CRH = CRH(15, CNF_ODOUTPUT|MODE_SLOW);
|
||||
// Set leds (PB8/9) as opendrain output
|
||||
GPIOB->CRH = CRH(8, CNF_ODOUTPUT|MODE_SLOW) | CRH(9, CNF_ODOUTPUT|MODE_SLOW);
|
||||
|
||||
/**************** Trigger inputs ******************/
|
||||
GPIOB->CRL = CRL(0, CNF_PUDINPUT|MODE_INPUT) | CRL(1, CNF_PUDINPUT|MODE_INPUT) | CRL(3, CNF_PUDINPUT|MODE_INPUT);
|
||||
// buzzer (PC13): pushpull output
|
||||
GPIOC->CRH = CRH(13, CNF_PPOUTPUT|MODE_SLOW);
|
||||
// exti: PB0, 3; PA1
|
||||
AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI0_PB | AFIO_EXTICR1_EXTI1_PA | AFIO_EXTICR1_EXTI3_PB;
|
||||
// PB0/1/3 - triggers
|
||||
for(int i = 0; i < DIGTRIG_AMOUNT; ++i){
|
||||
uint16_t pin = trigpin[i];
|
||||
if(pin == 1<<1) continue; // omit PB1
|
||||
// fill trigstate array
|
||||
uint8_t trgs = (the_conf.trigstate & (1<<i)) ? 1 : 0;
|
||||
trigstate[i] = trgs;
|
||||
trigport[i]->ODR |= pin; // turn on pullups
|
||||
if(i != 1){ // turn interrupts on
|
||||
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(EXTI0_IRQn); // PB0
|
||||
NVIC_EnableIRQ(EXTI3_IRQn); // PB3
|
||||
// <---------------------
|
||||
}
|
||||
|
||||
static inline void adc_setup(){
|
||||
GPIOB->CRL |= CRL(0, CNF_ANALOG|MODE_INPUT);
|
||||
uint32_t ctr = 0;
|
||||
// Enable clocking
|
||||
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
|
||||
RCC->CFGR &= ~(RCC_CFGR_ADCPRE);
|
||||
RCC->CFGR |= RCC_CFGR_ADCPRE_DIV8; // ADC clock = RCC / 8
|
||||
// sampling time - 239.5 cycles for channels 16 and 17
|
||||
ADC1->SMPR1 = ADC_SMPR1_SMP16 | ADC_SMPR1_SMP17;
|
||||
// we have three conversions in group -> ADC1->SQR1[L] = 2, order: 16->17
|
||||
// Tsens == 16, Vdd == 17
|
||||
ADC1->SQR3 = (16<<0) | (17<<5);
|
||||
ADC1->SQR1 = ADC_SQR1_L_0; // 2 conversions
|
||||
ADC1->CR1 |= ADC_CR1_SCAN; // scan mode
|
||||
// DMA configuration
|
||||
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
|
||||
DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR));
|
||||
DMA1_Channel1->CMAR = (uint32_t)(ADC_array);
|
||||
DMA1_Channel1->CNDTR = NUMBER_OF_ADC_CHANNELS * 9;
|
||||
DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0
|
||||
| DMA_CCR_CIRC | DMA_CCR_PL | DMA_CCR_EN;
|
||||
// continuous mode & DMA; enable vref & Tsens; wake up ADC
|
||||
ADC1->CR2 |= ADC_CR2_DMA | ADC_CR2_TSVREFE | ADC_CR2_CONT | ADC_CR2_ADON;
|
||||
// wait for Tstab - at least 1us
|
||||
while(++ctr < 0xff) nop();
|
||||
// calibration
|
||||
ADC1->CR2 |= ADC_CR2_RSTCAL;
|
||||
ctr = 0; while((ADC1->CR2 & ADC_CR2_RSTCAL) && ++ctr < 0xfffff);
|
||||
ADC1->CR2 |= ADC_CR2_CAL;
|
||||
ctr = 0; while((ADC1->CR2 & ADC_CR2_CAL) && ++ctr < 0xfffff);
|
||||
// turn ON ADC
|
||||
ADC1->CR2 |= ADC_CR2_ADON;
|
||||
}
|
||||
|
||||
void hw_setup(){
|
||||
gpio_setup();
|
||||
adc_setup();
|
||||
}
|
||||
|
||||
static trigtime trgtm;
|
||||
void savetrigtime(){
|
||||
trgtm.millis = Timer;
|
||||
memcpy(&trgtm.Time, ¤t_time, sizeof(curtime));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief fillshotms - save trigger shot time
|
||||
* @param i - trigger number
|
||||
*/
|
||||
void fillshotms(int i){
|
||||
if(i < 0 || i >= TRIGGERS_AMOUNT) return;
|
||||
if(Tms - shotms[i] > (uint32_t)the_conf.trigpause[i] || i == LIDAR_TRIGGER){
|
||||
memcpy(&shottime[i], &trgtm, sizeof(trigtime));
|
||||
shotms[i] = Tms;
|
||||
trigger_shot |= 1<<i;
|
||||
BUZZER_ON();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief fillunshotms - calculate trigger length time
|
||||
*/
|
||||
void fillunshotms(){
|
||||
if(!trigger_shot) return;
|
||||
uint8_t X = 1;
|
||||
for(int i = 0; i < TRIGGERS_AMOUNT; ++i, X<<=1){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
// check whether trigger is OFF but shot recently
|
||||
if(trigger_shot & X){
|
||||
uint32_t len = Tms - shotms[i];
|
||||
uint8_t rdy = 0;
|
||||
if(len > MAX_TRIG_LEN){
|
||||
triglen[i] = -1;
|
||||
rdy = 1;
|
||||
}else triglen[i] = (int16_t) len;
|
||||
if(i == LIDAR_TRIGGER){
|
||||
if(!parse_lidar_data(NULL)) rdy = 1;
|
||||
}else{
|
||||
uint8_t pinval = (trigport[i]->IDR & trigpin[i]) ? 1 : 0;
|
||||
if(pinval != trigstate[i]) rdy = 1; // trigger is OFF
|
||||
}
|
||||
if(rdy){
|
||||
if(i != LIDAR_TRIGGER) shotms[i] = Tms;
|
||||
show_trigger_shot(X);
|
||||
trigger_shot &= ~X;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void exti0_isr(){ // PB0 - trig0
|
||||
savetrigtime();
|
||||
fillshotms(0);
|
||||
EXTI->PR = EXTI_PR_PR0;
|
||||
}
|
||||
|
||||
void exti1_isr(){ // PPS - PA1
|
||||
systick_correction();
|
||||
LED_off(); // turn off LED0 @ each PPS
|
||||
EXTI->PR = EXTI_PR_PR1;
|
||||
}
|
||||
|
||||
void chkTrig1(){
|
||||
// ================> HARD HARDWARE DEPENDENT: PB1 trigger
|
||||
static uint8_t oldstate = 0;
|
||||
uint8_t curstate = GPIOB->IDR & 2;
|
||||
if(Tms < 100){ // don't mind for first 100ms
|
||||
oldstate = curstate;
|
||||
return;
|
||||
}
|
||||
if(curstate == oldstate){ // state didn't changed
|
||||
return;
|
||||
}
|
||||
oldstate = curstate;
|
||||
if(curstate != (the_conf.trigstate & 2)) return; // relax from trigger
|
||||
savetrigtime();
|
||||
fillshotms(1);
|
||||
// <================
|
||||
}
|
||||
|
||||
void exti3_isr(){ // PB3 - trig2
|
||||
savetrigtime();
|
||||
fillshotms(2);
|
||||
EXTI->PR = EXTI_PR_PR3;
|
||||
}
|
||||
|
||||
#ifdef EBUG
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
#endif
|
||||
|
||||
void chk_buzzer(){
|
||||
static uint32_t Ton = 0; // Time of first buzzer check
|
||||
if(!BUZZER_GET()) return; // buzzer if OFF
|
||||
if(!trigger_shot){ // should we turn off buzzer?
|
||||
uint8_t notrg = 1;
|
||||
for(int i = 0; i < DIGTRIG_AMOUNT; ++i){
|
||||
uint8_t curval = (trigport[i]->IDR & trigpin[i]) ? 1 : 0;
|
||||
if(curval == trigstate[i]){
|
||||
notrg = 0; // cheep while digital trigger is ON
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(notrg){ // turn off buzzer when there's no trigger events & timeout came
|
||||
if(Tms - Ton < BUZZER_CHEEP_TIME) return;
|
||||
Ton = 0;
|
||||
BUZZER_OFF();
|
||||
}
|
||||
}else{ // buzzer is ON - check timer
|
||||
if(Ton == 0){
|
||||
Ton = Tms;
|
||||
if(!Ton) Ton = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
118
F1:F103/deprecated/chronometer_v2/hardware.h
Normal file
118
F1:F103/deprecated/chronometer_v2/hardware.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* hardware.h
|
||||
*
|
||||
* Copyright 2018 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 __HARDWARE_H__
|
||||
#define __HARDWARE_H__
|
||||
|
||||
#include "stm32f1.h"
|
||||
#include "time.h"
|
||||
|
||||
#ifdef EBUG
|
||||
#define DO_PRAGMA(x) _Pragma (#x)
|
||||
#define TODO(x) DO_PRAGMA(message #x)
|
||||
#else
|
||||
#define TODO(x)
|
||||
#endif
|
||||
|
||||
// only 2 ADC channels used: Tmcu and Vdd
|
||||
#define NUMBER_OF_ADC_CHANNELS (2)
|
||||
#define ADC_TMCU_CHANNEL (0)
|
||||
#define ADC_VDD_CHANNEL (1)
|
||||
|
||||
// onboard LEDs - PB8/PB9
|
||||
#define LED0_port GPIOB
|
||||
#define LED0_pin (1<<9)
|
||||
#define LED1_port GPIOB
|
||||
#define LED1_pin (1<<8)
|
||||
|
||||
// buzzer (1 - active) - PC13
|
||||
extern uint8_t buzzer_on;
|
||||
#define BUZZER_port GPIOC
|
||||
#define BUZZER_pin (1<<13)
|
||||
#define BUZZER_ON() do{if(buzzer_on)pin_set(BUZZER_port, BUZZER_pin);}while(0)
|
||||
#define BUZZER_OFF() pin_clear(BUZZER_port, BUZZER_pin)
|
||||
#define BUZZER_GET() (pin_read(BUZZER_port, BUZZER_pin))
|
||||
// minimal time to buzzer to cheep (ms)
|
||||
#define BUZZER_CHEEP_TIME 500
|
||||
|
||||
// PPS pin - PA1
|
||||
#define PPS_port GPIOA
|
||||
#define PPS_pin (1<<1)
|
||||
|
||||
// PPS and triggers state
|
||||
// amount of triggers, should be less than 9; 4 - 0..2 - switches, 3 - LIDAR
|
||||
#define TRIGGERS_AMOUNT 4
|
||||
// number of LIDAR trigger
|
||||
#define LIDAR_TRIGGER 3
|
||||
// amount of digital triggers (on interrupts)
|
||||
#define DIGTRIG_AMOUNT 3
|
||||
// max length of trigger event (ms)
|
||||
#define MAX_TRIG_LEN 1000
|
||||
|
||||
#ifdef EBUG
|
||||
uint8_t gettrig(uint8_t N);
|
||||
#endif
|
||||
void fillshotms(int i);
|
||||
void fillunshotms();
|
||||
void savetrigtime();
|
||||
#define GET_PPS() ((GPIOA->IDR & (1<<1)) ? 1 : 0)
|
||||
|
||||
// USB pullup - PA15
|
||||
#define USBPU_port GPIOA
|
||||
#define USBPU_pin (1<<15)
|
||||
#define USBPU_ON() pin_clear(USBPU_port, USBPU_pin)
|
||||
#define USBPU_OFF() pin_set(USBPU_port, USBPU_pin)
|
||||
|
||||
#define LED_blink() do{if(LEDSon)pin_toggle(LED0_port, LED0_pin);}while(0)
|
||||
#define LED_on() do{if(LEDSon)pin_clear(LED0_port, LED0_pin);}while(0)
|
||||
#define LED_off() do{pin_set(LED0_port, LED0_pin);}while(0)
|
||||
#define LED1_blink() do{if(LEDSon)pin_toggle(LED1_port, LED1_pin);}while(0)
|
||||
#define LED1_on() do{if(LEDSon)pin_clear(LED1_port, LED1_pin);}while(0)
|
||||
#define LED1_off() do{pin_set(LED1_port, LED1_pin);}while(0)
|
||||
|
||||
// GPS USART == USART2, LIDAR USART == USART3
|
||||
#define GPS_USART (2)
|
||||
#define LIDAR_USART (3)
|
||||
|
||||
typedef struct{
|
||||
uint32_t millis;
|
||||
curtime Time;
|
||||
} trigtime;
|
||||
|
||||
// turn on/off LEDs:
|
||||
extern uint8_t LEDSon;
|
||||
// time of triggers shot
|
||||
extern trigtime shottime[TRIGGERS_AMOUNT];
|
||||
// length (in ms) of trigger event (-1 if > MAX_TRIG_LEN
|
||||
extern int16_t triglen[TRIGGERS_AMOUNT];
|
||||
// if trigger[N] shots, the bit N will be 1
|
||||
extern uint8_t trigger_shot;
|
||||
// Tms value when they shot
|
||||
extern uint32_t shotms[TRIGGERS_AMOUNT];
|
||||
|
||||
void chk_buzzer();
|
||||
void hw_setup();
|
||||
|
||||
void chkTrig1();
|
||||
|
||||
#endif // __HARDWARE_H__
|
||||
BIN
F1:F103/deprecated/chronometer_v2/kicad/2019.10.23-22:09:24.png
Normal file
BIN
F1:F103/deprecated/chronometer_v2/kicad/2019.10.23-22:09:24.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
BIN
F1:F103/deprecated/chronometer_v2/kicad/2019.10.23_22:08:42.png
Normal file
BIN
F1:F103/deprecated/chronometer_v2/kicad/2019.10.23_22:08:42.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 156 KiB |
31
F1:F103/deprecated/chronometer_v2/kicad/Chrono.lib
Normal file
31
F1:F103/deprecated/chronometer_v2/kicad/Chrono.lib
Normal file
@@ -0,0 +1,31 @@
|
||||
EESchema-LIBRARY Version 2.4
|
||||
#encoding utf-8
|
||||
#
|
||||
# L80-R
|
||||
#
|
||||
DEF L80-R U 0 40 Y Y 1 F N
|
||||
F0 "U" 0 -375 50 H V C CNN
|
||||
F1 "L80-R" 0 425 50 H V C CNN
|
||||
F2 "chrono:L80-R" 0 0 50 H I C CNN
|
||||
F3 "" -550 -50 50 H I C CNN
|
||||
$FPLIST
|
||||
L80-R
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
S -250 350 250 -325 0 1 0 N
|
||||
X RXD 1 -450 250 200 R 50 50 1 1 P
|
||||
X RESET 10 450 50 200 L 50 50 1 1 P
|
||||
X Res 11 450 150 200 L 50 50 1 1 P
|
||||
X Gnd 12 450 250 200 L 50 50 1 1 P
|
||||
X TXD 2 -450 150 200 R 50 50 1 1 P
|
||||
X Gnd 3 -450 50 200 R 50 50 1 1 P
|
||||
X Vcc 4 -450 -50 200 R 50 50 1 1 P
|
||||
X V_BKP 5 -450 -150 200 R 50 50 1 1 P
|
||||
X PPS 6 -450 -250 200 R 50 50 1 1 P
|
||||
X Res 7 450 -250 200 L 50 50 1 1 P
|
||||
X Res 8 450 -150 200 L 50 50 1 1 P
|
||||
X NC 9 450 -50 200 L 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
#End Library
|
||||
51
F1:F103/deprecated/chronometer_v2/kicad/chrono
Normal file
51
F1:F103/deprecated/chronometer_v2/kicad/chrono
Normal file
@@ -0,0 +1,51 @@
|
||||
,,,,,,
|
||||
Ref,Qnty,Value,Cmp name,Footprint,,Vendor
|
||||
"BZ1, ",1,Buzzer 3v3,Buzzer,Buzzer_Beeper:Buzzer_12x9.5RM7.6,,
|
||||
"C2, C1, ",2,12,C,Capacitor_SMD:C_0603_1608Metric_Pad1.05x0.95mm_HandSolder,,
|
||||
"C4, C13, ",2,47u,CP,Capacitor_Tantalum_SMD:CP_EIA-3216-18_Kemet-A_Pad1.58x1.35mm_HandSolder,,
|
||||
"C7, ",1,100u,CP,Capacitor_THT:CP_Radial_D8.0mm_P3.50mm,,
|
||||
"C10, ",1,10u,C,Capacitor_SMD:C_1206_3216Metric_Pad1.42x1.75mm_HandSolder,,
|
||||
"C14, C15, C16, C17, C3, C9, C11, C8, C5, C6, C12, ",11,0.1,C,Capacitor_SMD:C_0603_1608Metric_Pad1.05x0.95mm_HandSolder,,
|
||||
"D1, ",1,MM3Z7V5,D_Zener,Diode_SMD:D_0805_2012Metric_Pad1.15x1.40mm_HandSolder,,
|
||||
"D2, D6, ",2,IN5819,D_Schottky,Diode_SMD:D_SOD-323,,
|
||||
"D3, D4, D5, D10, D11, ",5,1N5819,D,Diode_SMD:D_SOD-323_HandSoldering,,
|
||||
"D7, ",1,B340A,D,Diode_SMD:D_SMA_Handsoldering,,
|
||||
"D8, ",1,LED0,LED-RESCUE-stm32,LED_THT:LED_D5.0mm,,
|
||||
"D9, ",1,LED1,LED-RESCUE-stm32,LED_THT:LED_D5.0mm,,
|
||||
"J1, ",1,Power 12V,Conn_01x02,"TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-2-5.08_1x02_P5.08mm_Horizontal",,
|
||||
"J2, ",1,GPS_ext,Conn_01x05_Male,Connector_JST:JST_PH_B5B-PH-K_1x05_P2.00mm_Vertical,,
|
||||
"J3, ",1,PPS,Conn_01x02,Connector_PinSocket_2.54mm:PinSocket_1x02_P2.54mm_Vertical,,
|
||||
"J4, ",1,Ext_trig1,Conn_01x02,"TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-2-5.08_1x02_P5.08mm_Horizontal",,
|
||||
"J5, ",1,Ext_trig0,Conn_01x02,"TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-2-5.08_1x02_P5.08mm_Horizontal",,
|
||||
"J6, ",1,USB_B_Mini,USB_B_Mini,Connector_USB:USB_Mini-B_Lumberg_2486_01_Horizontal,,
|
||||
"J7, ",1,Ext_trig2,Conn_01x02,"TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-2-5.08_1x02_P5.08mm_Horizontal",,
|
||||
"J8, ",1,SPI,Conn_01x05_Female,Connector_PinSocket_2.54mm:PinSocket_1x05_P2.54mm_Vertical,,
|
||||
"J9, ",1,I2C1,Conn_01x04_Female,Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Vertical,,
|
||||
"J10, ",1,LIDAR,Conn_01x04_Female,Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Vertical,,
|
||||
"J11, ",1,Bluetooth,Conn_01x06_Female,Connector_PinSocket_2.54mm:PinSocket_1x06_P2.54mm_Vertical,,
|
||||
"J12, ",1,SWD,Conn_01x04_Female,Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Vertical,,
|
||||
"JP3, JP4, JP1, JP2, ",4,Jumper,Jumper,Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical,,
|
||||
"L1, ",1,100u,L,Inductor_SMD:L_12x12mm_H4.5mm,,
|
||||
"P1, ",1,USB_B,USB_A-RESCUE-stm32,Connectors_USB:USB_B_OST_USB-B1HSxx_Horizontal,,
|
||||
"Q1, ",1,MMBTA42,Q_NPN_BEC,Package_TO_SOT_SMD:SOT-23_Handsoldering,,
|
||||
"Q2, ",1,AO3407,Q_PMOS_GSD,Package_TO_SOT_SMD:SOT-23_Handsoldering,,
|
||||
"Q3, ",1,SI2305,Q_PMOS_GSD,Package_TO_SOT_SMD:SOT-23_Handsoldering,,
|
||||
"Q4, ",1,IRML2502,Q_NMOS_GSD,Package_TO_SOT_SMD:SOT-23_Handsoldering,,
|
||||
"R2, ",1,2k2,R,Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder,,
|
||||
"R3, R4, ",2,22,R,Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder,,
|
||||
"R5, R19, R1, R23, R8, ",5,10k,R,Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder,,
|
||||
"R9, ",1,1k5,R,Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder,,
|
||||
"R11, R10, R12, R6, R20, ",5,1k,R,Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder,,
|
||||
"R13, R21, ",2,100,R,Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder,,
|
||||
"R14 (ÎÅ ÐÁÑÔØ), R24, ",2,47k,R,Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder,,
|
||||
"R16, R17, R15, ",3,220,R,Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder,,
|
||||
"R18, R7, ",2,510,R,Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder,,
|
||||
"R22, ",1,100k,R,Resistor_SMD:R_0603_1608Metric_Pad1.05x0.95mm_HandSolder,,
|
||||
"U1, ",1,USBLC6-2SC6,USBLC6-2SC6,TO_SOT_Packages_SMD:SOT-23-6_Handsoldering,,
|
||||
"U2, ",1,LM2576-5.0,LM2576HV,TO_SOT_Packages_THT:TO-220-5_P3.4x3.7mm_StaggerEven_Lead3.8mm_Vertical,,
|
||||
"U3, (ÎÅ ÐÁÑÔØ)",1,4N25,4N25,Package_DIP:DIP-6_W7.62mm,,
|
||||
"U4, ",1,LM1117-3.3,LM1117-3.3-RESCUE-stm32,TO_SOT_Packages_SMD:SOT-223,,
|
||||
"U5, ",1,L80-R,L80-R,chrono:L80-R,,
|
||||
"U6, ",1,STM32F103C6Tx,STM32F103C6Tx,Package_QFP:LQFP-48_7x7mm_P0.5mm,,
|
||||
"U7, ",1,PC817,PC817,Package_DIP:DIP-4_W7.62mm,,
|
||||
"Y1, ",1,8MHz,Crystal,Crystal:Crystal_HC49-U_Vertical,,
|
||||
33130
F1:F103/deprecated/chronometer_v2/kicad/chrono.kicad_pcb
Normal file
33130
F1:F103/deprecated/chronometer_v2/kicad/chrono.kicad_pcb
Normal file
File diff suppressed because it is too large
Load Diff
83
F1:F103/deprecated/chronometer_v2/kicad/chrono.kicad_prl
Normal file
83
F1:F103/deprecated/chronometer_v2/kicad/chrono.kicad_prl
Normal file
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"board": {
|
||||
"active_layer": 0,
|
||||
"active_layer_preset": "",
|
||||
"auto_track_width": true,
|
||||
"hidden_netclasses": [],
|
||||
"hidden_nets": [],
|
||||
"high_contrast_mode": 0,
|
||||
"net_color_mode": 1,
|
||||
"opacity": {
|
||||
"images": 0.6,
|
||||
"pads": 1.0,
|
||||
"tracks": 1.0,
|
||||
"vias": 1.0,
|
||||
"zones": 0.6
|
||||
},
|
||||
"ratsnest_display_mode": 0,
|
||||
"selection_filter": {
|
||||
"dimensions": true,
|
||||
"footprints": true,
|
||||
"graphics": true,
|
||||
"keepouts": true,
|
||||
"lockedItems": true,
|
||||
"otherItems": true,
|
||||
"pads": true,
|
||||
"text": true,
|
||||
"tracks": true,
|
||||
"vias": true,
|
||||
"zones": true
|
||||
},
|
||||
"visible_items": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36
|
||||
],
|
||||
"visible_layers": "fffffff_ffffffff",
|
||||
"zone_display_mode": 0
|
||||
},
|
||||
"git": {
|
||||
"repo_password": "",
|
||||
"repo_type": "",
|
||||
"repo_username": "",
|
||||
"ssh_key": ""
|
||||
},
|
||||
"meta": {
|
||||
"filename": "chrono.kicad_prl",
|
||||
"version": 3
|
||||
},
|
||||
"project": {
|
||||
"files": []
|
||||
}
|
||||
}
|
||||
862
F1:F103/deprecated/chronometer_v2/kicad/chrono.kicad_pro
Normal file
862
F1:F103/deprecated/chronometer_v2/kicad/chrono.kicad_pro
Normal file
@@ -0,0 +1,862 @@
|
||||
{
|
||||
"board": {
|
||||
"3dviewports": [],
|
||||
"design_settings": {
|
||||
"defaults": {
|
||||
"apply_defaults_to_fp_fields": false,
|
||||
"apply_defaults_to_fp_shapes": false,
|
||||
"apply_defaults_to_fp_text": false,
|
||||
"board_outline_line_width": 0.05,
|
||||
"copper_line_width": 0.2,
|
||||
"copper_text_italic": false,
|
||||
"copper_text_size_h": 1.5,
|
||||
"copper_text_size_v": 1.5,
|
||||
"copper_text_thickness": 0.3,
|
||||
"copper_text_upright": false,
|
||||
"courtyard_line_width": 0.05,
|
||||
"dimension_precision": 4,
|
||||
"dimension_units": 3,
|
||||
"dimensions": {
|
||||
"arrow_length": 1270000,
|
||||
"extension_offset": 500000,
|
||||
"keep_text_aligned": true,
|
||||
"suppress_zeroes": false,
|
||||
"text_position": 0,
|
||||
"units_format": 1
|
||||
},
|
||||
"fab_line_width": 0.1,
|
||||
"fab_text_italic": false,
|
||||
"fab_text_size_h": 1.0,
|
||||
"fab_text_size_v": 1.0,
|
||||
"fab_text_thickness": 0.15,
|
||||
"fab_text_upright": false,
|
||||
"other_line_width": 0.1,
|
||||
"other_text_italic": false,
|
||||
"other_text_size_h": 1.0,
|
||||
"other_text_size_v": 1.0,
|
||||
"other_text_thickness": 0.15,
|
||||
"other_text_upright": false,
|
||||
"pads": {
|
||||
"drill": 0.762,
|
||||
"height": 1.524,
|
||||
"width": 1.524
|
||||
},
|
||||
"silk_line_width": 0.12,
|
||||
"silk_text_italic": false,
|
||||
"silk_text_size_h": 1.0,
|
||||
"silk_text_size_v": 1.0,
|
||||
"silk_text_thickness": 0.15,
|
||||
"silk_text_upright": false,
|
||||
"zones": {
|
||||
"min_clearance": 0.508
|
||||
}
|
||||
},
|
||||
"diff_pair_dimensions": [],
|
||||
"drc_exclusions": [],
|
||||
"meta": {
|
||||
"filename": "board_design_settings.json",
|
||||
"version": 2
|
||||
},
|
||||
"rule_severities": {
|
||||
"annular_width": "error",
|
||||
"clearance": "error",
|
||||
"connection_width": "warning",
|
||||
"copper_edge_clearance": "error",
|
||||
"copper_sliver": "warning",
|
||||
"courtyards_overlap": "error",
|
||||
"diff_pair_gap_out_of_range": "error",
|
||||
"diff_pair_uncoupled_length_too_long": "error",
|
||||
"drill_out_of_range": "error",
|
||||
"duplicate_footprints": "warning",
|
||||
"extra_footprint": "warning",
|
||||
"footprint": "error",
|
||||
"footprint_symbol_mismatch": "warning",
|
||||
"footprint_type_mismatch": "ignore",
|
||||
"hole_clearance": "error",
|
||||
"hole_near_hole": "error",
|
||||
"invalid_outline": "error",
|
||||
"isolated_copper": "warning",
|
||||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "warning",
|
||||
"lib_footprint_mismatch": "warning",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
"missing_footprint": "warning",
|
||||
"net_conflict": "warning",
|
||||
"npth_inside_courtyard": "ignore",
|
||||
"padstack": "warning",
|
||||
"pth_inside_courtyard": "ignore",
|
||||
"shorting_items": "error",
|
||||
"silk_edge_clearance": "warning",
|
||||
"silk_over_copper": "warning",
|
||||
"silk_overlap": "warning",
|
||||
"skew_out_of_range": "error",
|
||||
"solder_mask_bridge": "error",
|
||||
"starved_thermal": "error",
|
||||
"text_height": "warning",
|
||||
"text_thickness": "warning",
|
||||
"through_hole_pad_without_hole": "error",
|
||||
"too_many_vias": "error",
|
||||
"track_dangling": "warning",
|
||||
"track_width": "error",
|
||||
"tracks_crossing": "error",
|
||||
"unconnected_items": "error",
|
||||
"unresolved_variable": "error",
|
||||
"via_dangling": "warning",
|
||||
"zones_intersect": "error"
|
||||
},
|
||||
"rule_severitieslegacy_courtyards_overlap": true,
|
||||
"rule_severitieslegacy_no_courtyard_defined": false,
|
||||
"rules": {
|
||||
"allow_blind_buried_vias": false,
|
||||
"allow_microvias": false,
|
||||
"max_error": 0.005,
|
||||
"min_clearance": 0.0,
|
||||
"min_connection": 0.0,
|
||||
"min_copper_edge_clearance": 0.025,
|
||||
"min_hole_clearance": 0.25,
|
||||
"min_hole_to_hole": 0.25,
|
||||
"min_microvia_diameter": 0.2,
|
||||
"min_microvia_drill": 0.1,
|
||||
"min_resolved_spokes": 2,
|
||||
"min_silk_clearance": 0.0,
|
||||
"min_text_height": 0.8,
|
||||
"min_text_thickness": 0.08,
|
||||
"min_through_hole_diameter": 0.3,
|
||||
"min_track_width": 0.2,
|
||||
"min_via_annular_width": 0.1,
|
||||
"min_via_diameter": 0.4,
|
||||
"solder_mask_clearance": 0.051,
|
||||
"solder_mask_min_width": 0.25,
|
||||
"solder_mask_to_copper_clearance": 0.0,
|
||||
"solder_paste_clearance": 0.0,
|
||||
"solder_paste_margin_ratio": -0.0,
|
||||
"use_height_for_length_calcs": true
|
||||
},
|
||||
"teardrop_options": [
|
||||
{
|
||||
"td_onpadsmd": true,
|
||||
"td_onroundshapesonly": false,
|
||||
"td_ontrackend": false,
|
||||
"td_onviapad": true
|
||||
}
|
||||
],
|
||||
"teardrop_parameters": [
|
||||
{
|
||||
"td_allow_use_two_tracks": true,
|
||||
"td_curve_segcount": 0,
|
||||
"td_height_ratio": 1.0,
|
||||
"td_length_ratio": 0.5,
|
||||
"td_maxheight": 2.0,
|
||||
"td_maxlen": 1.0,
|
||||
"td_on_pad_in_zone": false,
|
||||
"td_target_name": "td_round_shape",
|
||||
"td_width_to_size_filter_ratio": 0.9
|
||||
},
|
||||
{
|
||||
"td_allow_use_two_tracks": true,
|
||||
"td_curve_segcount": 0,
|
||||
"td_height_ratio": 1.0,
|
||||
"td_length_ratio": 0.5,
|
||||
"td_maxheight": 2.0,
|
||||
"td_maxlen": 1.0,
|
||||
"td_on_pad_in_zone": false,
|
||||
"td_target_name": "td_rect_shape",
|
||||
"td_width_to_size_filter_ratio": 0.9
|
||||
},
|
||||
{
|
||||
"td_allow_use_two_tracks": true,
|
||||
"td_curve_segcount": 0,
|
||||
"td_height_ratio": 1.0,
|
||||
"td_length_ratio": 0.5,
|
||||
"td_maxheight": 2.0,
|
||||
"td_maxlen": 1.0,
|
||||
"td_on_pad_in_zone": false,
|
||||
"td_target_name": "td_track_end",
|
||||
"td_width_to_size_filter_ratio": 0.9
|
||||
}
|
||||
],
|
||||
"track_widths": [
|
||||
0.0,
|
||||
0.2,
|
||||
0.3,
|
||||
0.5,
|
||||
1.0
|
||||
],
|
||||
"tuning_pattern_settings": {
|
||||
"diff_pair_defaults": {
|
||||
"corner_radius_percentage": 80,
|
||||
"corner_style": 1,
|
||||
"max_amplitude": 1.0,
|
||||
"min_amplitude": 0.2,
|
||||
"single_sided": false,
|
||||
"spacing": 1.0
|
||||
},
|
||||
"diff_pair_skew_defaults": {
|
||||
"corner_radius_percentage": 80,
|
||||
"corner_style": 1,
|
||||
"max_amplitude": 1.0,
|
||||
"min_amplitude": 0.2,
|
||||
"single_sided": false,
|
||||
"spacing": 0.6
|
||||
},
|
||||
"single_track_defaults": {
|
||||
"corner_radius_percentage": 80,
|
||||
"corner_style": 1,
|
||||
"max_amplitude": 1.0,
|
||||
"min_amplitude": 0.2,
|
||||
"single_sided": false,
|
||||
"spacing": 0.6
|
||||
}
|
||||
},
|
||||
"via_dimensions": [
|
||||
{
|
||||
"diameter": 0.0,
|
||||
"drill": 0.0
|
||||
},
|
||||
{
|
||||
"diameter": 0.8,
|
||||
"drill": 0.5
|
||||
},
|
||||
{
|
||||
"diameter": 1.2,
|
||||
"drill": 0.6
|
||||
}
|
||||
],
|
||||
"zones_allow_external_fillets": false
|
||||
},
|
||||
"ipc2581": {
|
||||
"dist": "",
|
||||
"distpn": "",
|
||||
"internal_id": "",
|
||||
"mfg": "",
|
||||
"mpn": ""
|
||||
},
|
||||
"layer_presets": [],
|
||||
"viewports": []
|
||||
},
|
||||
"boards": [],
|
||||
"cvpcb": {
|
||||
"equivalence_files": []
|
||||
},
|
||||
"erc": {
|
||||
"erc_exclusions": [],
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
"pin_map": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
]
|
||||
],
|
||||
"rule_severities": {
|
||||
"bus_definition_conflict": "error",
|
||||
"bus_entry_needed": "error",
|
||||
"bus_label_syntax": "error",
|
||||
"bus_to_bus_conflict": "error",
|
||||
"bus_to_net_conflict": "error",
|
||||
"conflicting_netclasses": "error",
|
||||
"different_unit_footprint": "error",
|
||||
"different_unit_net": "error",
|
||||
"duplicate_reference": "error",
|
||||
"duplicate_sheet_names": "error",
|
||||
"endpoint_off_grid": "warning",
|
||||
"extra_units": "error",
|
||||
"global_label_dangling": "warning",
|
||||
"hier_label_mismatch": "error",
|
||||
"label_dangling": "error",
|
||||
"lib_symbol_issues": "warning",
|
||||
"missing_bidi_pin": "warning",
|
||||
"missing_input_pin": "warning",
|
||||
"missing_power_pin": "error",
|
||||
"missing_unit": "warning",
|
||||
"multiple_net_names": "warning",
|
||||
"net_not_bus_member": "warning",
|
||||
"no_connect_connected": "warning",
|
||||
"no_connect_dangling": "warning",
|
||||
"pin_not_connected": "error",
|
||||
"pin_not_driven": "error",
|
||||
"pin_to_pin": "warning",
|
||||
"power_pin_not_driven": "error",
|
||||
"similar_labels": "warning",
|
||||
"simulation_model_issue": "ignore",
|
||||
"unannotated": "error",
|
||||
"unit_value_mismatch": "error",
|
||||
"unresolved_variable": "error",
|
||||
"wire_dangling": "error"
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"pinned_footprint_libs": [],
|
||||
"pinned_symbol_libs": []
|
||||
},
|
||||
"meta": {
|
||||
"filename": "chrono.kicad_pro",
|
||||
"version": 1
|
||||
},
|
||||
"net_settings": {
|
||||
"classes": [
|
||||
{
|
||||
"bus_width": 12,
|
||||
"clearance": 0.2,
|
||||
"diff_pair_gap": 0.25,
|
||||
"diff_pair_via_gap": 0.25,
|
||||
"diff_pair_width": 0.2,
|
||||
"line_style": 0,
|
||||
"microvia_diameter": 0.3,
|
||||
"microvia_drill": 0.1,
|
||||
"name": "Default",
|
||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||
"track_width": 0.2,
|
||||
"via_diameter": 0.8,
|
||||
"via_drill": 0.5,
|
||||
"wire_width": 6
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"version": 3
|
||||
},
|
||||
"net_colors": null,
|
||||
"netclass_assignments": null,
|
||||
"netclass_patterns": [
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "+3V3"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "+5V"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/DM"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/DP"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/LED0"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/LED1"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/MISO"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/MOSI"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/OSC_IN"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/OSC_OUT"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/PPS"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/SCK"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/SCL"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/SDA"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/SWCLK"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/SWDIO"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/TRIG0"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/TRIG1"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/TRIG2"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/U1Rx"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/U1Tx"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/U2Rx"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/U2Tx"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/U3Rx"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/U3Tx"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/USBDM"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/USBDP"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/USB_PU"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "/buzzer"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "GND"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(BZ1-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(C10-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(C12-Pad1)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(C3-Pad1)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(C5-Pad1)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(C5-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(C6-Pad1)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(D1-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(D2-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(D6-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(D7-Pad1)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(D8-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(D9-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(J1-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(J11-Pad1)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(J11-Pad6)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(J3-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(J4-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(JP2-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(JP3-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(JP4-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(Q1-Pad1)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(Q3-Pad1)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(Q3-Pad3)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(Q4-Pad1)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(R14-Pad2)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(R22-Pad1)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(R23-Pad1)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(R3-Pad1)"
|
||||
},
|
||||
{
|
||||
"netclass": "Default",
|
||||
"pattern": "Net-(R4-Pad1)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pcbnew": {
|
||||
"last_paths": {
|
||||
"gencad": "",
|
||||
"idf": "",
|
||||
"netlist": "chrono.net",
|
||||
"plot": "",
|
||||
"pos_files": "",
|
||||
"specctra_dsn": "",
|
||||
"step": "",
|
||||
"svg": "",
|
||||
"vrml": ""
|
||||
},
|
||||
"page_layout_descr_file": ""
|
||||
},
|
||||
"schematic": {
|
||||
"annotate_start_num": 0,
|
||||
"bom_fmt_presets": [],
|
||||
"bom_fmt_settings": {
|
||||
"field_delimiter": ",",
|
||||
"keep_line_breaks": false,
|
||||
"keep_tabs": false,
|
||||
"name": "CSV",
|
||||
"ref_delimiter": ",",
|
||||
"ref_range_delimiter": "",
|
||||
"string_delimiter": "\""
|
||||
},
|
||||
"bom_presets": [],
|
||||
"bom_settings": {
|
||||
"exclude_dnp": false,
|
||||
"fields_ordered": [
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "Reference",
|
||||
"name": "Reference",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": true,
|
||||
"label": "Value",
|
||||
"name": "Value",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "Datasheet",
|
||||
"name": "Datasheet",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "Footprint",
|
||||
"name": "Footprint",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "Qty",
|
||||
"name": "${QUANTITY}",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": true,
|
||||
"label": "DNP",
|
||||
"name": "${DNP}",
|
||||
"show": true
|
||||
}
|
||||
],
|
||||
"filter_string": "",
|
||||
"group_symbols": true,
|
||||
"name": "Grouped By Value",
|
||||
"sort_asc": true,
|
||||
"sort_field": "Обозначение"
|
||||
},
|
||||
"connection_grid_size": 50.0,
|
||||
"drawing": {
|
||||
"dashed_lines_dash_length_ratio": 12.0,
|
||||
"dashed_lines_gap_length_ratio": 3.0,
|
||||
"default_line_thickness": 6.0,
|
||||
"default_text_size": 50.0,
|
||||
"field_names": [],
|
||||
"intersheets_ref_own_page": false,
|
||||
"intersheets_ref_prefix": "",
|
||||
"intersheets_ref_short": false,
|
||||
"intersheets_ref_show": false,
|
||||
"intersheets_ref_suffix": "",
|
||||
"junction_size_choice": 3,
|
||||
"label_size_ratio": 0.25,
|
||||
"operating_point_overlay_i_precision": 3,
|
||||
"operating_point_overlay_i_range": "~A",
|
||||
"operating_point_overlay_v_precision": 3,
|
||||
"operating_point_overlay_v_range": "~V",
|
||||
"overbar_offset_ratio": 1.23,
|
||||
"pin_symbol_size": 0.0,
|
||||
"text_offset_ratio": 0.08
|
||||
},
|
||||
"legacy_lib_dir": "",
|
||||
"legacy_lib_list": [],
|
||||
"meta": {
|
||||
"version": 1
|
||||
},
|
||||
"net_format_name": "Pcbnew",
|
||||
"ngspice": {
|
||||
"fix_include_paths": true,
|
||||
"fix_passive_vals": false,
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
"model_mode": 0,
|
||||
"workbook_filename": ""
|
||||
},
|
||||
"page_layout_descr_file": "",
|
||||
"plot_directory": "",
|
||||
"spice_adjust_passive_values": false,
|
||||
"spice_current_sheet_as_root": false,
|
||||
"spice_external_command": "spice \"%I\"",
|
||||
"spice_model_current_sheet_as_root": true,
|
||||
"spice_save_all_currents": false,
|
||||
"spice_save_all_dissipations": false,
|
||||
"spice_save_all_voltages": false,
|
||||
"subpart_first_id": 65,
|
||||
"subpart_id_separator": 0
|
||||
},
|
||||
"sheets": [
|
||||
[
|
||||
"a6743a46-c12b-47c3-97ed-4a8c5f2ababd",
|
||||
"Корневой лист"
|
||||
]
|
||||
],
|
||||
"text_variables": {}
|
||||
}
|
||||
20118
F1:F103/deprecated/chronometer_v2/kicad/chrono.kicad_sch
Normal file
20118
F1:F103/deprecated/chronometer_v2/kicad/chrono.kicad_sch
Normal file
File diff suppressed because it is too large
Load Diff
1381
F1:F103/deprecated/chronometer_v2/kicad/chrono.net
Normal file
1381
F1:F103/deprecated/chronometer_v2/kicad/chrono.net
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
(module L80-R (layer F.Cu) (tedit 5D162F3C)
|
||||
(fp_text reference U3 (at 0 4) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text value L80-R (at 0 -15) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_line (start -8 -14) (end -8 3) (layer F.SilkS) (width 0.15))
|
||||
(fp_line (start -8 3) (end 8 3) (layer F.SilkS) (width 0.15))
|
||||
(fp_line (start 8 3) (end 8 -14) (layer F.SilkS) (width 0.15))
|
||||
(fp_line (start 8 -14) (end -8 -14) (layer F.SilkS) (width 0.15))
|
||||
(fp_text user 1 (at 10 3) (layer F.SilkS)
|
||||
(effects (font (size 2.5 2.5) (thickness 0.15)))
|
||||
)
|
||||
(fp_line (start -4 3) (end -4 1) (layer F.SilkS) (width 0.15))
|
||||
(fp_line (start -4 1) (end -8 1) (layer F.SilkS) (width 0.15))
|
||||
(fp_line (start 8 2) (end 7 3) (layer F.SilkS) (width 0.15))
|
||||
(fp_text user Keepout (at 0 -8) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text user area (at 0 -3.5) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_line (start -18 -24) (end -18 13) (layer F.SilkS) (width 0.15))
|
||||
(fp_line (start -18 13) (end 18 13) (layer F.SilkS) (width 0.15))
|
||||
(fp_line (start 18 13) (end 18 -24) (layer F.SilkS) (width 0.15))
|
||||
(fp_line (start 18 -24) (end -18 -24) (layer F.SilkS) (width 0.15))
|
||||
(fp_text user "Clear area" (at 0 -22) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text user "Clear area" (at 0 -22) (layer B.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
|
||||
)
|
||||
(fp_line (start -18 -24) (end -18 13) (layer B.SilkS) (width 0.15))
|
||||
(fp_line (start -18 13) (end 18 13) (layer B.SilkS) (width 0.15))
|
||||
(fp_line (start 18 13) (end 18 -24) (layer B.SilkS) (width 0.15))
|
||||
(fp_line (start 18 -24) (end -18 -24) (layer B.SilkS) (width 0.15))
|
||||
(pad 1 smd rect (at 8 0) (size 4 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 2 smd rect (at 8 -2.54) (size 4 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 3 smd rect (at 8 -5.08) (size 4 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 4 smd rect (at 8 -7.62) (size 4 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 5 smd rect (at 8 -10.16) (size 4 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 6 smd rect (at 8 -12.7) (size 4 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 12 smd rect (at -8 0) (size 4 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 11 smd rect (at -8 -2.54) (size 4 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 10 smd rect (at -8 -5.08) (size 4 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 9 smd rect (at -8 -7.62) (size 4 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 8 smd rect (at -8 -10.16) (size 4 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 7 smd rect (at -8 -12.7) (size 4 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad ~ smd circle (at 0 -5.5) (size 0.1 0.1) (layers B.Cu)
|
||||
(solder_mask_margin 1.5) (solder_paste_margin 1.5) (clearance 1.3) (zone_connect 0))
|
||||
(pad ~ smd circle (at 0 -5.5) (size 0.1 0.1) (layers F.Cu)
|
||||
(solder_mask_margin 1.5) (solder_paste_margin 1.5) (clearance 1.3) (zone_connect 0))
|
||||
)
|
||||
78
F1:F103/deprecated/chronometer_v2/kicad/chrono.pro
Normal file
78
F1:F103/deprecated/chronometer_v2/kicad/chrono.pro
Normal file
@@ -0,0 +1,78 @@
|
||||
update=Вт 14 янв 2020 18:17:49
|
||||
version=1
|
||||
last_client=kicad
|
||||
[general]
|
||||
version=1
|
||||
RootSch=
|
||||
BoardNm=
|
||||
[cvpcb]
|
||||
version=1
|
||||
NetIExt=net
|
||||
[eeschema]
|
||||
version=1
|
||||
LibDir=
|
||||
[eeschema/libraries]
|
||||
[pcbnew]
|
||||
version=1
|
||||
PageLayoutDescrFile=
|
||||
LastNetListRead=chrono.net
|
||||
CopperLayerCount=2
|
||||
BoardThickness=1.6
|
||||
AllowMicroVias=0
|
||||
AllowBlindVias=0
|
||||
RequireCourtyardDefinitions=0
|
||||
ProhibitOverlappingCourtyards=1
|
||||
MinTrackWidth=0.2
|
||||
MinViaDiameter=0.4
|
||||
MinViaDrill=0.3
|
||||
MinMicroViaDiameter=0.2
|
||||
MinMicroViaDrill=0.09999999999999999
|
||||
MinHoleToHole=0.25
|
||||
TrackWidth1=0.2
|
||||
TrackWidth2=0.2
|
||||
TrackWidth3=0.3
|
||||
TrackWidth4=0.5
|
||||
TrackWidth5=1
|
||||
ViaDiameter1=0.8
|
||||
ViaDrill1=0.5
|
||||
ViaDiameter2=0.8
|
||||
ViaDrill2=0.5
|
||||
ViaDiameter3=1.2
|
||||
ViaDrill3=0.6
|
||||
dPairWidth1=0.2
|
||||
dPairGap1=0.25
|
||||
dPairViaGap1=0.25
|
||||
SilkLineWidth=0.12
|
||||
SilkTextSizeV=1
|
||||
SilkTextSizeH=1
|
||||
SilkTextSizeThickness=0.15
|
||||
SilkTextItalic=0
|
||||
SilkTextUpright=1
|
||||
CopperLineWidth=0.2
|
||||
CopperTextSizeV=1.5
|
||||
CopperTextSizeH=1.5
|
||||
CopperTextThickness=0.3
|
||||
CopperTextItalic=0
|
||||
CopperTextUpright=1
|
||||
EdgeCutLineWidth=0.05
|
||||
CourtyardLineWidth=0.05
|
||||
OthersLineWidth=0.15
|
||||
OthersTextSizeV=1
|
||||
OthersTextSizeH=1
|
||||
OthersTextSizeThickness=0.15
|
||||
OthersTextItalic=0
|
||||
OthersTextUpright=1
|
||||
SolderMaskClearance=0.051
|
||||
SolderMaskMinWidth=0.25
|
||||
SolderPasteClearance=0
|
||||
SolderPasteRatio=-0
|
||||
[schematic_editor]
|
||||
version=1
|
||||
PageLayoutDescrFile=
|
||||
PlotDirectoryName=
|
||||
SubpartIdSeparator=0
|
||||
SubpartFirstId=65
|
||||
NetFmtName=Pcbnew
|
||||
SpiceAjustPassiveValues=0
|
||||
LabSize=50
|
||||
ERC_TestSimilarLabels=1
|
||||
2243
F1:F103/deprecated/chronometer_v2/kicad/chrono.sch
Normal file
2243
F1:F103/deprecated/chronometer_v2/kicad/chrono.sch
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user