소스 검색

Add support for stm32f105 and stm32f107. Based on the stm32f429 driver.

Fabián Inostroza 7 년 전
부모
커밋
a6cdbd15a5
7개의 변경된 파일646개의 추가작업 그리고 2개의 파일을 삭제
  1. 13 0
      Makefile
  2. 1 1
      demo/cdc_loop.c
  3. 46 0
      demo/cdc_startup.c
  4. 87 0
      demo/stm32f105xb.ld
  5. 8 0
      inc/usb.h
  6. 7 1
      readme.md
  7. 484 0
      src/usbd_stm32f105_otgfs.c

+ 13 - 0
Makefile

@@ -122,6 +122,19 @@ stm32f303xe 32f303re-nucleo:
 						DEFINES='STM32F3 STM32F303xE USBD_SOF_DISABLED' \
 						CFLAGS='-mcpu=cortex-m4 -mthumb'
 
+
+stm32f105xb:
+	@$(MAKE) clean demo STARTUP='$(CMSISDEV)/ST/STM32F1xx/Source/Templates/gcc/startup_stm32f105xc.s' \
+						LDSCRIPT='demo/stm32f105xb.ld' \
+						DEFINES='STM32F1 STM32F105xC USBD_VBUS_DETECT USBD_SOF_DISABLED' \
+						CFLAGS='-mcpu=cortex-m3 -mthumb -Wp,-w'
+
+stm32f107xb:
+	@$(MAKE) clean demo STARTUP='$(CMSISDEV)/ST/STM32F1xx/Source/Templates/gcc/startup_stm32f107xc.s' \
+						LDSCRIPT='demo/stm32f105xb.ld' \
+						DEFINES='STM32F1 STM32F107xC HSE_25MHZ USBD_VBUS_DETECT USBD_SOF_DISABLED' \
+						CFLAGS='-mcpu=cortex-m3 -mthumb -Wp,-w'
+
 stm32l052x8:
 	@$(MAKE) clean demo STARTUP='$(CMSISDEV)/ST/STM32L0xx/Source/Templates/gcc/startup_stm32l052xx.s' \
 						LDSCRIPT='demo/stm32l052x8.ld' \

+ 1 - 1
demo/cdc_loop.c

