Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/flipperdevices/libusb_stm32.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvia <via@matthewvia.info>2022-06-08 12:41:05 +0300
committerGitHub <noreply@github.com>2022-06-08 12:41:05 +0300
commit79d4443751bd4f8005a0ffc3a4fbb1310529e192 (patch)
tree3a840f9455636c5b73c800d33076e80a59659a6f
parentea56bf469ebbff47679be893bd2728e57ea20f4c (diff)
Implement STM32H743 (#113)
* Add support for stm32h743 * fixup! Only supporting FS
-rw-r--r--Makefile6
-rw-r--r--demo/cdc_loop.c3
-rw-r--r--demo/cdc_startup.c12
-rw-r--r--demo/stm32h743xx.ld8
-rw-r--r--hardware.md3
-rw-r--r--inc/usb.h8
-rw-r--r--readme.md8
-rw-r--r--src/usbd_stm32h743_otgfs.c467
8 files changed, 512 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 74ff96b..15f5f75 100644
--- a/Makefile
+++ b/Makefile
@@ -286,6 +286,12 @@ stm32wb55xg: clean
DEFINES='STM32WB STM32WB55xx USBD_SOF_DISABLED' \
CFLAGS='-mcpu=cortex-m4'
+stm32h743xx: clean
+ @$(MAKE) demo STARTUP='$(CMSISDEV)/ST/STM32H7xx/Source/Templates/gcc/startup_stm32h743xx.s' \
+ LDSCRIPT='demo/stm32h743xx.ld' \
+ DEFINES='STM32H7 STM32H743xx USBD_VBUS_DETECT USBD_SOF_DISABLED' \
+ CFLAGS='-mcpu=cortex-m7'
+
stm32f411xe stm32f411e-disco: clean
@$(MAKE) demo STARTUP='$(CMSISDEV)/ST/STM32F4xx/Source/Templates/gcc/startup_stm32f411xe.s' \
LDSCRIPT='demo/stm32f401xe.ld' \
diff --git a/demo/cdc_loop.c b/demo/cdc_loop.c
index c0e3a6d..cea9171 100644
--- a/demo/cdc_loop.c
+++ b/demo/cdc_loop.c
@@ -488,7 +488,8 @@ static void cdc_init_usbd(void) {
#define __WFI __NOP
#elif defined(STM32L476xx) || defined(STM32F429xx) || \
defined(STM32F105xC) || defined(STM32F107xC) || \
- defined(STM32F446xx) || defined(STM32F411xE)
+ defined(STM32F446xx) || defined(STM32F411xE) || \
+ defined(STM32H743xx)
#define USB_HANDLER OTG_FS_IRQHandler
#define USB_NVIC_IRQ OTG_FS_IRQn
#elif defined(STM32F103x6)
diff --git a/demo/cdc_startup.c b/demo/cdc_startup.c
index 8e71eea..68ce0ae 100644
--- a/demo/cdc_startup.c
+++ b/demo/cdc_startup.c
@@ -284,7 +284,19 @@ static void cdc_init_rcc (void) {
_BST(GPIOA->AFR[1], (0x0A << 12) | (0x0A << 16));
/* Disabling USB Vddusb power isolation. Vusb connected to Vdd */
_BST(PWR->CR2, PWR_CR2_USV);
+#elif defined(STM32H743xx)
+ /* Enable USB supply */
+ _BST(PWR->CR3, PWR_CR3_SCUEN | PWR_CR3_LDOEN | PWR_CR3_USB33DEN);
+ /* Enable HSI48 and use as USB PHY clock */
+ _BST(RCC->CR, RCC_CR_HSI48ON);
+ _WBS(RCC->CR, RCC_CR_HSI48RDY);
+ _BMD(RCC->D2CCIP2R, RCC_D2CCIP2R_USBSEL, 3 << RCC_D2CCIP2R_USBSEL_Pos);
+
+ /* enabling GPIOA and setting PA11 and PA12 to AF10 (USB_FS) */
+ _BST(RCC->AHB4ENR, RCC_AHB4ENR_GPIOAEN);
+ _BMD(GPIOA->MODER, (0x03 << 22) | (0x03 << 24), (0x02 << 22) | (0x02 << 24));
+ _BST(GPIOA->AFR[1], (0x0A << 12) | (0x0A << 16));
#else
#error Not supported
#endif
diff --git a/demo/stm32h743xx.ld b/demo/stm32h743xx.ld
new file mode 100644
index 0000000..c52171c
--- /dev/null
+++ b/demo/stm32h743xx.ld
@@ -0,0 +1,8 @@
+ENTRY(Reset_Handler)
+MEMORY
+{
+ ROM (rx): ORIGIN = 0x08000000, LENGTH = 1024K
+ RAM (rwx): ORIGIN = 0x20000000, LENGTH = 128K
+}
+
+INCLUDE sections.ld
diff --git a/hardware.md b/hardware.md
index d025724..88c0e41 100644
--- a/hardware.md
+++ b/hardware.md
@@ -22,6 +22,7 @@
| stm32f405xg_hs | NUCLEO-F405RG + NUCLEO2USB | based on NUCLEO-F103RE, 0.1uF at SB33, SB38 |
| stm32f745xe | NUCO-V-F745VE + NUCLEO2USB | |
| stm32f401xe | WeAct STM32F401CEU6 | |
+| stm32h743vt | Boring Tech STM32H743 | USB 5v connected to A9 |
[NUCLEO2USB SHIELD](https://github.com/dmitrystu/Nucleo2USB)
-[NUCO-V](https://github.com/dmitrystu/nuco-v) \ No newline at end of file
+[NUCO-V](https://github.com/dmitrystu/nuco-v)
diff --git a/inc/usb.h b/inc/usb.h
index 5a73df8..5c3e589 100644
--- a/inc/usb.h
+++ b/inc/usb.h
@@ -159,6 +159,14 @@
#define usbd_hw usbd_devfs
#endif
+#elif defined(STM32H743xx)
+ #define USBD_STM32H743FS
+
+ #if !defined(__ASSEMBLER__)
+ extern const struct usbd_driver usbd_otgfs;
+ #define usbd_hw usbd_otgfs
+ #endif //__ASSEMBLER__
+
#else
#error Unsupported STM32 family
#endif
diff --git a/readme.md b/readme.md
index bde1c77..a365c79 100644
--- a/readme.md
+++ b/readme.md
@@ -107,6 +107,12 @@ All requirements can be downloaded into a directory specified in environment var
<td>usbd_otghs</td>
<td>usbd_stm32f446_otghs.c</td>
</tr>
+ <tr>
+ <td>STM32H743</td>
+ <td nowrap>Doublebuffered<br/>6 endpoints<br/>VBUS detection<br/>SOF output</td>
+ <td>usbd_otgfs</td>
+ <td>usbd_stm32h743_otgfs.c</td>
+ </tr>
</table>
1. Single physical endpoint can be used to implement
@@ -119,7 +125,7 @@ All requirements can be downloaded into a directory specified in environment var
3. Tested with STM32L052K8, STM32L100RC, STM32L476RG, STM32F072C8, STM32F103C8, STM32F103CB,
STM32F303CC, STM32F303RE, STM32F429ZI, STM32F105RBT6, STM32F107VCT6, STM32L433CCT6, STM32F070CBT6,
STM32G431RB, STM32F411CEUx, STM32F405RG, STM32F446RE, STM32F373CC, STM32L053R8, GD32F103C8T6,
-STM32F745VE, STM32F401CE.
+STM32F745VE, STM32F401CE, STM32H743.
See [hardware.md](hardware.md) for details.
### Implemented definitions for classes ###
diff --git a/src/usbd_stm32h743_otgfs.c b/src/usbd_stm32h743_otgfs.c
new file mode 100644
index 0000000..b5de2c8
--- /dev/null
+++ b/src/usbd_stm32h743_otgfs.c
@@ -0,0 +1,467 @@
+/* This file is the part of the Lightweight USB device Stack for STM32 microcontrollers
+ *
+ * Copyright ©2016 Dmitry Filimonchuk <dmitrystu[at]gmail[dot]com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "stm32.h"
+#include "usb.h"
+
+#if defined(USBD_STM32H743FS)
+
+#define MAX_EP 6
+#define MAX_RX_PACKET 128
+#define MAX_CONTROL_EP 1
+#define MAX_FIFO_SZ 320 /*in 32-bit chunks */
+
+#define RX_FIFO_SZ ((4 * MAX_CONTROL_EP + 6) + ((MAX_RX_PACKET / 4) + 1) + (MAX_EP * 2) + 1)
+
+#define STATUS_VAL(x) (USBD_HW_ADDRFST | (x))
+
+static USB_OTG_GlobalTypeDef * const OTG = (void*)(USB_OTG_FS_PERIPH_BASE + USB_OTG_GLOBAL_BASE);
+static USB_OTG_DeviceTypeDef * const OTGD = (void*)(USB_OTG_FS_PERIPH_BASE + USB_OTG_DEVICE_BASE);
+static volatile uint32_t * const OTGPCTL = (void*)(USB_OTG_FS_PERIPH_BASE + USB_OTG_PCGCCTL_BASE);
+
+
+inline static uint32_t* EPFIFO(uint32_t ep) {
+ return (uint32_t*)(USB_OTG_FS_PERIPH_BASE + USB_OTG_FIFO_BASE + (ep << 12));
+}
+
+inline static USB_OTG_INEndpointTypeDef* EPIN(uint32_t ep) {
+ return (void*)(USB_OTG_FS_PERIPH_BASE + USB_OTG_IN_ENDPOINT_BASE + (ep << 5));
+}
+
+inline static USB_OTG_OUTEndpointTypeDef* EPOUT(uint32_t ep) {
+ return (void*)(USB_OTG_FS_PERIPH_BASE + USB_OTG_OUT_ENDPOINT_BASE + (ep << 5));
+}
+
+inline static void Flush_RX(void) {
+ _BST(OTG->GRSTCTL, USB_OTG_GRSTCTL_RXFFLSH);
+ _WBC(OTG->GRSTCTL, USB_OTG_GRSTCTL_RXFFLSH);
+}
+
+inline static void Flush_TX(uint8_t ep) {
+ _BMD(OTG->GRSTCTL, USB_OTG_GRSTCTL_TXFNUM,
+ _VAL2FLD(USB_OTG_GRSTCTL_TXFNUM, ep) | USB_OTG_GRSTCTL_TXFFLSH);
+ _WBC(OTG->GRSTCTL, USB_OTG_GRSTCTL_TXFFLSH);
+}
+
+static uint32_t getinfo(void) {
+ if (!(RCC->AHB1ENR & RCC_AHB1ENR_USB2OTGFSEN)) return STATUS_VAL(0);
+ if (!(OTGD->DCTL & USB_OTG_DCTL_SDIS)) return STATUS_VAL(USBD_HW_ENABLED | USBD_HW_SPEED_FS);
+ return STATUS_VAL(USBD_HW_ENABLED);
+}
+
+static void ep_setstall(uint8_t ep, bool stall) {
+ if (ep & 0x80) {
+ ep &= 0x7F;
+ uint32_t _t = EPIN(ep)->DIEPCTL;
+ if (_t & USB_OTG_DIEPCTL_USBAEP) {
+ if (stall) {
+ _BST(_t, USB_OTG_DIEPCTL_STALL);
+ } else {
+ _BMD(_t, USB_OTG_DIEPCTL_STALL,
+ USB_OTG_DIEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_SNAK);
+ }
+ EPIN(ep)->DIEPCTL = _t;
+ }
+ } else {
+ uint32_t _t = EPOUT(ep)->DOEPCTL;
+ if (_t & USB_OTG_DOEPCTL_USBAEP) {
+ if (stall) {
+ _BST(_t, USB_OTG_DOEPCTL_STALL);
+ } else {
+ _BMD(_t, USB_OTG_DOEPCTL_STALL,
+ USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_CNAK);
+ }
+ EPOUT(ep)->DOEPCTL = _t;
+ }
+ }
+}
+
+static bool ep_isstalled(uint8_t ep) {
+ if (ep & 0x80) {
+ ep &= 0x7F;
+ return (EPIN(ep)->DIEPCTL & USB_OTG_DIEPCTL_STALL) ? true : false;
+ } else {
+ return (EPOUT(ep)->DOEPCTL & USB_OTG_DOEPCTL_STALL) ? true : false;
+ }
+}
+
+static void enable(bool enable) {
+ if (enable) {
+ /* enabling USB_OTG in RCC */
+ _BST(RCC->AHB1ENR, RCC_AHB1ENR_USB2OTGFSEN);
+ _WBS(OTG->GRSTCTL, USB_OTG_GRSTCTL_AHBIDL);
+ /* configure OTG as device */
+ OTG->GUSBCFG = USB_OTG_GUSBCFG_FDMOD | USB_OTG_GUSBCFG_PHYSEL |
+ _VAL2FLD(USB_OTG_GUSBCFG_TRDT, 0x06);
+ /* configuring Vbus sense and powerup PHY */
+#if defined(USBD_VBUS_DETECT)
+ OTG->GCCFG |= USB_OTG_GCCFG_VBDEN | USB_OTG_GCCFG_PWRDWN;
+#else
+ OTG->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN | USB_OTG_GOTGCTL_BVALOVAL;
+ OTG->GCCFG = USB_OTG_GCCFG_PWRDWN;
+#endif
+ /* restart PHY*/
+ *OTGPCTL = 0;
+ /* soft disconnect device */
+ _BST(OTGD->DCTL, USB_OTG_DCTL_SDIS);
+ /* Setup USB FS speed and frame interval */
+ _BMD(OTGD->DCFG, USB_OTG_DCFG_PERSCHIVL | USB_OTG_DCFG_DSPD,
+ _VAL2FLD(USB_OTG_DCFG_PERSCHIVL, 0) | _VAL2FLD(USB_OTG_DCFG_DSPD, 0x03));
+ /* unmask EP interrupts */
+ OTGD->DIEPMSK = USB_OTG_DIEPMSK_XFRCM;
+ /* unmask core interrupts */
+ OTG->GINTMSK = USB_OTG_GINTMSK_USBRST | USB_OTG_GINTMSK_ENUMDNEM |
+#if !defined(USBD_SOF_DISABLED)
+ USB_OTG_GINTMSK_SOFM |
+#endif
+ USB_OTG_GINTMSK_USBSUSPM | USB_OTG_GINTMSK_WUIM |
+ USB_OTG_GINTMSK_IEPINT | USB_OTG_GINTMSK_RXFLVLM;
+ /* clear pending interrupts */
+ OTG->GINTSTS = 0xFFFFFFFF;
+ /* unmask global interrupt */
+ OTG->GAHBCFG = USB_OTG_GAHBCFG_GINT;
+ /* setting max RX FIFO size */
+ OTG->GRXFSIZ = RX_FIFO_SZ;
+ /* setting up EP0 TX FIFO SZ as 64 byte */
+ OTG->DIEPTXF0_HNPTXFSIZ = RX_FIFO_SZ | (0x10 << 16);
+ } else {
+ if (RCC->AHB1ENR & RCC_AHB1ENR_USB2OTGFSEN) {
+ _BST(RCC->AHB1RSTR, RCC_AHB1RSTR_USB2OTGFSRST);
+ _BCL(RCC->AHB1RSTR, RCC_AHB1RSTR_USB2OTGFSRST);
+ _BCL(RCC->AHB1ENR, RCC_AHB1ENR_USB2OTGFSEN);
+ }
+ }
+}
+
+static uint8_t connect(bool connect) {
+ if (connect) {
+ _BCL(OTGD->DCTL, USB_OTG_DCTL_SDIS);
+ } else {
+ _BST(OTGD->DCTL, USB_OTG_DCTL_SDIS);
+ }
+ return usbd_lane_unk;
+}
+
+static void setaddr (uint8_t addr) {
+ _BMD(OTGD->DCFG, USB_OTG_DCFG_DAD, addr << 4);
+}
+
+/**\brief Helper. Set up TX fifo
+ * \param ep endpoint index
+ * \param epsize required max packet size in bytes
+ * \return true if TX fifo is successfully set
+ */
+static bool set_tx_fifo(uint8_t ep, uint16_t epsize) {
+ uint32_t _fsa = OTG->DIEPTXF0_HNPTXFSIZ;
+ /* calculating initial TX FIFO address. next from EP0 TX fifo */
+ _fsa = 0xFFFF & (_fsa + (_fsa >> 16));
+ /* looking for next free TX fifo address */
+ for (int i = 0; i < (MAX_EP - 1); i++) {
+ uint32_t _t = OTG->DIEPTXF[i];
+ if ((_t & 0xFFFF) < 0x200) {
+ _t = 0xFFFF & (_t + (_t >> 16));
+ if (_t > _fsa) {
+ _fsa = _t;
+ }
+ }
+ }
+ /* calculating requited TX fifo size */
+ /* getting in 32 bit terms */
+ epsize = (epsize + 0x03) >> 2;
+ /* it must be 16 32-bit words minimum */
+ if (epsize < 0x10) epsize = 0x10;
+ /* checking for the available fifo */
+ if ((_fsa + epsize) > MAX_FIFO_SZ) return false;
+ /* programming fifo register */
+ _fsa |= (epsize << 16);
+ OTG->DIEPTXF[ep - 1] = _fsa;
+ return true;
+}
+
+static bool ep_config(uint8_t ep, uint8_t eptype, uint16_t epsize) {
+ if (ep == 0) {
+ /* configureing control endpoint EP0 */
+ uint32_t mpsize;
+ if (epsize <= 0x08) {
+ epsize = 0x08;
+ mpsize = 0x03;
+ } else if (epsize <= 0x10) {
+ epsize = 0x10;
+ mpsize = 0x02;
+ } else if (epsize <= 0x20) {
+ epsize = 0x20;
+ mpsize = 0x01;
+ } else {
+ epsize = 0x40;
+ mpsize = 0x00;
+ }
+ /* EP0 TX FIFO size is setted on init level */
+ /* enabling RX and TX interrupts from EP0 */
+ OTGD->DAINTMSK |= 0x00010001;
+ /* setting up EP0 TX and RX registers */
+ /*EPIN(ep)->DIEPTSIZ = epsize;*/
+ EPIN(ep)->DIEPCTL = mpsize | USB_OTG_DIEPCTL_SNAK;
+ /* 1 setup packet, 1 packets total */
+ EPOUT(ep)->DOEPTSIZ = epsize | (1 << 29) | (1 << 19);
+ EPOUT(ep)->DOEPCTL = mpsize | USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
+ return true;
+ }
+ if (ep & 0x80) {
+ ep &= 0x7F;
+ USB_OTG_INEndpointTypeDef* epi = EPIN(ep);
+ /* configuring TX endpoint */
+ /* setting up TX fifo and size register */
+ if ((eptype == USB_EPTYPE_ISOCHRONUS) ||
+ (eptype == (USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF))) {
+ if (!set_tx_fifo(ep, epsize << 1)) return false;
+ } else {
+ if (!set_tx_fifo(ep, epsize)) return false;
+ }
+ /* enabling EP TX interrupt */
+ OTGD->DAINTMSK |= (0x0001UL << ep);
+ /* setting up TX control register*/
+ switch (eptype) {
+ case USB_EPTYPE_ISOCHRONUS:
+ epi->DIEPCTL = USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK |
+ (0x01 << 18) | USB_OTG_DIEPCTL_USBAEP |
+ USB_OTG_DIEPCTL_SD0PID_SEVNFRM |
+ (ep << 22) | epsize;
+ break;
+ case USB_EPTYPE_BULK:
+ case USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF:
+ epi->DIEPCTL = USB_OTG_DIEPCTL_SNAK | USB_OTG_DIEPCTL_USBAEP |
+ (0x02 << 18) | USB_OTG_DIEPCTL_SD0PID_SEVNFRM |
+ (ep << 22) | epsize;
+ break;
+ default:
+ epi->DIEPCTL = USB_OTG_DIEPCTL_SNAK | USB_OTG_DIEPCTL_USBAEP |
+ (0x03 << 18) | USB_OTG_DIEPCTL_SD0PID_SEVNFRM |
+ (ep << 22) | epsize;
+ break;
+ }
+ } else {
+ /* configuring RX endpoint */
+ USB_OTG_OUTEndpointTypeDef* epo = EPOUT(ep);
+ /* setting up RX control register */
+ switch (eptype) {
+ case USB_EPTYPE_ISOCHRONUS:
+ epo->DOEPCTL = USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_CNAK |
+ USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_USBAEP |
+ (0x01 << 18) | epsize;
+ break;
+ case USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF:
+ case USB_EPTYPE_BULK:
+ epo->DOEPCTL = USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_CNAK |
+ USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_USBAEP |
+ (0x02 << 18) | epsize;
+ break;
+ default:
+ epo->DOEPCTL = USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_CNAK |
+ USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_USBAEP |
+ (0x03 << 18) | epsize;
+ break;
+ }
+ }
+ return true;
+}
+
+static void ep_deconfig(uint8_t ep) {
+ ep &= 0x7F;
+ volatile USB_OTG_INEndpointTypeDef* epi = EPIN(ep);
+ volatile USB_OTG_OUTEndpointTypeDef* epo = EPOUT(ep);
+ /* deconfiguring TX part */
+ /* disable interrupt */
+ OTGD->DAINTMSK &= ~(0x10001 << ep);
+ /* decativating endpoint */
+ _BCL(epi->DIEPCTL, USB_OTG_DIEPCTL_USBAEP);
+ /* flushing FIFO */
+ Flush_TX(ep);
+ /* disabling endpoint */
+ if ((epi->DIEPCTL & USB_OTG_DIEPCTL_EPENA) && (ep != 0)) {
+ epi->DIEPCTL = USB_OTG_DIEPCTL_EPDIS;
+ }
+ /* clean EP interrupts */
+ epi->DIEPINT = 0xFF;
+ /* deconfiguring TX FIFO */
+ if (ep > 0) {
+ OTG->DIEPTXF[ep-1] = 0x02000200 + 0x200 * ep;
+ }
+ /* deconfigureing RX part */
+ _BCL(epo->DOEPCTL, USB_OTG_DOEPCTL_USBAEP);
+ if ((epo->DOEPCTL & USB_OTG_DOEPCTL_EPENA) && (ep != 0)) {
+ epo->DOEPCTL = USB_OTG_DOEPCTL_EPDIS;
+ }
+ epo->DOEPINT = 0xFF;
+}
+
+static int32_t ep_read(uint8_t ep, void* buf, uint16_t blen) {
+ uint32_t len, tmp;
+ ep &= 0x7F;
+ volatile uint32_t *fifo = EPFIFO(0);
+ USB_OTG_OUTEndpointTypeDef* epo = EPOUT(ep);
+ /* no data in RX FIFO */
+ if (!(OTG->GINTSTS & USB_OTG_GINTSTS_RXFLVL)) return -1;
+ if ((OTG->GRXSTSR & USB_OTG_GRXSTSP_EPNUM) != ep) return -1;
+ /* pop data from fifo */
+ len = _FLD2VAL(USB_OTG_GRXSTSP_BCNT, OTG->GRXSTSP);
+ for (int idx = 0; idx < len; idx++) {
+ if ((idx & 0x03) == 0x00) {
+ tmp = *fifo;
+ }
+ if (idx < blen) {
+ ((uint8_t*)buf)[idx] = tmp & 0xFF;
+ tmp >>= 8;
+ }
+ }
+ _BST(epo->DOEPCTL, USB_OTG_DOEPCTL_CNAK | USB_OTG_DOEPCTL_EPENA);
+ return (len < blen) ? len : blen;
+}
+
+static int32_t ep_write(uint8_t ep, const void *buf, uint16_t blen) {
+ uint32_t len, tmp;
+ ep &= 0x7F;
+ volatile uint32_t* fifo = EPFIFO(ep);
+ USB_OTG_INEndpointTypeDef* epi = EPIN(ep);
+ /* transfer data size in 32-bit words */
+ len = (blen + 3) >> 2;
+ /* no enough space in TX fifo */
+ if (len > epi->DTXFSTS) return -1;
+ if (ep != 0 && epi->DIEPCTL & USB_OTG_DIEPCTL_EPENA) {
+ return -1;
+ }
+ epi->DIEPTSIZ = 0;
+ epi->DIEPTSIZ = (1 << 19) + blen;
+ _BMD(epi->DIEPCTL, USB_OTG_DIEPCTL_STALL, USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK);
+ /* push data to FIFO */
+ tmp = 0;
+ for (int idx = 0; idx < blen; idx++) {
+ tmp |= (uint32_t)((const uint8_t*)buf)[idx] << ((idx & 0x03) << 3);
+ if ((idx & 0x03) == 0x03 || (idx + 1) == blen) {
+ *fifo = tmp;
+ tmp = 0;
+ }
+ }
+ return blen;
+}
+
+static uint16_t get_frame (void) {
+ return _FLD2VAL(USB_OTG_DSTS_FNSOF, OTGD->DSTS);
+}
+
+static void evt_poll(usbd_device *dev, usbd_evt_callback callback) {
+ uint32_t evt;
+ uint32_t ep = 0;
+ while (1) {
+ uint32_t _t = OTG->GINTSTS;
+ /* bus RESET event */
+ if (_t & USB_OTG_GINTSTS_USBRST) {
+ OTG->GINTSTS = USB_OTG_GINTSTS_USBRST;
+ for (uint8_t i = 0; i < MAX_EP; i++ ) {
+ ep_deconfig(i);
+ }
+ Flush_RX();
+ continue;
+ } else if (_t & USB_OTG_GINTSTS_ENUMDNE) {
+ OTG->GINTSTS = USB_OTG_GINTSTS_ENUMDNE;
+ evt = usbd_evt_reset;
+ } else if (_t & USB_OTG_GINTSTS_IEPINT) {
+ for (;; ep++) {
+ USB_OTG_INEndpointTypeDef* epi = EPIN(ep);
+ if (ep >= MAX_EP) return;
+ if (epi->DIEPINT & USB_OTG_DIEPINT_XFRC) {
+ epi->DIEPINT = USB_OTG_DIEPINT_XFRC;
+ evt = usbd_evt_eptx;
+ ep |= 0x80;
+ break;
+ }
+ }
+ } else if (_t & USB_OTG_GINTSTS_RXFLVL) {
+ _t = OTG->GRXSTSR;
+ ep = _t & USB_OTG_GRXSTSP_EPNUM;
+ switch (_FLD2VAL(USB_OTG_GRXSTSP_PKTSTS, _t)) {
+ case 0x02:
+ evt = usbd_evt_eprx;
+ break;
+ case 0x06:
+ evt = usbd_evt_epsetup;
+ break;
+ default:
+ OTG->GRXSTSP;
+ continue;
+ }
+#if !defined(USBD_SOF_DISABLED)
+ } else if (_t & USB_OTG_GINTSTS_SOF) {
+ OTG->GINTSTS = USB_OTG_GINTSTS_SOF;
+ evt = usbd_evt_sof;
+#endif
+ } else if (_t & USB_OTG_GINTSTS_USBSUSP) {
+ evt = usbd_evt_susp;
+ OTG->GINTSTS = USB_OTG_GINTSTS_USBSUSP;
+ } else if (_t & USB_OTG_GINTSTS_WKUINT) {
+ OTG->GINTSTS = USB_OTG_GINTSTS_WKUINT;
+ evt = usbd_evt_wkup;
+ } else {
+ /* no more supported events */
+ return;
+ }
+ return callback(dev, evt, ep);
+ }
+}
+
+static uint32_t fnv1a32_turn (uint32_t fnv, uint32_t data ) {
+ for (int i = 0; i < 4 ; i++) {
+ fnv ^= (data & 0xFF);
+ fnv *= 16777619;
+ data >>= 8;
+ }
+ return fnv;
+}
+
+static uint16_t get_serialno_desc(void *buffer) {
+ struct usb_string_descriptor *dsc = buffer;
+ uint16_t *str = dsc->wString;
+ uint32_t fnv = 2166136261;
+ fnv = fnv1a32_turn(fnv, *(uint32_t*)(UID_BASE + 0x00));
+ fnv = fnv1a32_turn(fnv, *(uint32_t*)(UID_BASE + 0x04));
+ fnv = fnv1a32_turn(fnv, *(uint32_t*)(UID_BASE + 0x08));
+ for (int i = 28; i >= 0; i -= 4 ) {
+ uint16_t c = (fnv >> i) & 0x0F;
+ c += (c < 10) ? '0' : ('A' - 10);
+ *str++ = c;
+ }
+ dsc->bDescriptorType = USB_DTYPE_STRING;
+ dsc->bLength = 18;
+ return 18;
+}
+
+ __attribute__((externally_visible)) const struct usbd_driver usbd_otgfs = {
+ getinfo,
+ enable,
+ connect,
+ setaddr,
+ ep_config,
+ ep_deconfig,
+ ep_read,
+ ep_write,
+ ep_setstall,
+ ep_isstalled,
+ evt_poll,
+ get_frame,
+ get_serialno_desc,
+};
+
+#endif //USBD_STM32H743xx