diff --git a/F1:F103/BISS_C_encoders/encoders.creator.user.cf63021 b/F1:F103/BISS_C_encoders/encoders.creator.user.cf63021
new file mode 100644
index 0000000..48b5440
--- /dev/null
+++ b/F1:F103/BISS_C_encoders/encoders.creator.user.cf63021
@@ -0,0 +1,184 @@
+
+
+
+
+
+ EnvironmentId
+ {cf63021e-ef53-49b0-b03b-2f2570cdf3b6}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ true
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ KOI8-R
+ false
+ 4
+ false
+ 0
+ 80
+ true
+ true
+ 1
+ 0
+ false
+ false
+ false
+ 1
+ true
+ true
+ 0
+ 8
+ true
+ false
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ true
+ true
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ false
+ true
+ true
+ true
+ true
+
+ false
+
+
+ 0
+ true
+
+ true
+ true
+ Builtin.DefaultTidyAndClazy
+ 4
+ true
+
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop
+ Desktop
+ {91347f2c-5221-46a7-80b1-0a054ca02f79}
+ 0
+ 0
+ 0
+
+ /home/eddy/Docs/SAO/ELECTRONICS/STM32/F1-srcs/BISS_C_encoders
+
+
+
+ all
+
+ true
+ GenericProjectManager.GenericMakeStep
+
+ 1
+ Сборка
+ Сборка
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+ clean
+
+ true
+ GenericProjectManager.GenericMakeStep
+
+ 1
+ Очистка
+ Очистка
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ По умолчанию
+ GenericProjectManager.GenericBuildConfiguration
+
+ 1
+
+
+ 0
+ Развёртывание
+ Развёртывание
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ true
+ true
+ 0
+ true
+
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+
+ ProjectExplorer.CustomExecutableRunConfiguration
+
+ false
+ true
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/F3:F303/Readme.md b/F3:F303/Readme.md
index 9008d48..2cd20f3 100644
--- a/F3:F303/Readme.md
+++ b/F3:F303/Readme.md
@@ -1,7 +1,7 @@
Samples for STM32F303
=================================
-Most of these samples works with [my non-solder devboard](https://github.com/eddyem/stm32samples/tree/master/F0_F1_F3-LQFP48_testboard)
+Some simplest of these samples works with [my non-solder devboard](https://github.com/eddyem/stm32samples/tree/master/F0_F1_F3-LQFP48_testboard)
- **ADC** - work with ADC
- **blink** - simple LEDs blink on PB0 and PB1
@@ -10,9 +10,10 @@ Most of these samples works with [my non-solder devboard](https://github.com/edd
- **I2C_scan** - simple I2C scanner
- **Multistepper** - stepper motor controller (8 independend motors or up to 64 multiplexed)
- **NitrogenFlooding** - automatic nitrogen flooding
-- **PL2303** - emulates PL2303
+- **PL2303** - emulates PL2303 (old concept)
- **Seven_CDCs** - 7 CDCs in one device
- **usart1** - read data from USART1 and send it back (blocking sending)
- **usart1fullDMA** - USART1 Rx and Tx DMA access (Rx terminated by character match of '\n' or buffer overflow).
- **usarts** - work with all three USARTs with Tx DMA, send to USART1 data read from other, you can send "2\n" or "3\n" to USART1 for tests of USART2/USART3
-- **USB_template** - old USB template
+- **USB_template** - old USB PL2303 template
+- **USB_template_CDC** - new USB-CDC template
diff --git a/F3:F303/USB_template_CDC/Makefile b/F3:F303/USB_template_CDC/Makefile
new file mode 100644
index 0000000..838e7c5
--- /dev/null
+++ b/F3:F303/USB_template_CDC/Makefile
@@ -0,0 +1,9 @@
+BINARY := usbtemplate
+# MCU code
+MCU := F303xb
+# change this linking script depending on particular MCU model,
+LDSCRIPT := stm32f303xB.ld
+DEFINES := -DUSB1_16
+
+include ../makefile.f3
+include ../../makefile.stm32
diff --git a/F3:F303/USB_template_CDC/hardware.c b/F3:F303/USB_template_CDC/hardware.c
new file mode 100644
index 0000000..d1c02e4
--- /dev/null
+++ b/F3:F303/USB_template_CDC/hardware.c
@@ -0,0 +1,16 @@
+#include "hardware.h"
+
+static inline void gpio_setup(){
+ RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; // for USART and LEDs
+ for(int i = 0; i < 10000; ++i) nop();
+ // USB - alternate function 14 @ pins PA11/PA12; SWD - AF0 @PA13/14
+ GPIOA->AFR[1] = AFRf(14, 11) | AFRf(14, 12);
+ GPIOA->MODER = MODER_AF(11) | MODER_AF(12) | MODER_AF(13) | MODER_AF(14) | MODER_O(15);
+ GPIOB->MODER = MODER_O(0) | MODER_O(1);
+ GPIOB->ODR = 1;
+}
+
+void hw_setup(){
+ gpio_setup();
+}
+
diff --git a/F3:F303/USB_template_CDC/hardware.h b/F3:F303/USB_template_CDC/hardware.h
new file mode 100644
index 0000000..16c71e9
--- /dev/null
+++ b/F3:F303/USB_template_CDC/hardware.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include
+
+#define USBPU_port GPIOA
+#define USBPU_pin (1<<15)
+#define USBPU_ON() pin_clear(USBPU_port, USBPU_pin)
+#define USBPU_OFF() pin_set(USBPU_port, USBPU_pin)
+
+extern volatile uint32_t Tms;
+
+void hw_setup();
+
diff --git a/F3:F303/USB_template_CDC/main.c b/F3:F303/USB_template_CDC/main.c
new file mode 100644
index 0000000..6ea66fa
--- /dev/null
+++ b/F3:F303/USB_template_CDC/main.c
@@ -0,0 +1,38 @@
+#include "hardware.h"
+#include "proto.h"
+#include "usb_dev.h"
+
+#define MAXSTRLEN RBINSZ
+
+volatile uint32_t Tms = 0;
+
+void sys_tick_handler(void){
+ ++Tms;
+}
+
+int main(void){
+ char inbuff[MAXSTRLEN+1];
+ if(StartHSE()){
+ SysTick_Config((uint32_t)72000); // 1ms
+ }else{
+ StartHSI();
+ SysTick_Config((uint32_t)48000); // 1ms
+ }
+ hw_setup();
+ USBPU_OFF();
+ USB_setup();
+ uint32_t ctr = Tms;
+ USBPU_ON();
+ while(1){
+ if(Tms - ctr > 499){
+ ctr = Tms;
+ pin_toggle(GPIOB, 1 << 1 | 1 << 0); // toggle LED @ PB0
+ }
+ int l = USB_receivestr(inbuff, MAXSTRLEN);
+ if(l < 0) USB_sendstr("ERROR: USB buffer overflow or string was too long\n");
+ else if(l){
+ const char *ans = parse_cmd(inbuff);
+ if(ans) USB_sendstr(ans);
+ }
+ }
+}
diff --git a/F3:F303/USB_template_CDC/openocd.cfg b/F3:F303/USB_template_CDC/openocd.cfg
new file mode 100644
index 0000000..56ccc2e
--- /dev/null
+++ b/F3:F303/USB_template_CDC/openocd.cfg
@@ -0,0 +1,119 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# script for stm32f3x family
+
+#
+# stm32 devices support both JTAG and SWD transports.
+#
+source [find interface/stlink-v2-1.cfg]
+source [find target/swj-dp.tcl]
+source [find mem_helper.tcl]
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME stm32f3x
+}
+
+set _ENDIAN little
+
+# Work-area is a space in RAM used for flash programming
+# By default use 16kB
+if { [info exists WORKAREASIZE] } {
+ set _WORKAREASIZE $WORKAREASIZE
+} else {
+ set _WORKAREASIZE 0x4000
+}
+
+# JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz
+#
+# Since we may be running of an RC oscilator, we crank down the speed a
+# bit more to be on the safe side. Perhaps superstition, but if are
+# running off a crystal, we can run closer to the limit. Note
+# that there can be a pretty wide band where things are more or less stable.
+adapter speed 1000
+
+adapter srst delay 100
+if {[using_jtag]} {
+ jtag_ntrst_delay 100
+}
+
+#jtag scan chain
+if { [info exists CPUTAPID] } {
+ set _CPUTAPID $CPUTAPID
+} else {
+ if { [using_jtag] } {
+ # See STM Document RM0316
+ # Section 29.6.3 - corresponds to Cortex-M4 r0p1
+ set _CPUTAPID 0x4ba00477
+ } {
+ set _CPUTAPID 0x2ba01477
+ }
+}
+
+swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
+dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+
+if {[using_jtag]} {
+ jtag newtap $_CHIPNAME bs -irlen 5
+}
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap
+
+$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
+
+set _FLASHNAME $_CHIPNAME.flash
+flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME
+
+reset_config srst_nogate
+
+if {![using_hla]} {
+ # if srst is not fitted use SYSRESETREQ to
+ # perform a soft reset
+ cortex_m reset_config sysresetreq
+}
+
+proc stm32f3x_default_reset_start {} {
+ # Reset clock is HSI (8 MHz)
+ adapter speed 1000
+}
+
+proc stm32f3x_default_examine_end {} {
+ # Enable debug during low power modes (uses more power)
+ mmw 0xe0042004 0x00000007 0 ;# DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP
+
+ # Stop watchdog counters during halt
+ mmw 0xe0042008 0x00001800 0 ;# DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP
+}
+
+proc stm32f3x_default_reset_init {} {
+ # Configure PLL to boost clock to HSI x 8 (64 MHz)
+ mww 0x40021004 0x00380400 ;# RCC_CFGR = PLLMUL[3:1] | PPRE1[2]
+ mmw 0x40021000 0x01000000 0 ;# RCC_CR |= PLLON
+ mww 0x40022000 0x00000012 ;# FLASH_ACR = PRFTBE | LATENCY[1]
+ sleep 10 ;# Wait for PLL to lock
+ mmw 0x40021004 0x00000002 0 ;# RCC_CFGR |= SW[1]
+
+ # Boost JTAG frequency
+ adapter speed 8000
+}
+
+# Default hooks
+$_TARGETNAME configure -event examine-end { stm32f3x_default_examine_end }
+$_TARGETNAME configure -event reset-start { stm32f3x_default_reset_start }
+$_TARGETNAME configure -event reset-init { stm32f3x_default_reset_init }
+
+tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000
+
+lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu
+proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} {
+ targets $_targetname
+
+ # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync
+ # change this value accordingly to configure trace pins
+ # assignment
+ mmw 0xe0042004 0x00000020 0
+}
+
+$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME"
diff --git a/F3:F303/USB_template_CDC/proto.c b/F3:F303/USB_template_CDC/proto.c
new file mode 100644
index 0000000..7864c69
--- /dev/null
+++ b/F3:F303/USB_template_CDC/proto.c
@@ -0,0 +1,53 @@
+#include
+#include
+
+#include "strfunc.h"
+#include "usb_dev.h"
+#include "version.inc"
+
+//#define LOCBUFFSZ (32)
+// local buffer for I2C data to send
+//static uint8_t locBuffer[LOCBUFFSZ];
+extern volatile uint32_t Tms;
+
+const char *helpstring =
+ "https://github.com/eddyem/stm32samples/tree/master/F3:F303/USB_template build#" BUILD_NUMBER " @ " BUILD_DATE "\n"
+ "T - print current Tms\n"
+;
+/*
+// read N numbers from buf, @return 0 if wrong or none
+TRUE_INLINE uint16_t readNnumbers(const char *buf){
+ uint32_t D;
+ const char *nxt;
+ uint16_t N = 0;
+ while((nxt = getnum(buf, &D)) && nxt != buf && N < LOCBUFFSZ){
+ buf = nxt;
+ locBuffer[N++] = (uint8_t) D&0xff;
+ USND("add byte: "); USND(uhex2str(D&0xff)); USND("\n");
+ }
+ USND("Send "); USND(u2str(N)); USND(" bytes\n");
+ return N;
+}
+*/
+
+
+const char *parse_cmd(const char *buf){
+ // "long" commands
+ /* switch(*buf){
+ case '':
+ break;
+ }*/
+ // "short" commands
+ if(buf[1]) return buf; // echo wrong data
+ switch(*buf){
+ case 'T':
+ USB_sendstr("T=");
+ USB_sendstr(u2str(Tms));
+ newline();
+ break;
+ default: // help
+ USB_sendstr(helpstring);
+ break;
+ }
+ return NULL;
+}
diff --git a/F3:F303/USB_template_CDC/proto.h b/F3:F303/USB_template_CDC/proto.h
new file mode 100644
index 0000000..5c6c029
--- /dev/null
+++ b/F3:F303/USB_template_CDC/proto.h
@@ -0,0 +1,4 @@
+#pragma once
+
+char *parse_cmd(char *buf);
+
diff --git a/F3:F303/USB_template_CDC/ringbuffer.c b/F3:F303/USB_template_CDC/ringbuffer.c
new file mode 100644
index 0000000..b0ffe8e
--- /dev/null
+++ b/F3:F303/USB_template_CDC/ringbuffer.c
@@ -0,0 +1,166 @@
+/*
+ * 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 "ringbuffer.h"
+
+static int datalen(ringbuffer *b){
+ if(b->tail >= b->head) return (b->tail - b->head);
+ else return (b->length - b->head + b->tail);
+}
+
+// stored data length
+int RB_datalen(ringbuffer *b){
+ if(b->busy) return -1;
+ b->busy = 1;
+ int l = datalen(b);
+ b->busy = 0;
+ return l;
+}
+
+static int 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;
+}
+
+/**
+ * @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 or busy
+ */
+int RB_hasbyte(ringbuffer *b, uint8_t byte){
+ if(b->busy) return -1;
+ b->busy = 1;
+ int ret = hasbyte(b, byte);
+ b->busy = 0;
+ return ret;
+}
+
+// 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;
+}
+
+static int read(ringbuffer *b, uint8_t *s, int len){
+ int l = 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_read - read data from ringbuffer
+ * @param b - buffer
+ * @param s - array to write data
+ * @param len - max len of `s`
+ * @return bytes read or -1 if busy
+ */
+int RB_read(ringbuffer *b, uint8_t *s, int len){
+ if(b->busy) return -1;
+ b->busy = 1;
+ int r = read(b, s, len);
+ b->busy = 0;
+ return r;
+}
+
+static int readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len){
+ int idx = hasbyte(b, byte);
+ if(idx < 0) return 0;
+ int partlen = idx + 1 - b->head;
+ // now calculate length of new data portion
+ if(idx < b->head) partlen += b->length;
+ if(partlen > len) return -read(b, s, len);
+ return read(b, s, partlen);
+}
+
+/**
+ * @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 lenbusy) return -1;
+ b->busy = 1;
+ int n = readto(b, byte, s, len);
+ b->busy = 0;
+ return n;
+}
+
+static int write(ringbuffer *b, const uint8_t *str, int l){
+ int r = b->length - 1 - datalen(b); // rest length
+ if(l > r || !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;
+}
+
+/**
+ * @brief RB_write - write some data to ringbuffer
+ * @param b - buffer
+ * @param str - data
+ * @param l - length
+ * @return amount of bytes written or -1 if busy
+ */
+int RB_write(ringbuffer *b, const uint8_t *str, int l){
+ if(b->busy) return -1;
+ b->busy = 1;
+ int w = write(b, str, l);
+ b->busy = 0;
+ return w;
+}
+
+// just delete all information in buffer `b`
+int RB_clearbuf(ringbuffer *b){
+ if(b->busy) return -1;
+ b->busy = 1;
+ b->head = 0;
+ b->tail = 0;
+ b->busy = 0;
+ return 1;
+}
diff --git a/F3:F303/USB_template_CDC/ringbuffer.h b/F3:F303/USB_template_CDC/ringbuffer.h
new file mode 100644
index 0000000..ed2cf95
--- /dev/null
+++ b/F3:F303/USB_template_CDC/ringbuffer.h
@@ -0,0 +1,41 @@
+/*
+ * 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 .
+ */
+
+#pragma once
+
+#if defined STM32F0
+#include
+#elif defined STM32F1
+#include
+#elif defined STM32F3
+#include
+#endif
+
+typedef struct{
+ uint8_t *data; // data buffer
+ const int length; // its length
+ int head; // head index
+ int tail; // tail index
+ volatile int busy; // == TRUE if buffer is busy now
+} 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);
+int RB_clearbuf(ringbuffer *b);
diff --git a/F3:F303/USB_template_CDC/strfunc.c b/F3:F303/USB_template_CDC/strfunc.c
new file mode 100644
index 0000000..c006e59
--- /dev/null
+++ b/F3:F303/USB_template_CDC/strfunc.c
@@ -0,0 +1,256 @@
+#include
+
+/**
+ * @brief hexdump - dump hex array by 16 bytes in string
+ * @param sendfun - function to send data
+ * @param arr - array to dump
+ * @param len - length of `arr`
+ */
+void hexdump(int (*sendfun)(const char *s), uint8_t *arr, uint16_t len){
+ char buf[52], *bptr = buf;
+ for(uint16_t l = 0; l < len; ++l, ++arr){
+ for(int16_t j = 1; j > -1; --j){
+ register uint8_t half = (*arr >> (4*j)) & 0x0f;
+ if(half < 10) *bptr++ = half + '0';
+ else *bptr++ = half - 10 + 'a';
+ }
+ if(l % 16 == 15){
+ *bptr++ = '\n';
+ *bptr = 0;
+ sendfun(buf);
+ bptr = buf;
+ }else *bptr++ = ' ';
+ }
+ if(bptr != buf){
+ *bptr++ = '\n';
+ *bptr = 0;
+ sendfun(buf);
+ }
+}
+
+/**
+ * @brief _2str - convert value into string buffer
+ * @param val - |value|
+ * @param minus - ==0 if value > 0
+ * @return buffer with number
+ */
+static char *_2str(uint32_t val, uint8_t minus){
+ static char strbuf[12];
+ char *bufptr = &strbuf[11];
+ *bufptr = 0;
+ if(!val){
+ *(--bufptr) = '0';
+ }else{
+ while(val){
+ uint32_t x = val / 10;
+ *(--bufptr) = (val - 10*x) + '0';
+ val = x;
+ //*(--bufptr) = val % 10 + '0';
+ //val /= 10;
+ }
+ }
+ if(minus) *(--bufptr) = '-';
+ return bufptr;
+}
+
+// return string with number `val`
+char *u2str(uint32_t val){
+ return _2str(val, 0);
+}
+char *i2str(int32_t i){
+ uint8_t minus = 0;
+ uint32_t val;
+ if(i < 0){
+ minus = 1;
+ val = -i;
+ }else val = i;
+ return _2str(val, minus);
+}
+
+/**
+ * @brief uhex2str - print 32bit unsigned int as hex
+ * @param val - value
+ * @return string with number
+ */
+char *uhex2str(uint32_t val){
+ static char buf[12] = "0x";
+ int npos = 2;
+ uint8_t *ptr = (uint8_t*)&val + 3;
+ int8_t i, j, z=1;
+ for(i = 0; i < 4; ++i, --ptr){
+ if(*ptr == 0){ // omit leading zeros
+ if(i == 3) z = 0;
+ if(z) continue;
+ }
+ else z = 0;
+ for(j = 1; j > -1; --j){
+ uint8_t half = (*ptr >> (4*j)) & 0x0f;
+ if(half < 10) buf[npos++] = half + '0';
+ else buf[npos++] = half - 10 + 'a';
+ }
+ }
+ buf[npos] = 0;
+ return buf;
+}
+
+/**
+ * @brief omit_spaces - eliminate leading spaces and other trash in string
+ * @param buf - string
+ * @return - pointer to first character in `buf` > ' '
+ */
+const char *omit_spaces(const char *buf){
+ while(*buf){
+ if(*buf > ' ') break;
+ ++buf;
+ }
+ return buf;
+}
+
+/**
+ * @brief getdec - read decimal number & return pointer to next non-number symbol
+ * @param buf - string
+ * @param N - number read
+ * @return Next non-number symbol. In case of overflow return `buf` and N==0xffffffff
+ */
+static const char *getdec(const char *buf, uint32_t *N){
+ char *start = (char*)buf;
+ uint32_t num = 0;
+ while(*buf){
+ char c = *buf;
+ if(c < '0' || c > '9'){
+ break;
+ }
+ if(num > 429496729 || (num == 429496729 && c > '5')){ // overflow
+ *N = 0xffffff;
+ return start;
+ }
+ num *= 10;
+ num += c - '0';
+ ++buf;
+ }
+ *N = num;
+ return buf;
+}
+// read hexadecimal number (without 0x prefix!)
+static const char *gethex(const char *buf, uint32_t *N){
+ const char *start = buf;
+ 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){
+ if(num & 0xf0000000){ // overflow
+ *N = 0xffffff;
+ return start;
+ }
+ num <<= 4;
+ num += c - M;
+ }else{
+ break;
+ }
+ ++buf;
+ }
+ *N = num;
+ return buf;
+}
+// read octal number (without 0 prefix!)
+static const char *getoct(const char *buf, uint32_t *N){
+ const char *start = (char*)buf;
+ uint32_t num = 0;
+ while(*buf){
+ char c = *buf;
+ if(c < '0' || c > '7'){
+ break;
+ }
+ if(num & 0xe0000000){ // overflow
+ *N = 0xffffff;
+ return start;
+ }
+ num <<= 3;
+ num += c - '0';
+ ++buf;
+ }
+ *N = num;
+ return buf;
+}
+// read binary number (without b prefix!)
+static const char *getbin(const char *buf, uint32_t *N){
+ const char *start = (char*)buf;
+ uint32_t num = 0;
+ while(*buf){
+ char c = *buf;
+ if(c < '0' || c > '1'){
+ break;
+ }
+ if(num & 0x80000000){ // overflow
+ *N = 0xffffff;
+ return start;
+ }
+ num <<= 1;
+ if(c == '1') num |= 1;
+ ++buf;
+ }
+ *N = num;
+ return buf;
+}
+
+/**
+ * @brief getnum - read uint32_t from string (dec, hex or bin: 127, 0x7f, 0b1111111)
+ * @param buf - buffer with number and so on
+ * @param N - the number read
+ * @return pointer to first non-number symbol in buf
+ * (if it is == buf, there's no number or if *N==0xffffffff there was overflow)
+ */
+const char *getnum(const char *txt, uint32_t *N){
+ const char *nxt = NULL;
+ const char *s = omit_spaces(txt);
+ if(*s == '0'){ // hex, oct or 0
+ if(s[1] == 'x' || s[1] == 'X'){ // hex
+ nxt = gethex(s+2, N);
+ if(nxt == s+2) nxt = (char*)txt;
+ }else if(s[1] > '0'-1 && s[1] < '8'){ // oct
+ nxt = getoct(s+1, N);
+ if(nxt == s+1) nxt = (char*)txt;
+ }else{ // 0
+ nxt = s+1;
+ *N = 0;
+ }
+ }else if(*s == 'b' || *s == 'B'){
+ nxt = getbin(s+1, N);
+ if(nxt == s+1) nxt = (char*)txt;
+ }else{
+ nxt = getdec(s, N);
+ if(nxt == s) nxt = (char*)txt;
+ }
+ return nxt;
+}
+
+// get signed integer
+const char *getint(const char *txt, int32_t *I){
+ const char *s = omit_spaces(txt);
+ int32_t sign = 1;
+ uint32_t U;
+ if(*s == '-'){
+ sign = -1;
+ ++s;
+ }
+ const char *nxt = getnum(s, &U);
+ if(nxt == s) return txt;
+ if(U & 0x80000000) return txt; // overfull
+ *I = sign * (int32_t)U;
+ return nxt;
+}
+
+/*
+void mymemcpy(char *dest, const char *src, int len){
+ if(len < 1) return;
+ while(len--) *dest++ = *src++;
+}
+*/
diff --git a/F3:F303/USB_template_CDC/strfunc.h b/F3:F303/USB_template_CDC/strfunc.h
new file mode 100644
index 0000000..e42ffdb
--- /dev/null
+++ b/F3:F303/USB_template_CDC/strfunc.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include
+#include
+
+void hexdump(int (*sendfun)(const char *s), uint8_t *arr, uint16_t len);
+const char *u2str(uint32_t val);
+const char *i2str(int32_t i);
+const char *uhex2str(uint32_t val);
+const char *getnum(const char *txt, uint32_t *N);
+const char *omit_spaces(const char *buf);
+const char *getint(const char *txt, int32_t *I);
+//void mymemcpy(char *dest, const char *src, int len);
diff --git a/F3:F303/USB_template_CDC/usb_descr.c b/F3:F303/USB_template_CDC/usb_descr.c
new file mode 100644
index 0000000..3e1a872
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usb_descr.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2024 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_descr.h"
+
+// low/high for uint16_t
+#define L16(x) (x & 0xff)
+#define H16(x) (x >> 8)
+
+static const uint8_t USB_DeviceDescriptor[] = {
+ USB_DT_DEVICE_SIZE, // bLength
+ USB_DT_DEVICE, // bDescriptorType
+ L16(bcdUSB), // bcdUSB_L
+ H16(bcdUSB), // bcdUSB_H
+ USB_CLASS_MISC, // bDeviceClass
+ bDeviceSubClass, // bDeviceSubClass
+ bDeviceProtocol, // bDeviceProtocol
+ USB_EP0BUFSZ, // bMaxPacketSize
+ L16(idVendor), // idVendor_L
+ H16(idVendor), // idVendor_H
+ L16(idProduct), // idProduct_L
+ H16(idProduct), // idProduct_H
+ L16(bcdDevice_Ver), // bcdDevice_Ver_L
+ H16(bcdDevice_Ver), // bcdDevice_Ver_H
+ iMANUFACTURER_DESCR, // iManufacturer - indexes of string descriptors in array
+ iPRODUCT_DESCR, // iProduct
+ iSERIAL_DESCR, // iSerial
+ bNumConfigurations // bNumConfigurations
+};
+
+static const uint8_t USB_DeviceQualifierDescriptor[] = {
+ USB_DT_QUALIFIER_SIZE, //bLength
+ USB_DT_QUALIFIER, // bDescriptorType
+ L16(bcdUSB), // bcdUSB_L
+ H16(bcdUSB), // bcdUSB_H
+ USB_CLASS_PER_INTERFACE, // bDeviceClass
+ bDeviceSubClass, // bDeviceSubClass
+ bDeviceProtocol, // bDeviceProtocol
+ USB_EP0BUFSZ, // bMaxPacketSize0
+ bNumConfigurations, // bNumConfigurations
+ 0 // Reserved
+};
+
+#define wTotalLength (USB_DT_CONFIG_SIZE + (bNumInterfaces * USB_DT_INTERFACE_SIZE) + (bTotNumEndpoints * USB_DT_ENDPOINT_SIZE) + (bNumCsInterfaces * USB_DT_CS_INTERFACE_SIZE) - 1)
+
+static const uint8_t USB_ConfigDescriptor[] = {
+ // Configuration Descriptor
+ USB_DT_CONFIG_SIZE, // bLength: Configuration Descriptor size
+ USB_DT_CONFIG, // bDescriptorType: Configuration
+ L16(wTotalLength), // wTotalLength.L :no of returned bytes
+ H16(wTotalLength), // wTotalLength.H
+ bNumInterfaces, // bNumInterfaces
+ 1, // bConfigurationValue: Current configuration value
+ 0, // iConfiguration: Index of string descriptor describing the configuration or 0
+ BusPowered, // bmAttributes - Bus powered
+ 50, // MaxPower in 2mA units
+ //---------------------------------------------------------------------------
+ // Virtual command Interface Descriptor
+ USB_DT_INTERFACE_SIZE, // bLength: Interface Descriptor size
+ USB_DT_INTERFACE, // bDescriptorType: Interface
+ 0, // bInterfaceNumber: Number of Interface
+ 0, // bAlternateSetting: Alternate setting
+ 1, // bNumEndpoints: one for this
+ USB_CLASS_COMM, // bInterfaceClass
+ 2, // bInterfaceSubClass: ACM
+ 1, // bInterfaceProtocol: Common AT commands
+ iINTERFACE_DESCR1, // iInterface
+ // ---- CS Interfaces
+ USB_DT_CS_INTERFACE_SIZE, // bLength
+ USB_DT_CS_INTERFACE, // bDescriptorType: CS_INTERFACE
+ 0, // bDescriptorSubtype: Header Func Desc
+ 0x10, // bcdCDC: spec release number
+ 1, // bDataInterface
+ USB_DT_CS_INTERFACE_SIZE, // bLength
+ USB_DT_CS_INTERFACE, // bDescriptorType: CS_INTERFACE
+ 1, // bDescriptorSubtype: Call Management Func Desc
+ 0, // bmCapabilities: D0+D1
+ 1, // bDataInterface
+ USB_DT_CS_INTERFACE_SIZE-1, // bLength
+ USB_DT_CS_INTERFACE, // bDescriptorType: CS_INTERFACE
+ 2, // bDescriptorSubtype: Abstract Control Management desc
+ 2, // bmCapabilities
+ USB_DT_CS_INTERFACE_SIZE, // bLength
+ USB_DT_CS_INTERFACE, // bDescriptorType: CS_INTERFACE
+ 6, // bDescriptorSubtype: Union func desc
+ 0, // bMasterInterface: Communication class interface
+ 1, // bSlaveInterface0: Data Class Interface
+ // Virtual endpoint 1 Descriptor
+ USB_DT_ENDPOINT_SIZE, // bLength: Endpoint Descriptor size
+ USB_DT_ENDPOINT, // bDescriptorType: Endpoint
+ 0x8A, // bEndpointAddress IN10
+ USB_BM_ATTR_INTERRUPT, // bmAttributes: Interrupt
+ L16(USB_EP1BUFSZ), // wMaxPacketSize LO
+ H16(USB_EP1BUFSZ), // wMaxPacketSize HI
+ 0x10, // bInterval: 16ms
+ //---------------------------------------------------------------------------
+ // Data interface
+ USB_DT_INTERFACE_SIZE, // bLength: Interface Descriptor size
+ USB_DT_INTERFACE, // bDescriptorType: Interface
+ 1, // bInterfaceNumber: Number of Interface
+ 0, // bAlternateSetting: Alternate setting
+ 2, // bNumEndpoints: in and out
+ USB_CLASS_DATA, // bInterfaceClass
+ 2, // bInterfaceSubClass: ACM
+ 0, // bInterfaceProtocol
+ 0, // iInterface
+ //Endpoint IN1 Descriptor
+ USB_DT_ENDPOINT_SIZE, // bLength: Endpoint Descriptor size
+ USB_DT_ENDPOINT, // bDescriptorType: Endpoint
+ 0x81, // bEndpointAddress: IN1
+ USB_BM_ATTR_BULK, // bmAttributes: Bulk
+ L16(USB_TXBUFSZ), // wMaxPacketSize LO
+ H16(USB_TXBUFSZ), // wMaxPacketSize HI
+ 0, // bInterval: ignore for Bulk transfer
+ // Endpoint OUT1 Descriptor
+ USB_DT_ENDPOINT_SIZE, // bLength: Endpoint Descriptor size
+ USB_DT_ENDPOINT, // bDescriptorType: Endpoint
+ 0x01, // bEndpointAddress: OUT1
+ USB_BM_ATTR_BULK, // bmAttributes: Bulk
+ L16(USB_RXBUFSZ), // wMaxPacketSize LO
+ H16(USB_RXBUFSZ), // wMaxPacketSize HI
+ 0, // bInterval: ignore for Bulk transfer
+
+};
+
+//const uint8_t HID_ReportDescriptor[];
+
+_USB_LANG_ID_(LD, LANG_US);
+_USB_STRING_(SD, u"0.0.1");
+_USB_STRING_(MD, u"eddy@sao.ru");
+_USB_STRING_(PD, u"USB-CDC");
+_USB_STRING_(ID, u"usbcdc");
+
+static const void* const StringDescriptor[iDESCR_AMOUNT] = {
+ [iLANGUAGE_DESCR] = &LD,
+ [iMANUFACTURER_DESCR] = &MD,
+ [iPRODUCT_DESCR] = &PD,
+ [iSERIAL_DESCR] = &SD,
+ [iINTERFACE_DESCR1] = &ID
+};
+
+static void wr0(const uint8_t *buf, uint16_t size, uint16_t askedsize){
+ if(askedsize < size) size = askedsize; // shortened request
+ if(size < USB_EP0BUFSZ){
+ EP_WriteIRQ(0, buf, size);
+ return;
+ }
+ while(size){
+ uint16_t l = size;
+ if(l > USB_EP0BUFSZ) l = USB_EP0BUFSZ;
+ EP_WriteIRQ(0, buf, l);
+ buf += l;
+ size -= l;
+ uint8_t needzlp = (l == USB_EP0BUFSZ) ? 1 : 0;
+ if(size || needzlp){ // send last data buffer
+ uint16_t epstatus = KEEP_DTOG(USB->EPnR[0]);
+ // keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx
+ USB->EPnR[0] = (epstatus & ~(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, NULL, 0);
+ }
+ }
+}
+
+void get_descriptor(config_pack_t *pack){
+ uint8_t descrtype = pack->wValue >> 8,
+ descridx = pack->wValue & 0xff;
+ switch(descrtype){
+ case DEVICE_DESCRIPTOR:
+ wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor), pack->wLength);
+ break;
+ case CONFIGURATION_DESCRIPTOR:
+ wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor), pack->wLength);
+ break;
+ case STRING_DESCRIPTOR:
+ if(descridx < iDESCR_AMOUNT){
+ wr0((const uint8_t *)StringDescriptor[descridx], *((uint8_t*)StringDescriptor[descridx]), pack->wLength);
+ }else{
+ EP_WriteIRQ(0, NULL, 0);
+ }
+ break;
+ case DEVICE_QUALIFIER_DESCRIPTOR:
+ wr0(USB_DeviceQualifierDescriptor, sizeof(USB_DeviceQualifierDescriptor), pack->wLength);
+ break;
+ /* case HID_REPORT_DESCRIPTOR:
+ wr0(HID_ReportDescriptor, sizeof(HID_ReportDescriptor), pack->wLength);
+ break;*/
+ default:
+ break;
+ }
+}
diff --git a/F3:F303/USB_template_CDC/usb_descr.h b/F3:F303/USB_template_CDC/usb_descr.h
new file mode 100644
index 0000000..d260af2
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usb_descr.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2024 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
+
+#include
+
+#include "usb_lib.h"
+
+// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor
+// bcdUSB: 1.10
+#define bcdUSB 0x0110
+// Class - Misc (EF), subclass - common (2), protocol - interface association descr (1)
+#define bDeviceSubClass 0x02
+#define bDeviceProtocol 0x01
+#define idVendor 0x0483
+#define idProduct 0x5740
+#define bcdDevice_Ver 0x0200
+#define bNumConfigurations 1
+
+// amount of interfaces and endpoints (except 0) used
+#define bNumInterfaces 2
+#define bTotNumEndpoints 3
+#define bNumCsInterfaces 4
+
+// powered
+#define BusPowered (1<<7)
+#define SelfPowered (1<<6)
+#define RemoteWakeup (1<<5)
+
+// buffer sizes
+// for USB FS EP0 buffers are from 8 to 64 bytes long
+#define USB_EP0BUFSZ 64
+#define USB_EP1BUFSZ 10
+// Rx/Tx EPs
+#define USB_RXBUFSZ 64
+#define USB_TXBUFSZ 64
+
+// string descriptors
+enum{
+ iLANGUAGE_DESCR,
+ iMANUFACTURER_DESCR,
+ iPRODUCT_DESCR,
+ iSERIAL_DESCR,
+ iINTERFACE_DESCR1,
+ iDESCR_AMOUNT
+};
+
+void get_descriptor(config_pack_t *pack);
diff --git a/F3:F303/USB_template_CDC/usb_dev.c b/F3:F303/USB_template_CDC/usb_dev.c
new file mode 100644
index 0000000..8e519e4
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usb_dev.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2024 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
+
+#include "ringbuffer.h"
+#include "usb_descr.h"
+#include "usb_dev.h"
+
+// 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
+
+// inbuf overflow when receiving
+static volatile uint8_t bufovrfl = 0;
+
+// receive buffer: hold data until chkin() call
+static uint8_t volatile rcvbuf[USB_RXBUFSZ];
+static uint8_t volatile rcvbuflen = 0;
+// line coding
+usb_LineCoding WEAK lineCoding = {115200, 0, 0, 8};
+// CDC configured and ready to use
+volatile uint8_t CDCready = 0;
+
+// ring buffers for incoming and outgoing data
+static uint8_t obuf[RBOUTSZ], ibuf[RBINSZ];
+static volatile ringbuffer rbout = {.data = obuf, .length = RBOUTSZ, .head = 0, .tail = 0};
+static volatile ringbuffer rbin = {.data = ibuf, .length = RBINSZ, .head = 0, .tail = 0};
+// last send data size
+static volatile int lastdsz = 0;
+
+static void chkin(){
+ if(bufovrfl) return; // allow user to know that previous buffer was overflowed and cleared
+ if(!rcvbuflen) return;
+ int w = RB_write((ringbuffer*)&rbin, (uint8_t*)rcvbuf, rcvbuflen);
+ if(w < 0){
+ return;
+ }
+ if(w != rcvbuflen) bufovrfl = 1;
+ rcvbuflen = 0;
+ uint16_t status = KEEP_DTOG(USB->EPnR[1]); // don't change DTOG
+ USB->EPnR[1] = (status & ~(USB_EPnR_STAT_TX|USB_EPnR_CTR_RX)) ^ USB_EPnR_STAT_RX; // prepare to get next data portion
+}
+
+// called from transmit EP to send next data portion or by user - when new transmission starts
+static void send_next(){
+ uint8_t usbbuff[USB_TXBUFSZ];
+ int buflen = RB_read((ringbuffer*)&rbout, (uint8_t*)usbbuff, USB_TXBUFSZ);
+ if(buflen == 0){
+ if(lastdsz == 64) EP_Write(1, NULL, 0); // send ZLP after 64 bits packet when nothing more to send
+ lastdsz = 0;
+ return;
+ }else if(buflen < 0){
+ lastdsz = 0;
+ return;
+ }
+ EP_Write(1, (uint8_t*)usbbuff, buflen);
+ lastdsz = buflen;
+}
+
+// data IN/OUT handler
+static void rxtx_handler(){
+ uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]);
+ if(RX_FLAG(epstatus)){ // receive data
+ if(rcvbuflen){
+ bufovrfl = 1; // lost last data
+ rcvbuflen = 0;
+ }
+ rcvbuflen = EP_Read(1, (uint8_t*)rcvbuf);
+ USB->EPnR[1] = epstatus & ~(USB_EPnR_CTR_RX | USB_EPnR_STAT_RX | USB_EPnR_STAT_TX); // keep RX in STALL state until read data
+ chkin(); // try to write current data into RXbuf if it's not busy
+ }else{ // tx successfull
+ USB->EPnR[1] = (epstatus & ~(USB_EPnR_CTR_TX | USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX;
+ send_next();
+ }
+}
+
+// weak handlers: change them somewhere else if you want to setup USART
+// SET_LINE_CODING
+void WEAK linecoding_handler(usb_LineCoding *lc){
+ lineCoding = *lc;
+}
+
+// SET_CONTROL_LINE_STATE
+void WEAK clstate_handler(uint16_t val){
+ CDCready = val; // CONTROL_DTR | CONTROL_RTS -> interface connected; 0 -> disconnected
+}
+
+// SEND_BREAK
+void WEAK break_handler(){
+ CDCready = 0;
+}
+
+
+// USB is configured: setup endpoints
+void set_configuration(){
+ EP_Init(1, EP_TYPE_BULK, USB_TXBUFSZ, USB_RXBUFSZ, rxtx_handler); // IN1 and OUT1
+}
+
+// PL2303 CLASS request
+void usb_class_request(config_pack_t *req, uint8_t *data, uint16_t datalen){
+ uint8_t recipient = REQUEST_RECIPIENT(req->bmRequestType);
+ uint8_t dev2host = (req->bmRequestType & 0x80) ? 1 : 0;
+ switch(recipient){
+ case REQ_RECIPIENT_INTERFACE:
+ switch(req->bRequest){
+ case SET_LINE_CODING:
+ if(!data || !datalen) break; // wait for data
+ if(datalen == sizeof(usb_LineCoding))
+ linecoding_handler((usb_LineCoding*)data);
+ break;
+ case GET_LINE_CODING:
+ EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding));
+ break;
+ case SET_CONTROL_LINE_STATE:
+ clstate_handler(req->wValue);
+ break;
+ case SEND_BREAK:
+ break_handler();
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ if(dev2host) EP_WriteIRQ(0, NULL, 0);
+ }
+ if(!dev2host) EP_WriteIRQ(0, NULL, 0);
+}
+
+// blocking send full content of ring buffer
+int USB_sendall(){
+ while(lastdsz > 0){
+ if(!CDCready) return FALSE;
+ }
+ return TRUE;
+}
+
+// put `buf` into queue to send
+int USB_send(const uint8_t *buf, int len){
+ if(!buf || !CDCready || !len) return FALSE;
+ while(len){
+ int a = RB_write((ringbuffer*)&rbout, buf, len);
+ if(a > 0){
+ len -= a;
+ buf += a;
+ } else if (a < 0) continue; // do nothing if buffer is in reading state
+ if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN
+ }
+ return TRUE;
+}
+
+int USB_putbyte(uint8_t byte){
+ if(!CDCready) return FALSE;
+ int l = 0;
+ while((l = RB_write((ringbuffer*)&rbout, &byte, 1)) != 1){
+ if(l < 0) continue;
+ }
+ if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN
+ return TRUE;
+}
+
+int USB_sendstr(const char *string){
+ if(!string || !CDCready) return FALSE;
+ int len = 0;
+ const char *b = string;
+ while(*b++) ++len;
+ if(!len) return FALSE;
+ return USB_send((const uint8_t*)string, len);
+}
+
+/**
+ * @brief USB_receive - get binary data from receiving ring-buffer
+ * @param buf (i) - buffer for received data
+ * @param len - length of `buf`
+ * @return amount of received bytes (negative, if overfull happened)
+ */
+int USB_receive(uint8_t *buf, int len){
+ chkin();
+ if(bufovrfl){
+ while(1 != RB_clearbuf((ringbuffer*)&rbin));
+ bufovrfl = 0;
+ return -1;
+ }
+ int sz = RB_read((ringbuffer*)&rbin, buf, len);
+ if(sz < 0) return 0; // buffer in writting state
+ return sz;
+}
+
+/**
+ * @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){
+ chkin();
+ if(bufovrfl){
+ while(1 != RB_clearbuf((ringbuffer*)&rbin));
+ bufovrfl = 0;
+ return -1;
+ }
+ int l = RB_readto((ringbuffer*)&rbin, '\n', (uint8_t*)buf, len);
+ if(l < 1){
+ if(rbin.length == RB_datalen((ringbuffer*)&rbin)){ // buffer is full but no '\n' found
+ while(1 != RB_clearbuf((ringbuffer*)&rbin));
+ return -1;
+ }
+ return 0;
+ }
+ if(l == 0) return 0;
+ buf[l-1] = 0; // replace '\n' with strend
+ return l;
+}
+
diff --git a/F3:F303/USB_template_CDC/usb_dev.h b/F3:F303/USB_template_CDC/usb_dev.h
new file mode 100644
index 0000000..1f8003c
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usb_dev.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2024 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
+
+#include
+#include "usb_lib.h"
+
+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;
+
+extern usb_LineCoding lineCoding;
+extern volatile uint8_t CDCready;
+
+void break_handler();
+void clstate_handler(uint16_t val);
+void linecoding_handler(usb_LineCoding *lc);
+
+
+// sizes of ringbuffers for outgoing and incoming data
+#define RBOUTSZ (1024)
+#define RBINSZ (1024)
+
+#define newline() USB_putbyte('\n')
+#define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0)
+
+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/F3:F303/USB_template_CDC/usb_lib.c b/F3:F303/USB_template_CDC/usb_lib.c
new file mode 100644
index 0000000..9f01a8f
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usb_lib.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2024 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
+
+#include "usb_lib.h"
+#include "usb_descr.h"
+#include "usb_dev.h"
+
+static ep_t endpoints[STM32ENDPOINTS];
+
+static uint16_t USB_Addr = 0;
+static uint8_t setupdatabuf[EP0DATABUF_SIZE];
+static config_pack_t *setup_packet = (config_pack_t*) setupdatabuf;
+volatile uint8_t usbON = 0; // device is configured and active
+
+static uint16_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured)
+static inline void std_d2h_req(){
+ uint16_t st = 0;
+ switch(setup_packet->bRequest){
+ case GET_DESCRIPTOR:
+ get_descriptor(setup_packet);
+ break;
+ case GET_STATUS:
+ EP_WriteIRQ(0, (uint8_t *)&st, 2); // send status: Bus Powered
+ break;
+ case GET_CONFIGURATION:
+ EP_WriteIRQ(0, (uint8_t*)&configuration, 1);
+ break;
+ default:
+ EP_WriteIRQ(0, NULL, 0);
+ 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_Addr = setup_packet->wValue;
+ break;
+ case SET_CONFIGURATION:
+ // Now device configured
+ configuration = setup_packet->wValue;
+ set_configuration();
+ usbON = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+void WEAK usb_standard_request(){
+ uint8_t recipient = REQUEST_RECIPIENT(setup_packet->bmRequestType);
+ uint8_t dev2host = (setup_packet->bmRequestType & 0x80) ? 1 : 0;
+ switch(recipient){
+ case REQ_RECIPIENT_DEVICE:
+ if(dev2host){
+ std_d2h_req();
+ }else{
+ std_h2d_req();
+ }
+ break;
+ case REQ_RECIPIENT_INTERFACE:
+ if(dev2host && setup_packet->bRequest == GET_DESCRIPTOR){
+ get_descriptor(setup_packet);
+ }
+ break;
+ case REQ_RECIPIENT_ENDPOINT:
+ if(setup_packet->bRequest == CLEAR_FEATURE){
+ }else{ /* wrong */ }
+ break;
+ default:
+ break;
+ }
+ if(!dev2host) EP_WriteIRQ(0, NULL, 0);
+}
+
+void WEAK usb_class_request(config_pack_t *req, uint8_t _U_ *data, uint16_t _U_ datalen){
+ switch(req->bRequest){
+ case GET_INTERFACE:
+ break;
+ case SET_CONFIGURATION: // set featuring by req->wValue
+ break;
+ default:
+ break;
+ }
+ if(0 == (setup_packet->bmRequestType & 0x80)) // host2dev
+ EP_WriteIRQ(0, NULL, 0);
+}
+
+void WEAK usb_vendor_request(config_pack_t _U_ *packet, uint8_t _U_ *data, uint16_t _U_ datalen){
+ if(0 == (setup_packet->bmRequestType & 0x80)) // host2dev
+ EP_WriteIRQ(0, NULL, 0);
+}
+
+/*
+bmRequestType: 76543210
+7 direction: 0 - host->device, 1 - device->host
+65 type: 0 - standard, 1 - class, 2 - vendor
+4..0 getter: 0 - device, 1 - interface, 2 - endpoint, 3 - other
+*/
+/**
+ * Endpoint0 (control) handler
+ */
+static void EP0_Handler(){
+ uint8_t ep0dbuflen = 0;
+ uint8_t ep0databuf[EP0DATABUF_SIZE];
+ uint16_t epstatus = KEEP_DTOG(USB->EPnR[0]); // EP0R on input -> return this value after modifications
+ int rxflag = RX_FLAG(epstatus);
+ //if(rxflag){ }
+ // 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(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
+ //if(endpoints[0].rx_cnt){ }
+ ep0dbuflen = EP_Read(0, ep0databuf);
+ }
+ }
+ if(rxflag){
+ uint8_t reqtype = REQUEST_TYPE(setup_packet->bmRequestType);
+ switch(reqtype){
+ case REQ_TYPE_STANDARD:
+ if(SETUP_FLAG(epstatus)){
+ usb_standard_request();
+ }else{ }
+ break;
+ case REQ_TYPE_CLASS:
+ usb_class_request(setup_packet, ep0databuf, ep0dbuflen);
+ break;
+ case REQ_TYPE_VENDOR:
+ usb_vendor_request(setup_packet, ep0databuf, ep0dbuflen);
+ break;
+ default:
+ EP_WriteIRQ(0, NULL, 0);
+ break;
+ }
+ }
+ if(TX_FLAG(epstatus)){
+ // now we can change address after enumeration
+ if ((USB->DADDR & USB_DADDR_ADD) != USB_Addr){
+ USB->DADDR = USB_DADDR_EF | USB_Addr;
+ usbON = 0;
+ }
+ }
+ //epstatus = KEEP_DTOG(USB->EPnR[0]);
+ if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP or 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;
+}
+
+/**
+ * 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){
+ 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;
+#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;
+}
+
+/**
+ * Write data to EP buffer (called outside IRQ handler)
+ * @param number - EP number
+ * @param *buf - array with data
+ * @param size - its size
+ */
+void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){
+ EP_WriteIRQ(number, buf, size);
+ uint16_t epstatus = KEEP_DTOG(USB->EPnR[number]);
+ // keep DTOGs and RX stat, clear CTR_TX & set TX VALID to start transmission
+ USB->EPnR[number] = (epstatus & ~(USB_EPnR_CTR_TX | USB_EPnR_STAT_RX)) ^ USB_EPnR_STAT_TX;
+}
+
+/*
+ * Copy data from EP buffer into user buffer area
+ * @param *buf - user array for data
+ * @return amount of data read
+ */
+int EP_Read(uint8_t number, uint8_t *buf){
+ 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;
+}
+
+
+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/ACCESSZ || rxsz > USB_BTABLE_SIZE/ACCESSZ) return 1; // buffer too large
+ if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE/ACCESSZ) 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) 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
+void USB_IRQ(){
+ uint32_t CNTR = USB->CNTR;
+ USB->CNTR = 0;
+ if(USB->ISTR & USB_ISTR_RESET){
+ usbON = 0;
+ // Reinit registers
+ CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM;
+ // Endpoint 0 - CONTROL
+ // ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes!
+ lastaddr = LASTADDR_DEFAULT;
+ // clear address, leave only enable bit
+ USB->DADDR = USB_DADDR_EF;
+ USB->ISTR = ~USB_ISTR_RESET;
+ if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0BUFSZ, USB_EP0BUFSZ, EP0_Handler)){
+ return;
+ };
+ }
+ if(USB->ISTR & USB_ISTR_CTR){
+ // EP number
+ uint8_t n = USB->ISTR & USB_ISTR_EPID;
+ // copy received bytes amount
+ endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter
+ // call EP handler
+ if(endpoints[n].func) endpoints[n].func();
+ }
+ if(USB->ISTR & USB_ISTR_WKUP){ // wakeup
+#ifndef STM32F0
+ CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LP_MODE | USB_CNTR_WKUPM); // clear suspend flags
+#else
+ CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LPMODE | USB_CNTR_WKUPM);
+#endif
+ USB->ISTR = ~USB_ISTR_WKUP;
+ }
+ if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep
+ usbON = 0;
+#ifndef STM32F0
+ CNTR |= USB_CNTR_FSUSP | USB_CNTR_LP_MODE | USB_CNTR_WKUPM;
+#else
+ CNTR |= USB_CNTR_FSUSP | USB_CNTR_LPMODE | USB_CNTR_WKUPM;
+#endif
+ CNTR &= ~(USB_CNTR_SUSPM);
+ USB->ISTR = ~USB_ISTR_SUSP;
+ }
+ USB->CNTR = CNTR; // rewoke interrupts
+}
+
+// here we suppose that all PIN settings done in hw_setup earlier
+void USB_setup(){
+#if defined STM32F3
+ NVIC_DisableIRQ(USB_LP_IRQn);
+ // remap USB LP & Wakeup interrupts to 75 and 76 - works only on pure F303
+ RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // enable tacting of SYSCFG
+ SYSCFG->CFGR1 |= SYSCFG_CFGR1_USB_IT_RMP;
+#elif defined STM32F1
+ NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
+ NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
+#elif defined STM32F0
+ NVIC_DisableIRQ(USB_IRQn);
+ RCC->APB1ENR |= RCC_APB1ENR_CRSEN;
+ 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;
+#endif
+ RCC->APB1ENR |= RCC_APB1ENR_USBEN;
+ //??
+ USB->CNTR = USB_CNTR_FRES; // Force USB Reset
+ for(uint32_t ctr = 0; ctr < 72000; ++ctr) nop(); // wait >1ms
+ USB->CNTR = 0;
+ USB->BTABLE = 0;
+ USB->DADDR = 0;
+ USB->ISTR = 0;
+ USB->CNTR = USB_CNTR_RESETM; // allow only reset interrupts
+#if defined STM32F3
+ NVIC_EnableIRQ(USB_LP_IRQn);
+#elif defined STM32F1
+ NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
+#elif defined STM32F0
+ USB->BCDR |= USB_BCDR_DPPU;
+ NVIC_EnableIRQ(USB_IRQn);
+#endif
+}
+
+
+#if defined STM32F3
+void usb_lp_isr() __attribute__ ((alias ("USB_IRQ")));
+#elif defined STM32F1
+void usb_lp_can_rx0_isr() __attribute__ ((alias ("USB_IRQ")));
+#elif defined STM32F0
+void usb_isr() __attribute__ ((alias ("USB_IRQ")));
+#endif
diff --git a/F3:F303/USB_template_CDC/usb_lib.h b/F3:F303/USB_template_CDC/usb_lib.h
new file mode 100644
index 0000000..d55c83f
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usb_lib.h
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2024 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
+
+#include
+#include
+
+#ifndef _U_
+#define _U_ __attribute__((unused))
+#endif
+
+/******************************************************************
+ * Hardware registers etc *
+ *****************************************************************/
+#if defined STM32F0
+#include
+#elif defined STM32F1
+#include
+// there's no this define in standard header
+#define USB_BASE ((uint32_t)0x40005C00)
+#elif defined STM32F3
+#include
+#endif
+
+// max endpoints number
+#define STM32ENDPOINTS 8
+/**
+ * Buffers size definition
+ **/
+
+// F0 - USB2_16; F1 - USB1_16; F3 - 1/2 depending on series
+#if !defined USB1_16 && !defined USB2_16
+#if defined STM32F0
+#define USB2_16
+#elif defined STM32F1
+#define USB1_16
+#else
+#error "Can't determine USB1_16 or USB2_16, define by hands"
+#endif
+#endif
+
+// BTABLE_SIZE FOR STM32F3:
+// In STM32F303/302xB/C, 512 bytes SRAM is not shared with CAN.
+// In STM32F302x6/x8 and STM32F30xxD/E, 726 bytes dedicated SRAM and 256 bytes shared SRAM with CAN i.e.
+// 1Kbytes dedicated SRAM in case CAN is disabled.
+// remember, that USB_BTABLE_SIZE will be divided by ACCESSZ, so don't divide it twice for 32-bit addressing
+
+#ifdef NOCAN
+#if defined STM32F0
+#define USB_BTABLE_SIZE 1024
+#elif defined STM32F3
+#define USB_BTABLE_SIZE 726
+//#warning "Please, check real buffer size due to docs"
+#else
+#error "define STM32F0 or STM32F3"
+#endif
+#else // !NOCAN: F0/F3 with CAN or F1 (can't simultaneously run CAN and USB)
+#if defined STM32F0
+#define USB_BTABLE_SIZE 768
+#elif defined STM32F3
+#define USB_BTABLE_SIZE 726
+//#warning "Please, check real buffer size due to docs"
+#else // STM32F103: 1024 bytes but with 32-bit addressing
+#define USB_BTABLE_SIZE 1024
+#endif
+#endif // NOCAN
+
+// first 64 bytes of USB_BTABLE are registers!
+
+#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
+#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[STM32ENDPOINTS];
+ __IO uint32_t RESERVED[STM32ENDPOINTS];
+ __IO uint32_t CNTR;
+ __IO uint32_t ISTR;
+ __IO uint32_t FNR;
+ __IO uint32_t DADDR;
+ __IO uint32_t BTABLE;
+#ifdef STM32F0
+ __IO uint32_t LPMCSR;
+ __IO uint32_t BCDR;
+#endif
+} 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[STM32ENDPOINTS];
+} USB_BtableDef;
+
+#define EP0DATABUF_SIZE (64)
+#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8)
+
+/******************************************************************
+ * Defines from usb.h *
+ *****************************************************************/
+
+/*
+ * Device and/or Interface Class codes
+ */
+#define USB_CLASS_PER_INTERFACE 0
+#define USB_CLASS_AUDIO 1
+#define USB_CLASS_COMM 2
+#define USB_CLASS_HID 3
+#define USB_CLASS_PRINTER 7
+#define USB_CLASS_PTP 6
+#define USB_CLASS_MASS_STORAGE 8
+#define USB_CLASS_HUB 9
+#define USB_CLASS_DATA 10
+#define USB_CLASS_MISC 0xef
+#define USB_CLASS_VENDOR_SPEC 0xff
+
+/*
+ * Descriptor types
+ */
+#define USB_DT_DEVICE 0x01
+#define USB_DT_CONFIG 0x02
+#define USB_DT_STRING 0x03
+#define USB_DT_INTERFACE 0x04
+#define USB_DT_ENDPOINT 0x05
+#define USB_DT_QUALIFIER 0x06
+#define USB_DT_IAD 0x0B
+
+#define USB_DT_HID 0x21
+#define USB_DT_REPORT 0x22
+#define USB_DT_PHYSICAL 0x23
+#define USB_DT_CS_INTERFACE 0x24
+#define USB_DT_HUB 0x29
+
+/*
+ * Descriptor sizes per descriptor type
+ */
+#define USB_DT_DEVICE_SIZE 18
+#define USB_DT_CONFIG_SIZE 9
+#define USB_DT_INTERFACE_SIZE 9
+#define USB_DT_HID_SIZE 9
+#define USB_DT_ENDPOINT_SIZE 7
+#define USB_DT_QUALIFIER_SIZE 10
+#define USB_DT_CS_INTERFACE_SIZE 5
+#define USB_DT_IAD_SIZE 8
+
+
+// bmRequestType & 0x80 == dev2host (1) or host2dev (0)
+// recipient: bmRequestType & 0x1f
+#define REQUEST_RECIPIENT(b) (b & 0x1f)
+#define REQ_RECIPIENT_DEVICE 0
+#define REQ_RECIPIENT_INTERFACE 1
+#define REQ_RECIPIENT_ENDPOINT 2
+#define REQ_RECIPIENT_OTHER 3
+// type: [bmRequestType & 0x60 >> 5]
+#define REQUEST_TYPE(b) ((b&0x60)>>5)
+#define REQ_TYPE_STANDARD 0
+#define REQ_TYPE_CLASS 1
+#define REQ_TYPE_VENDOR 2
+#define REQ_TYPE_RESERVED 3
+
+
+//#define VENDOR_REQUEST 0x01
+
+// standard device requests
+#define GET_STATUS 0x00
+#define CLEAR_FEATURE 0x01
+#define SET_FEATURE 0x03
+#define SET_ADDRESS 0x05
+#define GET_DESCRIPTOR 0x06
+#define SET_DESCRIPTOR 0x07
+#define GET_CONFIGURATION 0x08
+#define SET_CONFIGURATION 0x09
+// and some standard interface requests
+#define GET_INTERFACE 0x0A
+#define SET_INTERFACE 0x0B
+// and some standard endpoint requests
+#define SYNC_FRAME 0x0C
+
+// Types of descriptors
+#define DEVICE_DESCRIPTOR 0x01
+#define CONFIGURATION_DESCRIPTOR 0x02
+#define STRING_DESCRIPTOR 0x03
+#define DEVICE_QUALIFIER_DESCRIPTOR 0x06
+#define DEBUG_DESCRIPTOR 0x0a
+#define HID_REPORT_DESCRIPTOR 0x22
+
+// EP types for EP_init
+#define EP_TYPE_BULK 0x00
+#define EP_TYPE_CONTROL 0x01
+#define EP_TYPE_ISO 0x02
+#define EP_TYPE_INTERRUPT 0x03
+
+// EP types for descriptors
+#define USB_BM_ATTR_CONTROL 0x00
+#define USB_BM_ATTR_ISO 0x01
+#define USB_BM_ATTR_BULK 0x02
+#define USB_BM_ATTR_INTERRUPT 0x03
+
+
+/******************************************************************
+ * Other stuff *
+ *****************************************************************/
+
+#define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX)
+#define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX)
+#define SETUP_FLAG(epstat) (epstat & USB_EPnR_SETUP)
+
+// EPnR bits manipulation
+#define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
+#define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
+
+#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}
+
+// EP0 configuration packet
+typedef struct {
+ uint8_t bmRequestType;
+ uint8_t bRequest;
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength;
+} config_pack_t;
+
+// endpoints state
+typedef struct{
+ uint16_t *tx_buf; // transmission buffer address
+ uint16_t txbufsz; // transmission buffer size
+ uint8_t *rx_buf; // reception buffer address
+ void (*func)(); // endpoint action function
+ unsigned rx_cnt : 10; // received data counter
+} ep_t;
+
+extern volatile uint8_t usbON;
+
+void USB_setup();
+int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)());
+void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size);
+void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size);
+int EP_Read(uint8_t number, uint8_t *buf);
+
+// could be [re]defined in usb_dev.c
+extern void usb_class_request(config_pack_t *packet, uint8_t *data, uint16_t datalen);
+extern void usb_vendor_request(config_pack_t *packet, uint8_t *data, uint16_t datalen);
+extern void set_configuration();
diff --git a/F3:F303/USB_template_CDC/usbtemplate.bin b/F3:F303/USB_template_CDC/usbtemplate.bin
new file mode 100755
index 0000000..6db82ea
Binary files /dev/null and b/F3:F303/USB_template_CDC/usbtemplate.bin differ
diff --git a/F3:F303/USB_template_CDC/usbtemplate.cflags b/F3:F303/USB_template_CDC/usbtemplate.cflags
new file mode 100644
index 0000000..68d5165
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usbtemplate.cflags
@@ -0,0 +1 @@
+-std=c17
\ No newline at end of file
diff --git a/F3:F303/USB_template_CDC/usbtemplate.config b/F3:F303/USB_template_CDC/usbtemplate.config
new file mode 100644
index 0000000..1cf1964
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usbtemplate.config
@@ -0,0 +1,7 @@
+// Add predefined macros for your project here. For example:
+// #define THE_ANSWER 42
+#define EBUG
+#define STM32F3
+#define STM32F303xb
+#define __thumb2__ 1
+#define __ARM_ARCH_7M__
diff --git a/F3:F303/USB_template_CDC/usbtemplate.creator b/F3:F303/USB_template_CDC/usbtemplate.creator
new file mode 100644
index 0000000..e94cbbd
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usbtemplate.creator
@@ -0,0 +1 @@
+[General]
diff --git a/F3:F303/USB_template_CDC/usbtemplate.creator.user b/F3:F303/USB_template_CDC/usbtemplate.creator.user
new file mode 100644
index 0000000..aa79e75
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usbtemplate.creator.user
@@ -0,0 +1,171 @@
+
+
+
+
+
+ EnvironmentId
+ {7bd84e39-ca37-46d3-be9d-99ebea85bc0d}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ KOI8-R
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ false
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ false
+ 1
+ true
+ false
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ false
+ true
+ true
+ true
+ true
+
+
+ 0
+ true
+
+ true
+ true
+ Builtin.DefaultTidyAndClazy
+ 2
+
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop
+ Desktop
+ {65a14f9e-e008-4c1b-89df-4eaa4774b6e3}
+ 0
+ 0
+ 0
+
+ /Big/Data/00__Electronics/STM32/F303-nolib/blink
+
+
+
+ all
+
+ true
+ GenericProjectManager.GenericMakeStep
+
+ 1
+ Сборка
+ Сборка
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+ clean
+
+ true
+ GenericProjectManager.GenericMakeStep
+
+ 1
+ Очистка
+ Очистка
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Default
+ GenericProjectManager.GenericBuildConfiguration
+
+ 1
+
+
+ 0
+ Развёртывание
+ Развёртывание
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+
+ 2
+
+ ProjectExplorer.CustomExecutableRunConfiguration
+
+ false
+ true
+ false
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/F3:F303/USB_template_CDC/usbtemplate.cxxflags b/F3:F303/USB_template_CDC/usbtemplate.cxxflags
new file mode 100644
index 0000000..6435dfc
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usbtemplate.cxxflags
@@ -0,0 +1 @@
+-std=c++17
\ No newline at end of file
diff --git a/F3:F303/USB_template_CDC/usbtemplate.files b/F3:F303/USB_template_CDC/usbtemplate.files
new file mode 100644
index 0000000..73f5622
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usbtemplate.files
@@ -0,0 +1,16 @@
+hardware.c
+hardware.h
+main.c
+proto.c
+proto.h
+ringbuffer.c
+ringbuffer.h
+usb.c
+usb.h
+usb_descr.c
+usb_descr.h
+usb_dev.c
+usb_dev.h
+usb_lib.c
+usb_lib.h
+usbhw.h
diff --git a/F3:F303/USB_template_CDC/usbtemplate.includes b/F3:F303/USB_template_CDC/usbtemplate.includes
new file mode 100644
index 0000000..06d1130
--- /dev/null
+++ b/F3:F303/USB_template_CDC/usbtemplate.includes
@@ -0,0 +1,6 @@
+.
+../inc
+../inc/Fx
+../inc/cm
+../inc/ld
+../inc/startup
diff --git a/F3:F303/USB_template_CDC/version.inc b/F3:F303/USB_template_CDC/version.inc
new file mode 100644
index 0000000..aa1bbb9
--- /dev/null
+++ b/F3:F303/USB_template_CDC/version.inc
@@ -0,0 +1,2 @@
+#define BUILD_NUMBER "4"
+#define BUILD_DATE "2025-09-04"
diff --git a/F3:F303/inc/Fx/stm32f3.h b/F3:F303/inc/Fx/stm32f3.h
index 16c13e8..c50b043 100644
--- a/F3:F303/inc/Fx/stm32f3.h
+++ b/F3:F303/inc/Fx/stm32f3.h
@@ -23,7 +23,9 @@
#define __STM32F3_H__
#include "vector.h"
-#if defined STM32F303xb || defined STM32F303xc
+#if defined STM32F303x8
+#include "stm32f303x8.h"
+#elif defined STM32F303xb || defined STM32F303xc
#include "stm32f303xc.h"
#elif defined STM32F302xb || defined STM32F302xc
#include "stm32f302xc.h"
diff --git a/F3:F303/inc/Fx/stm32f303x8.h b/F3:F303/inc/Fx/stm32f303x8.h
new file mode 100644
index 0000000..d4312cf
--- /dev/null
+++ b/F3:F303/inc/Fx/stm32f303x8.h
@@ -0,0 +1,12146 @@
+/**
+ ******************************************************************************
+ * @file stm32f303x8.h
+ * @author MCD Application Team
+ * @brief CMSIS STM32F303x8 Devices Peripheral Access Layer Header File.
+ *
+ * This file contains:
+ * - Data structures and the address mapping for all peripherals
+ * - Peripheral's registers declarations and bits definition
+ * - Macros to access peripheral's registers hardware
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2016 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/** @addtogroup CMSIS_Device
+ * @{
+ */
+
+/** @addtogroup stm32f303x8
+ * @{
+ */
+
+#ifndef __STM32F303x8_H
+#define __STM32F303x8_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif /* __cplusplus */
+
+/** @addtogroup Configuration_section_for_CMSIS
+ * @{
+ */
+
+/**
+ * @brief Configuration of the Cortex-M4 Processor and Core Peripherals
+ */
+#define __CM4_REV 0x0001U /*!< Core revision r0p1 */
+#define __MPU_PRESENT 0U /*!< STM32F303x8 devices do not provide an MPU */
+#define __NVIC_PRIO_BITS 4U /*!< STM32F303x8 devices use 4 Bits for the Priority Levels */
+#define __Vendor_SysTickConfig 0U /*!< Set to 1 if different SysTick Config is used */
+#define __FPU_PRESENT 1U /*!< STM32F303x8 devices provide an FPU */
+
+/**
+ * @}
+ */
+
+/** @addtogroup Peripheral_interrupt_number_definition
+ * @{
+ */
+
+/**
+ * @brief STM32F303x8 devices Interrupt Number Definition, according to the selected device
+ * in @ref Library_configuration_section
+ */
+typedef enum
+{
+/****** Cortex-M4 Processor Exceptions Numbers ****************************************************************/
+ NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */
+ HardFault_IRQn = -13, /*!< 3 Cortex-M4 Hard Fault Interrupt */
+ MemoryManagement_IRQn = -12, /*!< 4 Cortex-M4 Memory Management Interrupt */
+ BusFault_IRQn = -11, /*!< 5 Cortex-M4 Bus Fault Interrupt */
+ UsageFault_IRQn = -10, /*!< 6 Cortex-M4 Usage Fault Interrupt */
+ SVCall_IRQn = -5, /*!< 11 Cortex-M4 SV Call Interrupt */
+ DebugMonitor_IRQn = -4, /*!< 12 Cortex-M4 Debug Monitor Interrupt */
+ PendSV_IRQn = -2, /*!< 14 Cortex-M4 Pend SV Interrupt */
+ SysTick_IRQn = -1, /*!< 15 Cortex-M4 System Tick Interrupt */
+/****** STM32 specific Interrupt Numbers **********************************************************************/
+ WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */
+ PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */
+ TAMP_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts through the EXTI line 19 */
+ RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI line 20 */
+ FLASH_IRQn = 4, /*!< FLASH global Interrupt */
+ RCC_IRQn = 5, /*!< RCC global Interrupt */
+ EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */
+ EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */
+ EXTI2_TSC_IRQn = 8, /*!< EXTI Line2 Interrupt and Touch Sense Controller Interrupt */
+ EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */
+ EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */
+ DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 Interrupt */
+ DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 Interrupt */
+ DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 Interrupt */
+ DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 Interrupt */
+ DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 Interrupt */
+ DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 Interrupt */
+ DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 Interrupt */
+ ADC1_2_IRQn = 18, /*!< ADC1 & ADC2 Interrupts */
+ CAN_TX_IRQn = 19, /*!< CAN TX Interrupt */
+ CAN_RX0_IRQn = 20, /*!< CAN RX0 Interrupt */
+ CAN_RX1_IRQn = 21, /*!< CAN RX1 Interrupt */
+ CAN_SCE_IRQn = 22, /*!< CAN SCE Interrupt */
+ EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */
+ TIM1_BRK_TIM15_IRQn = 24, /*!< TIM1 Break and TIM15 Interrupts */
+ TIM1_UP_TIM16_IRQn = 25, /*!< TIM1 Update and TIM16 Interrupts */
+ TIM1_TRG_COM_TIM17_IRQn = 26, /*!< TIM1 Trigger and Commutation and TIM17 Interrupt */
+ TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */
+ TIM2_IRQn = 28, /*!< TIM2 global Interrupt */
+ TIM3_IRQn = 29, /*!< TIM3 global Interrupt */
+ I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */
+ I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */
+ SPI1_IRQn = 35, /*!< SPI1 global Interrupt */
+ USART1_IRQn = 37, /*!< USART1 global Interrupt & EXTI Line25 Interrupt (USART1 wakeup) */
+ USART2_IRQn = 38, /*!< USART2 global Interrupt & EXTI Line26 Interrupt (USART2 wakeup) */
+ USART3_IRQn = 39, /*!< USART3 global Interrupt & EXTI Line28 Interrupt (USART3 wakeup) */
+ EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
+ RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line 17 Interrupt */
+ TIM6_DAC1_IRQn = 54, /*!< TIM6 global and DAC1 underrun error Interrupts*/
+ TIM7_DAC2_IRQn = 55, /*!< TIM7 global and DAC2 channel1 underrun error Interrupt */
+ COMP2_IRQn = 64, /*!< COMP2 global Interrupt via EXTI Line22 */
+ COMP4_6_IRQn = 65, /*!< COMP4 and COMP6 global Interrupt via EXTI Line30 and 32 */
+ FPU_IRQn = 81, /*!< Floating point Interrupt */
+} IRQn_Type;
+
+/**
+ * @}
+ */
+
+#include "core_cm4.h" /* Cortex-M4 processor and core peripherals */
+#include
+
+/** @addtogroup Peripheral_registers_structures
+ * @{
+ */
+
+/**
+ * @brief Analog to Digital Converter
+ */
+
+typedef struct
+{
+ __IO uint32_t ISR; /*!< ADC Interrupt and Status Register, Address offset: 0x00 */
+ __IO uint32_t IER; /*!< ADC Interrupt Enable Register, Address offset: 0x04 */
+ __IO uint32_t CR; /*!< ADC control register, Address offset: 0x08 */
+ __IO uint32_t CFGR; /*!< ADC Configuration register, Address offset: 0x0C */
+ uint32_t RESERVED0; /*!< Reserved, 0x010 */
+ __IO uint32_t SMPR1; /*!< ADC sample time register 1, Address offset: 0x14 */
+ __IO uint32_t SMPR2; /*!< ADC sample time register 2, Address offset: 0x18 */
+ uint32_t RESERVED1; /*!< Reserved, 0x01C */
+ __IO uint32_t TR1; /*!< ADC watchdog threshold register 1, Address offset: 0x20 */
+ __IO uint32_t TR2; /*!< ADC watchdog threshold register 2, Address offset: 0x24 */
+ __IO uint32_t TR3; /*!< ADC watchdog threshold register 3, Address offset: 0x28 */
+ uint32_t RESERVED2; /*!< Reserved, 0x02C */
+ __IO uint32_t SQR1; /*!< ADC regular sequence register 1, Address offset: 0x30 */
+ __IO uint32_t SQR2; /*!< ADC regular sequence register 2, Address offset: 0x34 */
+ __IO uint32_t SQR3; /*!< ADC regular sequence register 3, Address offset: 0x38 */
+ __IO uint32_t SQR4; /*!< ADC regular sequence register 4, Address offset: 0x3C */
+ __IO uint32_t DR; /*!< ADC regular data register, Address offset: 0x40 */
+ uint32_t RESERVED3; /*!< Reserved, 0x044 */
+ uint32_t RESERVED4; /*!< Reserved, 0x048 */
+ __IO uint32_t JSQR; /*!< ADC injected sequence register, Address offset: 0x4C */
+ uint32_t RESERVED5[4]; /*!< Reserved, 0x050 - 0x05C */
+ __IO uint32_t OFR1; /*!< ADC offset register 1, Address offset: 0x60 */
+ __IO uint32_t OFR2; /*!< ADC offset register 2, Address offset: 0x64 */
+ __IO uint32_t OFR3; /*!< ADC offset register 3, Address offset: 0x68 */
+ __IO uint32_t OFR4; /*!< ADC offset register 4, Address offset: 0x6C */
+ uint32_t RESERVED6[4]; /*!< Reserved, 0x070 - 0x07C */
+ __IO uint32_t JDR1; /*!< ADC injected data register 1, Address offset: 0x80 */
+ __IO uint32_t JDR2; /*!< ADC injected data register 2, Address offset: 0x84 */
+ __IO uint32_t JDR3; /*!< ADC injected data register 3, Address offset: 0x88 */
+ __IO uint32_t JDR4; /*!< ADC injected data register 4, Address offset: 0x8C */
+ uint32_t RESERVED7[4]; /*!< Reserved, 0x090 - 0x09C */
+ __IO uint32_t AWD2CR; /*!< ADC Analog Watchdog 2 Configuration Register, Address offset: 0xA0 */
+ __IO uint32_t AWD3CR; /*!< ADC Analog Watchdog 3 Configuration Register, Address offset: 0xA4 */
+ uint32_t RESERVED8; /*!< Reserved, 0x0A8 */
+ uint32_t RESERVED9; /*!< Reserved, 0x0AC */
+ __IO uint32_t DIFSEL; /*!< ADC Differential Mode Selection Register, Address offset: 0xB0 */
+ __IO uint32_t CALFACT; /*!< ADC Calibration Factors, Address offset: 0xB4 */
+
+} ADC_TypeDef;
+
+typedef struct
+{
+ __IO uint32_t CSR; /*!< ADC Common status register, Address offset: ADC1/3 base address + 0x300 */
+ uint32_t RESERVED; /*!< Reserved, ADC1/3 base address + 0x304 */
+ __IO uint32_t CCR; /*!< ADC common control register, Address offset: ADC1/3 base address + 0x308 */
+ __IO uint32_t CDR; /*!< ADC common regular data register for dual
+ AND triple modes, Address offset: ADC1/3 base address + 0x30C */
+} ADC_Common_TypeDef;
+
+/**
+ * @brief Controller Area Network TxMailBox
+ */
+typedef struct
+{
+ __IO uint32_t TIR; /*!< CAN TX mailbox identifier register */
+ __IO uint32_t TDTR; /*!< CAN mailbox data length control and time stamp register */
+ __IO uint32_t TDLR; /*!< CAN mailbox data low register */
+ __IO uint32_t TDHR; /*!< CAN mailbox data high register */
+} CAN_TxMailBox_TypeDef;
+
+/**
+ * @brief Controller Area Network FIFOMailBox
+ */
+typedef struct
+{
+ __IO uint32_t RIR; /*!< CAN receive FIFO mailbox identifier register */
+ __IO uint32_t RDTR; /*!< CAN receive FIFO mailbox data length control and time stamp register */
+ __IO uint32_t RDLR; /*!< CAN receive FIFO mailbox data low register */
+ __IO uint32_t RDHR; /*!< CAN receive FIFO mailbox data high register */
+} CAN_FIFOMailBox_TypeDef;
+
+/**
+ * @brief Controller Area Network FilterRegister
+ */
+typedef struct
+{
+ __IO uint32_t FR1; /*!< CAN Filter bank register 1 */
+ __IO uint32_t FR2; /*!< CAN Filter bank register 1 */
+} CAN_FilterRegister_TypeDef;
+
+/**
+ * @brief Controller Area Network
+ */
+typedef struct
+{
+ __IO uint32_t MCR; /*!< CAN master control register, Address offset: 0x00 */
+ __IO uint32_t MSR; /*!< CAN master status register, Address offset: 0x04 */
+ __IO uint32_t TSR; /*!< CAN transmit status register, Address offset: 0x08 */
+ __IO uint32_t RF0R; /*!< CAN receive FIFO 0 register, Address offset: 0x0C */
+ __IO uint32_t RF1R; /*!< CAN receive FIFO 1 register, Address offset: 0x10 */
+ __IO uint32_t IER; /*!< CAN interrupt enable register, Address offset: 0x14 */
+ __IO uint32_t ESR; /*!< CAN error status register, Address offset: 0x18 */
+ __IO uint32_t BTR; /*!< CAN bit timing register, Address offset: 0x1C */
+ uint32_t RESERVED0[88]; /*!< Reserved, 0x020 - 0x17F */
+ CAN_TxMailBox_TypeDef sTxMailBox[3]; /*!< CAN Tx MailBox, Address offset: 0x180 - 0x1AC */
+ CAN_FIFOMailBox_TypeDef sFIFOMailBox[2]; /*!< CAN FIFO MailBox, Address offset: 0x1B0 - 0x1CC */
+ uint32_t RESERVED1[12]; /*!< Reserved, 0x1D0 - 0x1FF */
+ __IO uint32_t FMR; /*!< CAN filter master register, Address offset: 0x200 */
+ __IO uint32_t FM1R; /*!< CAN filter mode register, Address offset: 0x204 */
+ uint32_t RESERVED2; /*!< Reserved, 0x208 */
+ __IO uint32_t FS1R; /*!< CAN filter scale register, Address offset: 0x20C */
+ uint32_t RESERVED3; /*!< Reserved, 0x210 */
+ __IO uint32_t FFA1R; /*!< CAN filter FIFO assignment register, Address offset: 0x214 */
+ uint32_t RESERVED4; /*!< Reserved, 0x218 */
+ __IO uint32_t FA1R; /*!< CAN filter activation register, Address offset: 0x21C */
+ uint32_t RESERVED5[8]; /*!< Reserved, 0x220-0x23F */
+ CAN_FilterRegister_TypeDef sFilterRegister[28]; /*!< CAN Filter Register, Address offset: 0x240-0x31C */
+} CAN_TypeDef;
+
+/**
+ * @brief Analog Comparators
+ */
+typedef struct
+{
+ __IO uint32_t CSR; /*!< COMP control and status register, Address offset: 0x00 */
+} COMP_TypeDef;
+
+typedef struct
+{
+ __IO uint32_t CSR; /*!< COMP control and status register, used for bits common to several COMP instances, Address offset: 0x00 */
+} COMP_Common_TypeDef;
+
+/**
+ * @brief CRC calculation unit
+ */
+
+typedef struct
+{
+ __IO uint32_t DR; /*!< CRC Data register, Address offset: 0x00 */
+ __IO uint8_t IDR; /*!< CRC Independent data register, Address offset: 0x04 */
+ uint8_t RESERVED0; /*!< Reserved, 0x05 */
+ uint16_t RESERVED1; /*!< Reserved, 0x06 */
+ __IO uint32_t CR; /*!< CRC Control register, Address offset: 0x08 */
+ uint32_t RESERVED2; /*!< Reserved, 0x0C */
+ __IO uint32_t INIT; /*!< Initial CRC value register, Address offset: 0x10 */
+ __IO uint32_t POL; /*!< CRC polynomial register, Address offset: 0x14 */
+} CRC_TypeDef;
+
+/**
+ * @brief Digital to Analog Converter
+ */
+
+typedef struct
+{
+ __IO uint32_t CR; /*!< DAC control register, Address offset: 0x00 */
+ __IO uint32_t SWTRIGR; /*!< DAC software trigger register, Address offset: 0x04 */
+ __IO uint32_t DHR12R1; /*!< DAC channel1 12-bit right-aligned data holding register, Address offset: 0x08 */
+ __IO uint32_t DHR12L1; /*!< DAC channel1 12-bit left aligned data holding register, Address offset: 0x0C */
+ __IO uint32_t DHR8R1; /*!< DAC channel1 8-bit right aligned data holding register, Address offset: 0x10 */
+ __IO uint32_t DHR12R2; /*!< DAC channel2 12-bit right aligned data holding register, Address offset: 0x14 */
+ __IO uint32_t DHR12L2; /*!< DAC channel2 12-bit left aligned data holding register, Address offset: 0x18 */
+ __IO uint32_t DHR8R2; /*!< DAC channel2 8-bit right-aligned data holding register, Address offset: 0x1C */
+ __IO uint32_t DHR12RD; /*!< Dual DAC 12-bit right-aligned data holding register, Address offset: 0x20 */
+ __IO uint32_t DHR12LD; /*!< DUAL DAC 12-bit left aligned data holding register, Address offset: 0x24 */
+ __IO uint32_t DHR8RD; /*!< DUAL DAC 8-bit right aligned data holding register, Address offset: 0x28 */
+ __IO uint32_t DOR1; /*!< DAC channel1 data output register, Address offset: 0x2C */
+ __IO uint32_t DOR2; /*!< DAC channel2 data output register, Address offset: 0x30 */
+ __IO uint32_t SR; /*!< DAC status register, Address offset: 0x34 */
+} DAC_TypeDef;
+
+/**
+ * @brief Debug MCU
+ */
+
+typedef struct
+{
+ __IO uint32_t IDCODE; /*!< MCU device ID code, Address offset: 0x00 */
+ __IO uint32_t CR; /*!< Debug MCU configuration register, Address offset: 0x04 */
+ __IO uint32_t APB1FZ; /*!< Debug MCU APB1 freeze register, Address offset: 0x08 */
+ __IO uint32_t APB2FZ; /*!< Debug MCU APB2 freeze register, Address offset: 0x0C */
+}DBGMCU_TypeDef;
+
+/**
+ * @brief DMA Controller
+ */
+
+typedef struct
+{
+ __IO uint32_t CCR; /*!< DMA channel x configuration register */
+ __IO uint32_t CNDTR; /*!< DMA channel x number of data register */
+ __IO uint32_t CPAR; /*!< DMA channel x peripheral address register */
+ __IO uint32_t CMAR; /*!< DMA channel x memory address register */
+} DMA_Channel_TypeDef;
+
+typedef struct
+{
+ __IO uint32_t ISR; /*!< DMA interrupt status register, Address offset: 0x00 */
+ __IO uint32_t IFCR; /*!< DMA interrupt flag clear register, Address offset: 0x04 */
+} DMA_TypeDef;
+
+/**
+ * @brief External Interrupt/Event Controller
+ */
+
+typedef struct
+{
+ __IO uint32_t IMR; /*!