diff --git a/F0:F030,F042,F072/TSYS_controller/Makefile b/F0:F030,F042,F072/TSYS_controller/Makefile index 253bb3e..a589d58 100644 --- a/F0:F030,F042,F072/TSYS_controller/Makefile +++ b/F0:F030,F042,F072/TSYS_controller/Makefile @@ -4,7 +4,7 @@ MCU := F042x6 # change this linking script depending on particular MCU model, LDSCRIPT := stm32f042x6.ld -DEFINES := -DUSARTNUM=1 -DI2CPINS=67 +DEFINES := -DUSARTNUM=1 -DI2CPINS=67 -DUSB2_16 include ../makefile.f0 include ../../makefile.stm32 diff --git a/F0:F030,F042,F072/TSYS_controller/Makefile_old b/F0:F030,F042,F072/TSYS_controller/Makefile_old deleted file mode 100644 index 2081386..0000000 --- a/F0:F030,F042,F072/TSYS_controller/Makefile_old +++ /dev/null @@ -1,158 +0,0 @@ -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 diff --git a/F0:F030,F042,F072/TSYS_controller/TSYS_controller.creator.user b/F0:F030,F042,F072/TSYS_controller/TSYS_controller.creator.user index 7ca48ef..69f6562 100644 --- a/F0:F030,F042,F072/TSYS_controller/TSYS_controller.creator.user +++ b/F0:F030,F042,F072/TSYS_controller/TSYS_controller.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -8,7 +8,7 @@ ProjectExplorer.Project.ActiveTarget - 0 + 0 ProjectExplorer.Project.EditorSettings @@ -28,7 +28,7 @@ QmlJSGlobal - 2 + 2 KOI8-R false 4 @@ -54,6 +54,7 @@ *.md, *.MD, Makefile false true + true @@ -75,6 +76,7 @@ true Builtin.DefaultTidyAndClazy 8 + false @@ -89,9 +91,9 @@ Desktop Desktop {65a14f9e-e008-4c1b-89df-4eaa4774b6e3} - 0 - 0 - 0 + 0 + 0 + 0 /Big/Data/00__Electronics/STM32/F0-nolib/TSYS_controller @@ -102,7 +104,7 @@ true GenericProjectManager.GenericMakeStep - 1 + 1 Сборка Сборка ProjectExplorer.BuildSteps.Build @@ -115,7 +117,7 @@ true GenericProjectManager.GenericMakeStep - 1 + 1 Очистка Очистка ProjectExplorer.BuildSteps.Clean @@ -128,10 +130,10 @@ По умолчанию GenericProjectManager.GenericBuildConfiguration - 1 + 1 - 0 + 0 Развёртывание Развёртывание ProjectExplorer.BuildSteps.Deploy @@ -141,24 +143,26 @@ false ProjectExplorer.DefaultDeployConfiguration - 1 + 1 + true + true + true 2 + false ProjectExplorer.CustomExecutableRunConfiguration - false true - false true - 1 + 1 ProjectExplorer.Project.TargetCount - 1 + 1 ProjectExplorer.Project.Updater.FileVersion diff --git a/F0:F030,F042,F072/TSYS_controller/TSYS_controller.files b/F0:F030,F042,F072/TSYS_controller/TSYS_controller.files index cb15fe1..90c34f8 100644 --- a/F0:F030,F042,F072/TSYS_controller/TSYS_controller.files +++ b/F0:F030,F042,F072/TSYS_controller/TSYS_controller.files @@ -16,8 +16,12 @@ i2c.h main.c proto.c proto.h +ringbuffer.c +ringbuffer.h sensors_manage.c sensors_manage.h usart.c usart.h +usbhw.c +usbhw.h version.inc diff --git a/F0:F030,F042,F072/TSYS_controller/can.c b/F0:F030,F042,F072/TSYS_controller/can.c index 2f9bddc..fe3d24c 100644 --- a/F0:F030,F042,F072/TSYS_controller/can.c +++ b/F0:F030,F042,F072/TSYS_controller/can.c @@ -146,7 +146,7 @@ void CAN_setup(uint16_t speed){ /* Configure IT */ /* (14) Set priority for CAN_IRQn */ /* (15) Enable CAN_IRQn */ - NVIC_SetPriority(CEC_CAN_IRQn, 0); /* (14) */ + NVIC_SetPriority(CEC_CAN_IRQn, 10); /* (14) */ NVIC_EnableIRQ(CEC_CAN_IRQn); /* (15) */ can_status = CAN_READY; } diff --git a/F0:F030,F042,F072/TSYS_controller/can_process.c b/F0:F030,F042,F072/TSYS_controller/can_process.c index 4437138..c9c312a 100644 --- a/F0:F030,F042,F072/TSYS_controller/can_process.c +++ b/F0:F030,F042,F072/TSYS_controller/can_process.c @@ -103,6 +103,7 @@ void can_messages_proc(){ if(can_mesg->ID != CANID && can_mesg->ID != BCAST_ID) return; int16_t t; uint32_t U32; + IWDG->KR = IWDG_REFRESH; if(data[0] == COMMAND_MARK){ // process commands if(len < 2) return; // master shouldn't react to broadcast commands! diff --git a/F0:F030,F042,F072/TSYS_controller/ld/stm32f042k.ld b/F0:F030,F042,F072/TSYS_controller/ld/stm32f042k.ld deleted file mode 100644 index e747253..0000000 --- a/F0:F030,F042,F072/TSYS_controller/ld/stm32f042k.ld +++ /dev/null @@ -1,12 +0,0 @@ -/* 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 - diff --git a/F0:F030,F042,F072/TSYS_controller/main.c b/F0:F030,F042,F072/TSYS_controller/main.c index cb303ec..65296fd 100644 --- a/F0:F030,F042,F072/TSYS_controller/main.c +++ b/F0:F030,F042,F072/TSYS_controller/main.c @@ -44,7 +44,7 @@ void sys_tick_handler(void){ ++Tms; } -#ifdef EBUG +#ifndef EBUG static void iwdg_setup(){ /* Enable the peripheral clock RTC */ /* (1) Enable the LSI (40kHz) */ @@ -60,7 +60,7 @@ static void iwdg_setup(){ /* (6) Refresh counter */ IWDG->KR = IWDG_START; /* (1) */ IWDG->KR = IWDG_WRITE_ACCESS; /* (2) */ - IWDG->PR = IWDG_PR_PR_1; /* (3) */ + IWDG->PR = IWDG_PR_PR_2; /* (3) */ IWDG->RLR = 1250; /* (4) */ while(IWDG->SR); /* (5) */ IWDG->KR = IWDG_REFRESH; /* (6) */ @@ -68,7 +68,7 @@ static void iwdg_setup(){ #endif int main(void){ - uint32_t lastT = 0, lastS = 0, lastB = 0; + uint32_t lastT = 0, lastS = 0; uint8_t gotmeasurement = 0; char inbuf[256]; sysreset(); @@ -83,7 +83,9 @@ int main(void){ RCC->CSR |= RCC_CSR_RMVF; // remove reset flags USB_setup(); sensors_init(); - //iwdg_setup(); +#ifndef EBUG + iwdg_setup(); +#endif while (1){ IWDG->KR = IWDG_REFRESH; // refresh watchdog @@ -105,7 +107,6 @@ int main(void){ if(SENS_WAITING == Sstate) gotmeasurement = 0; } } - usb_proc(); can_proc(); CAN_status stat = CAN_get_status(); if(stat == CAN_FIFO_OVERRUN){ @@ -118,23 +119,22 @@ int main(void){ can_messages_proc(); IWDG->KR = IWDG_REFRESH; uint8_t r = 0; - if((r = USB_receive(inbuf, 255))){ + if((r = USB_receivestr(inbuf, 255))){ inbuf[r] = 0; - cmd_parser(inbuf, 1); + if(r) cmd_parser(inbuf, 1); } if(usartrx()){ // usart1 received data, store it in buffer char *txt = NULL; r = usart_getline(&txt); txt[r] = 0; #ifdef EBUG - USB_send("\n\nUSART got:\n"); - USB_send(txt); USB_send("\n\n"); + USB_sendstr("\n\nUSART got:\n"); + USB_sendstr(txt); USB_sendstr("\n\n"); #endif cmd_parser(txt, 0); } - if(lastB - Tms > 249){ // run `sendbuf` each 250ms + if(lastTprint - Tms > 249){ // run `sendbuf` each 250ms sendbuf(); - lastB = Tms; } } return 0; diff --git a/F0:F030,F042,F072/TSYS_controller/proto.c b/F0:F030,F042,F072/TSYS_controller/proto.c index 46b2fe7..fdfb04c 100644 --- a/F0:F030,F042,F072/TSYS_controller/proto.c +++ b/F0:F030,F042,F072/TSYS_controller/proto.c @@ -35,9 +35,10 @@ extern volatile uint8_t canerror; extern volatile uint32_t Tms; +volatile uint32_t lastTprint = 0; static char buff[UARTBUFSZ+1], /* +1 - for USB send (it receive \0-terminated line) */ *bptr = buff; -static int blen = 0, USBcmd = 0, debugmode = +static int blen = 0, cmdsource = SRC_NONE, debugmode = #ifdef EBUG 1 #else @@ -55,32 +56,54 @@ uint8_t noLED = void sendbuf(){ IWDG->KR = IWDG_REFRESH; + lastTprint = Tms; if(blen == 0) return; -#ifdef EBUG - USB_send(" sendbuf()\n"); -#endif - *bptr = 0; - if(USBcmd) USB_send(buff); - else for(int i = 0; (i < WAITFOR) && (LINE_BUSY == usart_send(buff, blen)); ++i){ -#ifdef EBUG - USB_send(" line busy\n"); -#endif - IWDG->KR = IWDG_REFRESH; + if(cmdsource == SRC_NONE){ + bptr = buff; + blen = 0; + return; } + *bptr = 0; + if(cmdsource == SRC_USB) USB_sendstr(buff); + else for(int i = 0; i < WAITFOR; ++i){ + IWDG->KR = IWDG_REFRESH; + TXstatus s = usart_send(buff, blen); + if(s == NO_RECEIVER){ #ifdef EBUG - USB_send(" sendbuf() done\n"); + USB_sendstr(" no receiver\n"); #endif + cmdsource = SRC_NONE; + break; + }else if(s != LINE_BUSY) break; +#ifdef EBUG + if(DMA1->ISR & DMA_ISR_TCIF2) USB_sendstr("DMA rdy\n"); + USB_sendstr(" sendbuf: line busy\n"); +#endif + } bptr = buff; blen = 0; + lastTprint = Tms; } void addtobuf(const char *txt){ + if(cmdsource == SRC_NONE) return; IWDG->KR = IWDG_REFRESH; int l = strlen(txt); if(l > UARTBUFSZ){ sendbuf(); // send prevoius data in buffer - if(USBcmd) USB_send(txt); - else for(int i = 0; (i < WAITFOR) && (LINE_BUSY == usart_send_blocking(txt, l)); ++i){IWDG->KR = IWDG_REFRESH;} + if(cmdsource == SRC_USB) USB_sendstr(txt); + else for(int i = 0; i < WAITFOR; ++i){ + TXstatus s = usart_send_blocking(txt, l); + if(s == NO_RECEIVER){ + cmdsource = SRC_NONE; + break; + }else if(s != LINE_BUSY) break; + IWDG->KR = IWDG_REFRESH; +#ifdef EBUG + if(DMA1->ISR & DMA_ISR_TCIF2) USB_sendstr("DMA rdy\n"); + USB_sendstr(" addtobuf: line busy\n"); +#endif + } }else{ if(blen+l > UARTBUFSZ){ sendbuf(); @@ -90,6 +113,7 @@ void addtobuf(const char *txt){ *bptr = 0; blen += l; } + lastTprint = Tms; } void bufputchar(char ch){ @@ -98,6 +122,7 @@ void bufputchar(char ch){ } *bptr++ = ch; ++blen; + lastTprint = Tms; } static void CANsend(uint16_t targetID, uint8_t cmd, char echo){ @@ -221,7 +246,8 @@ static void sendCANcommand(char *txt){ * @param isUSB - == 1 if data got from USB */ void cmd_parser(char *txt, uint8_t isUSB){ - USBcmd = isUSB; + cmdsource = isUSB ? SRC_USB : SRC_USART; +//addtobuf("\n\n__"); printuhex(*txt); addtobuf("__\n\n"); int16_t L = strlen(txt), ID = BCAST_ID; char _1st = txt[0]; if(_1st >= '0' && _1st < '8'){ // send command to Nth controller, not broadcast diff --git a/F0:F030,F042,F072/TSYS_controller/proto.h b/F0:F030,F042,F072/TSYS_controller/proto.h index 48e544f..7b10a31 100644 --- a/F0:F030,F042,F072/TSYS_controller/proto.h +++ b/F0:F030,F042,F072/TSYS_controller/proto.h @@ -38,6 +38,15 @@ #define newline() do{bufputchar('\n');}while(0) +extern volatile uint32_t lastTprint; + +// cmdsource: +enum{ + SRC_NONE, + SRC_USB, + SRC_USART +}; + extern uint8_t noLED; void cmd_parser(char *buf, uint8_t isUSB); void addtobuf(const char *txt); diff --git a/F0:F030,F042,F072/TSYS_controller/ringbuffer.c b/F0:F030,F042,F072/TSYS_controller/ringbuffer.c new file mode 100644 index 0000000..d70a9a7 --- /dev/null +++ b/F0:F030,F042,F072/TSYS_controller/ringbuffer.c @@ -0,0 +1,124 @@ +/* + * This file is part of the pl2303 project. + * Copyright 2022 Edward V. Emelianov . + * + * 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 . + */ + +#include "ringbuffer.h" + +// stored data length +int RB_datalen(ringbuffer *b){ + if(b->tail >= b->head) return (b->tail - b->head); + else return (b->length - b->head + b->tail); +} + +/** + * @brief RB_hasbyte - check if buffer has given byte stored + * @param b - buffer + * @param byte - byte to find + * @return index if found, -1 if none + */ +int RB_hasbyte(ringbuffer *b, uint8_t byte){ + if(b->head == b->tail) return -1; // no data in buffer + int startidx = b->head; + if(b->head > b->tail){ // + for(int found = b->head; found < b->length; ++found) + if(b->data[found] == byte) return found; + startidx = 0; + } + for(int found = startidx; found < b->tail; ++found) + if(b->data[found] == byte) return found; + return -1; +} + +// poor memcpy +static void mcpy(uint8_t *targ, const uint8_t *src, int l){ + while(l--) *targ++ = *src++; +} + +// increment head or tail +TRUE_INLINE void incr(ringbuffer *b, volatile int *what, int n){ + *what += n; + if(*what >= b->length) *what -= b->length; +} + +/** + * @brief RB_read - read data from ringbuffer + * @param b - buffer + * @param s - array to write data + * @param len - max len of `s` + * @return bytes read + */ +int RB_read(ringbuffer *b, uint8_t *s, int len){ + int l = RB_datalen(b); + if(!l) return 0; + if(l > len) l = len; + int _1st = b->length - b->head; + if(_1st > l) _1st = l; + if(_1st > len) _1st = len; + mcpy(s, b->data + b->head, _1st); + if(_1st < len && l > _1st){ + mcpy(s+_1st, b->data, l - _1st); + incr(b, &b->head, l); + return l; + } + incr(b, &b->head, _1st); + return _1st; +} + +/** + * @brief RB_readto fill array `s` with data until byte `byte` (with it) + * @param b - ringbuffer + * @param byte - check byte + * @param s - buffer to write data + * @param len - length of `s` + * @return amount of bytes written (negative, if lenhead; + // now calculate length of new data portion + if(idx < b->head) partlen += b->length; + if(partlen > len) return -RB_read(b, s, len); + return RB_read(b, s, partlen); +} + +/** + * @brief RB_write - write some data to ringbuffer + * @param b - buffer + * @param str - data + * @param l - length + * @return amount of bytes written + */ +int RB_write(ringbuffer *b, const uint8_t *str, int l){ + int r = b->length - 1 - RB_datalen(b); // rest length + if(l > r) l = r; + if(!l) return 0; + int _1st = b->length - b->tail; + if(_1st > l) _1st = l; + mcpy(b->data + b->tail, str, _1st); + if(_1st < l){ // add another piece from start + mcpy(b->data, str+_1st, l-_1st); + } + incr(b, &b->tail, l); + return l; +} + +// just delete all information in buffer `b` +void RB_clearbuf(ringbuffer *b){ + b->head = 0; + b->tail = 0; +} diff --git a/F0:F030,F042,F072/TSYS_controller/ringbuffer.h b/F0:F030,F042,F072/TSYS_controller/ringbuffer.h new file mode 100644 index 0000000..2c04863 --- /dev/null +++ b/F0:F030,F042,F072/TSYS_controller/ringbuffer.h @@ -0,0 +1,39 @@ +/* + * This file is part of the pl2303 project. + * Copyright 2022 Edward V. Emelianov . + * + * 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 . + */ + +#pragma once +#ifndef RINGBUFFER_H__ +#define RINGBUFFER_H__ + +#include + +typedef struct{ + uint8_t *data; // data buffer + const int length; // its length + int head; // head index + int tail; // tail index +} ringbuffer; + +int RB_read(ringbuffer *b, uint8_t *s, int len); +int RB_readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len); +int RB_hasbyte(ringbuffer *b, uint8_t byte); +int RB_write(ringbuffer *b, const uint8_t *str, int l); +int RB_datalen(ringbuffer *b); +void RB_clearbuf(ringbuffer *b); + +#endif // RINGBUFFER_H__ diff --git a/F0:F030,F042,F072/TSYS_controller/tsys01.bin b/F0:F030,F042,F072/TSYS_controller/tsys01.bin index b8d41e6..b6c1242 100755 Binary files a/F0:F030,F042,F072/TSYS_controller/tsys01.bin and b/F0:F030,F042,F072/TSYS_controller/tsys01.bin differ diff --git a/F0:F030,F042,F072/TSYS_controller/usart.c b/F0:F030,F042,F072/TSYS_controller/usart.c index 010ef0c..72f7f28 100644 --- a/F0:F030,F042,F072/TSYS_controller/usart.c +++ b/F0:F030,F042,F072/TSYS_controller/usart.c @@ -58,17 +58,20 @@ int usart_getline(char **line){ } TXstatus usart_send(const char *str, int len){ + dma1_channel2_3_isr(); +#ifdef EBUG + USB_sendstr("usart_send()\n"); +#endif if(!txrdy) return LINE_BUSY; if(len > UARTBUFSZ) return STR_TOO_LONG; - txrdy = 0; + for(int i = 0; (i < WAITFOR) && !(USARTX->ISR & USART_ISR_TXE); ++i){IWDG->KR = IWDG_REFRESH;} + if(!(USARTX->ISR & USART_ISR_TXE)) return NO_RECEIVER; #ifdef EBUG - USB_send("\n\n\nUSART send:\n"); - USB_send(str); - USB_send("\n\n"); + USB_sendstr("\n\n\nUSART send:\n"); + USB_sendstr(str); + USB_sendstr("\n\n"); #endif memcpy(tbuf, str, len); - for(int i = 0; (i < WAITFOR) && !(USARTX->ISR & USART_ISR_TXE); ++i){IWDG->KR = IWDG_REFRESH;} - if(!(USARTX->ISR & USART_ISR_TXE)) return LINE_BUSY; #if USARTNUM == 2 DMA1_Channel4->CCR &= ~DMA_CCR_EN; DMA1_Channel4->CNDTR = len; @@ -80,8 +83,9 @@ TXstatus usart_send(const char *str, int len){ #else #error "Not implemented" #endif + txrdy = 0; #ifdef EBUG - USB_send(" -> start transmission\n"); + USB_sendstr(" -> start transmission\n"); #endif return ALL_OK; } @@ -91,19 +95,19 @@ TXstatus usart_send_blocking(const char *str, int len){ bufovr = 0; IWDG->KR = IWDG_REFRESH; for(int i = 0; (i < WAITFOR) && !(USARTX->ISR & USART_ISR_TXE); ++i){IWDG->KR = IWDG_REFRESH;} - if(!(USARTX->ISR & USART_ISR_TXE)) return LINE_BUSY; + if(!(USARTX->ISR & USART_ISR_TXE)) return NO_RECEIVER; #ifdef EBUG - USB_send("\n\n\nUSART send blocking:\n"); - USB_send(str); - USB_send("\n"); + USB_sendstr("\n\n\nUSART send blocking:\n"); + USB_sendstr(str); + USB_sendstr("\n"); #endif for(int l = 0; l < len; ++l){ USARTX -> TDR = *str++; for(int i = 0; (i < WAITFOR) && !(USARTX->ISR & USART_ISR_TXE); ++i){IWDG->KR = IWDG_REFRESH;} - if(!(USARTX->ISR & USART_ISR_TXE)) return LINE_BUSY; + if(!(USARTX->ISR & USART_ISR_TXE)) return NO_RECEIVER; } #ifdef EBUG - USB_send(" -> done\n"); + USB_sendstr(" -> done\n"); #endif return ALL_OK; } @@ -122,9 +126,9 @@ void usart_setup(){ 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, 0); + NVIC_SetPriority(DMA1_Channel4_5_IRQn, 5); NVIC_EnableIRQ(DMA1_Channel4_5_IRQn); - NVIC_SetPriority(USART2_IRQn, 0); + NVIC_SetPriority(USART2_IRQn, 15); // setup usart2 RCC->APB1ENR |= RCC_APB1ENR_USART2EN; // clock // oversampling by16, 115200bps (fck=48mHz) @@ -148,9 +152,9 @@ void usart_setup(){ 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, 0); + NVIC_SetPriority(DMA1_Channel2_3_IRQn, 5); NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); - NVIC_SetPriority(USART1_IRQn, 0); + NVIC_SetPriority(USART1_IRQn, 15); // setup usart1 RCC->APB2ENR |= RCC_APB2ENR_USART1EN; USART1->BRR = 480000 / 1152; @@ -223,7 +227,7 @@ void dma1_channel4_5_isr(){ #elif USARTNUM == 1 void dma1_channel2_3_isr(){ if(DMA1->ISR & DMA_ISR_TCIF2){ // Tx - DMA1_Channel2->CCR &= ~DMA_CCR_EN; // stop DMA + //DMA1_Channel2->CCR &= ~DMA_CCR_EN; // stop DMA DMA1->IFCR |= DMA_IFCR_CTCIF2; // clear TC flag txrdy = 1; } diff --git a/F0:F030,F042,F072/TSYS_controller/usart.h b/F0:F030,F042,F072/TSYS_controller/usart.h index a39593d..82de9cb 100644 --- a/F0:F030,F042,F072/TSYS_controller/usart.h +++ b/F0:F030,F042,F072/TSYS_controller/usart.h @@ -32,12 +32,13 @@ #endif // timeout for cycles -#define WAITFOR (72000000) +#define WAITFOR (7200000) typedef enum{ ALL_OK, LINE_BUSY, - STR_TOO_LONG + STR_TOO_LONG, + NO_RECEIVER } TXstatus; #define usartrx() (linerdy) diff --git a/F0:F030,F042,F072/TSYS_controller/usb.c b/F0:F030,F042,F072/TSYS_controller/usb.c index 2756335..9a83e16 100644 --- a/F0:F030,F042,F072/TSYS_controller/usb.c +++ b/F0:F030,F042,F072/TSYS_controller/usb.c @@ -1,12 +1,10 @@ /* - * geany_encoding=koi8-r - * usb.c - base functions for different USB types + * This file is part of the usbcanrb project. + * Copyright 2023 Edward V. Emelianov . * - * Copyright 2018 Edward V. Emelianov - * - * This program is free software; you can redistribute it and/or modify + * 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 + * 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, @@ -15,159 +13,114 @@ * 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. - * + * along with this program. If not, see . */ #include -#include "usart.h" +#include "hardware.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 -volatile int8_t usbConn = 0; // ==1 when connected -static volatile uint8_t tx_succesfull = 0; +static volatile uint8_t usbbuff[USB_TXBUFSZ]; // temporary buffer for sending data +// ring buffers for incoming and outgoing data +static uint8_t obuf[RBOUTSZ], ibuf[RBINSZ]; +volatile ringbuffer rbout = {.data = obuf, .length = RBOUTSZ, .head = 0, .tail = 0}; +volatile ringbuffer rbin = {.data = ibuf, .length = RBINSZ, .head = 0, .tail = 0}; +// transmission is succesfull +volatile uint8_t bufisempty = 1; +volatile uint8_t bufovrfl = 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); +void send_next(){ + if(bufisempty) return; + static int lastdsz = 0; + int buflen = RB_read((ringbuffer*)&rbout, (uint8_t*)usbbuff, USB_TXBUFSZ); + if(!buflen){ + if(lastdsz == 64) EP_Write(3, NULL, 0); // send ZLP after 64 bits packet when nothing more to send + lastdsz = 0; + bufisempty = 1; + return; } - return ep.status; + EP_Write(3, (uint8_t*)usbbuff, buflen); + lastdsz = buflen; } -// 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; - } +// blocking send full content of ring buffer +int USB_sendall(){ + while(!bufisempty){ + if(!usbON) return 0; + } + return 1; +} + +// put `buf` into queue to send +int USB_send(const uint8_t *buf, int len){ + if(!buf || !usbON || !len) return 0; + while(len){ + int a = RB_write((ringbuffer*)&rbout, buf, len); + len -= a; + buf += a; + if(bufisempty){ + bufisempty = 0; + send_next(); } - 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; + return 1; } -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; +int USB_putbyte(uint8_t byte){ + if(!usbON) return 0; + while(0 == RB_write((ringbuffer*)&rbout, &byte, 1)){ + if(bufisempty){ + bufisempty = 0; + send_next(); } - }else{ - usbON = 0; } + return 1; } -void USB_send(const char *buf){ - if(!usbConn) return; - 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; - } +int USB_sendstr(const char *string){ + if(!string || !usbON) return 0; + int len = 0; + const char *b = string; + while(*b++) ++len; + if(!len) return 0; + return USB_send((const uint8_t*)string, len); } /** - * @brief USB_receive - read first received text string + * @brief USB_receive - get binary data from receiving ring-buffer * @param buf (i) - buffer for received data - * @param bufsize - its size - * @return amount of received bytes + * @param len - length of `buf` + * @return amount of received bytes (negative, if overfull happened) */ -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; - } +int USB_receive(uint8_t *buf, int len){ + int sz = RB_read((ringbuffer*)&rbin, buf, len); + if(bufovrfl){ + RB_clearbuf((ringbuffer*)&rbin); + if(!sz) sz = -1; + else sz = -sz; + bufovrfl = 0; } - if(i == idatalen || stlen == 0) return 0; - USB->CNTR = 0; - int sz = (stlen > bufsize) ? bufsize : stlen, rest = idatalen - sz; - memcpy(buf, incoming_data, sz); - buf[sz] = 0; - 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; -}*/ + * @brief USB_receivestr - get string up to '\n' and replace '\n' with 0 + * @param buf - receiving buffer + * @param len - its length + * @return strlen or negative value indicating overflow (if so, string won't be ends with 0 and buffer should be cleared) + */ +int USB_receivestr(char *buf, int len){ + int l = RB_readto((ringbuffer*)&rbin, '\n', (uint8_t*)buf, len); + if(l == 0) return 0; + if(--l < 0 || bufovrfl) RB_clearbuf((ringbuffer*)&rbin); + else buf[l] = 0; // replace '\n' with strend + if(bufovrfl){ + if(l > 0) l = -l; + else l = -1; + bufovrfl = 0; + } + return l; +} + diff --git a/F0:F030,F042,F072/TSYS_controller/usb.h b/F0:F030,F042,F072/TSYS_controller/usb.h index 00c5c0a..43dae6e 100644 --- a/F0:F030,F042,F072/TSYS_controller/usb.h +++ b/F0:F030,F042,F072/TSYS_controller/usb.h @@ -1,12 +1,10 @@ /* - * geany_encoding=koi8-r - * usb.h + * This file is part of the usbcanrb project. + * Copyright 2023 Edward V. Emelianov . * - * Copyright 2018 Edward V. Emelianov - * - * This program is free software; you can redistribute it and/or modify + * 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 + * 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, @@ -15,23 +13,36 @@ * 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. - * + * along with this program. If not, see . */ + #pragma once -#ifndef __USB_H__ -#define __USB_H__ -#include "hardware.h" +#include "ringbuffer.h" +#include "usbhw.h" -#define BUFFSIZE (64) +// sizes of ringbuffers for outgoing and incoming data +#define RBOUTSZ (512) +#define RBINSZ (512) -void USB_setup(); -void usb_proc(); -void USB_send(const char *buf); -int USB_receive(char *buf, int bufsize); -//int USB_configured(); +#define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0) -#endif // __USB_H__ +#define STR_HELPER(s) #s +#define STR(s) STR_HELPER(s) + +#ifdef EBUG +#define DBG(str) do{USB_sendstr(__FILE__ " (L" STR(__LINE__) "): " str); newline();}while(0) +#else +#define DBG(str) +#endif + +extern volatile ringbuffer rbout, rbin; +extern volatile uint8_t bufisempty, bufovrfl; + +void send_next(); +int USB_sendall(); +int USB_send(const uint8_t *buf, int len); +int USB_putbyte(uint8_t byte); +int USB_sendstr(const char *string); +int USB_receive(uint8_t *buf, int len); +int USB_receivestr(char *buf, int len); diff --git a/F0:F030,F042,F072/TSYS_controller/usb_lib.c b/F0:F030,F042,F072/TSYS_controller/usb_lib.c index 111a4ed..06e9f86 100644 --- a/F0:F030,F042,F072/TSYS_controller/usb_lib.c +++ b/F0:F030,F042,F072/TSYS_controller/usb_lib.c @@ -1,12 +1,10 @@ /* - * geany_encoding=koi8-r - * usb_lib.c + * This file is part of the usbcanrb project. + * Copyright 2023 Edward V. Emelianov . * - * Copyright 2018 Edward V. Emelianov - * - * This program is free software; you can redistribute it and/or modify + * 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 + * 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, @@ -15,36 +13,25 @@ * 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. - * + * along with this program. If not, see . */ -#include // memcpy - -#include "stm32f0.h" -#include "usart.h" +#include +#include "usb.h" #include "usb_lib.h" +#include "usbhw.h" -#ifdef EBUG -#include "usart.h" -#define MSG(x) do{usart_send(x, sizeof(x));}while(0) -#else -#define MSG(x) -#endif +ep_t endpoints[STM32ENDPOINTS]; - -ep_t endpoints[ENDPOINTS_NUM]; - -static usb_dev_t USB_Dev; +static uint16_t USB_Addr = 0; 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; +uint8_t ep0databuf[EP0DATABUF_SIZE], setupdatabuf[EP0DATABUF_SIZE]; +config_pack_t *setup_packet = (config_pack_t*) setupdatabuf; usb_LineCoding getLineCoding(){return lineCoding;} +volatile uint8_t usbON = 0; // device disconnected from terminal + // definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor #define bcdUSB_L 0x10 #define bcdUSB_H 0x01 @@ -68,9 +55,9 @@ static const uint8_t USB_DeviceDescriptor[] = { 0x23, // idProduct_H 0x00, // bcdDevice_Ver_L 0x03, // bcdDevice_Ver_H - 0x01, // iManufacturer - 0x02, // iProduct - 0x00, // iSerialNumber + iMANUFACTURER_DESCR, // iManufacturer + iPRODUCT_DESCR, // iProduct + iSERIAL_DESCR, // iSerialNumber bNumConfigurations // bNumConfigurations }; @@ -110,7 +97,7 @@ static const uint8_t USB_ConfigDescriptor[] = { 0xff, /* bInterfaceClass */ 0x00, /* bInterfaceSubClass */ 0x00, /* bInterfaceProtocol */ - 0x00, /* iInterface: */ + iINTERFACE_DESCR, /* iInterface: */ /////////////////////////////////////////////////// /*Endpoint 1 Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ @@ -140,35 +127,39 @@ static const uint8_t USB_ConfigDescriptor[] = { 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"); +_USB_LANG_ID_(LD, LANG_US); +_USB_STRING_(SD, u"0.0.1"); +_USB_STRING_(MD, u"Prolific Technology Inc."); +_USB_STRING_(PD, u"USB-Serial Controller"); +_USB_STRING_(ID, u"termocontroller"); +static void const *StringDescriptor[iDESCR_AMOUNT] = { + [iLANGUAGE_DESCR] = &LD, + [iMANUFACTURER_DESCR] = &MD, + [iPRODUCT_DESCR] = &PD, + [iSERIAL_DESCR] = &SD, + [iINTERFACE_DESCR] = &ID +}; + /* * 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){ + uint16_t c; if(packet->bmRequestType & 0x80){ // read - //SEND("Read"); - uint8_t c; switch(packet->wValue){ case 0x8484: c = 2; @@ -182,57 +173,67 @@ void WEAK vendor_handler(config_pack_t *packet){ default: c = 0; } - EP_WriteIRQ(0, &c, 1); + EP_WriteIRQ(0, (uint8_t*)&c, 1); }else{ // write ZLP - //SEND("Write"); - EP_WriteIRQ(0, (uint8_t *)0, 0); + c = 0; + EP_WriteIRQ(0, (uint8_t *)&c, 0); } - /*SEND(" vendor, reqt="); - printuhex(packet->bmRequestType); - SEND(", wval="); - printuhex(packet->wValue); - usart_putchar('\n');*/ } - static void wr0(const uint8_t *buf, uint16_t size){ - if(setup_packet.wLength < size) size = setup_packet.wLength; - EP_WriteIRQ(0, buf, size); + if(setup_packet->wLength < size) size = setup_packet->wLength; // shortened request + if(size < endpoints[0].txbufsz){ + EP_WriteIRQ(0, buf, size); + return; + } + while(size){ + uint16_t l = size; + if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz; + EP_WriteIRQ(0, buf, l); + buf += l; + size -= l; + uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0; + if(size || needzlp){ // send last data buffer + uint16_t status = KEEP_DTOG(USB->EPnR[0]); + // keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx + USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX)) + ^ USB_EPnR_STAT_TX; + uint32_t ctr = 1000000; + while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;}; + if((USB->ISTR & USB_ISTR_CTR) == 0){ + return; + } + if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0); + } + } } static inline void get_descriptor(){ - switch(setup_packet.wValue){ + uint8_t descrtype = setup_packet->wValue >> 8, + descridx = setup_packet->wValue & 0xff; + switch(descrtype){ 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); + case STRING_DESCRIPTOR: + if(descridx < iDESCR_AMOUNT) wr0((const uint8_t *)StringDescriptor[descridx], *((uint8_t*)StringDescriptor[descridx])); + else EP_WriteIRQ(0, (uint8_t*)0, 0); break; case DEVICE_QUALIFIER_DESCRIPTOR: wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]); break; default: - break; } } -static uint8_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured) +static uint16_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){ + switch(setup_packet->bRequest){ case GET_DESCRIPTOR: get_descriptor(); break; @@ -240,31 +241,60 @@ static inline void std_d2h_req(){ EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered break; case GET_CONFIGURATION: - EP_WriteIRQ(0, &configuration, 1); + EP_WriteIRQ(0, (uint8_t*)&configuration, 1); break; default: break; } } +// interrupt IN handler (never used?) +static void EP1_Handler(){ + uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]); + if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX + else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX); + // clear CTR + epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)); + USB->EPnR[1] = epstatus; +} + +// data IN/OUT handlers +static void transmit_Handler(){ // EP3IN + uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[3]); + // clear CTR keep DTOGs & STATs + USB->EPnR[3] = (epstatus & ~(USB_EPnR_CTR_TX)); // clear TX ctr + send_next(); +} + +static void receive_Handler(){ // EP2OUT + uint8_t buf[USB_RXBUFSZ]; + uint16_t epstatus = KEEP_DTOG(USB->EPnR[2]); + uint8_t sz = EP_Read(2, (uint8_t*)buf); + if(sz){ + if(RB_write((ringbuffer*)&rbin, buf, sz) != sz) bufovrfl = 1; + } + // keep stat_tx & set ACK rx, clear RX ctr + USB->EPnR[2] = (epstatus & ~USB_EPnR_CTR_RX) ^ USB_EPnR_STAT_RX; +} + static inline void std_h2d_req(){ - switch(setup_packet.bRequest){ + 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; + USB_Addr = setup_packet->wValue; break; case SET_CONFIGURATION: // Now device configured - USB_Dev.USB_Status = USB_CONFIGURE_STATE; - configuration = setup_packet.wValue; + configuration = setup_packet->wValue; + EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit + EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data + EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data break; default: break; } } - -extern volatile int8_t usbConn; /* bmRequestType: 76543210 7 direction: 0 - host->device, 1 - device->host @@ -273,186 +303,71 @@ bmRequestType: 76543210 */ /** * 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)){ +void EP0_Handler(){ + uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications + uint8_t reqtype = setup_packet->bmRequestType & 0x7f; + uint8_t dev2host = (setup_packet->bmRequestType & 0x80) ? 1 : 0; + int rxflag = RX_FLAG(epstatus); + if(rxflag && SETUP_FLAG(epstatus)){ switch(reqtype){ case STANDARD_DEVICE_REQUEST_TYPE: // standard device request if(dev2host){ std_d2h_req(); }else{ std_h2d_req(); - // 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 + if(setup_packet->bRequest == CLEAR_FEATURE){ EP_WriteIRQ(0, (uint8_t *)0, 0); - epstatus = SET_NAK_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); } break; case VENDOR_REQUEST_TYPE: - vendor_handler(&setup_packet); - epstatus = SET_NAK_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); + vendor_handler(setup_packet); break; case CONTROL_REQUEST_TYPE: - switch(setup_packet.bRequest){ + 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); + usbON = 1; + clstate_handler(setup_packet->wValue); break; case SEND_BREAK: + usbON = 0; break_handler(); - usbConn = 0; break; default: break; } - if(!dev2host) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement - epstatus = SET_VALID_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); + if(setup_packet->bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement break; default: EP_WriteIRQ(0, (uint8_t *)0, 0); - 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){ + }else if(rxflag){ // got data over EP0 or host acknowlegement + if(endpoints[0].rx_cnt){ + if(setup_packet->bRequest == SET_LINE_CODING){ linecoding_handler((usb_LineCoding*)ep0databuf); - usbConn = 1; // now we can transmit data: computer have stable connection } } - // 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 + } else if(TX_FLAG(epstatus)){ // package transmitted // now we can change address after enumeration - if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){ - USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr; - // change state to ADRESSED - USB_Dev.USB_Status = USB_ADRESSED_STATE; + if ((USB->DADDR & USB_DADDR_ADD) != USB_Addr){ + USB->DADDR = USB_DADDR_EF | USB_Addr; + usbON = 0; } - // end of transaction - epstatus = CLEAR_DTOG_RX(epstatus); - epstatus = CLEAR_DTOG_TX(epstatus); - epstatus = SET_VALID_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); - } - return epstatus; -} - -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; } + epstatus = KEEP_DTOG(USB->EPnR[0]); + if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP/data transmission + else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged + // keep DTOGs, clear CTR_RX,TX, set RX VALID + USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX; } /** @@ -462,14 +377,24 @@ void usb_isr(){ * @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; + if(size > endpoints[number].txbufsz) size = endpoints[number].txbufsz; uint16_t N2 = (size + 1) >> 1; // the buffer is 16-bit, so we should copy data as it would be uint16_t uint16_t *buf16 = (uint16_t *)buf; - for (i = 0; i < N2; i++){ +#if defined USB1_16 + // very bad: what if `size` is odd? + uint32_t *out = (uint32_t *)endpoints[number].tx_buf; + for(int i = 0; i < N2; ++i, ++out){ + *out = buf16[i]; + } +#elif defined USB2_16 + // use memcpy instead? + for(int i = 0; i < N2; i++){ endpoints[number].tx_buf[i] = buf16[i]; } +#else +#error "Define USB1_16 or USB2_16" +#endif USB_BTABLE->EP[number].USB_COUNT_TX = size; } @@ -480,13 +405,10 @@ void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){ * @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; + uint16_t status = KEEP_DTOG(USB->EPnR[number]); + // keep DTOGs, clear CTR_TX & set TX VALID to start transmission + USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX; } /* @@ -495,15 +417,22 @@ void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){ * @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; + int sz = endpoints[number].rx_cnt; + if(!sz) return 0; + endpoints[number].rx_cnt = 0; +#if defined USB1_16 + int n = (sz + 1) >> 1; + uint32_t *in = (uint32_t*)endpoints[number].rx_buf; + uint16_t *out = (uint16_t*)buf; + for(int i = 0; i < n; ++i, ++in) + out[i] = *(uint16_t*)in; +#elif defined USB2_16 + // use memcpy instead? + for(int i = 0; i < sz; ++i) + buf[i] = endpoints[number].rx_buf[i]; +#else +#error "Define USB1_16 or USB2_16" +#endif + return sz; } -// USB status -uint8_t USB_GetState(){ - return USB_Dev.USB_Status; -} diff --git a/F0:F030,F042,F072/TSYS_controller/usb_lib.h b/F0:F030,F042,F072/TSYS_controller/usb_lib.h index 0651e5f..8bfe48a 100644 --- a/F0:F030,F042,F072/TSYS_controller/usb_lib.h +++ b/F0:F030,F042,F072/TSYS_controller/usb_lib.h @@ -1,12 +1,10 @@ /* - * geany_encoding=koi8-r - * usb_lib.h + * This file is part of the usbcanrb project. + * Copyright 2023 Edward V. Emelianov . * - * Copyright 2018 Edward V. Emelianov - * - * This program is free software; you can redistribute it and/or modify + * 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 + * 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, @@ -15,23 +13,17 @@ * 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. - * + * along with this program. If not, see . */ #pragma once -#ifndef __USB_LIB_H__ -#define __USB_LIB_H__ #include -#include "usb_defs.h" +#include "usbhw.h" #define EP0DATABUF_SIZE (64) +#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8) -// Max EP amount (EP0 + other used) -#define ENDPOINTS_NUM 4 // bmRequestType & 0x7f #define STANDARD_DEVICE_REQUEST_TYPE 0 #define STANDARD_ENDPOINT_REQUEST_TYPE 2 @@ -68,40 +60,29 @@ #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 +// string descriptors +enum{ + iLANGUAGE_DESCR, + iMANUFACTURER_DESCR, + iPRODUCT_DESCR, + iSERIAL_DESCR, + iINTERFACE_DESCR, + iDESCR_AMOUNT +}; + +// Types of descriptors +#define DEVICE_DESCRIPTOR 0x01 +#define CONFIGURATION_DESCRIPTOR 0x02 +#define STRING_DESCRIPTOR 0x03 +#define DEVICE_QUALIFIER_DESCRIPTOR 0x06 + +#define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX) +#define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX) +#define SETUP_FLAG(epstat) (epstat & USB_EPnR_SETUP) // EPnR bits manipulation -#define 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 +#define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) +#define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) // EP types #define EP_TYPE_BULK 0x00 @@ -131,7 +112,6 @@ static const struct name \ \ } \ name = {0x04, 0x03, lng_id} -#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4) // EP0 configuration packet typedef struct { @@ -143,23 +123,14 @@ typedef struct { } config_pack_t; // endpoints state -typedef struct __ep_t{ +typedef struct{ uint16_t *tx_buf; // transmission buffer address + uint16_t txbufsz; // transmission buffer size uint8_t *rx_buf; // reception buffer address - uint16_t (*func)(); // endpoint action function - uint16_t status; // status flags + void (*func)(); // endpoint action function 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; @@ -184,19 +155,18 @@ typedef struct { } __attribute__ ((packed)) usb_cdc_notification; extern ep_t endpoints[]; +extern volatile uint8_t usbON; +extern config_pack_t *setup_packet; +extern uint8_t ep0databuf[], setupdatabuf[]; + +void EP0_Handler(); -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__ +void linecoding_handler(usb_LineCoding *lc); +void clstate_handler(uint16_t val); +void break_handler(); +void vendor_handler(config_pack_t *packet); diff --git a/F0:F030,F042,F072/TSYS_controller/usbhw.c b/F0:F030,F042,F072/TSYS_controller/usbhw.c new file mode 100644 index 0000000..345138c --- /dev/null +++ b/F0:F030,F042,F072/TSYS_controller/usbhw.c @@ -0,0 +1,127 @@ +/* + * This file is part of the usbcanrb project. + * Copyright 2023 Edward V. Emelianov . + * + * 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 . + */ + +#include "usb.h" +#include "usb_lib.h" + +// here we suppose that all PIN settings done in hw_setup earlier +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;} + 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 WKUPM interrupts + USB->CNTR = USB_CNTR_RESETM | USB_CNTR_WKUPM; + // clear flags + USB->ISTR = 0; + // and activate pullup + USB->BCDR |= USB_BCDR_DPPU; + NVIC_EnableIRQ(USB_IRQn); +} + +static uint16_t lastaddr = LASTADDR_DEFAULT; +/** + * Endpoint initialisation + * @param number - EP num (0...7) + * @param type - EP type (EP_TYPE_BULK, EP_TYPE_CONTROL, EP_TYPE_ISO, EP_TYPE_INTERRUPT) + * @param txsz - transmission buffer size @ USB/CAN buffer + * @param rxsz - reception buffer size @ USB/CAN buffer + * @param uint16_t (*func)(ep_t *ep) - EP handler function + * @return 0 if all OK + */ +int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)(ep_t ep)){ + if(number >= STM32ENDPOINTS) return 4; // out of configured amount + if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large + if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE) return 2; // out of btable + USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA); + USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1; + if(rxsz & 1 || rxsz > 512) return 3; // wrong rx buffer size + uint16_t countrx = 0; + if(rxsz < 64) countrx = rxsz / 2; + else{ + if(rxsz & 0x1f) return 3; // should be multiple of 32 + countrx = 31 + rxsz / 32; + } + USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr; + endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr * ACCESSZ); + endpoints[number].txbufsz = txsz; + lastaddr += txsz; + USB_BTABLE->EP[number].USB_COUNT_TX = 0; + USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr; + endpoints[number].rx_buf = (uint8_t *)(USB_BTABLE_BASE + lastaddr * ACCESSZ); + lastaddr += rxsz; + USB_BTABLE->EP[number].USB_COUNT_RX = countrx << 10; + endpoints[number].func = func; + return 0; +} + +// standard IRQ handler (just rename it due to MCU model) +void usb_isr(){ + if(USB->ISTR & USB_ISTR_RESET){ + usbON = 0; + // Reinit registers + USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; + // Endpoint 0 - CONTROL + // ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes! + lastaddr = LASTADDR_DEFAULT; + // clear address, leave only enable bit + USB->DADDR = USB_DADDR_EF; + if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler)){ + return; + } + USB->ISTR = ~USB_ISTR_RESET; + } + if(USB->ISTR & USB_ISTR_CTR){ + // EP number + uint8_t n = USB->ISTR & USB_ISTR_EPID; + // copy status register + uint16_t epstatus = USB->EPnR[n]; + // copy received bytes amount + endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter + // check direction + if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit) + if(n == 0){ // control endpoint + if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack + EP_Read(0, setupdatabuf); + // interrupt handler will be called later + }else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf + EP_Read(0, ep0databuf); + } + } + } + // call EP handler + if(endpoints[n].func) endpoints[n].func(endpoints[n]); + } + if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep + usbON = 0; + USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LPMODE; + USB->ISTR = ~USB_ISTR_SUSP; + } + if(USB->ISTR & USB_ISTR_WKUP){ // wakeup + USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LPMODE); // clear suspend flags + USB->ISTR = ~USB_ISTR_WKUP; + } +} + diff --git a/F0:F030,F042,F072/TSYS_controller/usb_defs.h b/F0:F030,F042,F072/TSYS_controller/usbhw.h similarity index 67% rename from F0:F030,F042,F072/TSYS_controller/usb_defs.h rename to F0:F030,F042,F072/TSYS_controller/usbhw.h index 6ac673c..14d40d1 100644 --- a/F0:F030,F042,F072/TSYS_controller/usb_defs.h +++ b/F0:F030,F042,F072/TSYS_controller/usbhw.h @@ -1,12 +1,10 @@ /* - * geany_encoding=koi8-r - * usb_defs.h + * This file is part of the usbcanrb project. + * Copyright 2023 Edward V. Emelianov . * - * Copyright 2018 Edward V. Emelianov - * - * This program is free software; you can redistribute it and/or modify + * 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 + * 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, @@ -15,34 +13,36 @@ * 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. - * + * along with this program. If not, see . */ #pragma once -#ifndef __USB_DEFS_H__ -#define __USB_DEFS_H__ -#include +#include +// max endpoints number +#define STM32ENDPOINTS 8 /** * Buffers size definition **/ -// !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!! -#define USB_BTABLE_SIZE 1024 +#define USB_BTABLE_SIZE 768 // first 64 bytes of USB_BTABLE are registers! -#define USB_EP0_BASEADDR 64 +//#define USB_EP0_BASEADDR 64 // for USB FS EP0 buffers are from 8 to 64 bytes long (64 for PL2303) #define USB_EP0_BUFSZ 64 // USB transmit buffer size (64 for PL2303) #define USB_TXBUFSZ 64 // USB receive buffer size (64 for PL2303) #define USB_RXBUFSZ 64 +// EP1 - interrupt - buffer size +#define USB_EP1BUFSZ 8 #define USB_BTABLE_BASE 0x40006000 +#define USB ((USB_TypeDef *) USB_BASE) + +#ifdef USB_BTABLE #undef USB_BTABLE +#endif #define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE)) #define USB_ISTR_EPID 0x0000000F #define USB_FNR_LSOF_0 0x00000800 @@ -73,16 +73,9 @@ #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; +typedef struct { + __IO uint32_t EPnR[STM32ENDPOINTS]; + __IO uint32_t RESERVED[STM32ENDPOINTS]; __IO uint32_t CNTR; __IO uint32_t ISTR; __IO uint32_t FNR; @@ -92,15 +85,31 @@ typedef struct{ __IO uint32_t BCDR; } USB_TypeDef; +// F303 D/E have 2x16 access scheme typedef struct{ +#if defined USB2_16 __IO uint16_t USB_ADDR_TX; __IO uint16_t USB_COUNT_TX; __IO uint16_t USB_ADDR_RX; __IO uint16_t USB_COUNT_RX; +#define ACCESSZ (1) +#define BUFTYPE uint8_t +#elif defined USB1_16 + __IO uint32_t USB_ADDR_TX; + __IO uint32_t USB_COUNT_TX; + __IO uint32_t USB_ADDR_RX; + __IO uint32_t USB_COUNT_RX; +#define ACCESSZ (2) +#define BUFTYPE uint16_t +#else +#error "Define USB1_16 or USB2_16" +#endif } USB_EPDATA_TypeDef; + typedef struct{ - __IO USB_EPDATA_TypeDef EP[8]; + __IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS]; } USB_BtableDef; -#endif // __USB_DEFS_H__ +void USB_setup(); +int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)()); diff --git a/F0:F030,F042,F072/TSYS_controller/version.inc b/F0:F030,F042,F072/TSYS_controller/version.inc index 55ef795..a2db9fe 100644 --- a/F0:F030,F042,F072/TSYS_controller/version.inc +++ b/F0:F030,F042,F072/TSYS_controller/version.inc @@ -1,3 +1,3 @@ -#define BUILD_NUMBER "90" -#define BUILD_DATE "2023-09-15" -#define BUILDNO 91 +#define BUILD_NUMBER "130" +#define BUILD_DATE "2023-09-29" +#define BUILDNO 130