Prechádzať zdrojové kódy

Added STM32L1xx driver

Dmitry 9 rokov pred
rodič
commit
221305cd99
6 zmenil súbory, kde vykonal 1433 pridanie a 63 odobranie
  1. 3 0
      readme.md
  2. 58 0
      src/memmap.inc
  3. 62 62
      src/usb_32v0A.S
  4. 475 0
      src/usb_32v1.c
  5. 825 0
      src/usb_32v1A.S
  6. 10 1
      usb.h

+ 3 - 0
readme.md

@@ -14,11 +14,14 @@
 | STM32L053(3) | usb_stmv0   | C          |             8 | FNV1A 32bit  | ISO, BULK OUT, BULK IN (2)|
 | STM32F042(3) | usb_stmv0   | C          |             8 | FNV1A 32bit  | ISO, BULK OUT, BULK IN (2)|
 | STM32F072(3) | usb_stmv0   | C          |             8 | FNV1A 32bit  | ISO, BULK OUT, BULK IN (2)|
+| STM32L1xx    | usb_stmv1a  | GCC ASM    |             8 | FNV1A 32bit  | ISO, BULK OUT, BULK IN (2)|
+| STM32L1xx    | usb_stmv1   | C          |             8 | FNV1A 32bit  | ISO, BULK OUT, BULK IN (2)|
 | STM32L432(3) | usb_stmv0   | C          |             8 | FNV1A 32bit  | ISO, BULK OUT, BULK IN (2)|
 | STM32L433(3) | usb_stmv0   | C          |             8 | FNV1A 32bit  | ISO, BULK OUT, BULK IN (2)|
 | STM32L442(3) | usb_stmv0   | C          |             8 | FNV1A 32bit  | ISO, BULK OUT, BULK IN (2)|
 | STM32L443(3) | usb_stmv0   | C          |             8 | FNV1A 32bit  | ISO, BULK OUT, BULK IN (2)|
 
+
 1. Single physicsl endpoint can be used to implement
   + one bi-directional/single-buffer logical endpoint (CONTROL)
   + one mono-directional/double-buffer logical endpoint (BULK OR ISOCHRONOUS)

+ 58 - 0
src/memmap.inc

@@ -0,0 +1,58 @@
+
+#if defined(STM32L0)
+    #define USB_EPBASE      0x40005C00
+    #define USB_REGBASE     0x40005C40
+    #define USB_CNTR        0x00
+    #define USB_ISTR        0x04
+    #define USB_FNR         0x08
+    #define USB_DADDR       0x0C
+    #define USB_BTABLE      0x10
+    #define USB_BCDR        0x18
+    #define USB_PMABASE     0x40006000
+
+    #define RCC_BASE        0x40021000
+    #define RCC_APB1RSTR    0x28
+    #define RCC_APB1ENR     0x38
+
+
+    #define UID_BASE        0x1FF80050
+
+
+
+
+
+
+#elif defined(STM32L1)
+/* common definitions for STM31L100xx STM32L151xx STM32L152xx STM32L162xx */
+    #define USB_EPBASE      0x40005C00
+    #define USB_REGBASE     0x40005C40
+    #define USB_CNTR        0x00
+    #define USB_ISTR        0x04
+    #define USB_FNR         0x08
+    #define USB_DADDR       0x0C
+    #define USB_BTABLE      0x10
+    #define USB_PMABASE     0x40006000
+
+    #define SYSCFG_BASE     0x40010000
+    #define SYSCFG_PMC      0x04
+
+    #define RCC_BASE        0x40023800
+    #define RCC_APB1ENR     0x24
+    #define RCC_APB1RSTR    0x18
+    #define RCC_APB2ENR     0x20
+
+
+    #if defined(STM32L100xB) || defined(STM32L100xBA) || \
+        defined(STM32L151xB) || defined(STM32L151xBA)
+    /* Cat.1 and Cat.2 devices */
+    #define UID_BASE        0x1FF80050
+    #else
+    #define UID_BASE        0x1FF800D0
+    #endif
+
+#else
+    #error Unsupported MCU
+
+#endif
+
+

+ 62 - 62
src/usb_32l0A.S → src/usb_32v0A.S

@@ -18,14 +18,9 @@
 #endif
 
 #include "../usb.h"
+#include "memmap.inc"
 #if defined(USE_STMV0A_DRIVER)
 
-#define USB_EPBASE  0x40005C00
-#define USB_REGBASE 0x40005C40
-#define USB_PMABASE 0x40006000
-#define RCC_BASE    0x40021000
-#define UID_BASE    0x1FF80050
-
 #define EP_SETUP    0x0800
 #define EP_TYPE     0x0600
 #define EP_KIND     0x0100
@@ -51,6 +46,21 @@
 #define EP_TX_NAK   0x0020
 #define EP_TX_VAL   0x0030
 
+#define RXADDR0     0x00
+#define RXCOUNT0    0x02
+#define RXADDR1     0x04
+#define RXCOUNT1    0x08
+
+#define TXADDR0     0x00
+#define TXCOUNT0    0x02
+#define TXADDR1     0x04
+#define TXCOUNT1    0x08
+
+#define TXADDR      0x00
+#define TXCOUNT     0x02
+#define RXADDR      0x04
+#define RXCOUNT     0x08
+
 
 #define EP_NOTOG    (EP_RX_CTR | EP_TX_CTR | EP_SETUP | EP_TYPE | EP_KIND | EP_ADDR)
 
@@ -131,24 +141,15 @@ _get_serial_desc:
     pop     {r4, r5, pc}
 
 .L_fnv1a:
+    movs    r3, #0x04
+.L_fnv1a_loop:
+    uxtb    r1, r2
+    eors    r4, r1
     ldr     r1, .L_fnv1a_prime       //FNV1A prime
-    movs    r3, #0xFF
-    ands    r3, r2
-    eors    r4, r3
-    muls    r4, r1
-    lsrs    r2, #8
-    movs    r3, #0xFF
-    ands    r3, r2
-    eors    r4, r3
-    muls    r4, r1
-    lsrs    r2, #8
-    movs    r3, #0xFF
-    ands    r3, r2
-    eors    r4, r3
-    muls    r4, r1
-    lsrs    r2, #8
-    eors    r4, r2
     muls    r4, r1
+    lsrs    r2, #0x08
+    subs    r3, #0x01
+    bne     .L_fnv1a_loop
     bx      lr
 
     .align 2
@@ -165,7 +166,7 @@ _connect:
     sbcs    r0, r1
     lsls    r0, #15
     ldr     r1, =#USB_REGBASE
