Browse Source

Implement STM32H743 (#113)

* Add support for stm32h743

* fixup! Only supporting FS
via 4 years ago
parent
commit
79d4443751
8 changed files with 512 additions and 3 deletions
  1. 6 0
      Makefile
  2. 2 1
      demo/cdc_loop.c
  3. 12 0
      demo/cdc_startup.c
  4. 8 0
      demo/stm32h743xx.ld
  5. 2 1
      hardware.md
  6. 8 0
      inc/usb.h
  7. 7 1
      readme.md
  8. 467 0
      src/usbd_stm32h743_otgfs.c

+ 6 - 0
Makefile

@@ -286,6 +286,12 @@ stm32wb55xg: clean
 						DEFINES='STM32WB STM32WB55xx USBD_SOF_DISABLED' \
 						DEFINES='STM32WB STM32WB55xx USBD_SOF_DISABLED' \
 						CFLAGS='-mcpu=cortex-m4'
 						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
 stm32f411xe stm32f411e-disco: clean
 	@$(MAKE) demo STARTUP='$(CMSISDEV)/ST/STM32F4xx/Source/Templates/gcc/startup_stm32f411xe.s' \
 	@$(MAKE) demo STARTUP='$(CMSISDEV)/ST/STM32F4xx/Source/Templates/gcc/startup_stm32f411xe.s' \
 						LDSCRIPT='demo/stm32f401xe.ld' \
 						LDSCRIPT='demo/stm32f401xe.ld' \

+ 2 - 1
demo/cdc_loop.c

@@ -488,7 +488,8 @@ static void cdc_init_usbd(void) {
     #define __WFI __NOP
     #define __WFI __NOP
 #elif defined(STM32L476xx) || defined(STM32F429xx) || \
 #elif defined(STM32L476xx) || defined(STM32F429xx) || \
       defined(STM32F105xC) || defined(STM32F107xC) || \
       defined(STM32F105xC) || defined(STM32F107xC) || \
-      defined(STM32F446xx) || defined(STM32F411xE)
+      defined(STM32F446xx) || defined(STM32F411xE) || \
+      defined(STM32H743xx)
     #define USB_HANDLER     OTG_FS_IRQHandler
     #define USB_HANDLER     OTG_FS_IRQHandler
     #define USB_NVIC_IRQ    OTG_FS_IRQn
     #define USB_NVIC_IRQ    OTG_FS_IRQn
 #elif defined(STM32F103x6)
 #elif defined(STM32F103x6)

+ 12 - 0
demo/cdc_startup.c

@@ -284,7 +284,19 @@ static void cdc_init_rcc (void) {
     _BST(GPIOA->AFR[1], (0x0A << 12) | (0x0A << 16));
     _BST(GPIOA->AFR[1], (0x0A << 12) | (0x0A << 16));
     /* Disabling USB Vddusb power isolation. Vusb connected to Vdd */
     /* Disabling USB Vddusb power isolation. Vusb connected to Vdd */
     _BST(PWR->CR2, PWR_CR2_USV);
     _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
 #else
     #error Not supported
     #error Not supported
 #endif
 #endif

+ 8 - 0
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

+ 2 - 1
hardware.md

@@ -22,6 +22,7 @@
 | stm32f405xg_hs | NUCLEO-F405RG + NUCLEO2USB | based on NUCLEO-F103RE, 0.1uF at SB33, SB38 |
 | stm32f405xg_hs | NUCLEO-F405RG + NUCLEO2USB | based on NUCLEO-F103RE, 0.1uF at SB33, SB38 |
 | stm32f745xe    | NUCO-V-F745VE + NUCLEO2USB |                                             |
 | stm32f745xe    | NUCO-V-F745VE + NUCLEO2USB |                                             |
 | stm32f401xe    | WeAct STM32F401CEU6        |                                             |
 | stm32f401xe    | WeAct STM32F401CEU6        |                                             |
+| stm32h743vt    | Boring Tech STM32H743      | USB 5v connected to A9                      |
 
 
 [NUCLEO2USB SHIELD](https://github.com/dmitrystu/Nucleo2USB)
 [NUCLEO2USB SHIELD](https://github.com/dmitrystu/Nucleo2USB)
-[NUCO-V](https://github.com/dmitrystu/nuco-v)
+[NUCO-V](https://github.com/dmitrystu/nuco-v)

+ 8 - 0
inc/usb.h

@@ -159,6 +159,14 @@
     #define usbd_hw usbd_devfs
     #define usbd_hw usbd_devfs
     #endif
     #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
 #else
     #error Unsupported STM32 family
     #error Unsupported STM32 family
 #endif
 #endif

+ 7 - 1
readme.md

@@ -107,6 +107,12 @@ All requirements can be downloaded into a directory specified in environment var
         <td>usbd_otghs</td>
         <td>usbd_otghs</td>
         <td>usbd_stm32f446_otghs.c</td>
         <td>usbd_stm32f446_otghs.c</td>
     </tr>
     </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>
 </table>
 
 
 1. Single physical endpoint can be used to implement
 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,
 3. Tested with STM32L052K8, STM32L100RC, STM32L476RG, STM32F072C8, STM32F103C8, STM32F103CB,
 STM32F303CC, STM32F303RE, STM32F429ZI, STM32F105RBT6, STM32F107VCT6, STM32L433CCT6, STM32F070CBT6,
 STM32F303CC, STM32F303RE, STM32F429ZI, STM32F105RBT6, STM32F107VCT6, STM32L433CCT6, STM32F070CBT6,
 STM32G431RB, STM32F411CEUx, STM32F405RG, STM32F446RE, STM32F373CC, STM32L053R8, GD32F103C8T6,
 STM32G431RB, STM32F411CEUx, STM32F405RG, STM32F446RE, STM32F373CC, STM32L053R8, GD32F103C8T6,
-STM32F745VE, STM32F401CE.
+STM32F745VE, STM32F401CE, STM32H743.
 See [hardware.md](hardware.md) for details.
 See [hardware.md](hardware.md) for details.
 
 
 ### Implemented definitions for classes ###
 ### Implemented definitions for classes ###

+ 467 - 0
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