mirror of
https://github.com/eddyem/stm32samples.git
synced 2025-12-06 10:45:11 +03:00
add copy of TSYS
This commit is contained in:
parent
e07260c9d0
commit
16dcbd52d9
10
F0:F030,F042,F072/TSYS_controller/Makefile
Normal file
10
F0:F030,F042,F072/TSYS_controller/Makefile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
BINARY := tsys01
|
||||||
|
# MCU code
|
||||||
|
MCU := F042x6
|
||||||
|
# change this linking script depending on particular MCU model,
|
||||||
|
LDSCRIPT := stm32f042x6.ld
|
||||||
|
|
||||||
|
DEFINES := -DUSARTNUM=1 -DI2CPINS=67
|
||||||
|
|
||||||
|
include ../makefile.f0
|
||||||
|
include ../../makefile.stm32
|
||||||
158
F0:F030,F042,F072/TSYS_controller/Makefile_old
Normal file
158
F0:F030,F042,F072/TSYS_controller/Makefile_old
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
BINARY = tsys01
|
||||||
|
BOOTPORT ?= /dev/ttyUSB0
|
||||||
|
BOOTSPEED ?= 57600
|
||||||
|
# MCU FAMILY
|
||||||
|
FAMILY = F0
|
||||||
|
# MCU code
|
||||||
|
MCU = F042x6
|
||||||
|
# hardware definitions
|
||||||
|
DEFS := -DUSARTNUM=1 -DI2CPINS=67
|
||||||
|
#DEFS += -DCHECK_TMOUT
|
||||||
|
#DEFS += -DEBUG
|
||||||
|
# change this linking script depending on particular MCU model,
|
||||||
|
# for example, if you have STM32F103VBT6, you should write:
|
||||||
|
LDSCRIPT = stm32f042x6.ld
|
||||||
|
|
||||||
|
# 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
|
||||||
|
ASM_FLAGS = -mthumb -mcpu=cortex-m0 -march=armv6-m -mtune=cortex-m0
|
||||||
|
ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS)
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Executables
|
||||||
|
OPREFIX ?= /opt/bin/arm-none-eabi
|
||||||
|
#PREFIX ?= /usr/x86_64-pc-linux-gnu/arm-none-eabi/gcc-bin/7.3.0/arm-none-eabi
|
||||||
|
PREFIX ?= $(OPREFIX)
|
||||||
|
|
||||||
|
RM := rm -f
|
||||||
|
RMDIR := rmdir
|
||||||
|
CC := $(PREFIX)-gcc
|
||||||
|
LD := $(PREFIX)-gcc
|
||||||
|
AR := $(PREFIX)-ar
|
||||||
|
AS := $(PREFIX)-as
|
||||||
|
OBJCOPY := $(OPREFIX)-objcopy
|
||||||
|
OBJDUMP := $(OPREFIX)-objdump
|
||||||
|
GDB := $(OPREFIX)-gdb
|
||||||
|
STFLASH := $(shell which st-flash)
|
||||||
|
STBOOT := $(shell which stm32flash)
|
||||||
|
DFUUTIL := $(shell which dfu-util)
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Source files
|
||||||
|
OBJDIR = mk
|
||||||
|
LDSCRIPT ?= $(BINARY).ld
|
||||||
|
SRC := $(wildcard *.c)
|
||||||
|
OBJS := $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o))
|
||||||
|
STARTUP = $(OBJDIR)/startup.o
|
||||||
|
OBJS += $(STARTUP)
|
||||||
|
DEPS := $(OBJS:.o=.d)
|
||||||
|
|
||||||
|
INC_DIR ?= ../inc
|
||||||
|
|
||||||
|
INCLUDE := -I$(INC_DIR)/F0 -I$(INC_DIR)/cm
|
||||||
|
LIB_DIR := $(INC_DIR)/ld
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# C flags
|
||||||
|
CFLAGS += -O2 -g -D__thumb2__=1
|
||||||
|
CFLAGS += -Wall -Werror -Wextra -Wshadow -Wimplicit-function-declaration
|
||||||
|
CFLAGS += -Wredundant-decls $(INCLUDE)
|
||||||
|
# -Wmissing-prototypes -Wstrict-prototypes
|
||||||
|
CFLAGS += -fno-common -ffunction-sections -fdata-sections
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Linker flags
|
||||||
|
LDFLAGS += --static -nostartfiles
|
||||||
|
#--specs=nano.specs
|
||||||
|
LDFLAGS += -L$(LIB_DIR)
|
||||||
|
LDFLAGS += -T$(LDSCRIPT)
|
||||||
|
LDFLAGS += -Wl,-Map=$(OBJDIR)/$(BINARY).map
|
||||||
|
LDFLAGS += -Wl,--gc-sections
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Used libraries
|
||||||
|
#LDLIBS += -Wl,--start-group -lc -lgcc -Wl,--end-group
|
||||||
|
#LDLIBS += $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
|
||||||
|
|
||||||
|
DEFS += -DSTM32$(FAMILY) -DSTM32$(MCU)
|
||||||
|
|
||||||
|
#.SUFFIXES: .elf .bin .hex .srec .list .map .images
|
||||||
|
#.SECONDEXPANSION:
|
||||||
|
#.SECONDARY:
|
||||||
|
|
||||||
|
ELF := $(OBJDIR)/$(BINARY).elf
|
||||||
|
LIST := $(OBJDIR)/$(BINARY).list
|
||||||
|
BIN := $(BINARY).bin
|
||||||
|
HEX := $(BINARY).hex
|
||||||
|
|
||||||
|
all: bin list
|
||||||
|
|
||||||
|
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) $(ARCH_FLAGS) -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 BUILDNO.*/#define BUILDNO $(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
|
||||||
|
@make $(VERSION_FILE)
|
||||||
|
@echo " CC $<"
|
||||||
|
$(CC) $(CFLAGS) -MD $(DEFS) $(INCLUDE) $(ARCH_FLAGS) -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) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(ELF)
|
||||||
|
@size $(ELF)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo " CLEAN"
|
||||||
|
$(RM) $(OBJS) $(DEPS) $(ELF) $(HEX) $(LIST) $(OBJDIR)/*.map *.d
|
||||||
|
@rmdir $(OBJDIR) 2>/dev/null || true
|
||||||
|
|
||||||
|
dfuboot: $(BIN)
|
||||||
|
@echo " LOAD $(BIN) THROUGH DFU"
|
||||||
|
$(DFUUTIL) -a0 -D $(BIN) -s 0x08000000
|
||||||
|
|
||||||
|
flash: $(BIN)
|
||||||
|
@echo " FLASH $(BIN)"
|
||||||
|
$(STFLASH) write $(BIN) 0x8000000
|
||||||
|
|
||||||
|
boot: $(BIN)
|
||||||
|
@echo " LOAD $(BIN) through bootloader"
|
||||||
|
$(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN)
|
||||||
|
|
||||||
|
.PHONY: clean flash boot dfuboot
|
||||||
133
F0:F030,F042,F072/TSYS_controller/Readme.md
Normal file
133
F0:F030,F042,F072/TSYS_controller/Readme.md
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
# Firmware for controllers of thermal sensors
|
||||||
|
|
||||||
|
Make regular scan of 8 sensors' pairs.
|
||||||
|
USART speed 115200. Code for ../../kicad/stm32
|
||||||
|
|
||||||
|
## Serial interface commands (ends with '\n'), small letter for only local processing:
|
||||||
|
- **0...7** send message to Nth controller, not broadcast (after number should be CAN command)
|
||||||
|
- **@** set/reset debug mode
|
||||||
|
- **a** get raw ADC values
|
||||||
|
- **B** send dummy CAN messages to broadcast address
|
||||||
|
- **b** get/set CAN bus baudrate
|
||||||
|
- **c** show coefficients for all thermosensors
|
||||||
|
- **D** send dummy CAN messages to master (0) address
|
||||||
|
- **d** get current CAN address of device
|
||||||
|
- **Ee** end temperature scan
|
||||||
|
- **Ff** turn sensors off
|
||||||
|
- **g** group (sniffer) CAN mode (print to USB terminal all incoming CAN messages with alien IDs)
|
||||||
|
- **Hh** switch I2C to high speed (100kHz)
|
||||||
|
- **Ii** (re)init sensors
|
||||||
|
- **Jj** get MCU temperature
|
||||||
|
- **Kk** get values of U and I
|
||||||
|
- **Ll** switch I2C to low speed (default, 10kHz)
|
||||||
|
- **Mm** change master id to 0 (**m**) / broadcast (**M**)
|
||||||
|
- **N** get build number
|
||||||
|
- **Oo** turn onboard diagnostic LEDs **O**n or **o**ff (both commands are local!)
|
||||||
|
- **P** ping everyone over CAN
|
||||||
|
- **Qq** get system time
|
||||||
|
- **Rr** reinit I2C
|
||||||
|
- **s** send CAN message (format: ID data[0..8], dec, 0x - hex, 0b - binary)
|
||||||
|
- **Tt** start single temperature measurement
|
||||||
|
- **u** unique ID (default) CAN mode
|
||||||
|
- **Vv** very low speed
|
||||||
|
- **Xx** go into temperature scan mode
|
||||||
|
- **Yy** get sensors state over CAN (data format: 3 - state, 4,5 - presense mask [0,1], 6 - npresent, 7 - ntempmeasured
|
||||||
|
- **z** check CAN status for errors
|
||||||
|
|
||||||
|
The command **M** allows to temporaly change master ID of all
|
||||||
|
controllers to broadcast ID. So all data they sent will be
|
||||||
|
accessed @ any controller.
|
||||||
|
|
||||||
|
## PINOUT
|
||||||
|
- **I2C**: PB6 (SCL) & PB7 (SDA)
|
||||||
|
- **USART1**: PA9 (Tx) & PA10 (Rx)
|
||||||
|
- **CAN bus**: PB8 (Rx), PB9 (Tx)
|
||||||
|
- **USB bus**: PA11 (DM), PA12 (DP)
|
||||||
|
- **I2C multiplexer**: PB0..PB2 (0..2 address bits), PB12 (~EN)
|
||||||
|
- **sensors' power**: PB3 (in, overcurrent), PA8 (out, enable power)
|
||||||
|
- **signal LEDs**: PB10 (LED0), PB11 (LED1)
|
||||||
|
- **ADC inputs**: PA0 (V12/4.93), PA1 (V5/2), PA3 (I12 - 1V/A), PA6 (V3.3/2)
|
||||||
|
- **controller CAN address**: PA13..PA15 (0..2 bits), PB15 (3rd bit); 0 - master, other address - slave
|
||||||
|
|
||||||
|
|
||||||
|
## LEDS
|
||||||
|
- LED0 (nearest to sensors' connectors) - heartbeat
|
||||||
|
- LED1 (above LED0) - CAN bus OK
|
||||||
|
|
||||||
|
## CAN protocol
|
||||||
|
Variable data length: from 1 to 8 bytes.
|
||||||
|
First (number zero) byte of every sequence is command mark (0xA5) or data mark (0x5A).
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
### Common commands
|
||||||
|
- `CMD_PING` (0) request for PONG cmd
|
||||||
|
- `CMD_START_MEASUREMENT` (1) start single temperature measurement
|
||||||
|
- `CMD_SENSORS_STATE` (2) get sensors state
|
||||||
|
- `CMD_START_SCAN` (3) run scan mode
|
||||||
|
- `CMD_STOP_SCAN` (4) stop scan mode
|
||||||
|
- `CMD_SENSORS_OFF` (5) turn off power of sensors
|
||||||
|
- `CMD_LOWEST_SPEED` (6) lowest I2C speed
|
||||||
|
- `CMD_LOW_SPEED` (7) low I2C speed (10kHz)
|
||||||
|
- `CMD_HIGH_SPEED` (8) high I2C speed (100kHz)
|
||||||
|
- `CMD_REINIT_I2C` (9) reinit I2C with current speed
|
||||||
|
- `CMD_CHANGE_MASTER_B` (10) change master id to broadcast
|
||||||
|
- `CMD_CHANGE_MASTER` (11) change master id to 0
|
||||||
|
- `CMD_GETMCUTEMP` (12) MCU temperature value
|
||||||
|
- `CMD_GETUIVAL` (13) request to get values of V12, V5, I12 and V3.3
|
||||||
|
- `CMD_GETUIVAL0` (14) answer with values of V12 and V5
|
||||||
|
- `CMD_GETUIVAL1` (15) answer with values of I12 and V3.3
|
||||||
|
- `CMD_REINIT_SENSORS` (16) (re)init all sensors (discover all and get calibrated data)
|
||||||
|
- `CMD_GETBUILDNO` (17) get by CAN firmware build number (uint32_t, littleendian, starting from byte #4)
|
||||||
|
- `CMD_SYSTIME` (18) get system time in ms (uint32_t, littleendian, starting from byte #4)
|
||||||
|
|
||||||
|
### Dummy commands for test purposes
|
||||||
|
- `CMD_DUMMY0` = 0xDA,
|
||||||
|
- `CMD_DUMMY1` = 0xAD
|
||||||
|
|
||||||
|
### Commands data format
|
||||||
|
- byte 1 - Controller number
|
||||||
|
- byte 2 - Command received
|
||||||
|
- bytes 3..7 - data
|
||||||
|
|
||||||
|
### Thermal data format
|
||||||
|
- byte 3 - Sensor number (10*N + M, where N is multiplexer number, M - number of sensor in pair, i.e. 0,1,10,11,20,21...70,71)
|
||||||
|
- byte 4 - thermal data H
|
||||||
|
- byte 5 - thermal data L
|
||||||
|
|
||||||
|
### Sensors state data format
|
||||||
|
- byte 3 - Sstate value:
|
||||||
|
- `[SENS_INITING]` = "init"
|
||||||
|
- `[SENS_RESETING]` = "reset"
|
||||||
|
- `[SENS_GET_COEFFS]` = "getcoeff"
|
||||||
|
- `[SENS_SLEEPING]` = "sleep"
|
||||||
|
- `[SENS_START_MSRMNT]` = "startmeasure"
|
||||||
|
- `[SENS_WAITING]` = "waitresults"
|
||||||
|
- `[SENS_GATHERING]` = "collectdata"
|
||||||
|
- `[SENS_OFF]` = "off"
|
||||||
|
- `[SENS_OVERCURNT]` = "overcurrent"
|
||||||
|
- `[SENS_OVERCURNT_OFF]` = "offbyovercurrent"
|
||||||
|
- byte 4 - `sens_present[0]` value
|
||||||
|
- byte 5 - `sens_present[1]` value
|
||||||
|
- byte 6 - `Nsens_present` value
|
||||||
|
- byte 7 - `Ntemp_measured` value
|
||||||
|
|
||||||
|
### MCU temperature data format
|
||||||
|
- byte 3 - data H
|
||||||
|
- byte 4 - data L
|
||||||
|
|
||||||
|
All temperature is in degrC/100!
|
||||||
|
|
||||||
|
### U and I data format
|
||||||
|
- byte 2 - type of data (`CMD_GETUIVAL0` - V12 and V5, `CMD_GETUIVAL1` - I12 and V3.3)
|
||||||
|
|
||||||
|
case CMD_GETUIVAL0
|
||||||
|
|
||||||
|
- bytes 3,4 - V12 H/L
|
||||||
|
- bytes 5,6 - V5 H/L
|
||||||
|
|
||||||
|
case CMD_GETUIVAL1
|
||||||
|
|
||||||
|
- bytes 3,4 - I12 H/L
|
||||||
|
- bytes 5,6 - V33 H/L
|
||||||
|
|
||||||
|
Voltage is in V/100, Current is in mA
|
||||||
1
F0:F030,F042,F072/TSYS_controller/TSYS_controller.cflags
Normal file
1
F0:F030,F042,F072/TSYS_controller/TSYS_controller.cflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c17
|
||||||
8
F0:F030,F042,F072/TSYS_controller/TSYS_controller.config
Normal file
8
F0:F030,F042,F072/TSYS_controller/TSYS_controller.config
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Add predefined macros for your project here. For example:
|
||||||
|
// #define THE_ANSWER 42
|
||||||
|
#define FAMILY F0
|
||||||
|
#define MCU F042x6
|
||||||
|
#define STM32F0
|
||||||
|
#define STM32F042x6
|
||||||
|
#define USARTNUM 1
|
||||||
|
#define I2CPINS 67
|
||||||
@ -0,0 +1 @@
|
|||||||
|
[General]
|
||||||
171
F0:F030,F042,F072/TSYS_controller/TSYS_controller.creator.user
Normal file
171
F0:F030,F042,F072/TSYS_controller/TSYS_controller.creator.user
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE QtCreatorProject>
|
||||||
|
<!-- Written by QtCreator 8.0.2, 2023-08-29T20:44:10. -->
|
||||||
|
<qtcreator>
|
||||||
|
<data>
|
||||||
|
<variable>EnvironmentId</variable>
|
||||||
|
<value type="QByteArray">{7bd84e39-ca37-46d3-be9d-99ebea85bc0d}</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||||
|
<value type="int">0</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||||
|
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||||
|
<value type="QString" key="language">Cpp</value>
|
||||||
|
<valuemap type="QVariantMap" key="value">
|
||||||
|
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||||
|
<value type="QString" key="language">QmlJS</value>
|
||||||
|
<valuemap type="QVariantMap" key="value">
|
||||||
|
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||||
|
<value type="QByteArray" key="EditorConfiguration.Codec">KOI8-R</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||||
|
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||||
|
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||||
|
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.cleanIndentation">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||||
|
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
|
||||||
|
<value type="bool" key="AutoTest.Framework.Boost">true</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.CTest">false</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.Catch">true</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.GTest">true</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
||||||
|
</valuemap>
|
||||||
|
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
||||||
|
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
||||||
|
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
||||||
|
<valuemap type="QVariantMap" key="ClangTools">
|
||||||
|
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||||
|
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||||
|
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||||
|
<value type="int" key="ClangTools.ParallelJobs">8</value>
|
||||||
|
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||||
|
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||||
|
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||||
|
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<value type="QString" key="DeviceType">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{65a14f9e-e008-4c1b-89df-4eaa4774b6e3}</value>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||||
|
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Big/Data/00__Electronics/STM32/F0-nolib/TSYS_controller</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||||
|
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||||
|
<value type="QString">all</value>
|
||||||
|
</valuelist>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||||
|
</valuemap>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||||
|
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||||
|
<value type="QString">clean</value>
|
||||||
|
</valuelist>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||||
|
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||||
|
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">По умолчанию</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||||
|
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||||
|
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||||
|
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||||
|
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||||
|
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||||
|
<value type="int">1</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||||
|
<value type="int">22</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>Version</variable>
|
||||||
|
<value type="int">22</value>
|
||||||
|
</data>
|
||||||
|
</qtcreator>
|
||||||
@ -0,0 +1,198 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE QtCreatorProject>
|
||||||
|
<!-- Written by QtCreator 4.6.2, 2019-09-09T09:34:18. -->
|
||||||
|
<qtcreator>
|
||||||
|
<data>
|
||||||
|
<variable>EnvironmentId</variable>
|
||||||
|
<value type="QByteArray">{cf63021e-ef53-49b0-b03b-2f2570cdf3b6}</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||||
|
<value type="int">0</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||||
|
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||||
|
<value type="QString" key="language">Cpp</value>
|
||||||
|
<valuemap type="QVariantMap" key="value">
|
||||||
|
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||||
|
<value type="QString" key="language">QmlJS</value>
|
||||||
|
<valuemap type="QVariantMap" key="value">
|
||||||
|
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||||
|
<value type="QByteArray" key="EditorConfiguration.Codec">KOI8-R</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||||
|
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||||
|
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||||
|
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||||
|
<value type="int" key="EditorConfiguration.Utf8BomBehavior">2</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.inEntireDocument">true</value>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||||
|
<valuemap type="QVariantMap"/>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{91347f2c-5221-46a7-80b1-0a054ca02f79}</value>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||||
|
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/eddy/Docs/SAO/BTA/MIRROR_CONTROL_termo/Project/STM32src/TSYS_controller</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||||
|
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||||
|
<value type="QString">all</value>
|
||||||
|
</valuelist>
|
||||||
|
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
|
||||||
|
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments"></value>
|
||||||
|
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||||
|
</valuemap>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||||
|
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||||
|
<value type="QString">clean</value>
|
||||||
|
</valuelist>
|
||||||
|
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
|
||||||
|
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments"></value>
|
||||||
|
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||||
|
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">По умолчанию</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">По умолчанию</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||||
|
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Установка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Конфигурация установки</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||||
|
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
|
||||||
|
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
|
||||||
|
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
|
||||||
|
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
|
||||||
|
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||||
|
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
|
||||||
|
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
|
||||||
|
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
|
||||||
|
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
|
||||||
|
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
|
||||||
|
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
|
||||||
|
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
|
||||||
|
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
|
||||||
|
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
|
||||||
|
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
|
||||||
|
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
|
||||||
|
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
|
||||||
|
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
|
||||||
|
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||||
|
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
|
||||||
|
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
|
||||||
|
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
|
||||||
|
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
|
||||||
|
<value type="int">0</value>
|
||||||
|
<value type="int">1</value>
|
||||||
|
<value type="int">2</value>
|
||||||
|
<value type="int">3</value>
|
||||||
|
<value type="int">4</value>
|
||||||
|
<value type="int">5</value>
|
||||||
|
<value type="int">6</value>
|
||||||
|
<value type="int">7</value>
|
||||||
|
<value type="int">8</value>
|
||||||
|
<value type="int">9</value>
|
||||||
|
<value type="int">10</value>
|
||||||
|
<value type="int">11</value>
|
||||||
|
<value type="int">12</value>
|
||||||
|
<value type="int">13</value>
|
||||||
|
<value type="int">14</value>
|
||||||
|
</valuelist>
|
||||||
|
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||||
|
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||||
|
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments"></value>
|
||||||
|
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable"></value>
|
||||||
|
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory"></value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName"></value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||||
|
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||||
|
<value type="int">1</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||||
|
<value type="int">18</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>Version</variable>
|
||||||
|
<value type="int">18</value>
|
||||||
|
</data>
|
||||||
|
</qtcreator>
|
||||||
@ -0,0 +1,160 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE QtCreatorProject>
|
||||||
|
<!-- Written by QtCreator 6.0.0, 2022-02-03T09:36:24. -->
|
||||||
|
<qtcreator>
|
||||||
|
<data>
|
||||||
|
<variable>EnvironmentId</variable>
|
||||||
|
<value type="QByteArray">{cf63021e-ef53-49b0-b03b-2f2570cdf3b6}</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||||
|
<value type="int">0</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||||
|
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||||
|
<value type="QString" key="language">Cpp</value>
|
||||||
|
<valuemap type="QVariantMap" key="value">
|
||||||
|
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||||
|
<value type="QString" key="language">QmlJS</value>
|
||||||
|
<valuemap type="QVariantMap" key="value">
|
||||||
|
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||||
|
<value type="QByteArray" key="EditorConfiguration.Codec">KOI8-R</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||||
|
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||||
|
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||||
|
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.Utf8BomBehavior">2</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||||
|
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.inEntireDocument">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<valuemap type="QVariantMap" key="ClangTools">
|
||||||
|
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||||
|
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||||
|
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||||
|
<value type="int" key="ClangTools.ParallelJobs">4</value>
|
||||||
|
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||||
|
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||||
|
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||||
|
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<value type="QString" key="DeviceType">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{91347f2c-5221-46a7-80b1-0a054ca02f79}</value>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||||
|
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/eddy/Docs/SAO/BTA/MIRROR_CONTROL_termo/Project/STM32src/TSYS_controller</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||||
|
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||||
|
<value type="QString">all</value>
|
||||||
|
</valuelist>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||||
|
</valuemap>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||||
|
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||||
|
<value type="QString">clean</value>
|
||||||
|
</valuelist>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||||
|
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||||
|
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">По умолчанию</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||||
|
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||||
|
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||||
|
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||||
|
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||||
|
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||||
|
<value type="int">1</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||||
|
<value type="int">22</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>Version</variable>
|
||||||
|
<value type="int">22</value>
|
||||||
|
</data>
|
||||||
|
</qtcreator>
|
||||||
@ -0,0 +1 @@
|
|||||||
|
-std=c++17
|
||||||
23
F0:F030,F042,F072/TSYS_controller/TSYS_controller.files
Normal file
23
F0:F030,F042,F072/TSYS_controller/TSYS_controller.files
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
adc.c
|
||||||
|
adc.h
|
||||||
|
usb.c
|
||||||
|
usb.h
|
||||||
|
usb_lib.h
|
||||||
|
usb_lib.c
|
||||||
|
usb_defs.h
|
||||||
|
can.c
|
||||||
|
can.h
|
||||||
|
can_process.c
|
||||||
|
can_process.h
|
||||||
|
hardware.c
|
||||||
|
hardware.h
|
||||||
|
i2c.c
|
||||||
|
i2c.h
|
||||||
|
main.c
|
||||||
|
proto.c
|
||||||
|
proto.h
|
||||||
|
sensors_manage.c
|
||||||
|
sensors_manage.h
|
||||||
|
usart.c
|
||||||
|
usart.h
|
||||||
|
version.inc
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
.
|
||||||
|
../inc
|
||||||
|
../inc/F0
|
||||||
|
../inc/cm
|
||||||
167
F0:F030,F042,F072/TSYS_controller/adc.c
Normal file
167
F0:F030,F042,F072/TSYS_controller/adc.c
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the TSYS_controller 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 "adc.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ADC_array - array for ADC channels with median filtering:
|
||||||
|
* 0..3 - external channels
|
||||||
|
* 4 - internal Tsens
|
||||||
|
* 5 - Vref
|
||||||
|
*/
|
||||||
|
#define TSENS_CHAN (NUMBER_OF_ADC_CHANNELS-2)
|
||||||
|
#define VREF_CHAN (NUMBER_OF_ADC_CHANNELS-1)
|
||||||
|
static uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ADC channels:
|
||||||
|
* IN0 - V12
|
||||||
|
* IN1 - V5
|
||||||
|
* IN3 - I12
|
||||||
|
* IN6 - V3.3
|
||||||
|
* IN16- temperature sensor
|
||||||
|
* IN17- vref
|
||||||
|
*/
|
||||||
|
void adc_setup(){
|
||||||
|
uint16_t ctr = 0; // 0xfff0 - more than 1.3ms
|
||||||
|
// Enable clocking
|
||||||
|
/* (1) Enable the peripheral clock of the ADC */
|
||||||
|
/* (2) Start HSI14 RC oscillator */
|
||||||
|
/* (3) Wait HSI14 is ready */
|
||||||
|
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; /* (1) */
|
||||||
|
RCC->CR2 |= RCC_CR2_HSI14ON; /* (2) */
|
||||||
|
while ((RCC->CR2 & RCC_CR2_HSI14RDY) == 0 && ++ctr < 0xfff0){}; /* (3) */
|
||||||
|
// calibration
|
||||||
|
/* (1) Ensure that ADEN = 0 */
|
||||||
|
/* (2) Clear ADEN */
|
||||||
|
/* (3) Launch the calibration by setting ADCAL */
|
||||||
|
/* (4) Wait until ADCAL=0 */
|
||||||
|
if ((ADC1->CR & ADC_CR_ADEN) != 0){ /* (1) */
|
||||||
|
ADC1->CR &= (uint32_t)(~ADC_CR_ADEN); /* (2) */
|
||||||
|
}
|
||||||
|
ADC1->CR |= ADC_CR_ADCAL; /* (3) */
|
||||||
|
ctr = 0; // ADC calibration time is 5.9us
|
||||||
|
while ((ADC1->CR & ADC_CR_ADCAL) != 0 && ++ctr < 0xfff0){}; /* (4) */
|
||||||
|
// enable ADC
|
||||||
|
ctr = 0;
|
||||||
|
do{
|
||||||
|
ADC1->CR |= ADC_CR_ADEN;
|
||||||
|
}while ((ADC1->ISR & ADC_ISR_ADRDY) == 0 && ++ctr < 0xfff0);
|
||||||
|
// configure ADC
|
||||||
|
/* (1) Select HSI14 by writing 00 in CKMODE (reset value) */
|
||||||
|
/* (2) Select the continuous mode */
|
||||||
|
/* (3) Select CHSEL0,1,3,6 - ADC inputs, 16,17 - t. sensor and vref */
|
||||||
|
/* (4) Select a sampling mode of 111 i.e. 239.5 ADC clk to be greater than 17.1us */
|
||||||
|
/* (5) Wake-up the VREFINT and Temperature sensor (only for VBAT, Temp sensor and VRefInt) */
|
||||||
|
// ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE; /* (1) */
|
||||||
|
ADC1->CFGR1 |= ADC_CFGR1_CONT; /* (2)*/
|
||||||
|
ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL3 |
|
||||||
|
ADC_CHSELR_CHSEL6 | ADC_CHSELR_CHSEL16 | ADC_CHSELR_CHSEL17; /* (3)*/
|
||||||
|
ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2; /* (4) */
|
||||||
|
ADC->CCR |= ADC_CCR_TSEN | ADC_CCR_VREFEN; /* (5) */
|
||||||
|
// configure DMA for ADC
|
||||||
|
// DMA for AIN
|
||||||
|
/* (1) Enable the peripheral clock on DMA */
|
||||||
|
/* (2) Enable DMA transfer on ADC and circular mode */
|
||||||
|
/* (3) Configure the peripheral data register address */
|
||||||
|
/* (4) Configure the memory address */
|
||||||
|
/* (5) Configure the number of DMA tranfer to be performs on DMA channel 1 */
|
||||||
|
/* (6) Configure increment, size, interrupts and circular mode */
|
||||||
|
/* (7) Enable DMA Channel 1 */
|
||||||
|
RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* (1) */
|
||||||
|
ADC1->CFGR1 |= ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG; /* (2) */
|
||||||
|
DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR)); /* (3) */
|
||||||
|
DMA1_Channel1->CMAR = (uint32_t)(ADC_array); /* (4) */
|
||||||
|
DMA1_Channel1->CNDTR = NUMBER_OF_ADC_CHANNELS * 9; /* (5) */
|
||||||
|
DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_CIRC; /* (6) */
|
||||||
|
DMA1_Channel1->CCR |= DMA_CCR_EN; /* (7) */
|
||||||
|
ADC1->CR |= ADC_CR_ADSTART; /* start the ADC conversions */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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) { if ((a)>(b)) PIX_SWAP((a),(b)); }
|
||||||
|
#define PIX_SWAP(a,b) { temp=(a);(a)=(b);(b)=temp; }
|
||||||
|
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(){
|
||||||
|
getVdd();
|
||||||
|
// make correction on Vdd value
|
||||||
|
// int32_t temperature = (int32_t)ADC_array[4] * VddValue / 330;
|
||||||
|
int32_t ADval = getADCval(TSENS_CHAN);
|
||||||
|
int32_t temperature = (int32_t) *TEMP30_CAL_ADDR - ADval;
|
||||||
|
temperature *= (int32_t)(1100 - 300);
|
||||||
|
temperature /= (int32_t)(*TEMP30_CAL_ADDR - *TEMP110_CAL_ADDR);
|
||||||
|
temperature += 300;
|
||||||
|
return(temperature);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return Vdd * 100 (V)
|
||||||
|
uint32_t getVdd(){
|
||||||
|
uint32_t vdd = ((uint32_t) *VREFINT_CAL_ADDR) * (uint32_t)330; // 3.3V
|
||||||
|
vdd /= getADCval(VREF_CHAN);
|
||||||
|
return vdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t Ufromadu(uint8_t nch, uint32_t vdd){
|
||||||
|
uint32_t ADU = getADCval(nch);
|
||||||
|
ADU *= vdd;
|
||||||
|
ADU >>= 12; // /4096
|
||||||
|
return ADU;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getUval - calculate U & I
|
||||||
|
* @return array with members:
|
||||||
|
* 0 - V12 * 100V (U12 = 12Vin/4.93)
|
||||||
|
* 1 - V5 * 100V (U5 = 5Vin /2)
|
||||||
|
* 2 - I12 mA (U = 1V/1A)
|
||||||
|
* 3 - V3.3* 100V (U3.3= 3.3Vin/2)
|
||||||
|
*/
|
||||||
|
uint16_t *getUval(){
|
||||||
|
static uint16_t Uval[4];
|
||||||
|
uint32_t vdd = getVdd();
|
||||||
|
uint32_t val = Ufromadu(0, vdd) * 493;
|
||||||
|
Uval[0] = (uint16_t)(val / 100);
|
||||||
|
Uval[1] = (uint16_t)(Ufromadu(1, vdd) << 1);
|
||||||
|
val = getADCval(2) * vdd * 10;
|
||||||
|
Uval[2] = (uint16_t)(val >> 12);
|
||||||
|
Uval[3] = (uint16_t)(Ufromadu(3, vdd) << 1);
|
||||||
|
return Uval;
|
||||||
|
}
|
||||||
31
F0:F030,F042,F072/TSYS_controller/adc.h
Normal file
31
F0:F030,F042,F072/TSYS_controller/adc.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the TSYS_controller 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ADC_H
|
||||||
|
#define ADC_H
|
||||||
|
#include "stm32f0.h"
|
||||||
|
|
||||||
|
#define NUMBER_OF_ADC_CHANNELS (6)
|
||||||
|
|
||||||
|
int32_t getMCUtemp();
|
||||||
|
uint32_t getVdd();
|
||||||
|
uint16_t getADCval(int nch);
|
||||||
|
void adc_setup();
|
||||||
|
uint16_t *getUval();
|
||||||
|
|
||||||
|
#endif // ADC_H
|
||||||
296
F0:F030,F042,F072/TSYS_controller/can.c
Normal file
296
F0:F030,F042,F072/TSYS_controller/can.c
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
/*
|
||||||
|
* geany_encoding=koi8-r
|
||||||
|
* can.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 <string.h> // memcpy
|
||||||
|
|
||||||
|
#include "can.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
#include "proto.h"
|
||||||
|
|
||||||
|
|
||||||
|
// incoming message buffer size
|
||||||
|
#define CAN_INMESSAGE_SIZE (32)
|
||||||
|
|
||||||
|
extern volatile uint32_t Tms;
|
||||||
|
|
||||||
|
// circular buffer for received messages
|
||||||
|
static CAN_message messages[CAN_INMESSAGE_SIZE];
|
||||||
|
static uint8_t first_free_idx = 0; // index of first empty cell
|
||||||
|
static int8_t first_nonfree_idx = -1; // index of first data cell
|
||||||
|
int8_t cansniffer = 0; // ==1 to listen all CAN ID's
|
||||||
|
|
||||||
|
uint16_t curcanspeed = CAN_SPEED_DEFAULT; // speed of last init
|
||||||
|
|
||||||
|
uint16_t CANID = 0xFFFF;
|
||||||
|
uint8_t Controller_address = 0;
|
||||||
|
static CAN_status can_status = CAN_STOP;
|
||||||
|
|
||||||
|
static void can_process_fifo(uint8_t fifo_num);
|
||||||
|
|
||||||
|
CAN_status CAN_get_status(){
|
||||||
|
CAN_status st = can_status;
|
||||||
|
// give overrun message only once
|
||||||
|
if(st == CAN_FIFO_OVERRUN) can_status = CAN_READY;
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
|
// push next message into buffer; return 1 if buffer overfull
|
||||||
|
static int CAN_messagebuf_push(CAN_message *msg){
|
||||||
|
MSG("Try to push\n");
|
||||||
|
if(first_free_idx == first_nonfree_idx) return 1; // no free space
|
||||||
|
if(first_nonfree_idx < 0) first_nonfree_idx = 0; // first message in empty buffer
|
||||||
|
memcpy(&messages[first_free_idx++], msg, sizeof(CAN_message));
|
||||||
|
// need to roll?
|
||||||
|
if(first_free_idx == CAN_INMESSAGE_SIZE) first_free_idx = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pop message from buffer
|
||||||
|
CAN_message *CAN_messagebuf_pop(){
|
||||||
|
if(first_nonfree_idx < 0) return NULL;
|
||||||
|
CAN_message *msg = &messages[first_nonfree_idx++];
|
||||||
|
if(first_nonfree_idx == CAN_INMESSAGE_SIZE) first_nonfree_idx = 0;
|
||||||
|
if(first_nonfree_idx == first_free_idx){ // buffer is empty - refresh it
|
||||||
|
first_nonfree_idx = -1;
|
||||||
|
first_free_idx = 0;
|
||||||
|
}
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get CAN address data from GPIO pins
|
||||||
|
void readCANID(){
|
||||||
|
uint8_t CAN_addr = READ_CAN_INV_ADDR();
|
||||||
|
Controller_address = ~CAN_addr & 0x0f;
|
||||||
|
CANID = (CAN_ID_PREFIX & CAN_ID_MASK) | Controller_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAN_setup(uint16_t speed){
|
||||||
|
if(speed == 0) speed = curcanspeed;
|
||||||
|
else if(speed < CAN_SPEED_MIN) speed = CAN_SPEED_MIN;
|
||||||
|
else if(speed > CAN_SPEED_MAX) speed = CAN_SPEED_MAX;
|
||||||
|
curcanspeed = speed;
|
||||||
|
readCANID();
|
||||||
|
CAN->TSR |= CAN_TSR_ABRQ0 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ2;
|
||||||
|
RCC->APB1RSTR |= RCC_APB1RSTR_CANRST;
|
||||||
|
RCC->APB1RSTR &= ~RCC_APB1RSTR_CANRST;
|
||||||
|
// Configure GPIO: PB8 - CAN_Rx, PB9 - CAN_Tx
|
||||||
|
/* (1) Select AF mode (10) on PB8 and PB9 */
|
||||||
|
/* (2) AF4 for CAN signals */
|
||||||
|
GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER8 | GPIO_MODER_MODER9))
|
||||||
|
| (GPIO_MODER_MODER8_AF | GPIO_MODER_MODER9_AF); /* (1) */
|
||||||
|
GPIOB->AFR[1] = (GPIOB->AFR[1] &~ (GPIO_AFRH_AFRH0 | GPIO_AFRH_AFRH1))\
|
||||||
|
| (4 << (0 * 4)) | (4 << (1 * 4)); /* (2) */
|
||||||
|
/* Enable the peripheral clock CAN */
|
||||||
|
RCC->APB1ENR |= RCC_APB1ENR_CANEN;
|
||||||
|
/* Configure CAN */
|
||||||
|
/* (1) Enter CAN init mode to write the configuration */
|
||||||
|
/* (2) Wait the init mode entering */
|
||||||
|
/* (3) Exit sleep mode */
|
||||||
|
/* (4) Normal mode, set timing to 100kb/s: BS1 = 4, BS2 = 3, prescaler = 6000/speed */
|
||||||
|
/* (5) Leave init mode */
|
||||||
|
/* (6) Wait the init mode leaving */
|
||||||
|
/* (7) Enter filter init mode, (16-bit + mask, filter 0 for FIFO 0) */
|
||||||
|
/* (8) Acivate filter 0 (1,2) */
|
||||||
|
/* (9) Identifier mode for bank#0, mask mode for #1 and #2 */
|
||||||
|
/* (10) Set the Id list */
|
||||||
|
/* (11) Set the mask list */
|
||||||
|
/* (12) Leave filter init */
|
||||||
|
/* (13) Set error interrupts enable */
|
||||||
|
CAN->MCR |= CAN_MCR_INRQ; /* (1) */
|
||||||
|
uint32_t tmout = 16000000;
|
||||||
|
while((CAN->MSR & CAN_MSR_INAK)!=CAN_MSR_INAK){ /* (2) */
|
||||||
|
if(--tmout == 0) break;
|
||||||
|
}
|
||||||
|
CAN->MCR &=~ CAN_MCR_SLEEP; /* (3) */
|
||||||
|
CAN->MCR |= CAN_MCR_ABOM;
|
||||||
|
|
||||||
|
CAN->BTR |= 2 << 20 | 3 << 16 | (6000/speed - 1); /* (4) */
|
||||||
|
CAN->MCR &=~ CAN_MCR_INRQ; /* (5) */
|
||||||
|
tmout = 16000000;
|
||||||
|
while((CAN->MSR & CAN_MSR_INAK)==CAN_MSR_INAK){ /* (6) */
|
||||||
|
if(--tmout == 0) break;
|
||||||
|
}
|
||||||
|
CAN->FMR = CAN_FMR_FINIT; /* (7) */
|
||||||
|
CAN->FA1R = CAN_FA1R_FACT0; /* (8) */
|
||||||
|
CAN->FM1R = CAN_FM1R_FBM0; /* (9) */
|
||||||
|
CAN->sFilterRegister[0].FR1 = CANID << 5 | ((BCAST_ID << 5) << 16); /* (10) */
|
||||||
|
if(cansniffer){ /* (11) */
|
||||||
|
CAN->FA1R |= CAN_FA1R_FACT1 | CAN_FA1R_FACT2; // activate 1 & 2
|
||||||
|
CAN->sFilterRegister[1].FR1 = (1<<21)|(1<<5); // all odd IDs
|
||||||
|
CAN->sFilterRegister[2].FR1 = (1<<21); // all even IDs
|
||||||
|
CAN->FFA1R = 2; // filter 1 for FIFO1, filters 0&2 - for FIFO0
|
||||||
|
}
|
||||||
|
CAN->FMR &=~ CAN_FMR_FINIT; /* (12) */
|
||||||
|
CAN->IER |= CAN_IER_ERRIE | CAN_IER_FOVIE0 | CAN_IER_FOVIE1; /* (13) */
|
||||||
|
|
||||||
|
/* Configure IT */
|
||||||
|
/* (14) Set priority for CAN_IRQn */
|
||||||
|
/* (15) Enable CAN_IRQn */
|
||||||
|
NVIC_SetPriority(CEC_CAN_IRQn, 0); /* (14) */
|
||||||
|
NVIC_EnableIRQ(CEC_CAN_IRQn); /* (15) */
|
||||||
|
can_status = CAN_READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add filters for ALL ID's
|
||||||
|
void CAN_listenall(){
|
||||||
|
cansniffer = 1;
|
||||||
|
CAN_setup(0);
|
||||||
|
}
|
||||||
|
// listen only packets to self & broadcast - delete filters 1&2
|
||||||
|
void CAN_listenone(){
|
||||||
|
cansniffer = 0;
|
||||||
|
CAN_setup(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void can_proc(){
|
||||||
|
// check for messages in FIFO0 & FIFO1
|
||||||
|
if(CAN->RF0R & CAN_RF0R_FMP0){
|
||||||
|
can_process_fifo(0);
|
||||||
|
}
|
||||||
|
if(CAN->RF1R & CAN_RF1R_FMP1){
|
||||||
|
can_process_fifo(1);
|
||||||
|
}
|
||||||
|
if(CAN->ESR & (CAN_ESR_BOFF | CAN_ESR_EPVF | CAN_ESR_EWGF)){ // much errors - restart CAN BUS
|
||||||
|
mesg("too much CAN errors, restart CAN");
|
||||||
|
MSG("bus-off, restarting\n");
|
||||||
|
// request abort for all mailboxes
|
||||||
|
CAN->TSR |= CAN_TSR_ABRQ0 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ2;
|
||||||
|
// reset CAN bus
|
||||||
|
RCC->APB1RSTR |= RCC_APB1RSTR_CANRST;
|
||||||
|
RCC->APB1RSTR &= ~RCC_APB1RSTR_CANRST;
|
||||||
|
can_status = CAN_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id){
|
||||||
|
if(!noLED) LED_on(LED1); // turn ON LED1 at first data sent/receive
|
||||||
|
uint8_t mailbox = 0;
|
||||||
|
// check first free mailbox
|
||||||
|
if(CAN->TSR & (CAN_TSR_TME)){
|
||||||
|
mailbox = (CAN->TSR & CAN_TSR_CODE) >> 24;
|
||||||
|
}else{ // no free mailboxes
|
||||||
|
return CAN_BUSY;
|
||||||
|
}
|
||||||
|
CAN_TxMailBox_TypeDef *box = &CAN->sTxMailBox[mailbox];
|
||||||
|
uint32_t lb = 0, hb = 0;
|
||||||
|
switch(len){
|
||||||
|
case 8:
|
||||||
|
hb |= (uint32_t)msg[7] << 24;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 7:
|
||||||
|
hb |= (uint32_t)msg[6] << 16;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 6:
|
||||||
|
hb |= (uint32_t)msg[5] << 8;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 5:
|
||||||
|
hb |= (uint32_t)msg[4];
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 4:
|
||||||
|
lb |= (uint32_t)msg[3] << 24;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 3:
|
||||||
|
lb |= (uint32_t)msg[2] << 16;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 2:
|
||||||
|
lb |= (uint32_t)msg[1] << 8;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
default:
|
||||||
|
lb |= (uint32_t)msg[0];
|
||||||
|
}
|
||||||
|
box->TDLR = lb;
|
||||||
|
box->TDHR = hb;
|
||||||
|
box->TDTR = len;
|
||||||
|
box->TIR = (target_id & 0x7FF) << 21 | CAN_TI0R_TXRQ;
|
||||||
|
return CAN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void can_process_fifo(uint8_t fifo_num){
|
||||||
|
if(fifo_num > 1) return;
|
||||||
|
CAN_FIFOMailBox_TypeDef *box = &CAN->sFIFOMailBox[fifo_num];
|
||||||
|
volatile uint32_t *RFxR = (fifo_num) ? &CAN->RF1R : &CAN->RF0R;
|
||||||
|
if(!noLED) LED_on(LED1); // turn ON LED1 at first data sent/receive
|
||||||
|
// read all
|
||||||
|
while(*RFxR & CAN_RF0R_FMP0){ // amount of messages pending
|
||||||
|
// CAN_RDTxR: (16-31) - timestamp, (8-15) - filter match index, (0-3) - data length
|
||||||
|
/* TODO: check filter match index if more than one ID can receive */
|
||||||
|
CAN_message msg;
|
||||||
|
uint8_t *dat = msg.data;
|
||||||
|
{ // set all data to 0
|
||||||
|
uint32_t *dptr = (uint32_t*)msg.data;
|
||||||
|
dptr[0] = dptr[1] = 0;
|
||||||
|
}
|
||||||
|
uint8_t len = box->RDTR & 0x0f;
|
||||||
|
msg.length = len;
|
||||||
|
msg.ID = box->RIR >> 21;
|
||||||
|
if(len){ // message can be without data
|
||||||
|
uint32_t hb = box->RDHR, lb = box->RDLR;
|
||||||
|
switch(len){
|
||||||
|
case 8:
|
||||||
|
dat[7] = hb>>24;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 7:
|
||||||
|
dat[6] = (hb>>16) & 0xff;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 6:
|
||||||
|
dat[5] = (hb>>8) & 0xff;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 5:
|
||||||
|
dat[4] = hb & 0xff;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 4:
|
||||||
|
dat[3] = lb>>24;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 3:
|
||||||
|
dat[2] = (lb>>16) & 0xff;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 2:
|
||||||
|
dat[1] = (lb>>8) & 0xff;
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 1:
|
||||||
|
dat[0] = lb & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(CAN_messagebuf_push(&msg)) return; // error: buffer is full, try later
|
||||||
|
*RFxR |= CAN_RF0R_RFOM0; // release fifo for access to next message
|
||||||
|
}
|
||||||
|
if(*RFxR & CAN_RF0R_FULL0) *RFxR &= ~CAN_RF0R_FULL0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cec_can_isr(){
|
||||||
|
if(CAN->RF0R & CAN_RF0R_FOVR0){ // FIFO overrun
|
||||||
|
CAN->RF0R &= ~CAN_RF0R_FOVR0;
|
||||||
|
can_status = CAN_FIFO_OVERRUN;
|
||||||
|
}
|
||||||
|
if(CAN->RF1R & CAN_RF1R_FOVR1){
|
||||||
|
CAN->RF1R &= ~CAN_RF1R_FOVR1;
|
||||||
|
can_status = CAN_FIFO_OVERRUN;
|
||||||
|
}
|
||||||
|
if(CAN->MSR & CAN_MSR_ERRI){ // Error
|
||||||
|
CAN->MSR &= ~CAN_MSR_ERRI;
|
||||||
|
// request abort for problem mailbox
|
||||||
|
if(CAN->TSR & CAN_TSR_TERR0) CAN->TSR |= CAN_TSR_ABRQ0;
|
||||||
|
if(CAN->TSR & CAN_TSR_TERR1) CAN->TSR |= CAN_TSR_ABRQ1;
|
||||||
|
if(CAN->TSR & CAN_TSR_TERR2) CAN->TSR |= CAN_TSR_ABRQ2;
|
||||||
|
}
|
||||||
|
}
|
||||||
73
F0:F030,F042,F072/TSYS_controller/can.h
Normal file
73
F0:F030,F042,F072/TSYS_controller/can.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* geany_encoding=koi8-r
|
||||||
|
* can.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 __CAN_H__
|
||||||
|
#define __CAN_H__
|
||||||
|
|
||||||
|
#include "hardware.h"
|
||||||
|
|
||||||
|
// identifier mask
|
||||||
|
#define CAN_ID_MASK ((uint16_t)0x7F0)
|
||||||
|
// prefix of identifiers
|
||||||
|
#define CAN_ID_PREFIX ((uint16_t)0xAAA)
|
||||||
|
// this is master - Controller_address==0
|
||||||
|
#define MASTER_ID (CAN_ID_PREFIX & CAN_ID_MASK)
|
||||||
|
// broadcasting to every slave
|
||||||
|
#define BCAST_ID ((uint16_t)0x7F7)
|
||||||
|
// send dummy message to this ID for testing CAN bus status
|
||||||
|
#define NOONE_ID ((uint16_t)0x7FF)
|
||||||
|
|
||||||
|
extern uint16_t curcanspeed;
|
||||||
|
extern uint16_t CANID;
|
||||||
|
extern int8_t cansniffer;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
uint8_t data[8];
|
||||||
|
uint8_t length;
|
||||||
|
uint16_t ID; // ID of receiver
|
||||||
|
} CAN_message;
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
CAN_NOTMASTER, // can't send command - not a master
|
||||||
|
CAN_STOP, // CAN stopped
|
||||||
|
CAN_READY, // ready to send
|
||||||
|
CAN_BUSY, // bus is busy
|
||||||
|
CAN_OK, // all OK?
|
||||||
|
CAN_FIFO_OVERRUN, // FIFO overrun
|
||||||
|
CAN_ERROR // no recipients on bus or too many errors
|
||||||
|
} CAN_status;
|
||||||
|
|
||||||
|
CAN_status CAN_get_status();
|
||||||
|
|
||||||
|
void readCANID();
|
||||||
|
|
||||||
|
void CAN_setup(uint16_t speed);
|
||||||
|
void CAN_listenall();
|
||||||
|
void CAN_listenone();
|
||||||
|
|
||||||
|
void can_proc();
|
||||||
|
CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id);
|
||||||
|
|
||||||
|
CAN_message *CAN_messagebuf_pop();
|
||||||
|
|
||||||
|
#endif // __CAN_H__
|
||||||
341
F0:F030,F042,F072/TSYS_controller/can_process.c
Normal file
341
F0:F030,F042,F072/TSYS_controller/can_process.c
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
/*
|
||||||
|
* geany_encoding=koi8-r
|
||||||
|
* can_process.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 "adc.h"
|
||||||
|
#include "can.h"
|
||||||
|
#include "can_process.h"
|
||||||
|
#include "proto.h"
|
||||||
|
#include "sensors_manage.h"
|
||||||
|
#include "version.inc"
|
||||||
|
|
||||||
|
extern volatile uint32_t Tms; // timestamp data
|
||||||
|
// id of master - all data will be sent to it
|
||||||
|
static uint16_t master_id = MASTER_ID;
|
||||||
|
|
||||||
|
static inline void sendmcut(uint8_t *data){
|
||||||
|
uint8_t t[3];
|
||||||
|
uint16_t T = getMCUtemp();
|
||||||
|
t[0] = data[1]; // command itself
|
||||||
|
t[1] = (T >> 8) & 0xff; // H
|
||||||
|
t[2] = T & 0xff; // L
|
||||||
|
can_send_data(t,3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void senduival(){
|
||||||
|
uint8_t buf[5];
|
||||||
|
uint16_t *vals = getUval();
|
||||||
|
buf[0] = CMD_GETUIVAL0; // V12 and V5
|
||||||
|
buf[1] = vals[0] >> 8; // H
|
||||||
|
buf[2] = vals[0] & 0xff;// L
|
||||||
|
buf[3] = vals[1] >> 8; // -//-
|
||||||
|
buf[4] = vals[1] & 0xff;
|
||||||
|
can_send_data(buf, 5);
|
||||||
|
buf[0] = CMD_GETUIVAL1; // I12 and V3.3
|
||||||
|
buf[1] = vals[2] >> 8; // H
|
||||||
|
buf[2] = vals[2] & 0xff;// L
|
||||||
|
buf[3] = vals[3] >> 8; // -//-
|
||||||
|
buf[4] = vals[3] & 0xff;
|
||||||
|
can_send_data(buf, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void showui(char *v1, char *v2, uint8_t *data){
|
||||||
|
char N = '0' + data[1];
|
||||||
|
addtobuf(v1);
|
||||||
|
bufputchar(N);
|
||||||
|
bufputchar('=');
|
||||||
|
uint16_t v = data[3]<<8 | data[4];
|
||||||
|
printu(v);
|
||||||
|
newline();
|
||||||
|
addtobuf(v2);
|
||||||
|
bufputchar(N);
|
||||||
|
bufputchar('=');
|
||||||
|
v = data[5]<<8 | data[6];
|
||||||
|
printu(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void can_messages_proc(){
|
||||||
|
CAN_message *can_mesg = CAN_messagebuf_pop();
|
||||||
|
if(!can_mesg) return; // no data in buffer
|
||||||
|
uint8_t len = can_mesg->length;
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
#ifdef EBUG
|
||||||
|
SEND("got message, len: "); bufputchar('0' + len);
|
||||||
|
SEND(", data: ");
|
||||||
|
uint8_t ctr;
|
||||||
|
for(ctr = 0; ctr < len; ++ctr){
|
||||||
|
printuhex(can_mesg->data[ctr]);
|
||||||
|
bufputchar(' ');
|
||||||
|
}
|
||||||
|
newline();
|
||||||
|
#endif
|
||||||
|
uint8_t *data = can_mesg->data, b[6];
|
||||||
|
b[0] = data[1];
|
||||||
|
// show received message in sniffer mode
|
||||||
|
if(cansniffer){
|
||||||
|
printu(Tms);
|
||||||
|
SEND(" #");
|
||||||
|
printuhex(can_mesg->ID);
|
||||||
|
for(int ctr = 0; ctr < len; ++ctr){
|
||||||
|
SEND(" ");
|
||||||
|
printuhex(can_mesg->data[ctr]);
|
||||||
|
}
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
// don't process alien messages
|
||||||
|
if(can_mesg->ID != CANID && can_mesg->ID != BCAST_ID) return;
|
||||||
|
int16_t t;
|
||||||
|
uint32_t U32;
|
||||||
|
if(data[0] == COMMAND_MARK){ // process commands
|
||||||
|
if(len < 2) return;
|
||||||
|
// master shouldn't react to broadcast commands!
|
||||||
|
if(can_mesg->ID == BCAST_ID && CANID == MASTER_ID) return;
|
||||||
|
switch(data[1]){
|
||||||
|
case CMD_DUMMY0:
|
||||||
|
case CMD_DUMMY1:
|
||||||
|
SEND("DUMMY");
|
||||||
|
bufputchar('0' + (data[1]==CMD_DUMMY0 ? 0 : 1));
|
||||||
|
newline();
|
||||||
|
break;
|
||||||
|
case CMD_PING: // pong
|
||||||
|
can_send_data(b, 1);
|
||||||
|
break;
|
||||||
|
case CMD_SENSORS_STATE:
|
||||||
|
b[1] = Sstate;
|
||||||
|
b[2] = sens_present[0];
|
||||||
|
b[3] = sens_present[1];
|
||||||
|
b[4] = Nsens_present;
|
||||||
|
b[5] = Ntemp_measured;
|
||||||
|
can_send_data(b, 6);
|
||||||
|
break;
|
||||||
|
case CMD_START_MEASUREMENT:
|
||||||
|
sensors_start();
|
||||||
|
break;
|
||||||
|
case CMD_START_SCAN:
|
||||||
|
sensors_scan_mode = 1;
|
||||||
|
break;
|
||||||
|
case CMD_STOP_SCAN:
|
||||||
|
sensors_scan_mode = 0;
|
||||||
|
break;
|
||||||
|
case CMD_SENSORS_OFF:
|
||||||
|
sensors_off();
|
||||||
|
break;
|
||||||
|
case CMD_LOWEST_SPEED:
|
||||||
|
i2c_setup(VERYLOW_SPEED);
|
||||||
|
break;
|
||||||
|
case CMD_LOW_SPEED:
|
||||||
|
i2c_setup(LOW_SPEED);
|
||||||
|
break;
|
||||||
|
case CMD_HIGH_SPEED:
|
||||||
|
i2c_setup(HIGH_SPEED);
|
||||||
|
break;
|
||||||
|
case CMD_REINIT_I2C:
|
||||||
|
i2c_setup(CURRENT_SPEED);
|
||||||
|
break;
|
||||||
|
case CMD_CHANGE_MASTER_B:
|
||||||
|
master_id = BCAST_ID;
|
||||||
|
break;
|
||||||
|
case CMD_CHANGE_MASTER:
|
||||||
|
master_id = MASTER_ID;
|
||||||
|
break;
|
||||||
|
case CMD_GETMCUTEMP:
|
||||||
|
sendmcut(data);
|
||||||
|
break;
|
||||||
|
case CMD_GETUIVAL:
|
||||||
|
senduival();
|
||||||
|
break;
|
||||||
|
case CMD_REINIT_SENSORS:
|
||||||
|
sensors_init();
|
||||||
|
break;
|
||||||
|
case CMD_GETBUILDNO:
|
||||||
|
b[1] = 0;
|
||||||
|
*((uint32_t*)&b[2]) = BUILDNO;
|
||||||
|
can_send_data(b, 6);
|
||||||
|
break;
|
||||||
|
case CMD_SYSTIME:
|
||||||
|
b[1] = 0;
|
||||||
|
*((uint32_t*)&b[2]) = Tms;
|
||||||
|
can_send_data(b, 6);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else if(data[0] == DATA_MARK){ // process received data
|
||||||
|
char Ns = '0' + data[1];
|
||||||
|
if(len < 3) return;
|
||||||
|
switch(data[2]){
|
||||||
|
case CMD_PING:
|
||||||
|
mesg("CMD_PING");
|
||||||
|
SEND("PONG");
|
||||||
|
bufputchar(Ns);
|
||||||
|
break;
|
||||||
|
case CMD_SENSORS_STATE:
|
||||||
|
mesg("CMD_SENSORS_STATE");
|
||||||
|
SEND("SSTATE");
|
||||||
|
bufputchar(Ns);
|
||||||
|
bufputchar('=');
|
||||||
|
SEND(sensors_get_statename(data[3]));
|
||||||
|
SEND("\nNSENS");
|
||||||
|
bufputchar(Ns);
|
||||||
|
bufputchar('=');
|
||||||
|
printu(data[6]);
|
||||||
|
SEND("\nSENSPRESENT");
|
||||||
|
bufputchar(Ns);
|
||||||
|
bufputchar('=');
|
||||||
|
printu(data[4] | (data[5]<<8));
|
||||||
|
SEND("\nNTEMP");
|
||||||
|
bufputchar(Ns);
|
||||||
|
bufputchar('=');
|
||||||
|
printu(data[7]);
|
||||||
|
break;
|
||||||
|
case CMD_START_MEASUREMENT: // temperature
|
||||||
|
mesg("CMD_START_MEASUREMENT");
|
||||||
|
if(len != 6) return;
|
||||||
|
bufputchar('T');
|
||||||
|
bufputchar(Ns);
|
||||||
|
bufputchar('_');
|
||||||
|
printu(data[3]);
|
||||||
|
bufputchar('=');
|
||||||
|
t = data[4]<<8 | data[5];
|
||||||
|
if(t < 0){
|
||||||
|
t = -t;
|
||||||
|
bufputchar('-');
|
||||||
|
}
|
||||||
|
printu(t);
|
||||||
|
break;
|
||||||
|
case CMD_GETMCUTEMP:
|
||||||
|
mesg("CMD_GETMCUTEMP");
|
||||||
|
addtobuf("TMCU");
|
||||||
|
bufputchar(Ns);
|
||||||
|
bufputchar('=');
|
||||||
|
t = data[3]<<8 | data[4];
|
||||||
|
if(t < 0){
|
||||||
|
bufputchar('-');
|
||||||
|
t = -t;
|
||||||
|
}
|
||||||
|
printu(t);
|
||||||
|
break;
|
||||||
|
case CMD_GETUIVAL0: // V12 and V5
|
||||||
|
mesg("CMD_GETUIVAL0");
|
||||||
|
showui("V12_", "V5_", data);
|
||||||
|
break;
|
||||||
|
case CMD_GETUIVAL1: // I12 and V3.3
|
||||||
|
mesg("CMD_GETUIVAL1");
|
||||||
|
showui("I12_", "V33_", data);
|
||||||
|
break;
|
||||||
|
case CMD_GETBUILDNO:
|
||||||
|
mesg("CMD_GETBUILDNO");
|
||||||
|
addtobuf("BUILDNO");
|
||||||
|
bufputchar(Ns);
|
||||||
|
bufputchar('=');
|
||||||
|
U32 = *((uint32_t*)&data[4]);
|
||||||
|
printu(U32);
|
||||||
|
break;
|
||||||
|
case CMD_SYSTIME:
|
||||||
|
mesg("CMD_SYSTIME");
|
||||||
|
addtobuf("SYSTIME");
|
||||||
|
bufputchar(Ns);
|
||||||
|
bufputchar('=');
|
||||||
|
U32 = *((uint32_t*)&data[4]);
|
||||||
|
printu(U32);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SEND("UNKNOWN_DATA");
|
||||||
|
}
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to send messages, wait no more than 100ms
|
||||||
|
static CAN_status try2send(uint8_t *buf, uint8_t len, uint16_t id){
|
||||||
|
uint32_t Tstart = Tms;
|
||||||
|
while(Tms - Tstart < SEND_TIMEOUT_MS){
|
||||||
|
if(CAN_OK == can_send(buf, len, id)) return CAN_OK;
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
}
|
||||||
|
SEND("CAN_BUSY\n");
|
||||||
|
return CAN_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send command over CAN bus (works only if controller number is 0 - master mode)
|
||||||
|
* @param targetID - target identifier
|
||||||
|
* @param cmd - command to send
|
||||||
|
*/
|
||||||
|
CAN_status can_send_cmd(uint16_t targetID, uint8_t cmd){
|
||||||
|
//if(Controller_address != 0 && cmd != CMD_DUMMY0 && cmd != CMD_DUMMY1) return CAN_NOTMASTER;
|
||||||
|
uint8_t buf[2];
|
||||||
|
buf[0] = COMMAND_MARK;
|
||||||
|
buf[1] = cmd;
|
||||||
|
return try2send(buf, 2, targetID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send data over CAN bus to MASTER_ID (not more than 6 bytes)
|
||||||
|
CAN_status can_send_data(uint8_t *data, uint8_t len){
|
||||||
|
if(len > 6) return CAN_OK;
|
||||||
|
uint8_t buf[8];
|
||||||
|
buf[0] = DATA_MARK;
|
||||||
|
buf[1] = Controller_address;
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < len; ++i) buf[i+2] = *data++;
|
||||||
|
return try2send(buf, len+2, master_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send temperature data over CAN bus once per call
|
||||||
|
* @return next number or -1 if all data sent
|
||||||
|
*/
|
||||||
|
int8_t send_temperatures(int8_t N){
|
||||||
|
if(N < 0 || Controller_address == 0) return -1; // don't need to send Master's data over CAN bus
|
||||||
|
int a, p;
|
||||||
|
uint8_t can_data[4];
|
||||||
|
int8_t retn = N;
|
||||||
|
can_data[0] = CMD_START_MEASUREMENT;
|
||||||
|
a = N / 10;
|
||||||
|
p = N - a*10;
|
||||||
|
if(p == 2){ // next sensor
|
||||||
|
if(++a > MUL_MAX_ADDRESS) return -1;
|
||||||
|
p = 0;
|
||||||
|
}
|
||||||
|
do{
|
||||||
|
if(!(sens_present[p] & (1<<a))){
|
||||||
|
if(p == 0) p = 1;
|
||||||
|
else{
|
||||||
|
p = 0;
|
||||||
|
++a;
|
||||||
|
}
|
||||||
|
} else break;
|
||||||
|
}while(a <= MUL_MAX_ADDRESS);
|
||||||
|
if(a > MUL_MAX_ADDRESS) return -1; // done
|
||||||
|
retn = a*10 + p; // current temperature sensor number
|
||||||
|
can_data[1] = a*10 + p;
|
||||||
|
//char b[] = {'T', a+'0', p+'0', '=', '+'};
|
||||||
|
int16_t t = Temperatures[a][p];
|
||||||
|
if(t == BAD_TEMPERATURE || t == NO_SENSOR){ // don't send data if it's absent on current measurement
|
||||||
|
++retn;
|
||||||
|
}else{
|
||||||
|
can_data[2] = t>>8; // H byte
|
||||||
|
can_data[3] = t&0xff; // L byte
|
||||||
|
if(CAN_OK == can_send_data(can_data, 4)){ // OK, calculate next address
|
||||||
|
++retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retn;
|
||||||
|
}
|
||||||
61
F0:F030,F042,F072/TSYS_controller/can_process.h
Normal file
61
F0:F030,F042,F072/TSYS_controller/can_process.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* geany_encoding=koi8-r
|
||||||
|
* can_process.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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "can.h"
|
||||||
|
|
||||||
|
// timeout for trying to send data
|
||||||
|
#define SEND_TIMEOUT_MS (10)
|
||||||
|
// mark first byte if command sent
|
||||||
|
#define COMMAND_MARK (0xA5)
|
||||||
|
// mark first byte if data sent
|
||||||
|
#define DATA_MARK (0x5A)
|
||||||
|
|
||||||
|
// 8-bit commands sent by master
|
||||||
|
typedef enum{
|
||||||
|
CMD_PING, // request for PONG cmd
|
||||||
|
CMD_START_MEASUREMENT, // start thermal measurement (and turn ON sensors if was OFF)
|
||||||
|
CMD_SENSORS_STATE, // reply data with sensors state (data: 0 - SState, 1,2 - sens_present0, 3 - Nsens_presend, 4 - Ntemp_measured)
|
||||||
|
CMD_START_SCAN, // run scan mode @ all controllers
|
||||||
|
CMD_STOP_SCAN, // stop scan mode
|
||||||
|
CMD_SENSORS_OFF, // turn off power of sensors
|
||||||
|
CMD_LOWEST_SPEED, // lowest I2C speed
|
||||||
|
CMD_LOW_SPEED, // low I2C speed (10kHz)
|
||||||
|
CMD_HIGH_SPEED, // high I2C speed (100kHz)
|
||||||
|
CMD_REINIT_I2C, // reinit I2C with current speed
|
||||||
|
CMD_CHANGE_MASTER_B, // change master id to broadcast
|
||||||
|
CMD_CHANGE_MASTER, // change master id to 0
|
||||||
|
CMD_GETMCUTEMP, // MCU temperature value
|
||||||
|
CMD_GETUIVAL, // request to get values of V12, V5, I12 and V3.3
|
||||||
|
CMD_GETUIVAL0, // answer with values of V12 and V5
|
||||||
|
CMD_GETUIVAL1, // answer with values of I12 and V3.3
|
||||||
|
CMD_REINIT_SENSORS, // (re)init sensors
|
||||||
|
CMD_GETBUILDNO, // request for firmware build number
|
||||||
|
CMD_SYSTIME, // get system time
|
||||||
|
// dummy commands for test purposes
|
||||||
|
CMD_DUMMY0 = 0xDA,
|
||||||
|
CMD_DUMMY1 = 0xAD
|
||||||
|
} CAN_commands;
|
||||||
|
|
||||||
|
void can_messages_proc();
|
||||||
|
CAN_status can_send_cmd(uint16_t targetID, uint8_t cmd);
|
||||||
|
CAN_status can_send_data(uint8_t *data, uint8_t len);
|
||||||
|
int8_t send_temperatures(int8_t N);
|
||||||
99
F0:F030,F042,F072/TSYS_controller/hardware.c
Normal file
99
F0:F030,F042,F072/TSYS_controller/hardware.c
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
I2C_SPEED curI2Cspeed = LOW_SPEED;
|
||||||
|
|
||||||
|
|
||||||
|
void gpio_setup(void){
|
||||||
|
// here we turn on clocking for all periph.
|
||||||
|
RCC->AHBENR |= RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOAEN | RCC_AHBENR_DMAEN;
|
||||||
|
// Set LEDS (PB10/11) & multiplexer as output (PB0..2,12)
|
||||||
|
GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER10 | GPIO_MODER_MODER11 |
|
||||||
|
GPIO_MODER_MODER0 | GPIO_MODER_MODER1 |
|
||||||
|
GPIO_MODER_MODER2 | GPIO_MODER_MODER12 )
|
||||||
|
) |
|
||||||
|
GPIO_MODER_MODER10_O | GPIO_MODER_MODER11_O |
|
||||||
|
GPIO_MODER_MODER0_O | GPIO_MODER_MODER1_O |
|
||||||
|
GPIO_MODER_MODER2_O | GPIO_MODER_MODER12_O;
|
||||||
|
// multiplexer outputs are push-pull, GPIOB->OTYPER = 0
|
||||||
|
MUL_OFF();
|
||||||
|
// PA8 - power enable
|
||||||
|
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER8)) |
|
||||||
|
GPIO_MODER_MODER8_O;
|
||||||
|
// PA13..15 (low bits) + PB15 (high bit) - CAN address, pullup inputs
|
||||||
|
GPIOA->PUPDR = (GPIOA->PUPDR & ~(GPIO_PUPDR_PUPDR13 | GPIO_PUPDR_PUPDR14 |
|
||||||
|
GPIO_PUPDR_PUPDR15)
|
||||||
|
) |
|
||||||
|
GPIO_PUPDR_PUPDR13_0 | GPIO_PUPDR_PUPDR14_0 |
|
||||||
|
GPIO_PUPDR_PUPDR15_0;
|
||||||
|
GPIOB->PUPDR = (GPIOB->PUPDR & ~(GPIO_PUPDR_PUPDR15)) |
|
||||||
|
GPIO_PUPDR_PUPDR15_0;
|
||||||
|
pin_set(LED0_port, LED0_pin); // clear LEDs
|
||||||
|
pin_set(LED1_port, LED1_pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void i2c_setup(I2C_SPEED speed){
|
||||||
|
if(speed == CURRENT_SPEED){
|
||||||
|
speed = curI2Cspeed;
|
||||||
|
}else{
|
||||||
|
curI2Cspeed = speed;
|
||||||
|
}
|
||||||
|
I2C1->CR1 = 0;
|
||||||
|
#if I2CPINS == 910
|
||||||
|
/*
|
||||||
|
* GPIO Resources: I2C1_SCL - PA9, I2C1_SDA - PA10
|
||||||
|
* GPIOA->AFR[1]
|
||||||
|
*/
|
||||||
|
GPIOA->AFR[1] &= ~0xff0; // alternate function F4 for PA9/PA10
|
||||||
|
GPIOA->AFR[1] |= 0x440;
|
||||||
|
GPIOA->MODER &= ~(GPIO_MODER_MODER9 | GPIO_MODER_MODER10);
|
||||||
|
GPIOA->MODER |= GPIO_MODER_MODER9_AF | GPIO_MODER_MODER10_AF; // alternate function
|
||||||
|
GPIOA->OTYPER |= GPIO_OTYPER_OT_9 | GPIO_OTYPER_OT_10; // opendrain
|
||||||
|
//GPIOA->OTYPER |= GPIO_OTYPER_OT_10; // opendrain
|
||||||
|
#elif I2CPINS == 67
|
||||||
|
/*
|
||||||
|
* GPIO Resources: I2C1_SCL - PB6, I2C1_SDA - PB7 (AF1)
|
||||||
|
* GPIOB->AFR[0] -> 1<<6*4 | 1<<7*4 = 0x11000000
|
||||||
|
*/
|
||||||
|
GPIOB->AFR[0] = (GPIOB->AFR[0] & ~0xff000000) | 0x11000000;
|
||||||
|
GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7)) |
|
||||||
|
GPIO_MODER_MODER6_AF | GPIO_MODER_MODER7_AF;
|
||||||
|
GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7;
|
||||||
|
#else // undefined
|
||||||
|
#error "Not implemented"
|
||||||
|
#endif
|
||||||
|
// I2C
|
||||||
|
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // timing
|
||||||
|
RCC->CFGR3 |= RCC_CFGR3_I2C1SW; // use sysclock for timing
|
||||||
|
if(speed == LOW_SPEED){ // 10kHz
|
||||||
|
// PRESC=B, SCLDEL=4, SDADEL=2, SCLH=0xC3, SCLL=0xB0
|
||||||
|
I2C1->TIMINGR = (0xB<<28) | (4<<20) | (2<<16) | (0xC3<<8) | (0xB0);
|
||||||
|
}else if(speed == HIGH_SPEED){ // 100kHz
|
||||||
|
I2C1->TIMINGR = (0xB<<28) | (4<<20) | (2<<16) | (0x12<<8) | (0x11);
|
||||||
|
}else{ // VERYLOW_SPEED - the lowest speed by STM register: 5.8kHz (presc = 16-1 = 15; )
|
||||||
|
I2C1->TIMINGR = (0xf<<28) | (4<<20) | (2<<16) | (0xff<<8) | (0xff);
|
||||||
|
}
|
||||||
|
I2C1->CR1 = I2C_CR1_PE;// | I2C_CR1_RXIE; // Enable I2C & (interrupt on receive - not supported yet)
|
||||||
|
}
|
||||||
97
F0:F030,F042,F072/TSYS_controller/hardware.h
Normal file
97
F0:F030,F042,F072/TSYS_controller/hardware.h
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* 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 "stm32f0.h"
|
||||||
|
|
||||||
|
#define CAN_SPEED_DEFAULT (250)
|
||||||
|
#define CAN_SPEED_MIN (12)
|
||||||
|
#define CAN_SPEED_MAX (1000)
|
||||||
|
|
||||||
|
// LED0
|
||||||
|
#define LED0_port GPIOB
|
||||||
|
#define LED0_pin (1<<10)
|
||||||
|
// LED1
|
||||||
|
#define LED1_port GPIOB
|
||||||
|
#define LED1_pin (1<<11)
|
||||||
|
|
||||||
|
#ifndef USARTNUM
|
||||||
|
#define USARTNUM 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CONCAT(a,b) a ## b
|
||||||
|
#define STR_HELPER(s) #s
|
||||||
|
#define STR(s) STR_HELPER(s)
|
||||||
|
|
||||||
|
#define FORMUSART(X) CONCAT(USART, X)
|
||||||
|
#define USARTX FORMUSART(USARTNUM)
|
||||||
|
|
||||||
|
#ifndef I2CPINS
|
||||||
|
#define I2CPINS 910
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LED1_port
|
||||||
|
#define LED1_port LED0_port
|
||||||
|
#endif
|
||||||
|
#ifndef LED1_pin
|
||||||
|
#define LED1_pin LED0_pin
|
||||||
|
#endif
|
||||||
|
#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)
|
||||||
|
|
||||||
|
// set active channel number
|
||||||
|
#define MUL_ADDRESS(x) do{GPIOB->BSRR = (0x7 << 16) | (x);}while(0)
|
||||||
|
// address from 0 to 7
|
||||||
|
// WARNING!!! In current case all variables for sensors counting are uint8_t, so if
|
||||||
|
// MUL_MAX_ADDRESS would be greater than 7 you need to edit all codes!!!11111111111111111111
|
||||||
|
#define MUL_MAX_ADDRESS (7)
|
||||||
|
// turn multiplexer on/off (PB12 -> 1/0)
|
||||||
|
#define MUL_ON() pin_clear(GPIOB, (1<<12))
|
||||||
|
#define MUL_OFF() pin_set(GPIOB, (1<<12))
|
||||||
|
|
||||||
|
// turn on/off power of sensors (PA8-> 1/0)
|
||||||
|
#define SENSORS_ON() pin_set(GPIOA, (1<<8))
|
||||||
|
#define SENSORS_OFF() pin_clear(GPIOA, (1<<8))
|
||||||
|
// check overcurrent (PB3 == 0)
|
||||||
|
#define SENSORS_OVERCURNT() ((1<<3) != (GPIOB->IDR & (1<<3)))
|
||||||
|
|
||||||
|
// CAN address - PA13..PA15
|
||||||
|
#define READ_CAN_INV_ADDR() (((GPIOA->IDR & (0x7<<13))>>13) | ((GPIOB->IDR & (1<<15)) >> 12))
|
||||||
|
extern uint8_t Controller_address;
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
VERYLOW_SPEED,
|
||||||
|
LOW_SPEED,
|
||||||
|
HIGH_SPEED,
|
||||||
|
CURRENT_SPEED
|
||||||
|
} I2C_SPEED;
|
||||||
|
|
||||||
|
extern I2C_SPEED curI2Cspeed;
|
||||||
|
|
||||||
|
void gpio_setup(void);
|
||||||
|
void i2c_setup(I2C_SPEED speed);
|
||||||
|
|
||||||
|
#endif // __HARDWARE_H__
|
||||||
129
F0:F030,F042,F072/TSYS_controller/i2c.c
Normal file
129
F0:F030,F042,F072/TSYS_controller/i2c.c
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* geany_encoding=koi8-r
|
||||||
|
* i2c.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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "hardware.h"
|
||||||
|
#include "i2c.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I2C for TSYS01
|
||||||
|
* Speed <= 400kHz (200)
|
||||||
|
* t_SCLH > 21ns
|
||||||
|
* t_SCLL > 21ns
|
||||||
|
* while reading, sends NACK
|
||||||
|
* after reading get 24bits of T value, we need upper 2 bytes: ADC16 = ADC>>8
|
||||||
|
* T = (-2) * k4 * 10^{-21} * ADC16^4
|
||||||
|
* + 4 * k3 * 10^{-16} * ADC16^3
|
||||||
|
* + (-2) * k2 * 10^{-11} * ADC16^2
|
||||||
|
* + 1 * k1 * 10^{-6} * ADC16
|
||||||
|
* +(-1.5)* k0 * 10^{-2}
|
||||||
|
* All coefficiens are in registers:
|
||||||
|
* k4 - 0xA2, k3 - 0xA4, k2 - 0xA6, k1 - 0xA8, k0 - 0xAA
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern volatile uint32_t Tms;
|
||||||
|
static uint32_t cntr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* write command byte to I2C
|
||||||
|
* @param addr - device address (TSYS01_ADDR0 or TSYS01_ADDR1)
|
||||||
|
* @param data - byte to write
|
||||||
|
* @return 0 if error
|
||||||
|
*/
|
||||||
|
uint8_t write_i2c(uint8_t addr, uint8_t data){
|
||||||
|
cntr = Tms;
|
||||||
|
I2C1->ICR = 0x3f38; // clear all errors
|
||||||
|
while(I2C1->ISR & I2C_ISR_BUSY){
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
if(Tms - cntr > I2C_TIMEOUT){
|
||||||
|
return 0; // check busy
|
||||||
|
}}
|
||||||
|
cntr = Tms;
|
||||||
|
while(I2C1->CR2 & I2C_CR2_START){
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
if(Tms - cntr > I2C_TIMEOUT){
|
||||||
|
return 0; // check start
|
||||||
|
}}
|
||||||
|
//I2C1->ICR = 0x3f38; // clear all errors
|
||||||
|
I2C1->CR2 = 1<<16 | addr | I2C_CR2_AUTOEND; // 1 byte, autoend
|
||||||
|
// now start transfer
|
||||||
|
I2C1->CR2 |= I2C_CR2_START;
|
||||||
|
cntr = Tms;
|
||||||
|
while(!(I2C1->ISR & I2C_ISR_TXIS)){ // ready to transmit
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
if(I2C1->ISR & I2C_ISR_NACKF){
|
||||||
|
I2C1->ICR |= I2C_ICR_NACKCF;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(Tms - cntr > I2C_TIMEOUT){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
I2C1->TXDR = data; // send data
|
||||||
|
// wait for data gone
|
||||||
|
while(I2C1->ISR & I2C_ISR_BUSY){
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
if(Tms - cntr > I2C_TIMEOUT){break;}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read nbytes (2 or 3) of data from I2C line
|
||||||
|
* @return 1 if all OK, 0 if NACK or no device found
|
||||||
|
*/
|
||||||
|
uint8_t read_i2c(uint8_t addr, uint32_t *data, uint8_t nbytes){
|
||||||
|
uint32_t result = 0;
|
||||||
|
cntr = Tms;
|
||||||
|
//MSG("read_i2c\n");
|
||||||
|
while(I2C1->ISR & I2C_ISR_BUSY){
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
if(Tms - cntr > I2C_TIMEOUT){
|
||||||
|
return 0; // check busy
|
||||||
|
}}
|
||||||
|
cntr = Tms;
|
||||||
|
while(I2C1->CR2 & I2C_CR2_START){
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
if(Tms - cntr > I2C_TIMEOUT){
|
||||||
|
return 0; // check start
|
||||||
|
}}
|
||||||
|
// I2C1->ICR = 0x3f38; // clear all errors
|
||||||
|
// read N bytes
|
||||||
|
I2C1->CR2 = (nbytes<<16) | addr | 1 | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN;
|
||||||
|
I2C1->CR2 |= I2C_CR2_START;
|
||||||
|
uint8_t i;
|
||||||
|
cntr = Tms;
|
||||||
|
for(i = 0; i < nbytes; ++i){
|
||||||
|
while(!(I2C1->ISR & I2C_ISR_RXNE)){ // wait for data
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
if(I2C1->ISR & I2C_ISR_NACKF){
|
||||||
|
I2C1->ICR |= I2C_ICR_NACKCF;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(Tms - cntr > I2C_TIMEOUT){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = (result << 8) | I2C1->RXDR;
|
||||||
|
}
|
||||||
|
*data = result;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
41
F0:F030,F042,F072/TSYS_controller/i2c.h
Normal file
41
F0:F030,F042,F072/TSYS_controller/i2c.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* geany_encoding=koi8-r
|
||||||
|
* i2c.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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stm32f0.h"
|
||||||
|
|
||||||
|
// timeout of I2C bus in ms
|
||||||
|
#define I2C_TIMEOUT (100)
|
||||||
|
// CSB=1, address 1110110
|
||||||
|
#define TSYS01_ADDR0 (0x76 << 1)
|
||||||
|
// CSB=0, address 1110111
|
||||||
|
#define TSYS01_ADDR1 (0x77 << 1)
|
||||||
|
// registers: reset, read ADC value, start converstion, start of PROM
|
||||||
|
#define TSYS01_RESET (0x1E)
|
||||||
|
#define TSYS01_ADC_READ (0x00)
|
||||||
|
#define TSYS01_START_CONV (0x48)
|
||||||
|
#define TSYS01_PROM_ADDR0 (0xA0)
|
||||||
|
// conversion time (with reserve)
|
||||||
|
#define CONV_TIME (15)
|
||||||
|
|
||||||
|
uint8_t read_i2c(uint8_t addr, uint32_t *data, uint8_t nbytes);
|
||||||
|
uint8_t write_i2c(uint8_t addr, uint8_t data);
|
||||||
12
F0:F030,F042,F072/TSYS_controller/ld/stm32f042k.ld
Normal file
12
F0:F030,F042,F072/TSYS_controller/ld/stm32f042k.ld
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/* Linker script for STM32F042x6, 32K flash, 6K RAM. */
|
||||||
|
|
||||||
|
/* Define memory regions. */
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K
|
||||||
|
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 6K
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Include the common ld script. */
|
||||||
|
INCLUDE stm32f0.ld
|
||||||
|
|
||||||
135
F0:F030,F042,F072/TSYS_controller/main.c
Normal file
135
F0:F030,F042,F072/TSYS_controller/main.c
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* 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 "can.h"
|
||||||
|
#include "can_process.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
#include "i2c.h"
|
||||||
|
#include "proto.h"
|
||||||
|
#include "sensors_manage.h"
|
||||||
|
#include "usart.h"
|
||||||
|
#include "usb.h"
|
||||||
|
|
||||||
|
#pragma message("USARTNUM=" STR(USARTNUM))
|
||||||
|
#pragma message("I2CPINS=" STR(I2CPINS))
|
||||||
|
#ifdef EBUG
|
||||||
|
#pragma message("Debug mode")
|
||||||
|
#else
|
||||||
|
#pragma message("Release mode")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
volatile uint32_t Tms = 0;
|
||||||
|
volatile uint8_t canerror = 0;
|
||||||
|
|
||||||
|
/* Called when systick fires */
|
||||||
|
void sys_tick_handler(void){
|
||||||
|
++Tms;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iwdg_setup(){
|
||||||
|
/* 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); /* (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) */
|
||||||
|
while(IWDG->SR); /* (5) */
|
||||||
|
IWDG->KR = IWDG_REFRESH; /* (6) */
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void){
|
||||||
|
uint32_t lastT = 0, lastS = 0, lastB = 0;
|
||||||
|
uint8_t gotmeasurement = 0;
|
||||||
|
char inbuf[256];
|
||||||
|
sysreset();
|
||||||
|
SysTick_Config(6000, 1);
|
||||||
|
gpio_setup();
|
||||||
|
adc_setup();
|
||||||
|
usart_setup();
|
||||||
|
i2c_setup(LOW_SPEED);
|
||||||
|
readCANID();
|
||||||
|
if(CANID == MASTER_ID) cansniffer = 1; // MASTER in sniffer mode by default
|
||||||
|
CAN_setup(0); // setup with default 250kbaud
|
||||||
|
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
|
||||||
|
USB_setup();
|
||||||
|
sensors_init();
|
||||||
|
iwdg_setup();
|
||||||
|
|
||||||
|
while (1){
|
||||||
|
IWDG->KR = IWDG_REFRESH; // refresh watchdog
|
||||||
|
if(lastT > Tms || Tms - lastT > 499){
|
||||||
|
if(!noLED) LED_blink(LED0);
|
||||||
|
lastT = Tms;
|
||||||
|
// send dummy command to noone to test CAN bus
|
||||||
|
//can_send_cmd(NOONE_ID, CMD_DUMMY0);
|
||||||
|
}
|
||||||
|
if(lastS != Tms){ // run sensors proc. once per 1ms
|
||||||
|
sensors_process();
|
||||||
|
lastS = Tms;
|
||||||
|
if(SENS_SLEEPING == Sstate){ // show temperature @ each sleeping occurence
|
||||||
|
if(!gotmeasurement){
|
||||||
|
gotmeasurement = 1;
|
||||||
|
showtemperature();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(SENS_WAITING == Sstate) gotmeasurement = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usb_proc();
|
||||||
|
can_proc();
|
||||||
|
CAN_status stat = CAN_get_status();
|
||||||
|
if(stat == CAN_FIFO_OVERRUN){
|
||||||
|
SEND("CAN bus fifo overrun occured!\n");
|
||||||
|
}else if(stat == CAN_ERROR){
|
||||||
|
if(!noLED) LED_off(LED1);
|
||||||
|
CAN_setup(0);
|
||||||
|
canerror = 1;
|
||||||
|
}
|
||||||
|
can_messages_proc();
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
uint8_t r = 0;
|
||||||
|
if((r = USB_receive(inbuf, 255))){
|
||||||
|
inbuf[r] = 0;
|
||||||
|
cmd_parser(inbuf, 1);
|
||||||
|
}
|
||||||
|
if(usartrx()){ // usart1 received data, store it in buffer
|
||||||
|
char *txt = NULL;
|
||||||
|
r = usart_getline(&txt);
|
||||||
|
txt[r] = 0;
|
||||||
|
cmd_parser(txt, 0);
|
||||||
|
}
|
||||||
|
if(lastB - Tms > 99){ // run `sendbuf` each 100ms
|
||||||
|
sendbuf();
|
||||||
|
lastB = Tms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
527
F0:F030,F042,F072/TSYS_controller/proto.c
Normal file
527
F0:F030,F042,F072/TSYS_controller/proto.c
Normal file
@ -0,0 +1,527 @@
|
|||||||
|
/*
|
||||||
|
* 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 <string.h>
|
||||||
|
|
||||||
|
#include "adc.h"
|
||||||
|
#include "can.h"
|
||||||
|
#include "can_process.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
#include "proto.h"
|
||||||
|
#include "sensors_manage.h"
|
||||||
|
#include "usart.h"
|
||||||
|
#include "usb.h"
|
||||||
|
#include "version.inc"
|
||||||
|
|
||||||
|
extern volatile uint8_t canerror;
|
||||||
|
extern volatile uint32_t Tms;
|
||||||
|
|
||||||
|
static char buff[UARTBUFSZ+1], /* +1 - for USB send (it receive \0-terminated line) */ *bptr = buff;
|
||||||
|
static int blen = 0, USBcmd = 0, debugmode = 0;
|
||||||
|
// LEDs are OFF by default
|
||||||
|
uint8_t noLED =
|
||||||
|
#ifdef EBUG
|
||||||
|
0
|
||||||
|
#else
|
||||||
|
1
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
void sendbuf(){
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
if(blen == 0) return;
|
||||||
|
*bptr = 0;
|
||||||
|
if(USBcmd) USB_send(buff);
|
||||||
|
else while(LINE_BUSY == usart_send(buff, blen)){IWDG->KR = IWDG_REFRESH;}
|
||||||
|
bptr = buff;
|
||||||
|
blen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addtobuf(const char *txt){
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
int l = strlen(txt);
|
||||||
|
if(l > UARTBUFSZ){
|
||||||
|
sendbuf(); // send prevoius data in buffer
|
||||||
|
if(USBcmd) USB_send(txt);
|
||||||
|
else while(LINE_BUSY == usart_send_blocking(txt, l)){IWDG->KR = IWDG_REFRESH;}
|
||||||
|
}else{
|
||||||
|
if(blen+l > UARTBUFSZ){
|
||||||
|
sendbuf();
|
||||||
|
}
|
||||||
|
strcpy(bptr, txt);
|
||||||
|
bptr += l;
|
||||||
|
}
|
||||||
|
*bptr = 0;
|
||||||
|
blen += l;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bufputchar(char ch){
|
||||||
|
if(blen > UARTBUFSZ-1){
|
||||||
|
sendbuf();
|
||||||
|
}
|
||||||
|
*bptr++ = ch;
|
||||||
|
++blen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CANsend(uint16_t targetID, uint8_t cmd, char echo){
|
||||||
|
if(CAN_OK == can_send_cmd(targetID, cmd)){
|
||||||
|
bufputchar(echo);
|
||||||
|
bufputchar('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// show all ADC values
|
||||||
|
static inline void showADCvals(){
|
||||||
|
char msg[] = "ADCn=";
|
||||||
|
for(int n = 0; n < NUMBER_OF_ADC_CHANNELS; ++n){
|
||||||
|
msg[3] = n + '0';
|
||||||
|
addtobuf(msg);
|
||||||
|
printu(getADCval(n));
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void printmcut(){
|
||||||
|
SEND("MCUT=");
|
||||||
|
int32_t T = getMCUtemp();
|
||||||
|
if(T < 0){
|
||||||
|
bufputchar('-');
|
||||||
|
T = -T;
|
||||||
|
}
|
||||||
|
printu(T);
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void showUIvals(){
|
||||||
|
uint16_t *vals = getUval();
|
||||||
|
SEND("V12="); printu(vals[0]);
|
||||||
|
SEND("\nV5="); printu(vals[1]);
|
||||||
|
SEND("\nV33="); printu(vals[3]);
|
||||||
|
SEND("\nI12="); printu(vals[2]);
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *omit_spaces(char *buf){
|
||||||
|
while(*buf){
|
||||||
|
if(*buf > ' ') break;
|
||||||
|
++buf;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void setCANbrate(char *str){
|
||||||
|
if(!str || !*str) return;
|
||||||
|
int32_t spd = 0;
|
||||||
|
str = omit_spaces(str);
|
||||||
|
char *e = getnum(str, &spd);
|
||||||
|
if(e == str){
|
||||||
|
SEND("BAUDRATE=");
|
||||||
|
printu(curcanspeed);
|
||||||
|
newline();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(spd < CAN_SPEED_MIN || spd > CAN_SPEED_MAX){
|
||||||
|
SEND("Wrong speed\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CAN_setup(spd);
|
||||||
|
SEND("OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse `txt` to CAN_message
|
||||||
|
static CAN_message *parseCANmsg(char *txt){
|
||||||
|
static CAN_message canmsg;
|
||||||
|
int32_t N;
|
||||||
|
char *n;
|
||||||
|
int ctr = -1;
|
||||||
|
canmsg.ID = 0xffff;
|
||||||
|
do{
|
||||||
|
txt = omit_spaces(txt);
|
||||||
|
n = getnum(txt, &N);
|
||||||
|
if(txt == n) break;
|
||||||
|
txt = n;
|
||||||
|
if(ctr == -1){
|
||||||
|
if(N > 0x7ff){
|
||||||
|
SEND("ID should be 11-bit number!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
canmsg.ID = (uint16_t)(N&0x7ff);
|
||||||
|
ctr = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(ctr > 7){
|
||||||
|
SEND("ONLY 8 data bytes allowed!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(N > 0xff){
|
||||||
|
SEND("Every data portion is a byte!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
canmsg.data[ctr++] = (uint8_t)(N&0xff);
|
||||||
|
}while(1);
|
||||||
|
if(canmsg.ID == 0xffff){
|
||||||
|
SEND("NO ID given, send nothing!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
SEND("Message parsed OK\n");
|
||||||
|
canmsg.length = (uint8_t) ctr;
|
||||||
|
return &canmsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send command, format: ID (hex/bin/dec) data bytes (up to 8 bytes, space-delimeted)
|
||||||
|
static void sendCANcommand(char *txt){
|
||||||
|
CAN_message *msg = parseCANmsg(txt);
|
||||||
|
if(!msg) return;
|
||||||
|
uint32_t N = 1000;
|
||||||
|
while(CAN_BUSY == can_send(msg->data, msg->length, msg->ID)){
|
||||||
|
if(--N == 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief cmd_parser - command parsing
|
||||||
|
* @param txt - buffer with commands & data
|
||||||
|
* @param isUSB - == 1 if data got from USB
|
||||||
|
*/
|
||||||
|
void cmd_parser(char *txt, uint8_t isUSB){
|
||||||
|
USBcmd = isUSB;
|
||||||
|
int16_t L = strlen(txt), ID = BCAST_ID;
|
||||||
|
char _1st = txt[0];
|
||||||
|
if(_1st >= '0' && _1st < '8'){ // send command to Nth controller, not broadcast
|
||||||
|
if(L == 3){ // with '\n' at end!
|
||||||
|
ID = (CAN_ID_PREFIX & CAN_ID_MASK) | (_1st - '0');
|
||||||
|
_1st = txt[1];
|
||||||
|
}else{
|
||||||
|
_1st = '?'; // show help
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch(_1st){
|
||||||
|
case '@':
|
||||||
|
debugmode = !debugmode;
|
||||||
|
SEND("DEBUG mode ");
|
||||||
|
if(debugmode) SEND("ON");
|
||||||
|
else SEND("OFF");
|
||||||
|
newline();
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
showADCvals();
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
CANsend(ID, CMD_DUMMY0, _1st);
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
setCANbrate(txt + 1);
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
showcoeffs();
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
CANsend(MASTER_ID, CMD_DUMMY1, _1st);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
SEND("Can address: ");
|
||||||
|
printuhex(CANID);
|
||||||
|
newline();
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
CANsend(ID, CMD_STOP_SCAN, _1st);
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
sensors_scan_mode = 0;
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
CANsend(ID, CMD_SENSORS_OFF, _1st);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
sensors_off();
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
SEND("Group ID (sniffer) CAN mode\n");
|
||||||
|
CAN_listenall();
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
CANsend(ID, CMD_HIGH_SPEED, _1st);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
i2c_setup(HIGH_SPEED);
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
CANsend(ID, CMD_REINIT_SENSORS, _1st);
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
sensors_init();
|
||||||
|
break;
|
||||||
|
case 'J':
|
||||||
|
CANsend(ID, CMD_GETMCUTEMP, _1st);
|
||||||
|
break;
|
||||||
|
case 'j':
|
||||||
|
printmcut();
|
||||||
|
break;
|
||||||
|
case 'K':
|
||||||
|
CANsend(ID, CMD_GETUIVAL, _1st);
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
showUIvals();
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
CANsend(ID, CMD_LOW_SPEED, _1st);
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
i2c_setup(LOW_SPEED);
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
CANsend(ID, CMD_CHANGE_MASTER_B, _1st);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
CANsend(ID, CMD_CHANGE_MASTER, _1st);
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
CANsend(ID, CMD_GETBUILDNO, _1st);
|
||||||
|
break;
|
||||||
|
case 'O':
|
||||||
|
noLED = 0;
|
||||||
|
SEND("LED on\n");
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
noLED = 1;
|
||||||
|
LED_off(LED0);
|
||||||
|
LED_off(LED1);
|
||||||
|
SEND("LED off\n");
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
CANsend(ID, CMD_PING, _1st);
|
||||||
|
break;
|
||||||
|
case 'Q':
|
||||||
|
CANsend(ID, CMD_SYSTIME, _1st);
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
SEND("SYSTIME0="); printu(Tms); newline();
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
CANsend(ID, CMD_REINIT_I2C, _1st);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
i2c_setup(CURRENT_SPEED);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sendCANcommand(txt+1);
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
CANsend(ID, CMD_START_MEASUREMENT, _1st);
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
if(!sensors_scan_mode) sensors_start();
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
SEND("Unique ID CAN mode\n");
|
||||||
|
CAN_listenone();
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
CANsend(ID, CMD_LOWEST_SPEED, _1st);
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
i2c_setup(VERYLOW_SPEED);
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
CANsend(ID, CMD_START_SCAN, _1st);
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
sensors_scan_mode = 1;
|
||||||
|
break;
|
||||||
|
case 'Y':
|
||||||
|
CANsend(ID, CMD_SENSORS_STATE, _1st);
|
||||||
|
break;
|
||||||
|
case 'y':
|
||||||
|
SEND("SSTATE0=");
|
||||||
|
SEND(sensors_get_statename(Sstate));
|
||||||
|
SEND("\nNSENS0=");
|
||||||
|
printu(Nsens_present);
|
||||||
|
SEND("\nSENSPRESENT0=");
|
||||||
|
printu(sens_present[0] | (sens_present[1]<<8));
|
||||||
|
SEND("\nNTEMP0=");
|
||||||
|
printu(Ntemp_measured);
|
||||||
|
newline();
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
SEND("CANERROR=");
|
||||||
|
if(canerror){
|
||||||
|
canerror = 0;
|
||||||
|
bufputchar('1');
|
||||||
|
}else bufputchar('0');
|
||||||
|
newline();
|
||||||
|
break;
|
||||||
|
default: // help
|
||||||
|
SEND("https://github.com/eddyem/tsys01/tree/master/STM32/TSYS_controller build#" BUILD_NUMBER " @ " BUILD_DATE "\n");
|
||||||
|
SEND(
|
||||||
|
"ALL little letters - without CAN messaging\n"
|
||||||
|
"0..7 - send command to given controller (0 - this) instead of broadcast\n"
|
||||||
|
"@ - set/reset debug mode\n"
|
||||||
|
"a - get raw ADC values\n"
|
||||||
|
"B - send broadcast CAN dummy message\n"
|
||||||
|
"b - get/set CAN bus baudrate\n"
|
||||||
|
"c - show coefficients (current)\n"
|
||||||
|
"d - get last CAN address\n"
|
||||||
|
"D - send CAN dummy message to master\n"
|
||||||
|
"Ee- end themperature scan\n"
|
||||||
|
"Ff- turn oFf sensors\n"
|
||||||
|
"g - group (sniffer) CAN mode\n"
|
||||||
|
"Hh- high I2C speed\n"
|
||||||
|
"Ii- (re)init sensors\n"
|
||||||
|
"Jj- get MCU temperature\n"
|
||||||
|
"Kk- get U/I values\n"
|
||||||
|
"Ll- low I2C speed\n"
|
||||||
|
"Mm- change master id to 0 (m) / broadcast (M)\n"
|
||||||
|
"N - get build number\n"
|
||||||
|
"Oo- turn onboard diagnostic LEDs *O*n or *o*ff (both commands are local)\n"
|
||||||
|
"P - ping everyone over CAN\n"
|
||||||
|
"Qq- get system time\n"
|
||||||
|
"Rr- reinit I2C\n"
|
||||||
|
"s - send CAN message\n"
|
||||||
|
"Tt- start temperature measurement\n"
|
||||||
|
"u - unique ID (default) CAN mode\n"
|
||||||
|
"Vv- very low I2C speed\n"
|
||||||
|
"Xx- Start themperature scan\n"
|
||||||
|
"Yy- get sensors state\n"
|
||||||
|
"z - check CAN status for errors\n"
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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){
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// show message in debug mode
|
||||||
|
void mesg(char *txt){
|
||||||
|
if(!debugmode) return;
|
||||||
|
addtobuf("[DBG] ");
|
||||||
|
addtobuf(txt);
|
||||||
|
bufputchar('\n');
|
||||||
|
}
|
||||||
51
F0:F030,F042,F072/TSYS_controller/proto.h
Normal file
51
F0:F030,F042,F072/TSYS_controller/proto.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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 "stm32f0.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
extern uint8_t noLED;
|
||||||
|
void cmd_parser(char *buf, uint8_t isUSB);
|
||||||
|
void addtobuf(const char *txt);
|
||||||
|
void bufputchar(char ch);
|
||||||
|
void printu(uint32_t val);
|
||||||
|
void printuhex(uint32_t val);
|
||||||
|
void sendbuf();
|
||||||
|
char *getnum(char *txt, int32_t *N);
|
||||||
|
void mesg(char *txt);
|
||||||
|
|
||||||
|
#endif // __PROTO_H__
|
||||||
442
F0:F030,F042,F072/TSYS_controller/sensors_manage.c
Normal file
442
F0:F030,F042,F072/TSYS_controller/sensors_manage.c
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
/*
|
||||||
|
* geany_encoding=koi8-r
|
||||||
|
* sensors_manage.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 "sensors_manage.h"
|
||||||
|
#include "can_process.h"
|
||||||
|
#include "i2c.h"
|
||||||
|
#include "proto.h" // addtobuf, bufputchar, memcpy
|
||||||
|
|
||||||
|
extern volatile uint32_t Tms;
|
||||||
|
uint8_t sensors_scan_mode = 0; // infinite scan mode
|
||||||
|
static uint32_t lastSensT = 0;
|
||||||
|
SensorsState Sstate = SENS_OFF; // turn on sensors only by request
|
||||||
|
static uint8_t curr_mul_addr = 0; // current sensors pair address @ multiplexer
|
||||||
|
static uint8_t overcurnt_ctr = 0; // if this counter > 32 go to OFF state
|
||||||
|
uint8_t sens_present[2] = {0,0}; // bit flag: Nth bit == 1 if sensor[s] on given channel found
|
||||||
|
uint8_t Nsens_present = 0; // total amount of sensors found
|
||||||
|
uint8_t Ntemp_measured = 0; // total amount of themperatures measured
|
||||||
|
|
||||||
|
// 8 - amount of pairs, 2 - amount in pair, 5 - amount of Coef.
|
||||||
|
static uint16_t coefficients[MUL_MAX_ADDRESS+1][2][5]; // Coefficients for given sensors
|
||||||
|
// measured temperatures * 100
|
||||||
|
int16_t Temperatures[MUL_MAX_ADDRESS+1][2];
|
||||||
|
|
||||||
|
// pair addresses
|
||||||
|
static const uint8_t Taddr[2] = {TSYS01_ADDR0, TSYS01_ADDR1};
|
||||||
|
|
||||||
|
static const char *statenames[] = {
|
||||||
|
[SENS_INITING] = "init"
|
||||||
|
,[SENS_RESETING] = "reset"
|
||||||
|
,[SENS_GET_COEFFS] = "getcoeff"
|
||||||
|
,[SENS_SLEEPING] = "sleep"
|
||||||
|
,[SENS_START_MSRMNT] = "startmeasure"
|
||||||
|
,[SENS_WAITING] = "waitresults"
|
||||||
|
,[SENS_GATHERING] = "collectdata"
|
||||||
|
,[SENS_OFF] = "off"
|
||||||
|
,[SENS_OVERCURNT] = "overcurrent"
|
||||||
|
,[SENS_OVERCURNT_OFF] = "offbyovercurrent"
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t getcoeff(uint8_t i);
|
||||||
|
|
||||||
|
const char *sensors_get_statename(SensorsState x){
|
||||||
|
if(x >= SENS_STATE_CNT) return "wrongstate";
|
||||||
|
return statenames[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check if we can convert double to float!
|
||||||
|
|
||||||
|
const double mul[5] = {-1.5e-2, 1., -2., 4., -2.};
|
||||||
|
/**
|
||||||
|
* Get temperature & calculate it by polinome
|
||||||
|
* T = (-2) * k4 * 10^{-21} * ADC16^4
|
||||||
|
* + 4 * k3 * 10^{-16} * ADC16^3
|
||||||
|
* + (-2) * k2 * 10^{-11} * ADC16^2
|
||||||
|
* + 1 * k1 * 10^{-6} * ADC16
|
||||||
|
* +(-1.5)* k0 * 10^{-2}
|
||||||
|
* k0*(-1.5e-2) + 1e-6*val*(k1 + 1e-5*val*(-2*k2 + 1e-5*val*(4*k3 + -2e-5*k4*val)))
|
||||||
|
*
|
||||||
|
* @param t - value from sensor
|
||||||
|
* @param i - number of sensor in pair
|
||||||
|
* @return -30000 if something wrong or T*100 if all OK
|
||||||
|
*/
|
||||||
|
static uint16_t calc_t(uint32_t t, int i){
|
||||||
|
uint16_t *coeff = coefficients[curr_mul_addr][i];
|
||||||
|
if(coeff[0] == 0){
|
||||||
|
if(!getcoeff(i)) return BAD_TEMPERATURE; // what is with coeffs?
|
||||||
|
}
|
||||||
|
if(t < 600000 || t > 30000000) return BAD_TEMPERATURE; // wrong value - too small or too large
|
||||||
|
int j;
|
||||||
|
double d = (double)t/256., tmp = 0.;
|
||||||
|
// k0*(-1.5e-2) + 0.1*1e-5*val*(1*k1 + 1e-5*val*(-2.*k2 + 1e-5*val*(4*k3 + 1e-5*val*(-2*k4))))
|
||||||
|
for(j = 4; j > 0; --j){
|
||||||
|
tmp += mul[j] * (double)coeff[j];
|
||||||
|
tmp *= 1e-5*d;
|
||||||
|
}
|
||||||
|
tmp = tmp * 10. + 100. * mul[0] * coeff[0];
|
||||||
|
return (uint16_t)tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn off sensors' power
|
||||||
|
void sensors_off(){
|
||||||
|
mesg("Turn off sensors");
|
||||||
|
MUL_OFF(); // turn off multiplexers
|
||||||
|
SENSORS_OFF(); // turn off sensors' power
|
||||||
|
Sstate = SENS_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if all OK with current, turn ON sensors' power
|
||||||
|
*/
|
||||||
|
static int sensors_on(){
|
||||||
|
mesg("Turn on sensors");
|
||||||
|
curr_mul_addr = 0;
|
||||||
|
MUL_OFF();
|
||||||
|
if(SENSORS_OVERCURNT()){
|
||||||
|
mesg("OVERCURRENT!");
|
||||||
|
SENSORS_OFF();
|
||||||
|
Sstate = (++overcurnt_ctr > 32) ? SENS_OVERCURNT_OFF : SENS_OVERCURNT;
|
||||||
|
return FALSE;
|
||||||
|
}else{
|
||||||
|
mesg("Powered on");
|
||||||
|
SENSORS_ON();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// init sensors
|
||||||
|
void sensors_init(){
|
||||||
|
sens_present[0] = sens_present[1] = 0;
|
||||||
|
overcurnt_ctr = 0;
|
||||||
|
Nsens_present = 0;
|
||||||
|
if(sensors_on()) Sstate = SENS_INITING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* start measurement if sensors are sleeping,
|
||||||
|
* turn ON if they were OFF
|
||||||
|
* do nothing if measurement processing
|
||||||
|
*/
|
||||||
|
void sensors_start(){
|
||||||
|
if(sensors_scan_mode) return;
|
||||||
|
switch(Sstate){
|
||||||
|
case SENS_SLEEPING:
|
||||||
|
Sstate = SENS_START_MSRMNT;
|
||||||
|
break;
|
||||||
|
case SENS_OFF:
|
||||||
|
overcurnt_ctr = 0;
|
||||||
|
if(sensors_on()) Sstate = SENS_START_MSRMNT;
|
||||||
|
break;
|
||||||
|
case SENS_OVERCURNT_OFF:
|
||||||
|
sensors_init();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// count 1 bits in sens_present & set `Nsens_present` to this value
|
||||||
|
static void count_sensors(){
|
||||||
|
Nsens_present = 0;
|
||||||
|
uint16_t B = sens_present[0]<<8 | sens_present[1];
|
||||||
|
while(B){
|
||||||
|
++Nsens_present;
|
||||||
|
B &= (B - 1);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
SEND("count_sensors(): ");
|
||||||
|
printu(Nsens_present);
|
||||||
|
newline();
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All procedures return TRUE if all OK or FALSE if failed and need to start scan again
|
||||||
|
*/
|
||||||
|
// procedure call each time @ resetting
|
||||||
|
static uint8_t resetproc(){
|
||||||
|
uint8_t i;
|
||||||
|
for(i = 0; i < 2; ++i){
|
||||||
|
if(write_i2c(Taddr[i], TSYS01_RESET)){
|
||||||
|
sens_present[i] |= 1<<curr_mul_addr; // set bit - found
|
||||||
|
}else{ // not found
|
||||||
|
sens_present[i] &= ~(1<<curr_mul_addr); // reset bit - not found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t getcoeff(uint8_t i){
|
||||||
|
const uint8_t regs[5] = {0xAA, 0xA8, 0xA6, 0xA4, 0xA2}; // commands for coefficients
|
||||||
|
uint8_t err = 5;
|
||||||
|
uint16_t *coef = coefficients[curr_mul_addr][i];
|
||||||
|
for(uint8_t j = 0; j < 5; ++j){
|
||||||
|
uint32_t K;
|
||||||
|
if(write_i2c(Taddr[i], regs[j])){
|
||||||
|
if(read_i2c(Taddr[i], &K, 2)){
|
||||||
|
coef[j] = K;
|
||||||
|
--err;
|
||||||
|
}else break;
|
||||||
|
}else break;
|
||||||
|
}
|
||||||
|
if(err){ // restart all procedures if we can't get coeffs of present sensor
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// procedure call each time @ getting coefficients
|
||||||
|
static uint8_t getcoefsproc(){
|
||||||
|
uint8_t r = TRUE;
|
||||||
|
for(uint8_t i = 0; i < 2; ++i){
|
||||||
|
if(!(sens_present[i] & (1<<curr_mul_addr))) continue; // no sensors @ given line
|
||||||
|
if(!getcoeff(i)) r = FALSE;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// procedure call each time @ start measurement
|
||||||
|
static uint8_t msrtempproc(){
|
||||||
|
uint8_t i, j;
|
||||||
|
for(i = 0; i < 2; ++i){
|
||||||
|
if(!(sens_present[i] & (1<<curr_mul_addr))){ // no sensors @ given line - try to find it
|
||||||
|
if(write_i2c(Taddr[i], TSYS01_RESET)){
|
||||||
|
sens_present[i] |= 1<<curr_mul_addr;
|
||||||
|
mesg("One sensor added");
|
||||||
|
count_sensors();
|
||||||
|
// if(getcoeff(i)) count_sensors();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for(j = 0; j < 5; ++j){
|
||||||
|
if(write_i2c(Taddr[i], TSYS01_START_CONV)) break;
|
||||||
|
//if(!write_i2c(Taddr[i], TSYS01_RESET)) i2c_setup(CURRENT_SPEED); // maybe I2C restart will solve the problem?
|
||||||
|
}
|
||||||
|
if(j == 5){
|
||||||
|
sens_present[i] &= ~(1<<curr_mul_addr); // clear presence flag
|
||||||
|
mesg("One sensor removed");
|
||||||
|
count_sensors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// procedure call each time @ read temp
|
||||||
|
static uint8_t gettempproc(){
|
||||||
|
uint8_t i;
|
||||||
|
for(i = 0; i < 2; ++i){
|
||||||
|
if(!(sens_present[i] & (1<<curr_mul_addr))) continue; // no sensors @ given line
|
||||||
|
Temperatures[curr_mul_addr][i] = NO_SENSOR;
|
||||||
|
uint8_t err = 1;
|
||||||
|
if(write_i2c(Taddr[i], TSYS01_ADC_READ)){
|
||||||
|
uint32_t t;
|
||||||
|
if(read_i2c(Taddr[i], &t, 3) && t){
|
||||||
|
if(BAD_TEMPERATURE != (Temperatures[curr_mul_addr][i] = calc_t(t, i))){
|
||||||
|
err = 0;
|
||||||
|
++Ntemp_measured;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(err){
|
||||||
|
write_i2c(Taddr[i], TSYS01_RESET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2 phase for each call: 1) set address & turn on mul.; 2) call function & turn off mul.
|
||||||
|
* Change address @ call function `procfn`
|
||||||
|
* @return TRUE if scan is over
|
||||||
|
*/
|
||||||
|
static uint8_t sensors_scan(uint8_t (* procfn)()){
|
||||||
|
static uint8_t callctr = 0;
|
||||||
|
if(callctr == 0){ // set address & turn on multiplexer
|
||||||
|
MUL_ADDRESS(curr_mul_addr);
|
||||||
|
MUL_ON();
|
||||||
|
callctr = 1;
|
||||||
|
}else{ // call procfn & turn off multiplexer
|
||||||
|
callctr = 0;
|
||||||
|
uint8_t s = procfn();
|
||||||
|
MUL_OFF();
|
||||||
|
if(!s){ // start scan again if error
|
||||||
|
curr_mul_addr = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if(++curr_mul_addr > MUL_MAX_ADDRESS){ // scan is over
|
||||||
|
curr_mul_addr = 0;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print coefficients @debug console
|
||||||
|
void showcoeffs(){
|
||||||
|
int a, p, k;
|
||||||
|
if(Nsens_present == 0){
|
||||||
|
SEND("showcoeffs(): no sensors found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for(a = 0; a <= MUL_MAX_ADDRESS; ++a){
|
||||||
|
for(p = 0; p < 2; ++p){
|
||||||
|
if(!(sens_present[p] & (1<<a))) continue; // no sensor
|
||||||
|
for(k = 0; k < 5; ++k){
|
||||||
|
char b[] = {'K', a+'0', p+'0', '_', k+'0', '=', 0};
|
||||||
|
addtobuf(b);
|
||||||
|
printu(coefficients[a][p][k]);
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// print temperatures @debug console
|
||||||
|
void showtemperature(){
|
||||||
|
int a, p;
|
||||||
|
if(Nsens_present == 0){
|
||||||
|
SEND("showtemperature(): no sensors found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(Ntemp_measured == 0){
|
||||||
|
SEND("showtemperature(): no temperatures measured");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for(a = 0; a <= MUL_MAX_ADDRESS; ++a){
|
||||||
|
for(p = 0; p < 2; ++p){
|
||||||
|
if(!(sens_present[p] & (1<<a))){
|
||||||
|
continue; // no sensor
|
||||||
|
}
|
||||||
|
bufputchar('T');
|
||||||
|
bufputchar('0' + Controller_address);
|
||||||
|
bufputchar('_');
|
||||||
|
printu(a*10+p);
|
||||||
|
bufputchar('=');
|
||||||
|
int16_t t = Temperatures[a][p];
|
||||||
|
if(t < 0){
|
||||||
|
t = -t;
|
||||||
|
bufputchar('-');
|
||||||
|
}
|
||||||
|
printu(t);
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finite state machine for sensors switching & checking
|
||||||
|
void sensors_process(){
|
||||||
|
static int8_t NsentOverCAN = -1; // number of T (N*10+p) sent over CAN bus; -1 - nothing to send
|
||||||
|
if(SENSORS_OVERCURNT()){
|
||||||
|
MUL_OFF();
|
||||||
|
SENSORS_OFF();
|
||||||
|
Sstate = (++overcurnt_ctr > 32) ? SENS_OVERCURNT_OFF : SENS_OVERCURNT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch(Sstate){
|
||||||
|
case SENS_INITING: // initialisation (restart I2C)
|
||||||
|
mesg("SENS_INITING");
|
||||||
|
i2c_setup(CURRENT_SPEED);
|
||||||
|
Sstate = SENS_RESETING;
|
||||||
|
lastSensT = Tms;
|
||||||
|
NsentOverCAN = -1;
|
||||||
|
break;
|
||||||
|
case SENS_RESETING: // reset & discovery procedure
|
||||||
|
if(NsentOverCAN == -1){
|
||||||
|
mesg("SENS_RESETING");
|
||||||
|
NsentOverCAN = 0;
|
||||||
|
}
|
||||||
|
if(Tms - lastSensT > POWERUP_TIME){
|
||||||
|
if(sensors_scan(resetproc)){
|
||||||
|
count_sensors(); // get total amount of sensors
|
||||||
|
if(Nsens_present){
|
||||||
|
Sstate = SENS_GET_COEFFS;
|
||||||
|
}else{ // no sensors found
|
||||||
|
mesg("No sensors found -> off");
|
||||||
|
sensors_off();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENS_GET_COEFFS: // get coefficients
|
||||||
|
mesg("SENS_GET_COEFFS");
|
||||||
|
if(sensors_scan(getcoefsproc)){
|
||||||
|
Sstate = SENS_SLEEPING; // sleep after got coefficients
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENS_START_MSRMNT: // send all sensors command to start measurements
|
||||||
|
mesg("SENS_START_MSRMNT");
|
||||||
|
if(sensors_scan(msrtempproc)){
|
||||||
|
lastSensT = Tms;
|
||||||
|
Sstate = SENS_WAITING;
|
||||||
|
Ntemp_measured = 0; // reset value of good measurements
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENS_WAITING: // wait for end of conversion
|
||||||
|
mesg("SENS_WAITING");
|
||||||
|
if(Tms - lastSensT > CONV_TIME){
|
||||||
|
NsentOverCAN = -1;
|
||||||
|
Sstate = SENS_GATHERING;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENS_GATHERING: // scan all sensors, get thermal data & calculate temperature
|
||||||
|
if(NsentOverCAN < 0){
|
||||||
|
mesg("SENS_SLEEPING");
|
||||||
|
NsentOverCAN = 0;
|
||||||
|
}
|
||||||
|
if(sensors_scan(gettempproc)){
|
||||||
|
lastSensT = Tms;
|
||||||
|
NsentOverCAN = 0;
|
||||||
|
Sstate = SENS_SENDING_DATA;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENS_SENDING_DATA:
|
||||||
|
mesg("SENS_SENDING_DATA");
|
||||||
|
NsentOverCAN = send_temperatures(NsentOverCAN); // call sending T process
|
||||||
|
if(NsentOverCAN < 0){ // all data sent -> sleep
|
||||||
|
Sstate = SENS_SLEEPING;
|
||||||
|
/*
|
||||||
|
if(Nsens_present != Ntemp_measured){ // restart sensors only after measurements sent
|
||||||
|
mesg("restart");
|
||||||
|
i2c_setup(CURRENT_SPEED);
|
||||||
|
sensors_on();
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENS_SLEEPING: // wait for `SLEEP_TIME` till next measurements in scan mode
|
||||||
|
if(NsentOverCAN < 0){
|
||||||
|
mesg("SENS_SLEEPING");
|
||||||
|
NsentOverCAN = 0;
|
||||||
|
}
|
||||||
|
if(sensors_scan_mode){ // sleep until next measurement start
|
||||||
|
if(Tms - lastSensT > SLEEP_TIME){
|
||||||
|
Sstate = SENS_START_MSRMNT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENS_OVERCURNT: // try to reinit all after overcurrent
|
||||||
|
mesg("SENS_OVERCURNT");
|
||||||
|
if(sensors_on()) Sstate = SENS_SLEEPING;
|
||||||
|
break;
|
||||||
|
default: // do nothing
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
69
F0:F030,F042,F072/TSYS_controller/sensors_manage.h
Normal file
69
F0:F030,F042,F072/TSYS_controller/sensors_manage.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* geany_encoding=koi8-r
|
||||||
|
* sensors_manage.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 __SENSORS_MANAGE_H__
|
||||||
|
#define __SENSORS_MANAGE_H__
|
||||||
|
|
||||||
|
#include "hardware.h"
|
||||||
|
|
||||||
|
// time for power up procedure (500ms)
|
||||||
|
#define POWERUP_TIME (500)
|
||||||
|
// time between readings in scan mode (15sec)
|
||||||
|
#define SLEEP_TIME (15000)
|
||||||
|
// error in measurement == -300degrC
|
||||||
|
#define BAD_TEMPERATURE (-30000)
|
||||||
|
// no sensor on given channel
|
||||||
|
#define NO_SENSOR (-31000)
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
SENS_INITING // 0 power on
|
||||||
|
,SENS_RESETING // 1 discovery sensors resetting them
|
||||||
|
,SENS_GET_COEFFS // 2 get coefficients from all sensors
|
||||||
|
,SENS_SLEEPING // 3 wait for a time to process measurements
|
||||||
|
,SENS_START_MSRMNT // 4 send command 2 start measurement
|
||||||
|
,SENS_WAITING // 5 wait for measurements end
|
||||||
|
,SENS_GATHERING // 6 collect information
|
||||||
|
,SENS_OFF // 7 sensors' power is off by external command
|
||||||
|
,SENS_OVERCURNT // 8 overcurrent detected @ any stage
|
||||||
|
,SENS_OVERCURNT_OFF // 9 sensors' power is off due to continuous overcurrent
|
||||||
|
,SENS_SENDING_DATA // A send data over CAN bus
|
||||||
|
,SENS_STATE_CNT
|
||||||
|
} SensorsState;
|
||||||
|
|
||||||
|
extern uint8_t sensors_scan_mode;
|
||||||
|
extern int16_t Temperatures[MUL_MAX_ADDRESS+1][2];
|
||||||
|
extern uint8_t sens_present[2];
|
||||||
|
extern SensorsState Sstate;
|
||||||
|
extern uint8_t Nsens_present;
|
||||||
|
extern uint8_t Ntemp_measured;
|
||||||
|
|
||||||
|
const char *sensors_get_statename(SensorsState x);
|
||||||
|
void sensors_process();
|
||||||
|
|
||||||
|
void sensors_off();
|
||||||
|
void sensors_init();
|
||||||
|
void sensors_start();
|
||||||
|
void showcoeffs();
|
||||||
|
void showtemperature();
|
||||||
|
|
||||||
|
#endif // __SENSORS_MANAGE_H__
|
||||||
BIN
F0:F030,F042,F072/TSYS_controller/tsys01.bin
Executable file
BIN
F0:F030,F042,F072/TSYS_controller/tsys01.bin
Executable file
Binary file not shown.
216
F0:F030,F042,F072/TSYS_controller/usart.c
Normal file
216
F0:F030,F042,F072/TSYS_controller/usart.c
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* usart.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 <string.h>
|
||||||
|
|
||||||
|
#include "stm32f0.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
#include "usart.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern volatile uint32_t Tms;
|
||||||
|
static int datalen[2] = {0,0}; // received data line length (including '\n')
|
||||||
|
|
||||||
|
volatile int linerdy = 0, // received data ready
|
||||||
|
dlen = 0, // length of data (including '\n') in current buffer
|
||||||
|
bufovr = 0, // input buffer overfull
|
||||||
|
txrdy = 1 // transmission done
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
int rbufno = 0; // current rbuf number
|
||||||
|
static char rbuf[UARTINBUFSZ][2], tbuf[UARTBUFSZ]; // receive & transmit buffers
|
||||||
|
static char *recvdata = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return length of received data (without trailing zero
|
||||||
|
*/
|
||||||
|
int usart_getline(char **line){
|
||||||
|
if(bufovr){
|
||||||
|
bufovr = 0;
|
||||||
|
linerdy = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*line = recvdata;
|
||||||
|
linerdy = 0;
|
||||||
|
return dlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
TXstatus usart_send(const char *str, int len){
|
||||||
|
if(!txrdy) return LINE_BUSY;
|
||||||
|
if(len > UARTBUFSZ) return STR_TOO_LONG;
|
||||||
|
txrdy = 0;
|
||||||
|
memcpy(tbuf, str, len);
|
||||||
|
#if USARTNUM == 2
|
||||||
|
DMA1_Channel4->CCR &= ~DMA_CCR_EN;
|
||||||
|
DMA1_Channel4->CNDTR = len;
|
||||||
|
DMA1_Channel4->CCR |= DMA_CCR_EN; // start transmission
|
||||||
|
#elif USARTNUM == 1
|
||||||
|
DMA1_Channel2->CCR &= ~DMA_CCR_EN;
|
||||||
|
DMA1_Channel2->CNDTR = len;
|
||||||
|
DMA1_Channel2->CCR |= DMA_CCR_EN;
|
||||||
|
#else
|
||||||
|
#error "Not implemented"
|
||||||
|
#endif
|
||||||
|
return ALL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
TXstatus usart_send_blocking(const char *str, int len){
|
||||||
|
if(!txrdy) return LINE_BUSY;
|
||||||
|
int i;
|
||||||
|
bufovr = 0;
|
||||||
|
for(i = 0; i < len; ++i){
|
||||||
|
USARTX -> TDR = *str++;
|
||||||
|
while(!(USARTX->ISR & USART_ISR_TXE)){IWDG->KR = IWDG_REFRESH;};
|
||||||
|
}
|
||||||
|
return ALL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usart_send_blck(const char *str){
|
||||||
|
while(!txrdy){IWDG->KR = IWDG_REFRESH;}
|
||||||
|
bufovr = 0;
|
||||||
|
while(*str){
|
||||||
|
USARTX -> TDR = *str++;
|
||||||
|
while(!(USARTX->ISR & USART_ISR_TXE)){IWDG->KR = IWDG_REFRESH;};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usart_setup(){
|
||||||
|
// Nucleo's USART2 connected to VCP proxy of st-link
|
||||||
|
#if USARTNUM == 2
|
||||||
|
// setup pins: PA2 (Tx - AF1), PA15 (Rx - AF1)
|
||||||
|
// AF mode (AF1)
|
||||||
|
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER2|GPIO_MODER_MODER15))\
|
||||||
|
| (GPIO_MODER_MODER2_AF | GPIO_MODER_MODER15_AF);
|
||||||
|
GPIOA->AFR[0] = (GPIOA->AFR[0] &~GPIO_AFRH_AFRH2) | 1 << (2 * 4); // PA2
|
||||||
|
GPIOA->AFR[1] = (GPIOA->AFR[1] &~GPIO_AFRH_AFRH7) | 1 << (7 * 4); // PA15
|
||||||
|
// DMA: Tx - Ch4
|
||||||
|
DMA1_Channel4->CPAR = (uint32_t) &USART2->TDR; // periph
|
||||||
|
DMA1_Channel4->CMAR = (uint32_t) tbuf; // mem
|
||||||
|
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_5_IRQn, 3);
|
||||||
|
NVIC_EnableIRQ(DMA1_Channel4_5_IRQn);
|
||||||
|
NVIC_SetPriority(USART2_IRQn, 0);
|
||||||
|
// setup usart2
|
||||||
|
RCC->APB1ENR |= RCC_APB1ENR_USART2EN; // clock
|
||||||
|
// oversampling by16, 115200bps (fck=48mHz)
|
||||||
|
//USART2_BRR = 0x1a1; // 48000000 / 115200
|
||||||
|
USART2->BRR = 480000 / 1152;
|
||||||
|
USART2->CR3 = USART_CR3_DMAT; // enable DMA Tx
|
||||||
|
USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART
|
||||||
|
while(!(USART2->ISR & USART_ISR_TC)); // polling idle frame Transmission
|
||||||
|
USART2->ICR |= USART_ICR_TCCF; // clear TC flag
|
||||||
|
USART2->CR1 |= USART_CR1_RXNEIE;
|
||||||
|
NVIC_EnableIRQ(USART2_IRQn);
|
||||||
|
// USART1 of main board
|
||||||
|
#elif USARTNUM == 1
|
||||||
|
// PA9 - Tx, PA10 - Rx (AF1)
|
||||||
|
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER9 | GPIO_MODER_MODER10))\
|
||||||
|
| (GPIO_MODER_MODER9_AF | GPIO_MODER_MODER10_AF);
|
||||||
|
GPIOA->AFR[1] = (GPIOA->AFR[1] & ~(GPIO_AFRH_AFRH1 | GPIO_AFRH_AFRH2)) |
|
||||||
|
1 << (1 * 4) | 1 << (2 * 4); // PA9, PA10
|
||||||
|
// USART1 Tx DMA - Channel2 (default value in SYSCFG_CFGR1)
|
||||||
|
DMA1_Channel2->CPAR = (uint32_t) &USART1->TDR; // periph
|
||||||
|
DMA1_Channel2->CMAR = (uint32_t) tbuf; // mem
|
||||||
|
DMA1_Channel2->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_Channel2_3_IRQn, 3);
|
||||||
|
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
|
||||||
|
NVIC_SetPriority(USART1_IRQn, 0);
|
||||||
|
// setup usart1
|
||||||
|
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
||||||
|
USART1->BRR = 480000 / 1152;
|
||||||
|
USART1->CR3 = USART_CR3_DMAT; // enable DMA Tx
|
||||||
|
USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART
|
||||||
|
while(!(USART1->ISR & USART_ISR_TC)); // polling idle frame Transmission
|
||||||
|
USART1->ICR |= USART_ICR_TCCF; // clear TC flag
|
||||||
|
USART1->CR1 |= USART_CR1_RXNEIE;
|
||||||
|
NVIC_EnableIRQ(USART1_IRQn);
|
||||||
|
#else
|
||||||
|
#error "Not implemented"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USARTNUM == 2
|
||||||
|
void usart2_isr(){
|
||||||
|
// USART1
|
||||||
|
#elif USARTNUM == 1
|
||||||
|
void usart1_isr(){
|
||||||
|
#else
|
||||||
|
#error "Not implemented"
|
||||||
|
#endif
|
||||||
|
#ifdef CHECK_TMOUT
|
||||||
|
static uint32_t tmout = 0;
|
||||||
|
#endif
|
||||||
|
if(USARTX->ISR & USART_ISR_RXNE){ // RX not emty - receive next char
|
||||||
|
#ifdef CHECK_TMOUT
|
||||||
|
if(tmout && Tms >= tmout){ // set overflow flag
|
||||||
|
bufovr = 1;
|
||||||
|
datalen[rbufno] = 0;
|
||||||
|
}
|
||||||
|
tmout = Tms + TIMEOUT_MS;
|
||||||
|
if(!tmout) tmout = 1; // prevent 0
|
||||||
|
#endif
|
||||||
|
// read RDR clears flag
|
||||||
|
uint8_t rb = USARTX->RDR;
|
||||||
|
if(datalen[rbufno] < UARTINBUFSZ){ // put next char into buf
|
||||||
|
rbuf[rbufno][datalen[rbufno]++] = rb;
|
||||||
|
if(rb == '\n'){ // got newline - line ready
|
||||||
|
linerdy = 1;
|
||||||
|
dlen = datalen[rbufno];
|
||||||
|
recvdata = rbuf[rbufno];
|
||||||
|
// prepare other buffer
|
||||||
|
rbufno = !rbufno;
|
||||||
|
datalen[rbufno] = 0;
|
||||||
|
#ifdef CHECK_TMOUT
|
||||||
|
// clear timeout at line end
|
||||||
|
tmout = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}else{ // buffer overrun
|
||||||
|
bufovr = 1;
|
||||||
|
datalen[rbufno] = 0;
|
||||||
|
#ifdef CHECK_TMOUT
|
||||||
|
tmout = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
51
F0:F030,F042,F072/TSYS_controller/usart.h
Normal file
51
F0:F030,F042,F072/TSYS_controller/usart.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* usart.h
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#ifndef __USART_H__
|
||||||
|
#define __USART_H__
|
||||||
|
|
||||||
|
// output buffers size
|
||||||
|
#define UARTBUFSZ (512)
|
||||||
|
// input buffer size
|
||||||
|
#define UARTINBUFSZ (64)
|
||||||
|
// timeout between data bytes
|
||||||
|
#ifndef TIMEOUT_MS
|
||||||
|
#define TIMEOUT_MS (1500)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
ALL_OK,
|
||||||
|
LINE_BUSY,
|
||||||
|
STR_TOO_LONG
|
||||||
|
} TXstatus;
|
||||||
|
|
||||||
|
#define usartrx() (linerdy)
|
||||||
|
#define usartovr() (bufovr)
|
||||||
|
|
||||||
|
extern volatile int linerdy, bufovr, txrdy;
|
||||||
|
|
||||||
|
void usart_setup();
|
||||||
|
int usart_getline(char **line);
|
||||||
|
TXstatus usart_send(const char *str, int len);
|
||||||
|
TXstatus usart_send_blocking(const char *str, int len);
|
||||||
|
void usart_send_blck(const char *str);
|
||||||
|
|
||||||
|
#endif // __USART_H__
|
||||||
183
F0:F030,F042,F072/TSYS_controller/usb.c
Normal file
183
F0:F030,F042,F072/TSYS_controller/usb.c
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* 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 <string.h>
|
||||||
|
|
||||||
|
#include "usart.h"
|
||||||
|
#include "usb.h"
|
||||||
|
#include "usb_lib.h"
|
||||||
|
|
||||||
|
// incoming buffer size
|
||||||
|
#define IDATASZ (256)
|
||||||
|
static uint8_t incoming_data[IDATASZ];
|
||||||
|
static uint8_t ovfl = 0;
|
||||||
|
static uint16_t idatalen = 0;
|
||||||
|
static int8_t usbON = 0; // ==1 when USB fully configured
|
||||||
|
static volatile uint8_t tx_succesfull = 0;
|
||||||
|
|
||||||
|
// interrupt IN handler (never used?)
|
||||||
|
static uint16_t EP1_Handler(ep_t ep){
|
||||||
|
uint8_t ep0buf[11];
|
||||||
|
if (ep.rx_flag){
|
||||||
|
EP_Read(1, ep0buf);
|
||||||
|
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, &incoming_data[idatalen]);
|
||||||
|
ovfl = 0;
|
||||||
|
}else{
|
||||||
|
ep.status = SET_NAK_RX(ep.status);
|
||||||
|
ovfl = 1;
|
||||||
|
return ep.status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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(){
|
||||||
|
RCC->APB1ENR |= RCC_APB1ENR_CRSEN | RCC_APB1ENR_USBEN; // enable CRS (hsi48 sync) & USB
|
||||||
|
RCC->CFGR3 &= ~RCC_CFGR3_USBSW; // reset USB
|
||||||
|
RCC->CR2 |= RCC_CR2_HSI48ON; // turn ON HSI48
|
||||||
|
uint32_t tmout = 16000000;
|
||||||
|
while(!(RCC->CR2 & RCC_CR2_HSI48RDY)){if(--tmout == 0) break; IWDG->KR = IWDG_REFRESH;}
|
||||||
|
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
|
||||||
|
CRS->CFGR &= ~CRS_CFGR_SYNCSRC;
|
||||||
|
CRS->CFGR |= CRS_CFGR_SYNCSRC_1; // USB SOF selected as sync source
|
||||||
|
CRS->CR |= CRS_CR_AUTOTRIMEN; // enable auto trim
|
||||||
|
CRS->CR |= CRS_CR_CEN; // enable freq counter & block CRS->CFGR as read-only
|
||||||
|
RCC->CFGR |= RCC_CFGR_SW;
|
||||||
|
// allow RESET and CTRM interrupts
|
||||||
|
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
|
||||||
|
// clear flags
|
||||||
|
USB->ISTR = 0;
|
||||||
|
// and activate pullup
|
||||||
|
USB->BCDR |= USB_BCDR_DPPU;
|
||||||
|
NVIC_EnableIRQ(USB_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_send(const char *buf){
|
||||||
|
uint16_t l = 0, ctr = 0;
|
||||||
|
const char *p = buf;
|
||||||
|
while(*p++) ++l;
|
||||||
|
while(l){
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
uint16_t s = (l > USB_TXBUFSZ) ? USB_TXBUFSZ : l;
|
||||||
|
tx_succesfull = 0;
|
||||||
|
EP_Write(3, (uint8_t*)&buf[ctr], s);
|
||||||
|
uint32_t ctra = 1000000;
|
||||||
|
while(--ctra && tx_succesfull == 0){IWDG->KR = IWDG_REFRESH;}
|
||||||
|
l -= s;
|
||||||
|
ctr += s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USB_receive - read first received text string
|
||||||
|
* @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<1 || !idatalen) return 0;
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
int stlen = 0, i;
|
||||||
|
for(i = 0; i < idatalen; ++i){
|
||||||
|
if(incoming_data[i] == '\n'){
|
||||||
|
stlen = i+1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(i == idatalen || stlen == 0) return 0;
|
||||||
|
/*
|
||||||
|
char x[] = "USB got x:\n";
|
||||||
|
x[8] = '0' + stlen;
|
||||||
|
usart_send_blck(x);
|
||||||
|
usart_send_blck((char*)incoming_data);
|
||||||
|
usart_send_blck("\n");
|
||||||
|
*/
|
||||||
|
USB->CNTR = 0;
|
||||||
|
int sz = (stlen > bufsize) ? bufsize : stlen, rest = idatalen - sz;
|
||||||
|
memcpy(buf, incoming_data, sz);
|
||||||
|
buf[sz] = 0;
|
||||||
|
/*
|
||||||
|
usart_send_blck("buf:\n");
|
||||||
|
usart_send_blck((char*)buf);
|
||||||
|
usart_send_blck("\n");
|
||||||
|
*/
|
||||||
|
if(rest > 0){
|
||||||
|
memmove(incoming_data, &incoming_data[sz], rest);
|
||||||
|
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;
|
||||||
|
}
|
||||||
37
F0:F030,F042,F072/TSYS_controller/usb.h
Normal file
37
F0:F030,F042,F072/TSYS_controller/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__
|
||||||
106
F0:F030,F042,F072/TSYS_controller/usb_defs.h
Normal file
106
F0:F030,F042,F072/TSYS_controller/usb_defs.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* 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 <stm32f0xx.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buffers size definition
|
||||||
|
**/
|
||||||
|
// !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!!
|
||||||
|
#define USB_BTABLE_SIZE 1024
|
||||||
|
// 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
|
||||||
|
#undef USB_BTABLE
|
||||||
|
#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
|
||||||
|
|
||||||
|
#define USB_TypeDef USB_TypeDef_custom
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
__IO uint32_t EPnR[8];
|
||||||
|
__IO uint32_t RESERVED1;
|
||||||
|
__IO uint32_t RESERVED2;
|
||||||
|
__IO uint32_t RESERVED3;
|
||||||
|
__IO uint32_t RESERVED4;
|
||||||
|
__IO uint32_t RESERVED5;
|
||||||
|
__IO uint32_t RESERVED6;
|
||||||
|
__IO uint32_t RESERVED7;
|
||||||
|
__IO uint32_t RESERVED8;
|
||||||
|
__IO uint32_t CNTR;
|
||||||
|
__IO uint32_t ISTR;
|
||||||
|
__IO uint32_t FNR;
|
||||||
|
__IO uint32_t DADDR;
|
||||||
|
__IO uint32_t BTABLE;
|
||||||
|
__IO uint32_t LPMCSR;
|
||||||
|
__IO uint32_t BCDR;
|
||||||
|
} USB_TypeDef;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
__IO uint16_t USB_ADDR_TX;
|
||||||
|
__IO uint16_t USB_COUNT_TX;
|
||||||
|
__IO uint16_t USB_ADDR_RX;
|
||||||
|
__IO uint16_t USB_COUNT_RX;
|
||||||
|
} USB_EPDATA_TypeDef;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
__IO USB_EPDATA_TypeDef EP[8];
|
||||||
|
} USB_BtableDef;
|
||||||
|
|
||||||
|
#endif // __USB_DEFS_H__
|
||||||
538
F0:F030,F042,F072/TSYS_controller/usb_lib.c
Normal file
538
F0:F030,F042,F072/TSYS_controller/usb_lib.c
Normal file
@ -0,0 +1,538 @@
|
|||||||
|
/*
|
||||||
|
* 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 <string.h> // memcpy
|
||||||
|
|
||||||
|
#include "stm32f0.h"
|
||||||
|
#include "usart.h"
|
||||||
|
#include "usb_lib.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef EBUG
|
||||||
|
#undef EBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ep_t endpoints[ENDPOINTS_NUM];
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* default handlers
|
||||||
|
*/
|
||||||
|
// SET_LINE_CODING
|
||||||
|
void WEAK linecoding_handler(usb_LineCoding __attribute__((unused)) *lc){
|
||||||
|
//MSG("linecoding_handler\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// SET_CONTROL_LINE_STATE
|
||||||
|
void WEAK clstate_handler(uint16_t __attribute__((unused)) val){
|
||||||
|
//MSG("clstate_handler\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEND_BREAK
|
||||||
|
void WEAK break_handler(){
|
||||||
|
//MSG("break_handler\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// handler of vendor requests
|
||||||
|
void WEAK vendor_handler(config_pack_t *packet){
|
||||||
|
if(packet->bmRequestType & 0x80){ // read
|
||||||
|
//SEND("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
|
||||||
|
//SEND("Write");
|
||||||
|
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||||
|
}
|
||||||
|
/*SEND(" vendor, reqt=");
|
||||||
|
printuhex(packet->bmRequestType);
|
||||||
|
SEND(", wval=");
|
||||||
|
printuhex(packet->wValue);
|
||||||
|
usart_putchar('\n');*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef EBUG
|
||||||
|
uint8_t _2wr = 0;
|
||||||
|
#define WRITEDUMP(str) do{MSG(str); _2wr = 1;}while(0)
|
||||||
|
#else
|
||||||
|
#define WRITEDUMP(str)
|
||||||
|
#endif
|
||||||
|
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:
|
||||||
|
WRITEDUMP("UNK_DES");
|
||||||
|
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:
|
||||||
|
WRITEDUMP("GET_CONFIGURATION");
|
||||||
|
EP_WriteIRQ(0, &configuration, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WRITEDUMP("80:WR_REQ");
|
||||||
|
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:
|
||||||
|
WRITEDUMP("0:WR_REQ");
|
||||||
|
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();
|
||||||
|
// send ZLP
|
||||||
|
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){
|
||||||
|
// send ZLP
|
||||||
|
EP_WriteIRQ(0, (uint8_t *)0, 0);
|
||||||
|
epstatus = SET_NAK_RX(epstatus);
|
||||||
|
epstatus = SET_VALID_TX(epstatus);
|
||||||
|
}else{
|
||||||
|
WRITEDUMP("02:WR_REQ");
|
||||||
|
}
|
||||||
|
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:
|
||||||
|
WRITEDUMP("undef control req");
|
||||||
|
}
|
||||||
|
if(!dev2host) 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){
|
||||||
|
//WRITEDUMP("SET_LINE_CODING");
|
||||||
|
linecoding_handler((usb_LineCoding*)ep0databuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Close transaction
|
||||||
|
epstatus = CLEAR_DTOG_RX(epstatus);
|
||||||
|
epstatus = CLEAR_DTOG_TX(epstatus);
|
||||||
|
// wait for new data from host
|
||||||
|
epstatus = SET_VALID_RX(epstatus);
|
||||||
|
epstatus = SET_STALL_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);
|
||||||
|
}
|
||||||
|
#ifdef EBUG
|
||||||
|
if(_2wr){
|
||||||
|
usart_putchar(' ');
|
||||||
|
if (ep.rx_flag) usart_putchar('r');
|
||||||
|
else usart_putchar('t');
|
||||||
|
printu(setup_packet.wLength);
|
||||||
|
if(ep.setup_flag) usart_putchar('s');
|
||||||
|
usart_putchar(' ');
|
||||||
|
usart_putchar('I');
|
||||||
|
printu(setup_packet.wIndex);
|
||||||
|
usart_putchar('V');
|
||||||
|
printu(setup_packet.wValue);
|
||||||
|
usart_putchar('R');
|
||||||
|
printu(setup_packet.bRequest);
|
||||||
|
usart_putchar('T');
|
||||||
|
printu(setup_packet.bmRequestType);
|
||||||
|
usart_putchar(' ');
|
||||||
|
usart_putchar('0' + ep0dbuflen);
|
||||||
|
usart_putchar(' ');
|
||||||
|
hexdump(ep0databuf, ep0dbuflen);
|
||||||
|
usart_putchar('\n');
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return epstatus;
|
||||||
|
}
|
||||||
|
#undef WRITEDUMP
|
||||||
|
|
||||||
|
static uint16_t lastaddr = USB_EP0_BASEADDR;
|
||||||
|
/**
|
||||||
|
* Endpoint initialisation
|
||||||
|
* !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!!
|
||||||
|
* @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 >= ENDPOINTS_NUM) 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 > 992) 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);
|
||||||
|
lastaddr += txsz;
|
||||||
|
USB_BTABLE->EP[number].USB_COUNT_TX = 0;
|
||||||
|
USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr;
|
||||||
|
endpoints[number].rx_buf = (uint8_t *)(USB_BTABLE_BASE + lastaddr);
|
||||||
|
lastaddr += rxsz;
|
||||||
|
// buffer size: Table127 of RM
|
||||||
|
USB_BTABLE->EP[number].USB_COUNT_RX = countrx << 10;
|
||||||
|
endpoints[number].func = func;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = USB_EP0_BASEADDR; // roll back to beginning of buffer
|
||||||
|
EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler);
|
||||||
|
// 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];
|
||||||
|
// 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
|
||||||
|
memcpy(&setup_packet, endpoints[0].rx_buf, sizeof(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;
|
||||||
|
memcpy(ep0databuf, endpoints[0].rx_buf, ep0dbuflen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
for (i = 0; i < N2; i++){
|
||||||
|
endpoints[number].tx_buf[i] = 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, uint8_t *buf){
|
||||||
|
int n = endpoints[number].rx_cnt;
|
||||||
|
if(n){
|
||||||
|
for(int i = 0; i < n; ++i)
|
||||||
|
buf[i] = endpoints[number].rx_buf[i];
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// USB status
|
||||||
|
uint8_t USB_GetState(){
|
||||||
|
return USB_Dev.USB_Status;
|
||||||
|
}
|
||||||
202
F0:F030,F042,F072/TSYS_controller/usb_lib.h
Normal file
202
F0:F030,F042,F072/TSYS_controller/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)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
uint8_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, uint8_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__
|
||||||
3
F0:F030,F042,F072/TSYS_controller/version.inc
Normal file
3
F0:F030,F042,F072/TSYS_controller/version.inc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#define BUILD_NUMBER "48"
|
||||||
|
#define BUILD_DATE "2023-08-29"
|
||||||
|
#define BUILDNO 45
|
||||||
Loading…
x
Reference in New Issue
Block a user