diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/can.c b/F0:F030,F042,F072/usbcan_ringbuffer/can.c
index 108ca3f..df82e92 100644
--- a/F0:F030,F042,F072/usbcan_ringbuffer/can.c
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/can.c
@@ -19,7 +19,7 @@
#include "can.h"
#include "hardware.h"
#include "proto.h"
-#include "usb.h"
+#include "usb_dev.h"
// circular buffer for received messages
static CAN_message messages[CAN_INMESSAGE_SIZE];
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/main.c b/F0:F030,F042,F072/usbcan_ringbuffer/main.c
index 4f99cb1..70c3a36 100644
--- a/F0:F030,F042,F072/usbcan_ringbuffer/main.c
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/main.c
@@ -19,8 +19,7 @@
#include "can.h"
#include "hardware.h"
#include "proto.h"
-#include "usb.h"
-#include "usb_lib.h"
+#include "usb_dev.h"
#define MAXSTRLEN 128
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/proto.c b/F0:F030,F042,F072/usbcan_ringbuffer/proto.c
index 43648fe..873735c 100644
--- a/F0:F030,F042,F072/usbcan_ringbuffer/proto.c
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/proto.c
@@ -19,7 +19,7 @@
#include "can.h"
#include "hardware.h"
#include "proto.h"
-#include "usb.h"
+#include "usb_dev.h"
#include "version.inc"
extern volatile uint8_t canerror;
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/ringbuffer.c b/F0:F030,F042,F072/usbcan_ringbuffer/ringbuffer.c
index 8d8d6ca..24c8b61 100644
--- a/F0:F030,F042,F072/usbcan_ringbuffer/ringbuffer.c
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/ringbuffer.c
@@ -15,6 +15,8 @@
* along with this program. If not, see .
*/
+#include
+#include
#include "ringbuffer.h"
static int datalen(ringbuffer *b){
@@ -24,7 +26,7 @@ static int datalen(ringbuffer *b){
// stored data length
int RB_datalen(ringbuffer *b){
- if(b->busy) return -1;
+ if(!b || b->busy) return -1;
b->busy = 1;
int l = datalen(b);
b->busy = 0;
@@ -32,7 +34,7 @@ int RB_datalen(ringbuffer *b){
}
static int hasbyte(ringbuffer *b, uint8_t byte){
- if(b->head == b->tail) return -1; // no data in buffer
+ if(!b || 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)
@@ -51,18 +53,13 @@ static int hasbyte(ringbuffer *b, uint8_t byte){
* @return index if found, -1 if none or busy
*/
int RB_hasbyte(ringbuffer *b, uint8_t byte){
- if(b->busy) return -1;
+ if(!b || 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;
@@ -76,9 +73,9 @@ static int read(ringbuffer *b, uint8_t *s, int len){
int _1st = b->length - b->head;
if(_1st > l) _1st = l;
if(_1st > len) _1st = len;
- mcpy(s, b->data + b->head, _1st);
+ memcpy(s, b->data + b->head, _1st);
if(_1st < len && l > _1st){
- mcpy(s+_1st, b->data, l - _1st);
+ memcpy(s+_1st, b->data, l - _1st);
incr(b, &b->head, l);
return l;
}
@@ -94,20 +91,27 @@ static int read(ringbuffer *b, uint8_t *s, int len){
* @return bytes read or -1 if busy
*/
int RB_read(ringbuffer *b, uint8_t *s, int len){
- if(b->busy) return -1;
+ if(!b || b->busy || !s || len < 1) 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){
+// length of data from current position to `byte` (including byte)
+static int lento(ringbuffer *b, uint8_t byte){
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 partlen;
+}
+
+static int readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len){
+ int partlen = lento(b, byte);
+ if(!partlen) return 0;
+ if(partlen > len) return -1;
return read(b, s, partlen);
}
@@ -115,27 +119,41 @@ static int readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len){
* @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`
+ * @param s - buffer to write data or NULL to clear data
+ * @param len - length of `s` or 0 to clear data
* @return amount of bytes written (negative, if lenbusy) return -1;
+ if(!b || b->busy) return -1;
b->busy = 1;
- int n = readto(b, byte, s, len);
+ int n = 0;
+ if(s && len > 0){
+ n = readto(b, byte, s, len);
+ }else{
+ incr(b, &b->head, lento(b, byte)); // just throw data out
+ }
b->busy = 0;
return n;
}
+int RB_datalento(ringbuffer *b, uint8_t byte){
+ if(!b || b->busy) return -1;
+ b->busy = 1;
+ int n = lento(b, byte);
+ b->busy = 0;
+ return n;
+}
+
+// if l < rest of buffer, truncate and return actually written bytes
static int write(ringbuffer *b, const uint8_t *str, int l){
int r = b->length - 1 - datalen(b); // rest length
+ if(r < 1) return 0;
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);
+ memcpy(b->data + b->tail, str, _1st);
if(_1st < l){ // add another piece from start
- mcpy(b->data, str+_1st, l-_1st);
+ memcpy(b->data, str+_1st, l-_1st);
}
incr(b, &b->tail, l);
return l;
@@ -149,7 +167,7 @@ static int write(ringbuffer *b, const uint8_t *str, int l){
* @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;
+ if(!b || b->busy || !str || l < 1) return -1;
b->busy = 1;
int w = write(b, str, l);
b->busy = 0;
@@ -158,7 +176,7 @@ int RB_write(ringbuffer *b, const uint8_t *str, int l){
// just delete all information in buffer `b`
int RB_clearbuf(ringbuffer *b){
- if(b->busy) return -1;
+ if(!b || b->busy) return -1;
b->busy = 1;
b->head = 0;
b->tail = 0;
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/ringbuffer.h b/F0:F030,F042,F072/usbcan_ringbuffer/ringbuffer.h
index ed2cf95..f9e1e64 100644
--- a/F0:F030,F042,F072/usbcan_ringbuffer/ringbuffer.h
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/ringbuffer.h
@@ -17,13 +17,7 @@
#pragma once
-#if defined STM32F0
-#include
-#elif defined STM32F1
-#include
-#elif defined STM32F3
-#include
-#endif
+#include
typedef struct{
uint8_t *data; // data buffer
@@ -38,4 +32,5 @@ 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_datalento(ringbuffer *b, uint8_t byte);
int RB_clearbuf(ringbuffer *b);
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/usb.c b/F0:F030,F042,F072/usbcan_ringbuffer/usb.c
deleted file mode 100644
index 7848e1a..0000000
--- a/F0:F030,F042,F072/usbcan_ringbuffer/usb.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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 "hardware.h"
-#include "usb.h"
-#include "usb_lib.h"
-
-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};
-// inbuf overflow when receiving
-volatile uint8_t bufovrfl = 0;
-// last send data size
-static volatile int lastdsz = 0;
-
-// called from transmit EP
-void send_next(){
- IWDG->KR = IWDG_REFRESH;
- int buflen = RB_read((ringbuffer*)&rbout, (uint8_t*)usbbuff, USB_TXBUFSZ);
- if(buflen == 0){
- if(lastdsz == 64) EP_Write(3, NULL, 0); // send ZLP after 64 bits packet when nothing more to send
- lastdsz = 0;
- return;
- }else if(buflen < 0){
- lastdsz = 0;
- // Uncomment next line if you want 4Mbit/s instead of 6Mbit/s
- //EP_Write(3, NULL, 0); // send ZLP if buffer is in writting state now
- return;
- }
- EP_Write(3, (uint8_t*)usbbuff, buflen);
- lastdsz = buflen;
-}
-
-// blocking send full content of ring buffer
-int USB_sendall(){
- while(lastdsz > 0){
- IWDG->KR = IWDG_REFRESH;
- if(!usbON) return FALSE;
- }
- return TRUE;
-}
-
-// put `buf` into queue to send
-int USB_send(const uint8_t *buf, int len){
- if(!buf || !usbON || !len) return FALSE;
- while(len){
- IWDG->KR = IWDG_REFRESH;
- 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(!usbON) return FALSE;
- int l = 0;
- while((l = RB_write((ringbuffer*)&rbout, &byte, 1)) != 1){
- IWDG->KR = IWDG_REFRESH;
- 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 || !usbON) 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)) IWDG->KR = IWDG_REFRESH;
- 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)) IWDG->KR = IWDG_REFRESH;
- 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)) IWDG->KR = IWDG_REFRESH;
- return -1;
- }
- return 0;
- }
- if(l == 0) return 0;
- buf[l-1] = 0; // replace '\n' with strend
- return l;
-}
-
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/usb_descr.c b/F0:F030,F042,F072/usbcan_ringbuffer/usb_descr.c
new file mode 100644
index 0000000..0bf3c30
--- /dev/null
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/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.2");
+_USB_STRING_(MD, u"eddy@sao.ru");
+_USB_STRING_(PD, u"USB-Serial Controller");
+_USB_STRING_(ID, u"USB-STM32");
+
+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/F0:F030,F042,F072/usbcan_ringbuffer/usb_descr.h b/F0:F030,F042,F072/usbcan_ringbuffer/usb_descr.h
new file mode 100644
index 0000000..d3bfcf0
--- /dev/null
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/usb_descr.h
@@ -0,0 +1,64 @@
+/*
+ * 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
+// Rx buffer should be not more than 64 and multiple of 2 (or 4 for STM32G0), or multiple of 32
+// Tx buffer should be multiple of 2 (or 4 for STM32G0)
+// for USB FS EP0 buffers are from 8 to 64 bytes long
+#define USB_EP0BUFSZ 64
+#define USB_EP1BUFSZ 10
+// Rx/Tx EPs (not more than 64 bytes for CDC)
+#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/F0:F030,F042,F072/usbcan_ringbuffer/usb_dev.c b/F0:F030,F042,F072/usbcan_ringbuffer/usb_dev.c
new file mode 100644
index 0000000..177c882
--- /dev/null
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/usb_dev.c
@@ -0,0 +1,252 @@
+/*
+ * 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] __attribute__((aligned(4)));
+static uint8_t volatile rcvbuflen = 0;
+// line coding
+usb_LineCoding 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] __attribute__((aligned(4)));
+ int buflen = RB_read((ringbuffer*)&rbout, (uint8_t*)usbbuff, USB_TXBUFSZ);
+ if(buflen == 0){
+ if(lastdsz == USB_TXBUFSZ) EP_Write(1, NULL, 0); // send ZLP after USB_TXBUFSZ 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 linecoding_handler(usb_LineCoding *lc){
+ lineCoding = *lc;
+}
+
+// SET_CONTROL_LINE_STATE
+void clstate_handler(uint16_t val){
+ CDCready = val; // CONTROL_DTR | CONTROL_RTS -> interface connected; 0 -> disconnected
+}
+
+// SEND_BREAK
+void 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){
+ IWDG->KR = IWDG_REFRESH;
+ int l = RB_datalen((ringbuffer*)&rbout);
+ if(l < 0) continue;
+ int portion = rbout.length - 1 - l;
+ if(portion < 1){
+ if(lastdsz == 0) send_next();
+ continue;
+ }
+ if(portion > len) portion = len;
+ int a = RB_write((ringbuffer*)&rbout, buf, portion);
+ 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
+ */
+int USB_receivestr(char *buf, int len){
+ chkin();
+ if(bufovrfl){
+ while(1 != RB_clearbuf((ringbuffer*)&rbin));
+ bufovrfl = 0;
+ return -1;
+ }
+ int l = RB_datalento((ringbuffer*)&rbin, '\n');
+ if(l > len){ // can't read: line too long -> clear it
+ RB_readto((ringbuffer*)&rbin, '\n', NULL, 0);
+ return -1;
+ }else if(l < 1){ // nothing or no '\n' ?
+ if(rbin.length == RB_datalen((ringbuffer*)&rbin)){ // buffer is full but no '\n' found
+ while(1 != RB_clearbuf((ringbuffer*)&rbin));
+ return -1;
+ }
+ return 0;
+ }
+ l = RB_readto((ringbuffer*)&rbin, '\n', (uint8_t*)buf, len);
+ if(l == 0) return 0;
+ buf[l-1] = 0; // replace '\n' with strend
+ return l;
+}
+
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/usb.h b/F0:F030,F042,F072/usbcan_ringbuffer/usb_dev.h
similarity index 62%
rename from F0:F030,F042,F072/usbcan_ringbuffer/usb.h
rename to F0:F030,F042,F072/usbcan_ringbuffer/usb_dev.h
index 4583b9b..70ee1bc 100644
--- a/F0:F030,F042,F072/usbcan_ringbuffer/usb.h
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/usb_dev.h
@@ -14,32 +14,41 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
#pragma once
-#include "ringbuffer.h"
-#include "usbhw.h"
+#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 (512)
-#define RBINSZ (256)
+#define RBOUTSZ (1024)
+#define RBINSZ (1024)
#define newline() USB_putbyte('\n')
#define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0)
-#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);
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/usb_lib.c b/F0:F030,F042,F072/usbcan_ringbuffer/usb_lib.c
index aea5344..15ebc88 100644
--- a/F0:F030,F042,F072/usbcan_ringbuffer/usb_lib.c
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/usb_lib.c
@@ -15,280 +15,37 @@
* along with this program. If not, see .
*/
#include
-#include "usb.h"
-#include "usb_lib.h"
-#include "usbhw.h"
-ep_t endpoints[STM32ENDPOINTS];
+#include "usb_lib.h"
+#include "usb_descr.h"
+#include "usb_dev.h"
+
+static ep_t endpoints[STM32ENDPOINTS];
static uint16_t USB_Addr = 0;
-static usb_LineCoding lineCoding = {115200, 0, 0, 8};
-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
-#define bDeviceClass 0
-#define bDeviceSubClass 0
-#define bDeviceProtocol 0
-#define bNumConfigurations 1
-
-static const uint8_t USB_DeviceDescriptor[] = {
- 18, // bLength
- 0x01, // bDescriptorType - Device descriptor
- bcdUSB_L, // bcdUSB_L - 1.10
- bcdUSB_H, // bcdUSB_H
- bDeviceClass, // bDeviceClass - USB_COMM
- bDeviceSubClass, // bDeviceSubClass
- bDeviceProtocol, // bDeviceProtocol
- USB_EP0_BUFSZ, // bMaxPacketSize
- 0x7b, // idVendor_L PL2303: VID=0x067b, PID=0x2303
- 0x06, // idVendor_H
- 0x03, // idProduct_L
- 0x23, // idProduct_H
- 0x00, // bcdDevice_Ver_L
- 0x03, // bcdDevice_Ver_H
- iMANUFACTURER_DESCR, // iManufacturer
- iPRODUCT_DESCR, // iProduct
- iSERIAL_DESCR, // iSerialNumber
- bNumConfigurations // bNumConfigurations
-};
-
-static const uint8_t USB_DeviceQualifierDescriptor[] = {
- 10, //bLength
- 0x06, // bDescriptorType - Device qualifier
- bcdUSB_L, // bcdUSB_L
- bcdUSB_H, // bcdUSB_H
- bDeviceClass, // bDeviceClass
- bDeviceSubClass, // bDeviceSubClass
- bDeviceProtocol, // bDeviceProtocol
- USB_EP0_BUFSZ, // bMaxPacketSize0
- bNumConfigurations, // bNumConfigurations
- 0x00 // Reserved
-};
-
-static const uint8_t USB_ConfigDescriptor[] = {
- /*Configuration Descriptor*/
- 0x09, /* bLength: Configuration Descriptor size */
- 0x02, /* bDescriptorType: Configuration */
- 39, /* wTotalLength:no of returned bytes */
- 0x00,
- 0x01, /* bNumInterfaces: 1 interface */
- 0x01, /* bConfigurationValue: Configuration value */
- 0x00, /* iConfiguration: Index of string descriptor describing the configuration */
- 0xa0, /* bmAttributes - Bus powered, Remote wakeup */
- 0x32, /* MaxPower 100 mA */
-
- /*---------------------------------------------------------------------------*/
-
- /*Interface Descriptor */
- 0x09, /* bLength: Interface Descriptor size */
- 0x04, /* bDescriptorType: Interface */
- 0x00, /* bInterfaceNumber: Number of Interface */
- 0x00, /* bAlternateSetting: Alternate setting */
- 0x03, /* bNumEndpoints: 3 endpoints used */
- 0xff, /* bInterfaceClass */
- 0x00, /* bInterfaceSubClass */
- 0x00, /* bInterfaceProtocol */
- iINTERFACE_DESCR, /* iInterface: */
-///////////////////////////////////////////////////
- /*Endpoint 1 Descriptor*/
- 0x07, /* bLength: Endpoint Descriptor size */
- 0x05, /* bDescriptorType: Endpoint */
- 0x81, /* bEndpointAddress IN1 */
- 0x03, /* bmAttributes: Interrupt */
- 0x0a, /* wMaxPacketSize LO: */
- 0x00, /* wMaxPacketSize HI: */
- 0x01, /* bInterval: */
-
- /*Endpoint OUT2 Descriptor*/
- 0x07, /* bLength: Endpoint Descriptor size */
- 0x05, /* bDescriptorType: Endpoint */
- 0x02, /* bEndpointAddress: OUT2 */
- 0x02, /* bmAttributes: Bulk */
- (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
- (USB_RXBUFSZ >> 8),
- 0x00, /* bInterval: ignore for Bulk transfer */
-
- /*Endpoint IN3 Descriptor*/
- 0x07, /* bLength: Endpoint Descriptor size */
- 0x05, /* bDescriptorType: Endpoint */
- 0x83, /* bEndpointAddress IN3 */
- 0x02, /* bmAttributes: Bulk */
- (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
- (USB_TXBUFSZ >> 8),
- 0x00, /* bInterval: ignore for Bulk transfer */
-};
-
-_USB_LANG_ID_(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"USB-STM32");
-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){
-}
-
-// SET_CONTROL_LINE_STATE
-void WEAK clstate_handler(uint16_t __attribute__((unused)) val){
-}
-
-// SEND_BREAK
-void WEAK break_handler(){
-}
-
-// handler of vendor requests
-void WEAK vendor_handler(config_pack_t *packet){
- uint16_t c;
- if(packet->bmRequestType & 0x80){ // read
- switch(packet->wValue){
- case 0x8484:
- c = 2;
- break;
- case 0x0080:
- c = 1;
- break;
- case 0x8686:
- c = 0xaa;
- break;
- default:
- c = 0;
- }
- EP_WriteIRQ(0, (uint8_t*)&c, 1);
- }else{ // write ZLP
- c = 0;
- EP_WriteIRQ(0, (uint8_t *)&c, 0);
- }
-}
-
-static void wr0(const uint8_t *buf, uint16_t size){
- if(setup_packet->wLength < size) size = setup_packet->wLength; // shortened request
- if(size < endpoints[0].txbufsz){
- EP_WriteIRQ(0, buf, size);
- return;
- }
- while(size){
- uint16_t l = size;
- if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz;
- EP_WriteIRQ(0, buf, l);
- buf += l;
- size -= l;
- uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0;
- if(size || needzlp){ // send last data buffer
- uint16_t status = KEEP_DTOG(USB->EPnR[0]);
- // keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx
- USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX))
- ^ USB_EPnR_STAT_TX;
- uint32_t ctr = 1000000;
- while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;};
- if((USB->ISTR & USB_ISTR_CTR) == 0){
- return;
- }
- if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0);
- }
- }
-}
-
-static inline void get_descriptor(){
- 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_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 setupdatabuf[EP0DATABUF_SIZE] __attribute__((aligned(4)));
+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 status = 0; // bus powered
+ uint16_t st = 0;
switch(setup_packet->bRequest){
case GET_DESCRIPTOR:
- get_descriptor();
+ get_descriptor(setup_packet);
break;
case GET_STATUS:
- EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered
+ 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;
}
}
-// 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 uint8_t volatile rcvbuf[USB_RXBUFSZ];
-static uint8_t volatile rcvbuflen = 0;
-
-void chkin(){
- if(bufovrfl) return;
- 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[2]); // don't change DTOG
- USB->EPnR[2] = status ^ USB_EPnR_STAT_RX;
-}
-
-// receiver reads data from local buffer and only then ACK'ed
-static void receive_Handler(){ // EP2OUT
- uint16_t status = KEEP_DTOG_STAT(USB->EPnR[2]); // don't change DTOG and NACK
- if(rcvbuflen){
- bufovrfl = 1; // lost last data
- rcvbuflen = 0;
- }
- rcvbuflen = EP_Read(2, (uint8_t*)rcvbuf);
- USB->EPnR[2] = status & ~USB_EPnR_CTR_RX;
-}
-
static inline void std_h2d_req(){
switch(setup_packet->bRequest){
case SET_ADDRESS:
@@ -298,15 +55,58 @@ static inline void std_h2d_req(){
case SET_CONFIGURATION:
// Now device configured
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
+ 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
@@ -316,67 +116,49 @@ bmRequestType: 76543210
/**
* Endpoint0 (control) handler
*/
-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;
+static void EP0_Handler(){
+ uint8_t ep0dbuflen = 0;
+ uint8_t ep0databuf[EP0DATABUF_SIZE] __attribute__((aligned(4)));
+ uint16_t epstatus = KEEP_DTOG(USB->EPnR[0]); // EP0R on input -> return this value after modifications
int rxflag = RX_FLAG(epstatus);
- if(rxflag && SETUP_FLAG(epstatus)){
- switch(reqtype){
- case STANDARD_DEVICE_REQUEST_TYPE: // standard device request
- if(dev2host){
- std_d2h_req();
- }else{
- std_h2d_req();
- EP_WriteIRQ(0, (uint8_t *)0, 0);
- }
- break;
- case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request
- if(setup_packet->bRequest == CLEAR_FEATURE){
- EP_WriteIRQ(0, (uint8_t *)0, 0);
- }
- break;
- case VENDOR_REQUEST_TYPE:
- vendor_handler(setup_packet);
- break;
- case CONTROL_REQUEST_TYPE:
- switch(setup_packet->bRequest){
- case GET_LINE_CODING:
- EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding));
- break;
- case SET_LINE_CODING: // omit this for next stage, when data will come
- break;
- case SET_CONTROL_LINE_STATE:
- usbON = 1;
- clstate_handler(setup_packet->wValue);
- break;
- case SEND_BREAK:
- usbON = 0;
- break_handler();
- break;
- default:
- break;
- }
- if(setup_packet->bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement
- break;
- default:
- EP_WriteIRQ(0, (uint8_t *)0, 0);
- }
- }else if(rxflag){ // got data over EP0 or host acknowlegement
- if(endpoints[0].rx_cnt){
- if(setup_packet->bRequest == SET_LINE_CODING){
- linecoding_handler((usb_LineCoding*)ep0databuf);
+ // 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;
}
- } else if(TX_FLAG(epstatus)){ // package transmitted
+ }
+ 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/data transmission
+ //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;
@@ -390,9 +172,14 @@ void EP0_Handler(){
*/
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
if(size > endpoints[number].txbufsz) size = endpoints[number].txbufsz;
+#ifndef USB32
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;
+#else
+ int N4 = (size + 3) >> 2;
+ uint32_t *buf32 = (uint32_t *)buf;
+#endif
#if defined USB1_16
// very bad: what if `size` is odd?
uint32_t *out = (uint32_t *)endpoints[number].tx_buf;
@@ -401,13 +188,19 @@ void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
}
#elif defined USB2_16
// use memcpy instead?
- for(int i = 0; i < N2; i++){
+ for(int i = 0; i < N2; ++i){
endpoints[number].tx_buf[i] = buf16[i];
}
+#elif defined USB32
+ for(int i = 0; i < N4; ++i) endpoints[number].tx_buf[i] = buf32[i];
#else
-#error "Define USB1_16 or USB2_16"
+#error "Define USB1_16 / USB2_16 / USB32"
#endif
+#ifndef USB32
USB_BTABLE->EP[number].USB_COUNT_TX = size;
+#else
+ USB_BTABLE->EP[number].USB_ADDR_COUNT_TX = (USB_BTABLE->EP[number].USB_ADDR_COUNT_TX & 0xffff) | (size << 16);
+#endif
}
/**
@@ -418,9 +211,9 @@ 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){
EP_WriteIRQ(number, buf, size);
- uint16_t status = KEEP_DTOG(USB->EPnR[number]);
- // keep DTOGs, clear CTR_TX & set TX VALID to start transmission
- USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX;
+ 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;
}
/*
@@ -442,8 +235,12 @@ int EP_Read(uint8_t number, uint8_t *buf){
// use memcpy instead?
for(int i = 0; i < sz; ++i)
buf[i] = endpoints[number].rx_buf[i];
+#elif defined USB32
+ uint32_t *u32buf = (uint32_t*) buf;
+ int N4 = (sz + 3) >> 2;
+ for(int i = 0; i < N4; ++i) u32buf[i] = endpoints[number].rx_buf[i];
#else
-#error "Define USB1_16 or USB2_16"
+#error "Define USB1_16 / USB2_16 / USB32"
#endif
return sz;
}
@@ -460,91 +257,182 @@ static uint16_t lastaddr = LASTADDR_DEFAULT;
* @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)){
+#ifdef STM32G0
+ // in STM32G0 all buffers should be aligned by 32 bits
+ if(txsz & 3) txsz = ((txsz >> 2)+1) << 2;
+ if(rxsz & 3) rxsz = ((rxsz >> 2)+1) << 2;
+#endif
if(number >= STM32ENDPOINTS) return 4; // out of configured amount
- if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large
+ 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 || rxsz > USB_BTABLE_SIZE) return 3; // wrong rx buffer size
+ USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX;
+ 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;
+#ifdef USB32
+ endpoints[number].tx_buf = (uint32_t *)(USB_BTABLE_BASE + lastaddr * ACCESSZ);
+#else
endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr * ACCESSZ);
+#endif
endpoints[number].txbufsz = txsz;
- lastaddr += txsz;
+#ifdef USB32
+ USB_BTABLE->EP[number].USB_ADDR_COUNT_TX = (uint32_t) lastaddr;
+#else
+ USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr;
USB_BTABLE->EP[number].USB_COUNT_TX = 0;
- USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr;
+#endif
+ lastaddr += txsz;
+#ifdef USB32
+ endpoints[number].rx_buf = (uint32_t *)(USB_BTABLE_BASE + lastaddr * ACCESSZ);
+ USB_BTABLE->EP[number].USB_ADDR_COUNT_RX = (uint32_t) lastaddr | countrx << 26;
+#else
endpoints[number].rx_buf = (uint8_t *)(USB_BTABLE_BASE + lastaddr * ACCESSZ);
- lastaddr += rxsz;
+ USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr;
USB_BTABLE->EP[number].USB_COUNT_RX = countrx << 10;
+#endif
+ lastaddr += rxsz;
endpoints[number].func = func;
return 0;
}
// standard IRQ handler
void USB_IRQ(){
- if(USB->ISTR & USB_ISTR_RESET){
+ uint32_t CNTR = USB->CNTR;
+ USB->CNTR = 0;
+ uint32_t istr = USB->ISTR;
+ if(istr & USB_ISTR_RESET){
usbON = 0;
// Reinit registers
- USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
+ 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;
- if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler)){
+ //USB->ISTR = ~(USB_ISTR_RESET); // clear all flags
+ if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0BUFSZ, USB_EP0BUFSZ, EP0_Handler)){
return;
- }
- USB->ISTR = ~USB_ISTR_RESET;
+ };
}
- if(USB->ISTR & USB_ISTR_CTR){
+ if(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);
- }
- }
+ uint8_t n = istr & USB_ISTR_EPID;
+ if (istr & USB_ISTR_DIR){ // OUT
+ }else{ // IN
}
+ // copy received bytes amount
+ endpoints[n].rx_cnt =
+#ifdef USB32
+ (USB_BTABLE->EP[n].USB_ADDR_COUNT_RX >> 16) & 0x3FF;
+#else
+ USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter
+#endif
// call EP handler
- if(endpoints[n].func) endpoints[n].func(endpoints[n]);
+ if(endpoints[n].func) endpoints[n].func();
}
- if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep
+ if(istr & USB_ISTR_WKUP){ // wakeup
+#if defined STM32F0
+ CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LPMODE | USB_CNTR_WKUPM);
+#elif defined STM32G0
+ CNTR &= ~(USB_CNTR_SUSPEN | USB_CNTR_PDWN | USB_CNTR_WKUPM);
+#else
+ CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LP_MODE | USB_CNTR_WKUPM); // clear suspend flags
+#endif
+ //USB->ISTR = ~USB_ISTR_WKUP;
+ }
+ if(istr & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep
usbON = 0;
-#ifndef STM32F0
- USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LP_MODE;
+#if defined STM32F0
+ CNTR |= USB_CNTR_FSUSP | USB_CNTR_LPMODE | USB_CNTR_WKUPM;
+#elif defined STM32G0
+ CNTR |= USB_CNTR_SUSPEN | USB_CNTR_WKUPM;
#else
- USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LPMODE;
+ CNTR |= USB_CNTR_FSUSP | USB_CNTR_LP_MODE | USB_CNTR_WKUPM;
#endif
- USB->ISTR = ~USB_ISTR_SUSP;
- }
- if(USB->ISTR & USB_ISTR_WKUP){ // wakeup
-#ifndef STM32F0
- USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LP_MODE); // clear suspend flags
-#else
- USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LPMODE);
-#endif
- USB->ISTR = ~USB_ISTR_WKUP;
+ CNTR &= ~(USB_CNTR_SUSPM);
+ //USB->ISTR = ~USB_ISTR_SUSP;
}
+ USB->ISTR = 0; // clear all flags
+ USB->CNTR = CNTR; // rewoke interrupts
}
+// here we suppose that all PIN settings done in hw_setup earlier
+void USB_setup(){
+ lastaddr = LASTADDR_DEFAULT; // clear last address settings
+#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
+ // All is clocking from HSI48
+ 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;
+#elif defined STM32G0
+ NVIC_DisableIRQ(USB_UCPD1_2_IRQn);
+ PWR->CR2 |= PWR_CR2_USV; // enable USB powering
+ //RCC->APBENR2 |= RCC_APBENR2_SYSCFGEN; // enable tacting of SYSCFG
+ // independent clocking of USB from HSI48
+ RCC->CR |= RCC_CR_HSI48ON;
+ uint32_t tmout = 16000000;
+ while(!(RCC->CR & RCC_CR_HSI48RDY)) if(--tmout == 0) break;
+ RCC->CCIPR2 &= ~RCC_CCIPR2_USBSEL; // select HSI48 for USB
+ RCC->APBENR1 |= RCC_APBENR1_CRSEN; // CRS clocking
+ CRS->CFGR = (31LL << CRS_CFGR_FELIM_Pos) | // tolerance (usually 31)
+ (48000LL / 1LL - 1LL) << CRS_CFGR_RELOAD_Pos | // 48MHz / 1kHZ (SOF)
+ CRS_CFGR_SYNCSRC_1; // USB SOF as sync source (0x2)
+ CRS->CR |= CRS_CR_AUTOTRIMEN | CRS_CR_CEN; // Enable autotrim and turn on Clock Recovery System
+ RCC->APBENR1 |= RCC_APBENR1_USBEN;
+#endif
+#ifndef STM32G0
+ RCC->APB1ENR |= RCC_APB1ENR_USBEN;
+ USB->CNTR = USB_CNTR_FRES; // Force USB Reset
+ USB->BTABLE = 0;
+#else
+ USB->CNTR = USB_CNTR_USBRST;
+#endif
+ for(uint32_t ctr = 0; ctr < 72000; ++ctr) nop(); // wait >1ms
+ USB->CNTR = USB_CNTR_RESETM; // allow only reset interrupts
+ USB->DADDR = 0;
+ USB->ISTR = 0;
+#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);
+#elif defined STM32G0
+ USB->BCDR |= USB_BCDR_DPPU; // turn ON DP pullup
+ NVIC_EnableIRQ(USB_UCPD1_2_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")));
+#elif defined STM32G0
+void usb_ucpd1_2_isr() __attribute__ ((alias ("USB_IRQ")));
#endif
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/usb_lib.h b/F0:F030,F042,F072/usbcan_ringbuffer/usb_lib.h
index ec26927..e7ec4c9 100644
--- a/F0:F030,F042,F072/usbcan_ringbuffer/usb_lib.h
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/usb_lib.h
@@ -16,63 +16,271 @@
*/
#pragma once
+#include
#include
-#include "usbhw.h"
+
+#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
+#elif defined STM32G0
+#include
+#endif
+
+// max endpoints number
+#define STM32ENDPOINTS 8
+/**
+ * Buffers size definition
+ **/
+
+// F0 - USB2_16; F1 - USB1_16; F3 - 1/2 depending on series; G0 - USB32
+#if !defined USB1_16 && !defined USB2_16 && !defined USB32
+#if defined STM32F0
+#define USB2_16
+#elif defined STM32F1
+#define USB1_16
+#elif defined STM32G0
+#define USB32
+#else
+#error "Can't determine USB1_16/USB2_16/USB32, 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 1024
+//#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 768
+#elif defined STM32G0
+#define USB_BTABLE_SIZE 2048
+//#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!
+#ifndef STM32G0
+#define USB_BTABLE_BASE 0x40006000
+#else
+#define USB_BTABLE_BASE 0x40009800
+#endif
+#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;
+#ifndef USB32
+ __IO uint32_t BTABLE;
+#else
+ __IO uint32_t RESERVED1; // there's no BTABLE register in STM32G0
+#endif
+#if defined STM32F0 || defined USB32
+ __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)
+#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)
+#elif defined USB32
+ // 32-bit registers: addr & count in one!
+ __IO uint32_t USB_ADDR_COUNT_TX;
+ __IO uint32_t USB_ADDR_COUNT_RX;
+#define ACCESSZ (1)
+#else
+#error "Define USB1_16 (16 bits over 32bit register), USB2_16 (16 bits over 16 bit register) or USB32 (32 bist over 32 bit register)"
+#endif
+} USB_EPDATA_TypeDef;
+
+
+typedef struct{
+ __IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS];
+} USB_BtableDef;
#define EP0DATABUF_SIZE (64)
#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8)
-// bmRequestType & 0x7f
-#define STANDARD_DEVICE_REQUEST_TYPE 0
-#define STANDARD_ENDPOINT_REQUEST_TYPE 2
-#define VENDOR_REQUEST_TYPE 0x40
-#define CONTROL_REQUEST_TYPE 0x21
-// bRequest, standard; for bmRequestType == 0x80
+/******************************************************************
+ * 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 GET_DESCRIPTOR 0x06
-#define GET_CONFIGURATION 0x08
-// for bmRequestType == 0
#define CLEAR_FEATURE 0x01
-#define SET_FEATURE 0x03 // unused
+#define SET_FEATURE 0x03
#define SET_ADDRESS 0x05
-#define SET_DESCRIPTOR 0x07 // unused
+#define GET_DESCRIPTOR 0x06
+#define SET_DESCRIPTOR 0x07
+#define GET_CONFIGURATION 0x08
#define SET_CONFIGURATION 0x09
-// for bmRequestType == 0x81, 1 or 0xB2
-#define GET_INTERFACE 0x0A // unused
-#define SET_INTERFACE 0x0B // unused
-#define SYNC_FRAME 0x0C // unused
-#define VENDOR_REQUEST 0x01 // unused
-
-// Class-Specific Control Requests
-#define SEND_ENCAPSULATED_COMMAND 0x00 // unused
-#define GET_ENCAPSULATED_RESPONSE 0x01 // unused
-#define SET_COMM_FEATURE 0x02 // unused
-#define GET_COMM_FEATURE 0x03 // unused
-#define CLEAR_COMM_FEATURE 0x04 // unused
-#define SET_LINE_CODING 0x20
-#define GET_LINE_CODING 0x21
-#define SET_CONTROL_LINE_STATE 0x22
-#define SEND_BREAK 0x23
-
-// control line states
-#define CONTROL_DTR 0x01
-#define CONTROL_RTS 0x02
-
-// string descriptors
-enum{
- iLANGUAGE_DESCR,
- iMANUFACTURER_DESCR,
- iPRODUCT_DESCR,
- iSERIAL_DESCR,
- iINTERFACE_DESCR,
- iDESCR_AMOUNT
-};
+// 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)
@@ -82,12 +290,6 @@ enum{
#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
-#define EP_TYPE_CONTROL 0x01
-#define EP_TYPE_ISO 0x02
-#define EP_TYPE_INTERRUPT 0x03
-
#define LANG_US (uint16_t)0x0409
#define _USB_STRING_(name, str) \
@@ -101,7 +303,6 @@ static const struct name \
name = {sizeof(name), 0x03, str}
#define _USB_LANG_ID_(name, lng_id) \
- \
static const struct name \
{ \
uint8_t bLength; \
@@ -122,51 +323,30 @@ typedef struct {
// endpoints state
typedef struct{
+#ifdef USB32
+ uint32_t *tx_buf; // transmission buffer address
+#else
uint16_t *tx_buf; // transmission buffer address
+#endif
uint16_t txbufsz; // transmission buffer size
+#ifdef USB32
+ uint32_t *rx_buf; // reception buffer address
+#else
uint8_t *rx_buf; // reception buffer address
+#endif
void (*func)(); // endpoint action function
unsigned rx_cnt : 10; // received data counter
} ep_t;
-typedef struct {
- uint32_t dwDTERate;
- uint8_t bCharFormat;
- #define USB_CDC_1_STOP_BITS 0
- #define USB_CDC_1_5_STOP_BITS 1
- #define USB_CDC_2_STOP_BITS 2
- uint8_t bParityType;
- #define USB_CDC_NO_PARITY 0
- #define USB_CDC_ODD_PARITY 1
- #define USB_CDC_EVEN_PARITY 2
- #define USB_CDC_MARK_PARITY 3
- #define USB_CDC_SPACE_PARITY 4
- uint8_t bDataBits;
-} __attribute__ ((packed)) usb_LineCoding;
-
-typedef struct {
- uint8_t bmRequestType;
- uint8_t bNotificationType;
- uint16_t wValue;
- uint16_t wIndex;
- uint16_t wLength;
-} __attribute__ ((packed)) usb_cdc_notification;
-
-extern ep_t endpoints[];
extern volatile uint8_t usbON;
-extern config_pack_t *setup_packet;
-extern uint8_t ep0databuf[], setupdatabuf[];
-
-void EP0_Handler();
+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);
-usb_LineCoding getLineCoding();
-void linecoding_handler(usb_LineCoding *lc);
-void clstate_handler(uint16_t val);
-void break_handler();
-void vendor_handler(config_pack_t *packet);
-void chkin();
-int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)());
+// 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/F0:F030,F042,F072/usbcan_ringbuffer/usbcan.bin b/F0:F030,F042,F072/usbcan_ringbuffer/usbcan.bin
index 2f09925..63cf722 100755
Binary files a/F0:F030,F042,F072/usbcan_ringbuffer/usbcan.bin and b/F0:F030,F042,F072/usbcan_ringbuffer/usbcan.bin differ
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/usbcanrb.creator.user b/F0:F030,F042,F072/usbcan_ringbuffer/usbcanrb.creator.user
index 8800663..9e909a0 100644
--- a/F0:F030,F042,F072/usbcan_ringbuffer/usbcanrb.creator.user
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/usbcanrb.creator.user
@@ -1,6 +1,6 @@
-
+
EnvironmentId
@@ -13,8 +13,8 @@
ProjectExplorer.Project.EditorSettings
+ true
true
- false
true
Cpp
@@ -33,6 +33,7 @@
false
4
false
+ 0
80
true
true
@@ -85,12 +86,14 @@
true
+ 0
ProjectExplorer.Project.Target.0
Desktop
+ true
Desktop
Desktop
{65a14f9e-e008-4c1b-89df-4eaa4774b6e3}
@@ -132,6 +135,41 @@
Default
GenericProjectManager.GenericBuildConfiguration
+ 0
+ 0
+
+
+ 0
+ Deploy
+ Deploy
+ 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
1
@@ -162,6 +200,7 @@
ProjectExplorer.CustomExecutableRunConfiguration
false
+
true
true
@@ -172,10 +211,6 @@
ProjectExplorer.Project.TargetCount
1
-
- ProjectExplorer.Project.Updater.FileVersion
- 22
-
Version
22
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/usbcanrb.creator.user.cf63021 b/F0:F030,F042,F072/usbcan_ringbuffer/usbcanrb.creator.user.cf63021
deleted file mode 100644
index 819893c..0000000
--- a/F0:F030,F042,F072/usbcan_ringbuffer/usbcanrb.creator.user.cf63021
+++ /dev/null
@@ -1,160 +0,0 @@
-
-
-
-
-
- EnvironmentId
- {cf63021e-ef53-49b0-b03b-2f2570cdf3b6}
-
-
- 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
- false
- false
- 1
- true
- true
- 0
- 8
- true
- false
- 2
- true
- true
- true
- *.md, *.MD, Makefile
- true
- true
-
-
-
- ProjectExplorer.Project.PluginSettings
-
-
- true
- true
- Builtin.DefaultTidyAndClazy
- 4
-
-
-
- true
-
-
-
-
- ProjectExplorer.Project.Target.0
-
- Desktop
- Desktop
- Desktop
- {91347f2c-5221-46a7-80b1-0a054ca02f79}
- 0
- 0
- 0
-
- /home/eddy/Docs/SAO/ELECTRONICS/STM32/F0-srcs/usbcan_ringbuffer
-
-
-
- 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
-
-
- 2
-
- ProjectExplorer.CustomExecutableRunConfiguration
-
- false
- true
- false
- true
-
- 1
-
-
-
- ProjectExplorer.Project.TargetCount
- 1
-
-
- ProjectExplorer.Project.Updater.FileVersion
- 22
-
-
- Version
- 22
-
-
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/usbcanrb.files b/F0:F030,F042,F072/usbcan_ringbuffer/usbcanrb.files
index f1d9ab8..80fcf35 100644
--- a/F0:F030,F042,F072/usbcan_ringbuffer/usbcanrb.files
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/usbcanrb.files
@@ -10,6 +10,10 @@ ringbuffer.h
usb.c
usb.h
usb_defs.h
+usb_descr.c
+usb_descr.h
+usb_dev.c
+usb_dev.h
usb_lib.c
usb_lib.h
usbhw.c
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/usbhw.c b/F0:F030,F042,F072/usbcan_ringbuffer/usbhw.c
deleted file mode 100644
index 4f061b7..0000000
--- a/F0:F030,F042,F072/usbcan_ringbuffer/usbhw.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.h"
-#include "usb_lib.h"
-
-// 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 | USB_CNTR_WKUPM; // allow only wakeup & 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
-}
-
-
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/usbhw.h b/F0:F030,F042,F072/usbcan_ringbuffer/usbhw.h
deleted file mode 100644
index 1ca0482..0000000
--- a/F0:F030,F042,F072/usbcan_ringbuffer/usbhw.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * 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
-
-#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 512
-#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 512
-#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_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
-#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;
-
-void USB_setup();
diff --git a/F0:F030,F042,F072/usbcan_ringbuffer/version.inc b/F0:F030,F042,F072/usbcan_ringbuffer/version.inc
index b735266..1041b00 100644
--- a/F0:F030,F042,F072/usbcan_ringbuffer/version.inc
+++ b/F0:F030,F042,F072/usbcan_ringbuffer/version.inc
@@ -1,2 +1,2 @@
-#define BUILD_NUMBER "50"
-#define BUILD_DATE "2024-11-18"
+#define BUILD_NUMBER "54"
+#define BUILD_DATE "2026-03-06"