@@ -300,7 +300,7 @@ static void cdc_init_usbd(void) {
 #elif defined(STM32F103xE)
     #define USB_HANDLER     USB_LP_CAN1_RX0_IRQHandler
     #define USB_NVIC_IRQ    USB_LP_CAN1_RX0_IRQn
-#elif defined(STM32F429xx)
+#elif defined(STM32F429xx) || defined(STM32F105xC) || defined(STM32F107xC)
     #define USB_HANDLER     OTG_FS_IRQHandler
     #define USB_NVIC_IRQ    OTG_FS_IRQn
 #else

+ 46 - 0
demo/cdc_startup.c

@@ -109,6 +109,52 @@ static void cdc_init_rcc (void) {
     _BST(RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN);
     _BST(GPIOA->AFR[1], (0x0A << 12) | (0x0A << 16));
     _BMD(GPIOA->MODER, (0x03 << 22) | (0x03 << 24), (0x02 << 22) | (0x02 << 24));
+
+#elif defined(STM32F105xC) || defined(STM32F107xC)
+    _BST(RCC->CR, RCC_CR_HSION);
+    _WBS(RCC->CR, RCC_CR_HSIRDY);
+    _BMD(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_HSI);
+    _BMD(RCC->CFGR, RCC_CFGR_SWS, RCC_CFGR_SWS_HSI);
+    /* set flash latency 1WS */
+    _BMD(FLASH->ACR, FLASH_ACR_LATENCY, FLASH_ACR_LATENCY_1);
+
+    _BST(RCC->CR, RCC_CR_HSEON);
+    _WBS(RCC->CR, RCC_CR_HSERDY);
+
+    /* switch to HSE */
+    _BMD(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_HSE);
+    _WVL(RCC->CFGR, RCC_CFGR_SWS, RCC_CFGR_SWS_HSE);
+
+    #if defined(HSE_25MHZ)
+    RCC->CFGR = RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC | \
+                RCC_CFGR_ADCPRE_DIV8 | RCC_CFGR_PPRE2_DIV1 | \
+                RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_HPRE_DIV1 | \
+                RCC_CFGR_OTGFSPRE*0;
+    /* PREDIV1SRC= PLL2, PLL2MUL = 8, PREDIV1 = 5, PREDIV2=5 */
+    RCC->CFGR2 = RCC_CFGR2_PREDIV1SRC | RCC_CFGR2_PLL2MUL8 | \
+                 RCC_CFGR2_PREDIV1_DIV5 | RCC_CFGR2_PREDIV2_DIV5;
+
+    _BST(RCC->CR, RCC_CR_PLL2ON);
+    _WBS(RCC->CR, RCC_CR_PLL2RDY);
+
+    _BST(RCC->CR, RCC_CR_PLLON);
+    _WBS(RCC->CR, RCC_CR_PLLRDY);
+    #else
+    RCC->CFGR = RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC | RCC_CFGR_ADCPRE_DIV8 | \
+                RCC_CFGR_PPRE2_DIV1 | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_HPRE_DIV1;
+    _BMD(RCC->CFGR2, RCC_CFGR2_PREDIV1, RCC_CFGR2_PREDIV1_DIV1);
+    _BCL(RCC->CFGR2, RCC_CFGR2_PREDIV1SRC);
+    _BST(RCC->CR, RCC_CR_PLLON);
+    _WBS(RCC->CR, RCC_CR_PLLRDY);
+    #endif
+
+    RCC->CFGR |= RCC_CFGR_MCO_PLLCLK_DIV2;
+
+    /* set flash latency 2WS */
+    _BMD(FLASH->ACR, FLASH_ACR_LATENCY, FLASH_ACR_LATENCY_2);
+    /* switch to PLL */
+    _BMD(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_PLL);
+    _WVL(RCC->CFGR, RCC_CFGR_SWS, RCC_CFGR_SWS_PLL);
 #else
     #error Not supported
 #endif

+ 87 - 0
demo/stm32f105xb.ld

@@ -0,0 +1,87 @@
+ENTRY(Reset_Handler)
+MEMORY
+{
+    ROM  (rx): ORIGIN = 0x08000000, LENGTH =  128K
+    RAM (rwx): ORIGIN = 0x20000000, LENGTH =  64K
+}
+SECTIONS
+{
+    .text :
+    {
+        KEEP(*(.isr_vector))
+        *(.text*)
+        KEEP(*(.init))  KEEP(*(.fini))
+        *crtbegin.o(.ctors)
+        *crtbegin?.o(.ctors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+        *(SORT(.ctors.*))
+        *(.ctors)
+        *crtbegin.o(.dtors)
+        *crtbegin?.o(.dtors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o).dtors)
+        *(SORT(.dtors.*))
+        *(.dtors)
+        *(.rodata*)
+        KEEP(*(.eh_frame*))
+    } > ROM
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > ROM
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > ROM
+    __exidx_end = .;
+    __etext = .;
+    .data : AT (__etext)
+    {
+        __data_start__ = .;
+        *(vtable)
+        *(.data*)
+        . = ALIGN(4);
+        PROVIDE_HIDDEN (__preinit_array_start = .);
+        KEEP(*(.preinit_array))
+        PROVIDE_HIDDEN (__preinit_array_end = .);
+        . = ALIGN(4);
+        PROVIDE_HIDDEN (__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE_HIDDEN (__init_array_end = .);
+        . = ALIGN(4);
+        PROVIDE_HIDDEN (__fini_array_start = .);
+        KEEP(*(SORT(.fini_array.*)))
+        KEEP(*(.fini_array))
+        PROVIDE_HIDDEN (__fini_array_end = .);
+        . = ALIGN(4);
+        __data_end__ = .;
+    } > RAM
+    .bss (NOLOAD) :
+    {
+        __bss_start__ = .;
+        *(.bss*)
+        *(COMMON)
+        __bss_end__ = .;
+    } > RAM
+    .heap (NOLOAD) :
+    {
+        __end__ = .;
+        *(.heap*)
+        __HeapLimit = .;
+    } > RAM
+    .stack_dummy (NOLOAD) :
+    {
+        *(.stack)
+    } > RAM
+    __StackTop = ORIGIN(RAM) + LENGTH(RAM);
+    __StackLimit = __StackTop - SIZEOF(.stack_dummy);
+    PROVIDE(__stack = __StackTop);
+    ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
+    PROVIDE(_estack = __stack);
+    PROVIDE(_sidata = __etext);
+    PROVIDE(_sdata = __data_start__);
+    PROVIDE(_edata = __data_end__);
+    PROVIDE(_sbss = __bss_start__);
+    PROVIDE(_ebss = __bss_end__);
+}

+ 8 - 0
inc/usb.h

@@ -101,6 +101,14 @@
     #endif
     #endif
 
+#elif defined(STM32F105xC) || defined(STM32F107xC)
+    #define USBD_STM32F105
+
+    #if !defined(__ASSEMBLER__)
+    extern const struct usbd_driver usbd_otgfs;
+    #define usbd_hw usbd_otgfs
+    #endif
+
 #else
     #error Unsupported STM32 family
 #endif

+ 7 - 1
readme.md

@@ -57,6 +57,12 @@
         <td>usbd_otgfs</td>
         <td>usbd_stm32l429_otgfs.c</td>
     </tr>
+    <tr>
+        <td>STM32F105 STM32F107</td>
+        <td nowrap>Doublebuffered<br/>6 endpoints<br/>VBUS detection<br/>SOF output</td>
+        <td>usbd_otgfs</td>
+        <td>usbd_stm32f105_otgfs.c</td>
+    </tr>
 </table>
 
 1. Single physical endpoint can be used to implement
@@ -66,7 +72,7 @@
 
 2. At this moment BULK IN endpoint can use both buffers, but it is not **real** doublebuffered.
 
-3. Tested with STM32L052K8, STM32L100RC, STM32L476RG, STM32F072C8, STM32F103C8, STM32F103CB, STM32F303CC, STM32F303RE, STM32F429ZI
+3. Tested with STM32L052K8, STM32L100RC, STM32L476RG, STM32F072C8, STM32F103C8, STM32F103CB, STM32F303CC, STM32F303RE, STM32F429ZI, STM32F105RBT6, STM32F107VCT6
 
 ### Implemented definitions for classes ###
 1. USB HID based on [Device Class Definition for Human Interface Devices (HID) Version 1.11](http://www.usb.org/developers/hidpage/HID1_11.pdf)

+ 484 - 0
src/usbd_stm32f105_otgfs.c

@@ -0,0 +1,484 @@
+/* This file is the part of the Lightweight USB device Stack for STM32 microcontrollers
+ *
+ * Copyright ©2016 Dmitry Filimonchuk <dmitrystu[at]gmail[dot]com>
+ * Adapted from the stm32f429 driver by Fabian Inostroza
+ *
+ * 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_STM32F105)
+
+#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))
+
+USB_OTG_GlobalTypeDef * const OTG  = (void*)(USB_OTG_FS_PERIPH_BASE + USB_OTG_GLOBAL_BASE);
+USB_OTG_DeviceTypeDef * const OTGD = (void*)(USB_OTG_FS_PERIPH_BASE + USB_OTG_DEVICE_BASE);
+volatile uint32_t * const OTGPCTL  = (void*)(USB_OTG_FS_PERIPH_BASE + USB_OTG_PCGCCTL_BASE);
+
+
+inline static volatile uint32_t* EPFIFO(uint8_t ep) {
+    return (uint32_t*)(USB_OTG_FS_PERIPH_BASE + USB_OTG_FIFO_BASE + (ep << 12));
+}
+
+inline static USB_OTG_INEndpointTypeDef* EPIN(uint8_t ep) {
+    return (void*)(USB_OTG_FS_PERIPH_BASE + USB_OTG_IN_ENDPOINT_BASE + (ep << 5));
+}
+
+inline static USB_OTG_OUTEndpointTypeDef* EPOUT(uint8_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);
+}
+
+uint32_t getinfo(void) {
+    if (!(RCC->AHBENR & RCC_AHBENR_OTGFSEN)) 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);
+}
+
+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;
+        }
+    }
+}
+
+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;
+    }
+}
+
+void enable(bool enable) {
+    if (enable) {
+        /* enabling USB_OTG in RCC */
+        _BST(RCC->AHBENR, RCC_AHBENR_OTGFSEN);
+        /* do core soft reset */
+        _WBS(OTG->GRSTCTL, USB_OTG_GRSTCTL_AHBIDL);
+        _BST(OTG->GRSTCTL, USB_OTG_GRSTCTL_CSRST);
+        _WBC(OTG->GRSTCTL, USB_OTG_GRSTCTL_CSRST);
+        /* configure OTG as device */
+        OTG->GUSBCFG = USB_OTG_GUSBCFG_FDMOD | USB_OTG_GUSBCFG_PHYSEL |
+                       _VAL2FLD(USB_OTG_GUSBCFG_TRDT, 0x06);
+        /* configuring Vbus sense and SOF output */
+#if defined (USBD_VBUS_DETECT) && defined(USBD_SOF_OUT)
+        OTG->GCCFG = USB_OTG_GCCFG_VBUSBSEN | USB_OTG_GCCFG_SOFOUTEN;
+#elif defined(USBD_VBUS_DETECT)
+         OTG->GCCFG = USB_OTG_GCCFG_VBUSBSEN;
+#elif defined(USBD_SOF_OUT)
+        OTG->GCCFG = USB_OTG_GCCFG_SOFOUTEN;
+#else
+        OTG->GCCFG &= ~(USB_OTG_GCCFG_SOFOUTEN | USB_OTG_GCCFG_VBUSBSEN);
+#endif
+        /* enable PHY clock */
+        *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));
+        /* 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);
+        /* 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 */
+        _BST(OTG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
+    } else {
+        if (RCC->AHBENR & RCC_AHBENR_OTGFSEN) {
+            _BST(RCC->AHBRSTR, RCC_AHBRSTR_OTGFSRST);
+            _BCL(RCC->AHBRSTR, RCC_AHBRSTR_OTGFSRST);
+            _BCL(RCC->AHBENR, RCC_AHBENR_OTGFSEN);
+        }
+    }
+}
+
+uint8_t connect(bool connect) {
+    if (connect) {
+/* The ST made a strange thing again. Really i dont'understand what is the reason to name
+   signal as PWRDWN (Power down PHY) when it works as "Power up" */
+        _BST(OTG->GCCFG, USB_OTG_GCCFG_PWRDWN);
+        _BCL(OTGD->DCTL, USB_OTG_DCTL_SDIS);
+    } else {
+        _BST(OTGD->DCTL, USB_OTG_DCTL_SDIS);
+        _BCL(OTG->GCCFG, USB_OTG_GCCFG_PWRDWN);
+    }
+    return usbd_lane_unk;
+}
+
+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;
+}
+
+bool ep_config(uint8_t ep, uint8_t eptype, uint16_t epsize) {
+    if (ep == 0) {
+        /* configuring 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 << USB_OTG_DOEPTSIZ_STUPCNT_Pos) | \
+                             (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos);
+        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;
+}
+
+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;
+}
+
+int32_t ep_read(uint8_t ep, void* buf, uint16_t blen) {
+    int32_t len;
+    volatile uint32_t *fifo = EPFIFO(0);
+    /* no data in RX FIFO */
+    if (!(OTG->GINTSTS & USB_OTG_GINTSTS_RXFLVL)) return -1;
+    ep &= 0x7F;
+    if ((OTG->GRXSTSR & USB_OTG_GRXSTSP_EPNUM) != ep) return -1;
+    /* pop data from fifo */
+    len = _FLD2VAL(USB_OTG_GRXSTSP_BCNT, OTG->GRXSTSP);
+    for (unsigned i = 0; i < len; i +=4) {
+        uint32_t _t = *fifo;
+        if (blen >= 4) {
+            *(__attribute__((packed))uint32_t*)buf = _t;
+            blen -= 4;
+            buf += 4;
+        } else {
+            while (blen){
+                *(uint8_t*)buf++ = 0xFF & _t;
+                _t >>= 8;
+                blen --;
+            }
+        }
+    }
+    return len;
+}
+
+int32_t ep_write(uint8_t ep, void *buf, uint16_t blen) {
+    ep &= 0x7F;
+    volatile uint32_t* _fifo = EPFIFO(ep);
+    USB_OTG_INEndpointTypeDef* epi = EPIN(ep);
+    /* transfer data size in 32-bit words */
+    uint32_t  _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 << USB_OTG_DIEPTSIZ_PKTCNT_Pos) + blen;
+    _BMD(epi->DIEPCTL, USB_OTG_DIEPCTL_STALL, USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK);
+    while (_len--) {
+        *_fifo = *(__attribute__((packed)) uint32_t*)buf;
+        buf += 4;
+    }
+    return blen;
+}
+
+uint16_t get_frame (void) {
+    return _FLD2VAL(USB_OTG_DSTS_FNSOF, OTGD->DSTS);
+}
+
+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:  /* OUT recieved */
+                evt = usbd_evt_eprx;
+                break;
+            case 0x06:  /* SETUP recieved */
+                /* flushing TX if sonething stuck in control endpoint */
+                if (EPIN(ep)->DIEPTSIZ & USB_OTG_DIEPTSIZ_PKTCNT) {
+                    Flush_TX(ep);
+                }
+                evt = usbd_evt_epsetup;
+                break;
+            case 0x03:  /* OUT completed */
+            case 0x04:  /* SETUP completed */
+                _BST(EPOUT(ep)->DOEPCTL, USB_OTG_DOEPCTL_CNAK | USB_OTG_DOEPCTL_EPENA);
+            default:
+                /* pop GRXSTSP */
+                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;
+}
+
+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;
+}
+
+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_STM32F105