-    strh    r0, [r1, #0x18]      //USB->BCDR
+    strh    r0, [r1, #USB_BCDR]      //USB->BCDR
     bx      lr
     .size   _connect, . - _connect
 
@@ -175,7 +176,7 @@ _connect:
 _setaddr:
     ldr     r1, =USB_REGBASE
     adds    r0, #0x80
-    strh    r0, [r1, #0x0C]     //USB->DADDR
+    strh    r0, [r1, #USB_DADDR]     //USB->DADDR
     bx      lr
     .size   _setaddr, . - _setaddr
 
@@ -184,11 +185,11 @@ _setaddr:
 _reset:
     ldr     r2, =#USB_REGBASE
     movs    r0, #0x01           //FRES
-    ldrh    r1, [r2]            //USB->CNTR
+    ldrh    r1, [r2, #USB_CNTR] //USB->CNTR
     orrs    r1, r0
-    strh    r1, [r2]            // set FRES
+    strh    r1, [r2, #USB_CNTR] // set FRES
     bics    r1, r0
-    strh    r1, [r2]            // clr FRES
+    strh    r1, [r2, #USB_CNTR] // clr FRES
     bx      lr
     .size   _reset, . - _reset
 
@@ -196,7 +197,7 @@ _reset:
     .type   _get_frame, %function
 _get_frame:
     ldr     r0, =#USB_REGBASE
-    ldrh    r0, [r0, #0x08]     //FNR
+    ldrh    r0, [r0, #USB_FNR]     //FNR
     lsls    r0, #21
     lsrs    r0, #21
     bx      lr
@@ -212,30 +213,30 @@ _enable:
     tst     r0, r0
     beq     .L_disable
 .L_enable:
-    ldr     r0, [r2, #0x38]
+    ldr     r0, [r2, #RCC_APB1ENR]
     orrs    r0, r3
-    str     r0, [r2, #0x38]     //RCC->APB1ENR |= USBEN
-    ldr     r0, [r2, #0x28]
+    str     r0, [r2, #RCC_APB1ENR]     //RCC->APB1ENR |= USBEN
+    ldr     r0, [r2, #RCC_APB1RSTR]
     orrs    r0, r3
-    str     r0, [r2, #0x28]     //RCC->APB1RSTR |= USBRST
+    str     r0, [r2, #RCC_APB1RSTR]     //RCC->APB1RSTR |= USBRST
     bics    r0, r3
-    str     r0, [r2, #0x28]     //RCC->APB1RSTR &= ~USBRST
+    str     r0, [r2, #RCC_APB1RSTR]     //RCC->APB1RSTR &= ~USBRST
     movs    r0, #0xBE
     lsls    r0, #0x08           // CTRM | ERRM | WKUPM | SUSPM | RESETM | SOFM
     strh    r0, [r1]            //set USB->CNTR
     bx      lr
 .L_disable:
-    ldr     r0, [r2, #0x38]
+    ldr     r0, [r2, #RCC_APB1ENR]
     tst     r0, r3
     beq     .L_enable_end       // usb is disabled
     movs    r0, #0x00
-    strh    r0, [r1, #0x18]     //USB->BCDR disable USB I/O
-    ldr     r0, [r2, #0x28]
+    strh    r0, [r1, #USB_BCDR]     //USB->BCDR disable USB I/O
+    ldr     r0, [r2, #RCC_APB1RSTR]
     orrs    r0, r3
-    str     r0, [r2, #0x28]     //RCC->APB1RSTR |= USBRST
-    ldr     r0, [r2, #0x38]
+    str     r0, [r2, #RCC_APB1RSTR]     //RCC->APB1RSTR |= USBRST
+    ldr     r0, [r2, #RCC_APB1ENR]
     bics    r0, r3
-    str     r0, [r2, #0x38]     //RCC->APB1ENR &= ~USBEN
+    str     r0, [r2, #RCC_APB1ENR]     //RCC->APB1ENR &= ~USBEN
 .L_enable_end:
     bx      lr
     .size   _enable, . - _enable
@@ -488,7 +489,7 @@ _get_next_pma:
     lsls    r3, #10         //R3 MAX_PMA_SIZE
     ldr     r0, =#USB_PMABASE
 .L_gnp_chkaddr:
-    ldrh    r4, [r0, #0]    //txaddr
+    ldrh    r4, [r0, #0]    //addr
     tst     r4, r4
     beq     .L_gnp_nxtaddr
     cmp     r3, r4
@@ -552,9 +553,9 @@ _ep_config:
     adds    r5, r4
     bl      _get_next_pma
     bcc     .L_epc_fail
-    strh    r0, [r5, #0]    //store txaddr or txaddr0
+    strh    r0, [r5, #TXADDR]    //store txaddr or txaddr0
     movs    r0, #0x00
-    strh    r0, [r5, #2]    //store txcnt
+    strh    r0, [r5, #TXCOUNT]    //store txcnt
     cmp     r1, #0x06       // is DBLBULK
     beq     .L_epc_txdbl
     ldr     r3, =#TX_USTALL  //set state NAKED , clr DTOG_TX
@@ -564,9 +565,9 @@ _ep_config:
     ldr     r3, =#DTX_USTALL //set state VALID clr DTOG_TX & SWBUF_TX
     bl      _get_next_pma
     bcc     .L_epc_fail
-    strh    r0, [r5, #4]    //store txaddr1
+    strh    r0, [r5, #TXADDR1]    //store txaddr1
     movs    r0, #0x00
-    strh    r0, [r5, #6]    //store txcnt
+    strh    r0, [r5, #TXCOUNT1]    //store txcnt
 .L_epc_txsetstate:
     ldr     r5, =#USB_EPBASE
     lsrs    r4, #1
@@ -602,19 +603,19 @@ _ep_config:
 .L_epc_rxdbl:
     bl      _get_next_pma
     bcc     .L_epc_fail
-    strh    r0, [r5, #0]    //store rxaddr0
-    strh    r3, [r5, #2]    //store rxcnt0
+    strh    r0, [r5, #RXADDR0]    //store rxaddr0
+    strh    r3, [r5, #RXCOUNT0]    //store rxcnt0
     bl      _get_next_pma
     bcc     .L_epc_fail
-    strh    r0, [r5, #4]    //store rxaddr1
-    strh    r3, [r5, #6]    //store rxcnt1
+    strh    r0, [r5, #RXADDR1]    //store rxaddr1
+    strh    r3, [r5, #RXCOUNT1]    //store rxcnt1
     ldr     r3, =#DRX_USTALL
     b       .L_epc_rxsetstate
 .L_epc_rxsngl:
     bl      _get_next_pma
     bcc     .L_epc_fail
-    strh    r0, [r5, #4]    //store rxaddr1 or rxaddr
-    strh    r3, [r5, #6]    //store rxcnt1 or rxcnt
+    strh    r0, [r5, #RXADDR]    //store rxaddr1 or rxaddr
+    strh    r3, [r5, #RXCOUNT]    //store rxcnt1 or rxcnt
     ldr     r3, =#RX_USTALL
 .L_epc_rxsetstate:
     ldr     r5, =#USB_EPBASE
@@ -655,10 +656,10 @@ _ep_deconfig:
     strh    r0, [r2]
 /* clearing PMA data */
     movs    r0, #0x00
-    strh    r0, [r3, #0x00]
-    strh    r0, [r3, #0x02]
-    strh    r0, [r3, #0x04]
-    strh    r0, [r3, #0x06]
+    strh    r0, [r3, #TXADDR]
+    strh    r0, [r3, #TXCOUNT]
+    strh    r0, [r3, #RXADDR]
+    strh    r0, [r3, #RXCOUNT]
     bx      lr
 
     .size   _ep_deconfig, . - _ep_config
@@ -735,7 +736,6 @@ _evt_poll:
     orrs    r4, r3
     strh    r4, [r0]            // clr CTR flag
     b       .L_ep_callback
-
 .L_ep_errm:
     movs    r1, #usbd_evt_error
     movs    r4, #ISTRBIT(13)
@@ -761,10 +761,10 @@ _evt_poll:
     b       .L_ep_clristr
 
 .L_ep_suspm:
-    ldrh    r1, [r3, #0]            //R1 USB->CNTR
+    ldrh    r1, [r3, #USB_CNTR]     //R1 USB->CNTR
     movs    r5, #0x08
     orrs    r1, r5                  //set FSUSP
-    strh    r1, [r3, #0]            //USB->CNTR R2
+    strh    r1, [r3, #USB_CNTR]     //USB->CNTR R2
     movs    r1, #usbd_evt_susp
     movs    r4, #ISTRBIT(11)
     b       .L_ep_clristr
@@ -780,16 +780,16 @@ _evt_poll:
     bics    r4, r5
     strh    r4, [r2]
     movs    r4, #0
-    strh    r4, [r0, #0]
-    strh    r4, [r0, #2]
-    strh    r4, [r0, #4]
-    strh    r4, [r0, #6]
+    strh    r4, [r0, #TXADDR]
+    strh    r4, [r0, #TXCOUNT]
+    strh    r4, [r0, #RXADDR]
+    strh    r4, [r0, #RXCOUNT]
     adds    r2, #4
     adds    r0, #8
     subs    r1, #1
     bpl     .L_ep_reset_loop
     movs    r2, #0x00
-    strh    r2, [r3, #0x10]     // 0 -> USB->BTABLE
+    strh    r2, [r3, #USB_BTABLE]     // 0 -> USB->BTABLE
     movs    r1, #usbd_evt_reset
     movs    r4, #ISTRBIT(10)
 .L_ep_clristr:

+ 475 - 0
src/usb_32v1.c

@@ -0,0 +1,475 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include "stm32.h"
+#include "../usb.h"
+
+#if defined(USE_STMV1_DRIVER)
+
+#ifndef USB_PMASIZE
+    #warning PMA memory size is not defined. Use 512 bytes by default
+    #define USB_PMASIZE 0x200
+#endif
+
+#define USB_EP_SWBUF_TX     USB_EP_DTOG_RX
+#define USB_EP_SWBUF_RX     USB_EP_DTOG_TX
+
+
+#define EP_TOGGLE_SET(epr, bits, mask) *(epr) = (*(epr) ^ (bits)) & (USB_EPREG_MASK | (mask))
+
+#define EP_TX_STALL(epr)    EP_TOGGLE_SET((epr), USB_EP_TX_STALL,                   USB_EPTX_STAT)
+#define EP_RX_STALL(epr)    EP_TOGGLE_SET((epr), USB_EP_RX_STALL,                   USB_EPRX_STAT)
+#define EP_TX_UNSTALL(epr)  EP_TOGGLE_SET((epr), USB_EP_TX_NAK,                     USB_EPTX_STAT | USB_EP_DTOG_TX)
+#define EP_RX_UNSTALL(epr)  EP_TOGGLE_SET((epr), USB_EP_RX_VALID,                   USB_EPRX_STAT | USB_EP_DTOG_RX)
+#define EP_DTX_UNSTALL(epr) EP_TOGGLE_SET((epr), USB_EP_TX_VALID,                   USB_EPTX_STAT | USB_EP_DTOG_TX | USB_EP_SWBUF_TX)
+#define EP_DRX_UNSTALL(epr) EP_TOGGLE_SET((epr), USB_EP_RX_VALID | USB_EP_SWBUF_RX, USB_EPRX_STAT | USB_EP_DTOG_RX | USB_EP_SWBUF_RX)
+#define EP_TX_VALID(epr)    EP_TOGGLE_SET((epr), USB_EP_TX_VALID,                   USB_EPTX_STAT)
+#define EP_RX_VALID(epr)    EP_TOGGLE_SET((epr), USB_EP_RX_VALID,                   USB_EPRX_STAT)
+
+
+
+typedef union pma_table {
+    struct {
+    uint16_t    txadr;
+    uint16_t    :16;
+    uint16_t    txcnt;
+    uint16_t    :16;
+    uint16_t    rxadr;
+    uint16_t    :16;
+    uint16_t    rxcnt;
+    uint16_t    :16;
+    };
+    struct {
+    uint16_t    txadr0;
+    uint16_t    :16;
+    uint16_t    txcnt0;
+    uint16_t    :16;
+    uint16_t    txadr1;
+    uint16_t    :16;
+    uint16_t    txcnt1;
+    uint16_t    :16;
+    };
+    struct {
+    uint16_t    rxadr0;
+    uint16_t    :16;
+    uint16_t    rxcnt0;
+    uint16_t    :16;
+    uint16_t    rxadr1;
+    uint16_t    :16;
+    uint16_t    rxcnt1;
+    uint16_t    :16;
+    };
+} pma_table;
+
+
+/** \brief Helper function. Returns pointer to the buffer descriptor table.
+ */
+inline static pma_table *EPT(uint8_t ep) {
+    return (pma_table*)((ep & 0x07) * 16 + USB_PMAADDR);
+
+}
+
+/** \brief Helper function. Returns pointer to the endpoint control register.
+ */
+inline static volatile uint16_t *EPR(uint8_t ep) {
+    return (uint16_t*)((ep & 0x07) * 4 + USB_BASE);
+}
+
+
+/** \brief Helper function. Returns next available PMA buffer.
+ *
+ * \param sz uint16_t Requested buffer size.
+ * \return uint16_t Buffer address for PMA table.
+ * \note PMA buffers grown from top to bottom like stack.
+ */
+static uint16_t get_next_pma(uint16_t sz) {
+    unsigned _result = USB_PMASIZE;
+    for (int i = 0; i < 8; i++) {
+        pma_table *tbl = EPT(i);
+        if ((tbl->rxadr) && (tbl->rxadr < _result)) _result = tbl->rxadr;
+        if ((tbl->txadr) && (tbl->txadr < _result)) _result = tbl->txadr;
+    }
+    if ( _result < (4 * sizeof(pma_table) + sz)) {
+        return 0;
+    } else {
+        return _result - sz;
+    }
+}
+
+void ep_setstall(uint8_t ep, bool stall) {
+    volatile uint16_t *reg = EPR(ep);
+    /* ISOCHRONOUS endpoint can't be stalled or unstalled */
+    if (USB_EP_ISOCHRONOUS == (*reg & USB_EP_T_FIELD)) return;
+    /* If it's an IN endpoint */
+    if (ep & 0x80) {
+        /* DISABLED endpoint can't be stalled or unstalled */
+        if (USB_EP_TX_DIS == (*reg & USB_EPTX_STAT)) return;
+        if (stall) {
+            EP_TX_STALL(reg);
+        } else {
+            /* if it's a doublebuffered endpoint */
+            if ((USB_EP_KIND | USB_EP_BULK) == (*reg & (USB_EP_T_FIELD | USB_EP_KIND))) {
+                /* set endpoint to VALID and clear DTOG_TX & SWBUF_TX */
+                EP_DTX_UNSTALL(reg);
+            } else {
+                /* set endpoint to NAKED and clear DTOG_TX */
+                EP_TX_UNSTALL(reg);
+            }
+        }
+    } else {
+        if (USB_EP_RX_DIS == (*reg & USB_EPRX_STAT)) return;
+        if (stall) {
+            EP_RX_STALL(reg);
+        } else {
+            /* if it's a doublebuffered endpoint */
+            if ((USB_EP_KIND | USB_EP_BULK) == (*reg & (USB_EP_T_FIELD | USB_EP_KIND))) {
+                /* set endpoint to VALID, clear DTOG_RX, set SWBUF_RX */
+                EP_DRX_UNSTALL(reg);
+            } else {
+                /* set endpoint to VALID and clear DTOG_RX */
+                EP_RX_UNSTALL(reg);
+            }
+        }
+    }
+}
+
+bool ep_isstalled(uint8_t ep) {
+    if (ep & 0x80) {
+        return (USB_EP_TX_STALL == (USB_EPTX_STAT & *EPR(ep)));
+    } else {
+        return (USB_EP_RX_STALL == (USB_EPRX_STAT & *EPR(ep)));
+    }
+}
+
+void enable(bool enable) {
+    if (enable) {
+        RCC->APB1ENR  |= RCC_APB1ENR_USBEN;
+        RCC->APB2ENR  |= RCC_APB2ENR_SYSCFGEN;
+        RCC->APB1RSTR |= RCC_APB1RSTR_USBRST;
+        RCC->APB1RSTR &= ~RCC_APB1RSTR_USBRST;
+        USB->CNTR = USB_CNTR_CTRM | USB_CNTR_RESETM | USB_CNTR_SOFM | USB_CNTR_ESOFM | USB_CNTR_ERRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM ;
+    } else if (RCC->APB1ENR & RCC_APB1ENR_USBEN) {
+        SYSCFG->PMC &= ~SYSCFG_PMC_USB_PU;
+        RCC->APB1RSTR |= RCC_APB1RSTR_USBRST;
+        RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
+    }
+}
+
+void reset (void) {
+    USB->CNTR |= USB_CNTR_FRES;
+    USB->CNTR &= ~USB_CNTR_FRES;
+}
+
+void connect(bool connect) {
+    if (connect) {
+        SYSCFG->PMC |= SYSCFG_PMC_USB_PU;
+    } else {
+        SYSCFG->PMC &= ~SYSCFG_PMC_USB_PU;
+    }
+}
+
+void setaddr (uint8_t addr) {
+    USB->DADDR = USB_DADDR_EF | addr;
+}
+
+
+bool ep_config(uint8_t ep, uint8_t eptype, uint16_t epsize) {
+    volatile uint16_t *reg = EPR(ep);
+    pma_table *tbl = EPT(ep);
+    /* epsize should be 16-bit aligned */
+    if (epsize & 0x01) epsize++;
+
+    switch (eptype) {
+    case USB_EPTYPE_CONTROL:
+        *reg = USB_EP_CONTROL | (ep & 0x07);
+        break;
+    case USB_EPTYPE_ISOCHRONUS:
+        *reg = USB_EP_ISOCHRONOUS | (ep & 0x07);
+        break;
+    case USB_EPTYPE_BULK:
+        *reg = USB_EP_BULK | (ep & 0x07);
+        break;
+    case USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF:
+        *reg = USB_EP_BULK | USB_EP_KIND | (ep & 0x07);
+        break;
+    default:
+        *reg = USB_EP_INTERRUPT | (ep & 0x07);
+        break;
+    }
+    /* if it TX or CONTROL endpoint */
+    if ((ep & 0x80) || (eptype == USB_EPTYPE_CONTROL)) {
+        uint16_t _pma;
+        _pma = get_next_pma(epsize);
+        if (_pma == 0) return false;
+        if ((eptype == USB_EPTYPE_ISOCHRONUS) ||
+            (eptype == (USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF))) {
+            tbl->txadr0 = _pma;
+            _pma = get_next_pma(epsize);
+            if (_pma == 0) return false;
+            tbl->txadr1 = _pma;
+            tbl->txcnt0 = 0;
+            tbl->txcnt1 = 0;
+            EP_DTX_UNSTALL(reg);
+        } else {
+            tbl->txadr = _pma;
+            tbl->txcnt = 0;
+            EP_TX_UNSTALL(reg);
+        }
+    }
+    if (!(ep & 0x80)) {
+        uint16_t _rxcnt;
+        uint16_t _pma;
+        if (epsize > 62) {
+            if (epsize & 0x1F) {
+                epsize &= 0x1F;
+            } else {
+                epsize -= 0x20;
+            }
+            _rxcnt = 0x8000 | (epsize << 5);
+            epsize += 0x20;
+        } else {
+            _rxcnt = epsize << 9;
+        }
+        _pma = get_next_pma(epsize);
+        if (_pma == 0) return false;
+        if ((eptype == USB_EPTYPE_ISOCHRONUS) ||
+            (eptype == (USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF))) {
+            tbl->rxadr0 = _pma;
+            _pma = get_next_pma(epsize);
+            if (_pma == 0) return false;
+            tbl->rxadr1 = _pma;
+            tbl->rxcnt0 = _rxcnt;
+            tbl->rxcnt1 = _rxcnt;
+            EP_DRX_UNSTALL(reg);
+        } else {
+            tbl->rxadr = _pma;
+            tbl->rxcnt = _rxcnt;
+            EP_RX_UNSTALL(reg);
+        }
+    }
+    return true;
+}
+
+static void ep_deconfig(uint8_t ep) {
+    pma_table *ept = EPT(ep);
+    *EPR(ep) &= ~USB_EPREG_MASK;
+    ept->rxadr = 0;
+    ept->rxcnt = 0;
+    ept->txadr = 0;
+    ept->txcnt = 0;
+}
+
+
+
+static void pma_write(const uint16_t txadr, const uint8_t *buf, uint16_t blen) {
+    uint16_t *pma = (void*)(USB_PMAADDR + 2 * txadr);
+    while (blen > 1) {
+        *pma = buf[1] << 8 | buf[0];
+        pma += 2;
+        buf += 2;
+        blen -= 2;
+    }
+    if (blen) *pma = *buf;
+}
+
+static void pma_read (const uint16_t rxadr, uint8_t *buf, uint16_t blen, uint16_t rxlen) {
+    uint16_t *pma = (void*)(USB_PMAADDR + 2 * rxadr);
+    if (blen > rxlen) blen = rxlen;
+    while (blen) {
+        uint16_t _t = *pma;
+        *buf++ = _t & 0xFF;
+        if (--blen) {
+            *buf++ = _t >> 8;
+            pma += 2;
+            blen--;
+        } else break;
+    }
+}
+
+uint16_t ep_read(uint8_t ep, void *buf, uint16_t blen) {
+    pma_table *tbl = EPT(ep);
+    volatile uint16_t *reg = EPR(ep);
+    uint16_t rxlen, rxbuf;
+
+    switch (*reg & (USB_EP_T_FIELD | USB_EP_KIND)) {
+    case (USB_EP_BULK | USB_EP_KIND):
+        if (*reg & USB_EP_SWBUF_RX) {
+            rxbuf = tbl->rxadr1;
+            rxlen = tbl->rxcnt1 & 0x03FF;
+        } else {
+            rxbuf = tbl->rxadr0;
+            rxlen = tbl->rxcnt0 & 0x03FF;
+        }
+        pma_read(rxbuf, buf, blen, rxlen);
+        break;
+    case USB_EP_ISOCHRONOUS:
+        if (*reg & USB_EP_DTOG_RX) {
+            rxbuf = tbl->rxadr0;
+            rxlen = tbl->rxcnt0 & 0x03FF;
+        } else {
+            rxbuf = tbl->rxadr1;
+            rxlen = tbl->rxcnt1 & 0x03FF;
+        }
+        pma_read(rxbuf, buf, blen, rxlen);
+        break;
+    default:
+        rxbuf = tbl->rxadr;
+        rxlen = tbl->rxcnt & 0x03FF;
+        pma_read(rxbuf, buf, blen, rxlen);
+        /* setting endpoint to VALID state */
+        EP_RX_VALID(reg);
+        break;
+    }
+    return rxlen;
+}
+
+
+
+uint16_t ep_write(uint8_t ep, void *buf, uint16_t blen) {
+    pma_table *tbl = EPT(ep);
+    volatile uint16_t *reg = EPR(ep);
+    uint16_t txbuf;
+    switch (*reg & (USB_EP_T_FIELD | USB_EP_KIND)) {
+    case (USB_EP_BULK | USB_EP_KIND):
+        if (*reg & USB_EP_SWBUF_TX) {
+            tbl->txcnt1 = blen;
+            txbuf = tbl->txadr1;
+        } else {
+            tbl->txcnt0 = blen;
+            txbuf = tbl->txadr0;
+        }
+        break;
+    case USB_EP_ISOCHRONOUS:
+        if (*reg & USB_EP_DTOG_TX) {
+            tbl->txcnt0 = blen;
+            txbuf = tbl->txadr0;
+        } else {
+            tbl->txcnt1 = blen;
+            txbuf = tbl->txadr1;
+        }
+        break;
+    default:
+        tbl->txcnt = blen;
+        txbuf = tbl->txadr;
+        break;
+    }
+    pma_write(txbuf, buf, blen);
+
+    switch (*reg & (USB_EP_T_FIELD | USB_EP_KIND)) {
+    case (USB_EP_BULK | USB_EP_KIND):
+        /* switching buffer if doublebuffered bulk endpoint */
+        *reg = (*reg & USB_EPREG_MASK) | USB_EP_SWBUF_TX;
+        break;
+    case USB_EP_ISOCHRONOUS:
+        break;
+    default:
+        /* set TX valid to start transfer */
+        EP_TX_VALID(reg);
+    }
+    return blen;
+
+}
+
+uint16_t get_frame (void) {
+    return USB->FNR & USB_FNR_FN;
+}
+
+
+
+void evt_poll(usbd_device *dev, usbd_evt_callback callback) {
+    uint8_t _ev, _ep;
+    uint16_t _istr = USB->ISTR;
+    _ep = _istr & USB_ISTR_EP_ID;
+
+    if (_istr & USB_ISTR_CTR) {
+        volatile uint16_t *reg = EPR(_ep);
+        if (*reg & USB_EP_CTR_TX) {
+            *reg &= (USB_EPREG_MASK ^ USB_EP_CTR_TX);
+            _ep |= 0x80;
+            _ev = usbd_evt_eptx;
+        } else {
+            /* clearing CTR */
+            if ((*reg & (USB_EP_T_FIELD | USB_EP_KIND)) == (USB_EP_BULK | USB_EP_KIND)) {
+                /* switching RX buffer and if doublebuffered bulk endpoint */
+                *reg = (*reg & (USB_EPREG_MASK ^ USB_EP_CTR_RX)) | USB_EP_SWBUF_RX;
+            } else {
+                *reg &= (USB_EPREG_MASK ^ USB_EP_CTR_RX);
+            }
+            _ev = (*reg & USB_EP_SETUP) ? usbd_evt_epsetup : usbd_evt_eprx;
+        }
+    } else if (_istr & USB_ISTR_RESET) {
+        USB->ISTR &= ~USB_ISTR_RESET;
+        USB->BTABLE = 0;
+        for (int i = 0; i < 8; i++) {
+            ep_deconfig(i);
+        }
+        _ev = usbd_evt_reset;
+    } else if (_istr & USB_ISTR_SOF) {
+        _ev = usbd_evt_sof;
+        USB->ISTR &= ~USB_ISTR_SOF;
+    } else if (_istr & USB_ISTR_WKUP) {
+        _ev = usbd_evt_wkup;
+        USB->CNTR &= ~USB_CNTR_FSUSP;
+        USB->ISTR &= ~USB_ISTR_WKUP;
+    } else if (_istr & USB_ISTR_SUSP) {
+        _ev = usbd_evt_susp;
+        USB->CNTR |= USB_CNTR_FSUSP;
+        USB->ISTR &= ~USB_ISTR_SUSP;
+    } else if (_istr & USB_ISTR_ESOF) {
+        USB->ISTR &= ~USB_ISTR_ESOF;
+        _ev = usbd_evt_esof;
+    } else if (_istr & USB_ISTR_ERR) {
+        USB->ISTR &= ~USB_ISTR_ERR;
+        _ev = usbd_evt_error;
+    } else {
+        return;
+    }
+    callback(dev, _ev, _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 + 0x14));
+    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 usb_stmv1 = {
+    enable,
+    reset,
+    connect,
+    setaddr,
+    ep_config,
+    ep_deconfig,
+    ep_read,
+    ep_write,
+    ep_setstall,
+    ep_isstalled,
+    evt_poll,
+    get_frame,
+    get_serialno_desc,
+};
+
+#endif //USE_STM32V1_DRIVER

+ 825 - 0
src/usb_32v1A.S

@@ -0,0 +1,825 @@
+/* This file is the part of the LUS32 project
+ *
+ * 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.
+ */
+
+#if !defined (__ASSEMBLER__)
+    #define __ASSEMBLER__
+#endif
+
+#include "../usb.h"
+#include "memmap.inc"
+#if defined(USE_STMV1A_DRIVER)
+
+
+#define EP_SETUP    0x0800
+#define EP_TYPE     0x0600
+#define EP_KIND     0x0100
+#define EP_ADDR     0x000F
+
+#define EP_RX_CTR   0x8000
+#define EP_RX_DTOG  0x4000
+#define EP_RX_STAT  0x3000
+#define EP_RX_SWBUF 0x0040
+
+#define EP_RX_DIS   0x0000
+#define EP_RX_STAL  0x1000
+#define EP_RX_NAK   0x2000
+#define EP_RX_VAL   0x3000
+
+#define EP_TX_CTR   0x0080
+#define EP_TX_DTOG  0x0040
+#define EP_TX_STAT  0x0030
+#define EP_TX_SWBUF 0x4000
+
+#define EP_TX_DIS   0x0000
+#define EP_TX_STAL  0x0010
+#define EP_TX_NAK   0x0020
+#define EP_TX_VAL   0x0030
+
+#define RXADDR0     0x00
+#define RXCOUNT0    0x04
+#define RXADDR1     0x08
+#define RXCOUNT1    0x0C
+
+#define TXADDR0     0x00
+#define TXCOUNT0    0x04
+#define TXADDR1     0x08
+#define TXCOUNT1    0x0C
+
+#define TXADDR      0x00
+#define TXCOUNT     0x04
+#define RXADDR      0x08
+#define RXCOUNT     0x0C
+
+
+
+#define EP_NOTOG    (EP_RX_CTR | EP_TX_CTR | EP_SETUP | EP_TYPE | EP_KIND | EP_ADDR)
+
+#define TGL_SET(mask, bits)  ((EP_NOTOG | (mask))<<16 | (bits))
+
+#define TX_STALL    TGL_SET(EP_TX_STAT,                            EP_TX_STAL)
+#define RX_STALL    TGL_SET(EP_RX_STAT,                            EP_RX_STAL)
+#define TX_USTALL   TGL_SET(EP_TX_STAT | EP_TX_DTOG,               EP_TX_NAK)
+#define RX_USTALL   TGL_SET(EP_RX_STAT | EP_RX_DTOG,               EP_RX_VAL)
+#define DTX_USTALL  TGL_SET(EP_TX_STAT | EP_TX_DTOG | EP_TX_SWBUF, EP_TX_VAL)
+#define DRX_USTALL  TGL_SET(EP_RX_STAT | EP_RX_DTOG | EP_RX_SWBUF, EP_RX_VAL | EP_RX_SWBUF)
+
+
+    .syntax unified
+    .cpu cortex-m3
+    .text
+    .thumb
+
+
+    .globl  usb_stmv1a
+    .align  2
+usb_stmv1a:
+    .long   _enable
+    .long   _reset
+    .long   _connect
+    .long   _setaddr
+    .long   _ep_config
+    .long   _ep_deconfig
+    .long   _ep_read
+    .long   _ep_write
+    .long   _ep_setstall
+    .long   _ep_isstalled
+    .long   _evt_poll
+    .long   _get_frame
+    .long   _get_serial_desc
+    .size   usb_stmv1a, . - usb_stmv1a
+
+
+    .thumb_func
+    .type _get_serial_desc, %function
+
+/*  uint16_t get_serial_desc (void *buffer)
+ *  R0 <- buffer for the string descriptor
+ *  descrpitor size -> R0
+ */
+_get_serial_desc:
+    push    {r4, r5, lr}
+    movs    r1, #18             //descriptor size 18 bytes
+    strb    r1, [r0]
+    movs    r1, #0x03           //DTYPE_STRING
+    strb    r1, [r0, #0x01]
+    ldr     r5, .L_uid_base     //UID3 this is the serial number
+    ldr     r4, .L_fnv1a_offset //FNV1A offset
+    ldr     r2, [r5, 0x00]      //UID0
+    bl      .L_fnv1a
+    ldr     r2, [r5, 0x04]      //UID1
+    bl      .L_fnv1a
+    ldr     r2, [r5, 0x14]      //UID2
+    bl      .L_fnv1a
+    movs    r3, #28
+.L_gsn_loop:
+    lsrs    r1, r4, r3
+    and     r1, #0x0F
+    cmp     r1, #0x09
+    ite     gt
+    addgt   r1, #55
+    addle   r1, #48
+.L_gsn_store:
+    adds    r0, #0x02
+    strb    r1, [r0]
+    lsrs    r1, #0x08
+    strb    r1, [r0, #0x01]
+    subs    r3, #0x04
+    bpl     .L_gsn_loop
+    movs    r0, #18
+    pop     {r4, r5, pc}
+
+.L_fnv1a:
+    movs    r3, #0x04
+.L_fnv1a_loop:
+    uxtb    r1, r2
+    eors    r4, r1
+    ldr     r1, .L_fnv1a_prime       //FNV1A prime
+    muls    r4, r1
+    lsrs    r2, #0x08
+    subs    r3, #0x01
+    bne     .L_fnv1a_loop
+    bx      lr
+
+    .align 2
+.L_uid_base:        .long   UID_BASE
+.L_fnv1a_offset:    .long   2166136261
+.L_fnv1a_prime:     .long   16777619
+
+    .size _get_serial_desc, . - _get_serial_desc
+
+    .thumb_func
+    .type   _connect, %function
+_connect:
+    ldr     r1, =#SYSCFG_BASE
+    movs    r3, #0x01
+    ldr     r2, [r1, #SYSCFG_PMC]
+    bics    r2, r3
+    cbz     r0, .L_conn_store
+    orrs    r2, r3
+.L_conn_store:
+    str     r2, [r1, #SYSCFG_PMC]
+    bx      lr
+    .size   _connect, . - _connect
+
+
+    .thumb_func
+    .type   _setaddr, %function
+_setaddr:
+    ldr     r1, =USB_REGBASE
+    adds    r0, #0x80
+    strh    r0, [r1, #USB_DADDR]     //USB->DADDR
+    bx      lr
+    .size   _setaddr, . - _setaddr
+
+    .thumb_func
+    .type   _reset, %function
+_reset:
+    ldr     r2, =#USB_REGBASE
+    movs    r0, #0x01           //FRES
+    ldrh    r1, [r2, #USB_CNTR]
+    orrs    r1, r0
+    strh    r1, [r2, #USB_CNTR]  // set FRES
+    bics    r1, r0
+    strh    r1, [r2, #USB_CNTR]  // clr FRES
+    bx      lr
+    .size   _reset, . - _reset
+
+    .thumb_func
+    .type   _get_frame, %function
+_get_frame:
+    ldr     r0, =#USB_REGBASE
+    ldrh    r0, [r0, #USB_FNR]     //FNR
+    lsls    r0, #21
+    lsrs    r0, #21
+    bx      lr
+    .size   _get_frame, . - _get_frame
+
+    .thumb_func
+    .type   _enable, %function
+_enable:
+
+    ldr     r2, =#RCC_BASE        //RCC
+    movs    r3, #0x01
+    lsls    r3, #23             //USBEN or USBRST
+    cbz     r0, .L_disable
+.L_enable:
+/* enabling and resetting USB peripheral */
+    ldr     r1, =#USB_REGBASE
+    ldr     r0, [r2, #RCC_APB1ENR]
+    orrs    r0, r3
+    str     r0, [r2, #RCC_APB1ENR]     //RCC->APB1ENR |= USBEN
+    ldr     r0, [r2, #RCC_APB1RSTR]
+    orrs    r0, r3
+    str     r0, [r2, #RCC_APB1RSTR]     //RCC->APB1RSTR |= USBRST
+    bics    r0, r3
+    str     r0, [r2, #RCC_APB1RSTR]     //RCC->APB1RSTR &= ~USBRST
+/* enabling SYSCFG peripheral */
+    movs    r3, #0x01                   //SYSCFGEN
+    ldr     r0, [r2, #RCC_APB2ENR]
+    orrs    r0, r3
+    str     r0, [r2, #RCC_APB2ENR]
+/* setting up USB CNTR */
+    movs    r0, #0xBE
+    lsls    r0, #0x08                   // CTRM | ERRM | WKUPM | SUSPM | RESETM | SOFM
+    strh    r0, [r1, #USB_CNTR]         //set USB->CNTR
+    bx      lr
+.L_disable:
+    ldr     r0, [r2, #RCC_APB1ENR]
+    tst     r0, r3
+    beq     .L_enable_end               // usb is already disabled
+/* disabling USB peripheral */
+    bics    r0, r3
+    str     r0, [r2, #RCC_APB1ENR]
+/* disabling USB_PU in SYSCFG_PMC */
+    movs    r3, #0x01
+    ldr     r1, =#SYSCFG_BASE
+    ldr     r0, [r1, #SYSCFG_PMC]
+    bics    r0, r3
+    str     r0, [r1, #SYSCFG_PMC]
+    bx      lr
+.L_enable_end:
+    bx      lr
+    .size   _enable, . - _enable
+
+    .thumb_func
+    .type   _ep_setstall, %function
+
+/*void ep_settall(uint8_t ep, bool stall)
+ * in  R0 <- endpoint number
+ * in  R1 <- 0 if unstall, !0 if stall
+ */
+_ep_setstall:
+    lsls    r2, r0, #28
+    lsrs    r2, #26
+    ldr     r3, =#USB_EPBASE
+    adds    r3, r2          // epr -> r3
+    movs    r2, 0x30        // TX_STAT_MASK -> r2
+    cmp     r0, #80
+    blo     .L_eps_rx
+.L_eps_tx:
+    ldr     r0, =#TX_STALL   //stall TX
+    tst     r1, r1
+    bne     .L_eps_reg_set
+.L_eps_tx_unstall:
+    ldrh    r1, [r3]        // *epr -> r1
+    lsls    r1, #21
+    lsrs    r1, #29         // EPTTYPE | EPKIND mask only
+    ldr     r0, =#DTX_USTALL //unstall dblbulk or iso TX (VALID and clr DTOG_TX & SWBUF_TX)
+    cmp     r1, #0x01       // if doublebuffered bulk endpoint
+    beq     .L_eps_reg_set
+    cmp     r1, #0x04       // if isochronous endpoint
+    ldr     r0, =#TX_USTALL  // unstall other TX (NAKED + clr DTOG_TX)
+    b       .L_eps_reg_set
+.L_eps_rx:
+    lsls    r2, #8          // RX_STAT_MASK -> R2
+    ldr     r0,=#RX_STALL    //stall RX
+    tst     r1, r1
+    bne     .L_eps_reg_set
+.L_eps_rx_unstall:
+    ldrh    r1, [r3]        // *epr -> r1
+    lsls    r1, #21
+    lsrs    r1, #29         // EPTTYPE | EPKIND mask only
+    ldr     r0, =#DRX_USTALL //unstall dblbulk or iso (VALID. clr DTOG_RX set SWBUF_RX)
+    cmp     r1, #0x01       // if dblbulk
+    beq     .L_eps_reg_set
+    cmp     r1, #0x04       // if iso
+    beq     .L_eps_reg_set
+    ldr     r0, =#RX_USTALL  // unstall other RX (VALID + clr
+/* R0 - mask and toggle bits
+ * R2 - mask for STAT bits
+ * R3 - endpoint register pointer
+ */
+.L_eps_reg_set:
+    ldrh    r1, [r3]        // *epr -> r1
+    ands    r2, r1          // check if endpoint disabled
+    beq     .L_eps_exit     // do nothing
+    eors    r1, r0
+    lsrs    r0, #16
+    ands    r1, r0
+    strh    r1, [r3]
+.L_eps_exit:
+    bx      lr
+    .size   _ep_setstall, . - _ep_setstall
+
+
+    .thumb_func
+    .type   _ep_isstalled, %function
+/* bool ep_isstalled(uint8t ep) */
+_ep_isstalled:
+    ldr     r1, =#USB_EPBASE
+    lsls    r2, r0, #28
+    lsrs    r2, #26
+    ldr     r1, [r1, r2]
+    lsls    r1, #17
+    cmp     r0, #0x80
+    bhs     .L_eis_check
+    lsls    r1, #8
+.L_eis_check:
+    lsrs    r1, r1, #28
+    subs    r1, #0x01
+    subs    r0, r1, #0x01
+    sbcs    r1, r1
+    rsbs    r0, r1, #0
+    bx      lr
+    .size  _ep_isstalled, . - _ep_isstalled
+
+
+    .thumb_func
+    .type       _ep_read, %function
+/* uint16_t _ep_read(uint8_t ep, void *buf, uint16_t blen)
+ * in  R0 <- endpoint
+ * in  R1 <- *buffer
+ * in  R2 <- length of the buffer
+ * out length of the recieved data -> R0
+ */
+_ep_read:
+    push    {r4, r5, lr}
+    ldr     r3, =#USB_EPBASE
+    ldr     r4, =#USB_PMABASE
+    lsls    r0, #28
+    lsrs    r0, #26
+    adds    r3, r0          // *EPR -> R3
+    lsls    r0, #2
+    adds    r4, r0          // *EPT -> R4
+    ldrh    r0, [r3]        // reading epr
+    lsls    r5, r0, #21
+    lsrs    r5, #29
+    cmp     r5, #0x04
+    beq     .L_epr_iso
+    cmp     r5, #0x01
+    bne     .L_epr_sngl
+.L_epr_dblbulk:
+    negs    r0, r0
+    lsrs    r0, #7          // ~SW_RX in CF
+    b       .L_epr_load_table
+.L_epr_iso:
+    lsrs    r0, #15         // DTOG_RX passsed to CF
+.L_epr_load_table:
+    ldrh    r0, [r4, #RXADDR0]    // R0 rxaddr0
+    ldrh    r5, [r4, #RXCOUNT0]    // R5 rxcnt0
+    bcs     .L_epr_prepare
+.L_epr_sngl:
+    ldrh    r0, [r4, #RXADDR]    // R0 rxaddr1 or rxaddr
+    ldrh    r5, [r4, #RXCOUNT]   // R5 rxcnt1 or rxcnt
+.L_epr_prepare:
+    ldr     r4, =#USB_PMABASE
+    lsls    r0, #0x01
+    adds    r0, r4          // R0 now has a physical address
+    lsls    r5, #22
+    lsrs    r5, #22         // R5 bytes count
+    cmp     r2, r5
+    blo     .L_epr_read
+    mov     r2, r5          // if buffer is larger
+.L_epr_read:
+    cmp     r2, #1
+    blo     .L_epr_read_end
+    ldrh    r4, [r0]
+    strb    r4, [r1]
+    beq     .L_epr_read_end
+    lsrs    r4, #8
+    strb    r4, [r1, #1]
+    adds    r1, #2
+    adds    r0, #4
+    subs    r2, #2
+    bne     .L_epr_read
+.L_epr_read_end:
+    ldrh    r0, [r3]
+    lsls    r1, r0, #21
+    lsrs    r1, #29
+    cmp     r1, #0x04
+    beq     .L_epr_exit     // ep is iso. no needs to set it to valid
+    cmp     r1, #0x01
+    beq     .L_epr_exit     // ep is dblbulk. no needs to set it to valid
+    ldr     r2, =#TGL_SET(EP_RX_STAT , EP_RX_VAL)
+    eors    r0, r2
+    lsrs    r2, #16
+    ands    r0, r2
+    strh    r0, [r3]        // set ep to VALID state
+.L_epr_exit:
+    mov     r0, r5
+    pop     {r4, r5, pc}
+    .size   _ep_read, . - _ep_read
+
+
+
+    .thumb_func
+    .type   _ep_write, %function
+/* uint16_t ep_write(uint8_t ep, void *buf, uint16_t blen)
+ *
+
+ */
+_ep_write:
+    push    {r2, r4, r5, lr}
+    ldr     r3, =#USB_EPBASE
+    ldr     r4, =#USB_PMABASE
+    lsls    r0, #28
+    lsrs    r0, #26
+    adds    r3, r0          // *EPR -> R3
+    lsls    r0, #2
+    adds    r4, r0          // *EPT -> R4
+    ldrh    r0, [r3]        // reading epr
+    lsls    r0, #21
+    lsrs    r0, #29
+    subs    r0, #0x04
+    beq     .L_epw_iso
+    adds    r0, #0x03
+    bne     .L_epw_sngl
+.L_epw_dblbulk:
+    ldrh    r0, [r3]
+    lsrs    r0, #15          // SW_TX in CF
+    bcc     .L_epw_sngl
+    b       .L_epw_settx1
+.L_epw_iso:
+    ldrh    r0, [r3]
+    lsrs    r0, #7          // DTOG_TX passsed to CF
+    bcs     .L_epw_sngl
+.L_epw_settx1:
+    adds    r4, #0x08
+.L_epw_sngl:
+    ldrh    r0, [r4, #TXADDR]    // R0 txaddr
+    lsls    r0, #0x01
+//.L_epw_prepare:
+    strh    r2, [r4, #TXCOUNT]   // set txcount
+    ldr     r4, =#USB_PMABASE
+    adds    r0, r4
+.L_epw_write:
+    cmp     r2, #0x01
+    blo     .L_epw_writeend
+    ldrb    r4, [r1]
+    beq     .L_epw_halfw
+    ldrb    r5, [r1, #1]
+    lsls    r5, #8
+    orrs    r4, r5
+    strh    r4, [r0]
+    adds    r1, #2
+    adds    r0, #4
+    subs    r2, #2
+    b       .L_epw_write
+.L_epw_halfw:
+    strh    r4, [r0]
+.L_epw_writeend:
+    ldrh    r0, [r3]
+    lsls    r1, r0, #21
+    lsrs    r1, #29
+    cmp     r1, #0x04
+    beq     .L_epw_exit        //nothing to do with ISO ep
+    ldr     r2, =#TGL_SET(EP_TX_STAT, EP_TX_VAL)
+    cmp     r1, #0x01
+    bne     .L_epw_setstate
+// ep is dblbulk. needs to switch SW_TX
+    ldr     r2, =#TGL_SET(EP_TX_SWBUF, EP_TX_SWBUF)
+    bics    r0, r2              //clearing SW_BUF for setting in to 1 by XOR
+ .L_epw_setstate:
+    eors    r0, r2
+    lsrs    r2, #16
+    ands    r0, r2
+    strh    r0, [r3]
+.L_epw_exit:
+    pop     {r0, r4, r5, pc}
+    .size   _ep_write, .- _ep_write
+
+
+
+/* internal function */
+/* requester size passed in R2 */
+/* result returns in R0 CF=1 if OK*/
+
+_get_next_pma:
+    push    {r1, r3, r4, lr}
+    movs    r1, #16
+    movs    r3, #1
+    lsls    r3, #9         //R3 MAX_PMA_SIZE 512b
+    ldr     r0, =#USB_PMABASE
+.L_gnp_chkaddr:
+    ldrh    r4, [r0, #0]    //txaddr
+    tst     r4, r4
+    beq     .L_gnp_nxtaddr
+    cmp     r3, r4
+    blo     .L_gnp_nxtaddr
+    mov     r3, r4
+.L_gnp_nxtaddr:
+    adds    r0, #8
+    subs    r1, #1
+    bne     .L_gnp_chkaddr
+    subs    r0, r3, r2
+    blo     .L_gnp_exit
+    cmp     r0, #0x40       //check for the pma table overlap
+.L_gnp_exit:
+    pop     {r1, r3, r4, pc}
+
+
+
+    .size   _get_next_pma, . - _get_next_pma
+
+    .thumb_func
+    .type   _ep_config, %function
+/* bool ep_config(uint8_t ep, uint8_t eptype, uint16_t epsize)
+ * R0 <- ep
+ * R1 <- eptype
+ * R2 <- epsize
+ * result -> R0
+ */
+_ep_config:
+    push    {r4, r5, lr}
+    movs    r3, 0x01
+    ands    r3, r2
+    adds    r2, r3      //R2 -> halfword aligned epsize
+    movs    r3, #0x00   //BULK
+    cmp     r1, #0x02   // is eptype bulk ?
+    beq     .L_epc_settype
+    movs    r3, #0x01   //DBLBULK
+    cmp     r1, #0x06
+    beq     .L_epc_settype
+    movs    r3, #0x02   //CONTROL
+    cmp     r1, #0x00
+    beq     .L_epc_settype
+    movs    r3, #0x04   //ISO
+    cmp     r1, #0x01
+    beq     .L_epc_settype
+    movs    r3, #0x06   //INTERRUPT
+.L_epc_settype:
+    lsls    r3, #8
+    lsls    r4, r0, #28
+    lsrs    r4, #28
+    orrs    r3, r4
+    lsls    r4, #2
+    ldr     r5, =#USB_EPBASE
+    strh    r3, [r5, r4]    //setup EPTYPE EPKIND EPADDR
+    cmp     r1, #0x00       // is a control ep ?
+    beq     .L_epc_setuptx
+    cmp     r0, #0x80
+    blo     .L_epc_setuprx
+.L_epc_setuptx:
+    ldr     r5, =#USB_PMABASE
+    lsls    r4, #2
+    adds    r5, r4
+    bl      _get_next_pma
+    bcc     .L_epc_fail
+    strh    r0, [r5, #TXADDR]    //store txaddr or txaddr0
+    movs    r0, #0x00
+    strh    r0, [r5, #TXCOUNT]    //store txcnt
+    cmp     r1, #0x06       // is DBLBULK
+    beq     .L_epc_txdbl
+    ldr     r3, =#TX_USTALL  //set state NAKED , clr DTOG_TX
+    cmp     r1, #0x01       // is ISO
+    bne     .L_epc_txsetstate   //
+.L_epc_txdbl:
+    ldr     r3, =#DTX_USTALL //set state VALID clr DTOG_TX & SWBUF_TX
+    bl      _get_next_pma
+    bcc     .L_epc_fail
+    strh    r0, [r5, #TXADDR1]    //store txaddr1
+    movs    r0, #0x00
+    strh    r0, [r5, #TXCOUNT1]    //store txcnt
+.L_epc_txsetstate:
+    ldr     r5, =#USB_EPBASE
+    lsrs    r4, #1
+    ldrh    r0, [r5, r4]
+    eors    r0, r3
+    lsrs    r3, #16
+    ands    r0, r3
+    strh    r0, [r5, r4]
+    cmp     r1, #0x00       //is a control ep ?
+    bne     .L_epc_exit
+.L_epc_setuprx:
+    mov     r3, r2
+    cmp     r2, #62
+    bls     .L_epc_rxbb
+    movs    r3, #0x1F
+    ands    r3, r2
+    bne     .L_epc_rxaa
+    subs    r2, #0x20
+.L_epc_rxaa:
+    bics    r2, r3
+    lsrs    r3, r2, #4
+    adds    r3, #0x40
+    adds    r2, #0x20
+.L_epc_rxbb:
+    lsls    r3, #9
+    ldr     r5, =#USB_PMABASE
+    lsls    r4, #2
+    adds    r5, r4
+    cmp     r1, 0x06    //if dblbulk
+    beq     .L_epc_rxdbl
+    cmp     r1, 0x01    // iso
+    bne     .L_epc_rxsngl
+.L_epc_rxdbl:
+    bl      _get_next_pma
+    bcc     .L_epc_fail
+    strh    r0, [r5, #RXADDR0]    //store rxaddr0
+    strh    r3, [r5, #RXCOUNT0]    //store rxcnt0
+    bl      _get_next_pma
+    bcc     .L_epc_fail
+    strh    r0, [r5, #RXADDR1]    //store rxaddr1
+    strh    r3, [r5, #RXCOUNT1]    //store rxcnt1
+    ldr     r3, =#DRX_USTALL
+    b       .L_epc_rxsetstate
+.L_epc_rxsngl:
+    bl      _get_next_pma
+    bcc     .L_epc_fail
+    strh    r0, [r5, #RXADDR]    //store rxaddr1 or rxaddr
+    strh    r3, [r5, #RXCOUNT]    //store rxcnt1 or rxcnt
+    ldr     r3, =#RX_USTALL
+.L_epc_rxsetstate:
+    ldr     r5, =#USB_EPBASE
+    lsrs    r4, #1
+    ldrh    r0, [r5, r4]
+    eors    r0, r3
+    lsrs    r3, #16
+    ands    r0, r3
+    strh    r0, [r5, r4]
+.L_epc_exit:
+    movs    r0, #0x01
+    pop     {r4, r5, pc}
+.L_epc_fail:
+    movs    r0, #0x00
+    pop     {r4, r5, pc}
+
+    .size   _ep_config, . - _ep_config
+
+    .thumb_func
+    .type   _ep_deconfig, %function
+
+
+/* void ep_deconfig( uint8_t ep)
+ * R0 <- ep
+ */
+_ep_deconfig:
+    lsls    r1, r0, #28
+    lsrs    r1, #26
+    ldr     r2, =#USB_EPBASE
+    ldr     r3, =#USB_PMABASE
+    adds    r2, r1
+    lsls    r1, #1
+    adds    r3, r1
+/* clearing endpoint register */
+    ldr     r1, =#EP_NOTOG
+    ldrh    r0, [r2]
+    bics    r0, r1
+    strh    r0, [r2]
+/* clearing PMA data */
+    movs    r0, #0x00
+    strh    r0, [r3, #TXADDR]
+    strh    r0, [r3, #TXCOUNT]
+    strh    r0, [r3, #RXADDR]
+    strh    r0, [r3, #RXCOUNT]
+    bx      lr
+
+    .size   _ep_deconfig, . - _ep_config
+
+
+
+
+#define ISTRSHIFT   8
+#define ISTRBIT(bit) ((1 << bit) >> ISTRSHIFT)
+
+
+    .thumb_func
+    .type     _evt_poll, %function
+/*void evt_poll(usbd_device *dev, usbd_evt_callback callback)*/
+_evt_poll:
+    push    {r0, r1, r4, r5}
+    ldr     r3, =#USB_REGBASE
+    ldrh    r0, [r3, #4]        //USB->ISTR -> R2
+/* ep_index -> R2 */
+    movs    r2, 0x07
+    ands    r2, r0
+/* checking USB->ISTR for events */
+    lsls    r0, #17             //CTRM -> CF
+    bcs     .L_ep_ctrm
+    lsls    r0, #2              //ERRM -> CF
+    bcs     .L_ep_errm
+    lsls    r0, #1              //WKUPM -> CF
+    bcs     .L_ep_wkupm
+    lsls    r0, #1              //SUSPM -> CF
+    bcs     .L_ep_suspm
+    lsls    r0, #1              //RESETM -> CF
+    bcs     .L_ep_resetm
+    lsls    r0, #1              //SOFM -> CF
+    bcs     .L_ep_sofm
+    lsls    r0, #1
+    bcs     .L_ep_esofm
+    /* exit with no callback */
+    pop     {r0, r1, r4 , r5}
+    bx      lr
+
+.L_ep_ctrm:
+    movs    r3, #0x00
+    ldr     r0,=#USB_EPBASE
+    lsrs    r0, #2
+    adds    r0, r2
+    lsls    r0, #2              // R0 ep register address
+    ldrh    r4, [r0]            //R4 *USB->EPx
+    lsrs    r5, r4, #8         // CTR_TX -> CF
+    bcc     .L_ep_ctr_rx
+/* CTR_TX event */
+    movs    r1, #usbd_evt_eptx
+    movs    r5, #0x80
+    adds    r2, #0x80           // set endpoint tx
+    b       .L_ep_clr_ctr
+.L_ep_ctr_rx:
+/* CTR_RX  RX or SETUP */
+    movs    r1, #usbd_evt_epsetup
+    lsls    r5, r4, #21             //SETUP -> CF
+    bcs     .L_ep_ctr_evt
+    movs    r1, #usbd_evt_eprx
+    lsrs    r5, #29                 //EP_TYPE | EP_KIND -> R5 LSB
+    cmp     r5, #0x01               //if dblbuf bulk
+    bne     .L_ep_ctr_evt
+/* if ep is dblbulk RX */
+    movs    r3, #EP_RX_SWBUF
+.L_ep_ctr_evt:
+/* clear CTR_RX */
+    movs    r5, #0x80
+    lsls    r5, #0x08
+.L_ep_clr_ctr:
+    bics    r4, r5
+    ldr     r5, =#EP_NOTOG
+    ands    r4, r5
+    orrs    r4, r3
+    strh    r4, [r0]            // clr CTR flag
+    b       .L_ep_callback
+
+.L_ep_errm:
+    movs    r1, #usbd_evt_error
+    movs    r4, #ISTRBIT(13)
+    b      .L_ep_clristr
+
+.L_ep_sofm:
+    movs    r1, #usbd_evt_sof
+    movs    r4, #ISTRBIT(9)
+    b       .L_ep_clristr
+
+.L_ep_esofm:
+    movs    r1, #usbd_evt_esof
+    movs    r4, #ISTRBIT(8)
+    b       .L_ep_clristr
+
+.L_ep_wkupm:
+    ldrh    r1, [r3, #0]            //R1 USB->CNTR
+    movs    r5, #0x08
+    bics    r1, r5                  //clr FSUSP
+    strh    r1, [r3, #0]            //USB->CNTR R2
+    movs    r1, #usbd_evt_wkup
+    movs    r4, #ISTRBIT(12)
+    b       .L_ep_clristr
+
+.L_ep_suspm:
+    ldrh    r1, [r3, #0]            //R1 USB->CNTR
+    movs    r5, #0x08
+    orrs    r1, r5                  //set FSUSP
+    strh    r1, [r3, #0]            //USB->CNTR R2
+    movs    r1, #usbd_evt_susp
+    movs    r4, #ISTRBIT(11)
+    b       .L_ep_clristr
+
+/* do reset routine */
+.L_ep_resetm:
+    movs    r1, #7
+    ldr     r2, =#USB_EPBASE
+    ldr     r0, =#USB_PMABASE
+    ldr     r5, =#EP_NOTOG
+.L_ep_reset_loop:
+    ldrh    r4, [r2]
+    bics    r4, r5
+    strh    r4, [r2]
+    movs    r4, #0
+    strh    r4, [r0, #TXADDR]
+    strh    r4, [r0, #TXCOUNT]
+    strh    r4, [r0, #RXADDR]
+    strh    r4, [r0, #RXCOUNT]
+    adds    r2, #0x04
+    adds    r0, #0x10
+    subs    r1, #1
+    bpl     .L_ep_reset_loop
+    movs    r2, #0x00
+    strh    r2, [r3, #0x10]     // 0 -> USB->BTABLE
+    movs    r1, #usbd_evt_reset
+    movs    r4, #ISTRBIT(10)
+.L_ep_clristr:
+    lsls    r4, #ISTRSHIFT
+    ldrh    r0, [r3, #4]
+    bics    r0, r4
+    strh    r0, [r3, #4]
+.L_ep_callback:
+    pop     {r0, r3, r4, r5 }
+    bx      r3
+
+    .size   _evt_poll, . - _evt_poll
+
+    .pool
+
+   .end
+
+#endif

+ 10 - 1
usb.h

@@ -32,6 +32,8 @@
       defined(STM32L443xx)
     #define USE_STMV0_DRIVER
     #warning "Driver has not been tested with this MPU"
+#elif defined(STM32L100xC)
+    #define USE_STMV1A_DRIVER
 #else
     #error "No supported MCU family selected"
 #endif
@@ -45,7 +47,14 @@
         #define usbd_hw usb_stmv0a
     #elif defined(USE_STMV0_DRIVER)
         extern const struct usbd_driver usb_stmv0;
-        #define usbd_hw usb_stmv0
+        #define usbd_hw usb_stmv0
+    #elif defined(USE_STMV1_DRIVER)
+        extern const struct usbd_driver usb_stmv1;
+        #define usbd_hw usb_stmv1
+    #elif defined(USE_STMV1A_DRIVER)
+        extern const struct usbd_driver usb_stmv1a;
+        #define usbd_hw usb_stmv1a
+
     #endif
 #endif