From ef220e5e4d0c380052e94b7985af7c4810b1e93d Mon Sep 17 00:00:00 2001 From: henrik Date: Fri, 3 Dec 2021 15:18:24 +0100 Subject: [PATCH] add STM32L552xE --- Makefile | 5 + demo/stm32l552xe.ld | 9 + inc/usb.h | 14 + readme.md | 10 + src/memmap.inc | 17 + src/usbd_stm32l552_devfs.c | 470 ++++++++++++++++++ src/usbd_stm32l552_devfs_asm.S | 861 +++++++++++++++++++++++++++++++++ 7 files changed, 1386 insertions(+) create mode 100644 demo/stm32l552xe.ld create mode 100644 src/usbd_stm32l552_devfs.c create mode 100644 src/usbd_stm32l552_devfs_asm.S diff --git a/Makefile b/Makefile index 0c9290b..02b0ff4 100644 --- a/Makefile +++ b/Makefile @@ -201,6 +201,11 @@ stm32l433cc: clean DEFINES='STM32L4 STM32L433xx USBD_SOF_DISABLED' \ CFLAGS='-mcpu=cortex-m4' +stm32l552xe: clean + @$(MAKE) demo STARTUP='$(CMSISDEV)/ST/STM32L5xx/Source/Templates/gcc/startup_stm32l55sxx.s' \ + LDSCRIPT='demo/stm32l552xe.ld' \ + DEFINES='STM32L5 STM32L552xx USBD_SOF_DISABLED' \ + CFLAGS='-mcpu=cortex-m33' stm32f070xb: clean @$(MAKE) demo STARTUP='$(CMSISDEV)/ST/STM32F0xx/Source/Templates/gcc/startup_stm32f070xb.s' \ diff --git a/demo/stm32l552xe.ld b/demo/stm32l552xe.ld new file mode 100644 index 0000000..fe8b8f5 --- /dev/null +++ b/demo/stm32l552xe.ld @@ -0,0 +1,9 @@ +ENTRY(Reset_Handler) +MEMORY +{ + ROM (rx): ORIGIN = 0x08000000, LENGTH = 512K + RAM (rwx): ORIGIN = 0x30000000, LENGTH = 192K + SRAM (rwx): ORIGIN = 0x0A030000, LENGTH = 16K +} + +INCLUDE sections.ld diff --git a/inc/usb.h b/inc/usb.h index 5c3e589..8232f88 100644 --- a/inc/usb.h +++ b/inc/usb.h @@ -61,6 +61,20 @@ #endif #endif +#elif defined(STM32L552xx) + + #define USBD_STM32L552 + + #if !defined(__ASSEMBLER__) + extern const struct usbd_driver usbd_devfs; + extern const struct usbd_driver usbd_devfs_asm; + #if defined(USBD_ASM_DRIVER) + #define usbd_hw usbd_devfs_asm + #else + #define usbd_hw usbd_devfs + #endif + #endif + #elif defined(STM32L1) #define USBD_STM32L100 diff --git a/readme.md b/readme.md index 504c87d..86e79c1 100644 --- a/readme.md +++ b/readme.md @@ -73,6 +73,16 @@ All requirements can be downloaded into a directory specified in environment var usbd_otgfs usbd_stm32l476_otgfs.c + + STM32L552 + Doublebuffered[2]
8[1] endpoints
BC1.2 + usbd_devfs + usbd_stm32l552_devfs.c + + + usbd_devfs_asm + usbd_stm32l552_devfs_asm.S + STM32F401 STM32F411 Doublebuffered
4 endpoints
VBUS detection
SOF output diff --git a/src/memmap.inc b/src/memmap.inc index ca931c2..a35e8a0 100644 --- a/src/memmap.inc +++ b/src/memmap.inc @@ -71,6 +71,23 @@ #define UID_BASE 0x1FFF7590 #define RCC_USBEN 26 +#elif defined(STM32L552xx) + + #define USB_EPBASE 0x4000D400 + #define USB_REGBASE 0x4000D440 + #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 0x4000D800 + #define RCC_BASE 0x40021000 + #define RCC_APB1RSTR2 0x3C + #define RCC_APB1ENR2 0x5C + #define UID_BASE 0x0BFA0590 + #define RCC_USBEN 21 + #elif defined(STM32G4) #define USB_EPBASE 0x40005C00 diff --git a/src/usbd_stm32l552_devfs.c b/src/usbd_stm32l552_devfs.c new file mode 100644 index 0000000..73ebeb4 --- /dev/null +++ b/src/usbd_stm32l552_devfs.c @@ -0,0 +1,470 @@ +/* This file is the part of the Lightweight USB device Stack for STM32 microcontrollers + * + * Copyright ©2016 Dmitry Filimonchuk + * + * 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 +#include +#include "stm32.h" +#include "usb.h" + +#if defined(USBD_STM32L552) + +#define USB_PMAADDR USB_PMAADDR_NS + +#ifndef USB_PMASIZE + #pragma message "PMA memory size is not defined. Use 1k by default" + #define USB_PMASIZE 0x400 +#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) + +#define STATUS_VAL(x) (USBD_HW_BC | (x)) + +typedef struct { + uint16_t addr; + uint16_t cnt; +} pma_rec; + +typedef union pma_table { + struct { + pma_rec tx; + pma_rec rx; + }; + struct { + pma_rec tx0; + pma_rec tx1; + }; + struct { + pma_rec rx0; + pma_rec rx1; + }; +} 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) * 8 + 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->rx.addr) && (tbl->rx.addr < _result)) _result = tbl->rx.addr; + if ((tbl->tx.addr) && (tbl->tx.addr < _result)) _result = tbl->tx.addr; + } + return (_result < (0x020 + sz)) ? 0 : (_result - sz); +} + +static uint32_t getinfo(void) { + if (!(RCC->APB1ENR2 & RCC_APB1ENR2_USBFSEN)) return STATUS_VAL(0); + if (USB->BCDR & USB_BCDR_DPPU) 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) { + 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); + } + } + } +} + +static 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))); + } +} + +static void enable(bool enable) { + if (enable) { + RCC->APB1ENR2 |= RCC_APB1ENR2_USBFSEN; + RCC->APB1RSTR2 |= RCC_APB1RSTR2_USBFSRST; + RCC->APB1RSTR2 &= ~RCC_APB1RSTR2_USBFSRST; + USB->CNTR = USB_CNTR_CTRM | USB_CNTR_RESETM | USB_CNTR_ERRM | +#if !defined(USBD_SOF_DISABLED) + USB_CNTR_SOFM | +#endif + USB_CNTR_SUSPM | USB_CNTR_WKUPM; + } else if (RCC->APB1ENR2 & RCC_APB1ENR2_USBFSEN) { + USB->BCDR = 0; + RCC->APB1RSTR2 |= RCC_APB1RSTR2_USBFSRST; + RCC->APB1ENR2 &= ~RCC_APB1ENR2_USBFSEN; + } +} + +static uint8_t connect(bool connect) { + uint8_t res; + USB->BCDR = USB_BCDR_BCDEN | USB_BCDR_DCDEN; + if (USB->BCDR & USB_BCDR_DCDET) { + USB->BCDR = USB_BCDR_BCDEN | USB_BCDR_PDEN; + if (USB->BCDR & USB_BCDR_PS2DET) { + res = usbd_lane_unk; + } else if (USB->BCDR & USB_BCDR_PDET) { + USB->BCDR = USB_BCDR_BCDEN | USB_BCDR_SDEN; + if (USB->BCDR & USB_BCDR_SDET) { + res = usbd_lane_dcp; + } else { + res = usbd_lane_cdp; + } + } else { + res = usbd_lane_sdp; + } + } else { + res = usbd_lane_dsc; + } + USB->BCDR = (connect) ? USB_BCDR_DPPU : 0; + return res; +} + +static void setaddr (uint8_t addr) { + USB->DADDR = USB_DADDR_EF | addr; +} + +static bool ep_config(uint8_t ep, uint8_t eptype, uint16_t epsize) { + volatile uint16_t *reg = EPR(ep); + pma_table *tbl = EPT(ep); + /* epsize must be 2-byte aligned */ + epsize = (~0x01U) & (epsize + 1); + + 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; + tbl->tx.addr = _pma; + tbl->tx.cnt = 0; + if ((eptype == USB_EPTYPE_ISOCHRONUS) || + (eptype == (USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF))) { + _pma = get_next_pma(epsize); + if (_pma == 0) return false; + tbl->tx1.addr = _pma; + tbl->tx1.cnt = 0; + EP_DTX_UNSTALL(reg); + } else { + EP_TX_UNSTALL(reg); + } + } + if (!(ep & 0x80)) { + uint16_t _rxcnt; + uint16_t _pma; + if (epsize > 62) { + /* using 32-byte blocks. epsize must be 32-byte aligned */ + epsize = (~0x1FU) & (epsize + 0x1FU); + _rxcnt = 0x8000 - 0x400 + (epsize << 5); + } else { + _rxcnt = epsize << 9; + } + _pma = get_next_pma(epsize); + if (_pma == 0) return false; + tbl->rx.addr = _pma; + tbl->rx.cnt = _rxcnt; + if ((eptype == USB_EPTYPE_ISOCHRONUS) || + (eptype == (USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF))) { + _pma = get_next_pma(epsize); + if (_pma == 0) return false; + tbl->rx0.addr = _pma; + tbl->rx0.cnt = _rxcnt; + EP_DRX_UNSTALL(reg); + } else { + EP_RX_UNSTALL(reg); + } + } + return true; +} + +static void ep_deconfig(uint8_t ep) { + pma_table *ept = EPT(ep); + *EPR(ep) &= ~USB_EPREG_MASK; + ept->rx.addr = 0; + ept->rx.cnt = 0; + ept->tx.addr = 0; + ept->tx.cnt = 0; +} + +static uint16_t pma_read (uint8_t *buf, uint16_t blen, pma_rec *rx) { + uint16_t *pma = (void*)(USB_PMAADDR + rx->addr); + uint16_t rxcnt = rx->cnt & 0x03FF; + rx->cnt &= ~0x3FF; + + if (blen > rxcnt) { + blen = rxcnt; + } + rxcnt = blen; + while (blen) { + uint16_t _t = *pma; + *buf++ = _t & 0xFF; + if (--blen) { + *buf++ = _t >> 8; + pma++; + blen--; + } else break; + } + return rxcnt; +} + +static int32_t ep_read(uint8_t ep, void *buf, uint16_t blen) { + pma_table *tbl = EPT(ep); + volatile uint16_t *reg = EPR(ep); + switch (*reg & (USB_EPRX_STAT | USB_EP_T_FIELD | USB_EP_KIND)) { + /* doublebuffered bulk endpoint */ + case (USB_EP_RX_VALID | USB_EP_BULK | USB_EP_KIND): + /* switching SWBUF if EP is NAKED */ + switch (*reg & (USB_EP_DTOG_RX | USB_EP_SWBUF_RX)) { + case 0: + case (USB_EP_DTOG_RX | USB_EP_SWBUF_RX): + *reg = (*reg & USB_EPREG_MASK) | USB_EP_SWBUF_RX; + break; + default: + break; + } + if (*reg & USB_EP_SWBUF_RX) { + return pma_read(buf, blen, &(tbl->rx1)); + } else { + return pma_read(buf, blen, &(tbl->rx0)); + } + /* isochronous endpoint */ + case (USB_EP_RX_VALID | USB_EP_ISOCHRONOUS): + if (*reg & USB_EP_DTOG_RX) { + return pma_read(buf, blen, &(tbl->rx1)); + } else { + return pma_read(buf, blen, &(tbl->rx0)); + } + /* regular endpoint */ + case (USB_EP_RX_NAK | USB_EP_BULK): + case (USB_EP_RX_NAK | USB_EP_CONTROL): + case (USB_EP_RX_NAK | USB_EP_INTERRUPT): + { + int32_t res = pma_read(buf, blen, &(tbl->rx)); + /* setting endpoint to VALID state */ + EP_RX_VALID(reg); + return res; + } + /* invalid or not ready */ + default: + return -1; + } +} + +static void pma_write(uint8_t *buf, uint16_t blen, pma_rec *tx) { + uint16_t *pma = (void*)(USB_PMAADDR + tx->addr); + tx->cnt = blen; + while (blen > 1) { + *pma++ = buf[1] << 8 | buf[0]; + buf += 2; + blen -= 2; + } + if (blen) *pma = *buf; +} + +static int32_t ep_write(uint8_t ep, void *buf, uint16_t blen) { + pma_table *tbl = EPT(ep); + volatile uint16_t *reg = EPR(ep); + switch (*reg & (USB_EPTX_STAT | USB_EP_T_FIELD | USB_EP_KIND)) { + /* doublebuffered bulk endpoint */ + case (USB_EP_TX_NAK | USB_EP_BULK | USB_EP_KIND): + if (*reg & USB_EP_SWBUF_TX) { + pma_write(buf, blen, &(tbl->tx1)); + } else { + pma_write(buf, blen, &(tbl->tx0)); + } + *reg = (*reg & USB_EPREG_MASK) | USB_EP_SWBUF_TX; + break; + /* isochronous endpoint */ + case (USB_EP_TX_VALID | USB_EP_ISOCHRONOUS): + if (!(*reg & USB_EP_DTOG_TX)) { + pma_write(buf, blen, &(tbl->tx1)); + } else { + pma_write(buf, blen, &(tbl->tx0)); + } + break; + /* regular endpoint */ + case (USB_EP_TX_NAK | USB_EP_BULK): + case (USB_EP_TX_NAK | USB_EP_CONTROL): + case (USB_EP_TX_NAK | USB_EP_INTERRUPT): + pma_write(buf, blen, &(tbl->tx)); + EP_TX_VALID(reg); + break; + /* invalid or not ready */ + default: + return -1; + } + return blen; +} + +static uint16_t get_frame (void) { + return USB->FNR & USB_FNR_FN; +} + +static 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 { + *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; +#if !defined(USBD_SOF_DISABLED) + } else if (_istr & USB_ISTR_SOF) { + _ev = usbd_evt_sof; + USB->ISTR &= ~USB_ISTR_SOF; +#endif + } 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_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; +} + + __attribute__((externally_visible)) const struct usbd_driver usbd_devfs = { + 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_STM32L052 diff --git a/src/usbd_stm32l552_devfs_asm.S b/src/usbd_stm32l552_devfs_asm.S new file mode 100644 index 0000000..c300333 --- /dev/null +++ b/src/usbd_stm32l552_devfs_asm.S @@ -0,0 +1,861 @@ +/* This file is the part of the Lightweight USB device Stack for STM32 microcontrollers + * + * Copyright ©2016 Dmitry Filimonchuk + * + * 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" +#if defined(USBD_STM32L552) +#include "memmap.inc" + +#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 0x02 +#define RXADDR1 0x04 +#define RXCOUNT1 0x06 + +#define TXADDR0 0x00 +#define TXCOUNT0 0x02 +#define TXADDR1 0x04 +#define TXCOUNT1 0x06 + +#define TXADDR 0x00 +#define TXCOUNT 0x02 +#define RXADDR 0x04 +#define RXCOUNT 0x06 + +#if defined(STM32F070x6) || defined(STM32F070xB) || \ + defined(STM32F042x6) || defined(STM32F048xx) || \ + defined(STM32F072xB) || defined(STM32F078xx) + #define UID_OFFSET_0 0x00 + #define UID_OFFSET_1 0x04 + #define UID_OFFSET_2 0x08 +#else + #define UID_OFFSET_0 0x00 + #define UID_OFFSET_1 0x04 + #define UID_OFFSET_2 0x14 +#endif + +#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-m0plus + .thumb + + .section .rodata.usbd_devfs_asm + .align 4 + .globl usbd_devfs_asm +usbd_devfs_asm: + .long _getinfo + .long _enable + .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 usbd_devfs_asm, . - usbd_devfs_asm + + .text + .align 2 + .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, UID_OFFSET_0] //UID0 + bl .L_fnv1a + ldr r2, [r5, UID_OFFSET_1] //UID1 + bl .L_fnv1a + ldr r2, [r5, UID_OFFSET_2] //UID2 + bl .L_fnv1a + movs r3, #28 +.L_gsn_loop: + movs r1, r4 + lsrs r1, r3 + lsls r1, #28 + lsrs r1, #28 + adds r1, #0x30 //'0' + cmp r1, #0x3A + blo .L_gsn_store + adds r1, #0x07 //'A' - '0' +.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_fnv1a_prime: .long 16777619 +.L_fnv1a_offset: .long 2166136261 +.L_uid_base: .long UID_BASE + + .size _get_serial_desc, . - _get_serial_desc + + .thumb_func + .type _connect, %function +_connect: + ldr r3, =USB_REGBASE + movs r1, #0x03 //BCDEN + DCDEN + movs r2, #usbd_lane_dsc + strh r1, [r3, #USB_BCDR] + ldrh r1, [r3, #USB_BCDR] + lsrs r1, #0x05 //DCDET->CF + bcc .L_connect + movs r1, #0x05 //BCDEN + PDEN + movs r2, #usbd_lane_unk + strh r1, [r3, #USB_BCDR] + ldrh r1, [r3, #USB_BCDR] + lsls r1, #25 //PS2DET->CF + bcs .L_connect + movs r2, #usbd_lane_sdp + lsls r1, #2 //PDET->CF + bcc .L_connect + movs r1, #0x09 //BCDEN + SDET + movs r2, #usbd_lane_cdp + strh r1, [r3, #USB_BCDR] + ldrh r1, [r3, #USB_BCDR] + lsrs r1, #7 //SDET->CF + bcc .L_connect + movs r2, #usbd_lane_dcp +.L_connect: + subs r1, r0, #1 + sbcs r0, r1 + lsls r0, #15 + strh r0, [r3, #USB_BCDR] + mov r0, r2 + 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 _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 r1, =USB_REGBASE //USB->CNTR + ldr r2, =RCC_BASE //RCC + movs r3, #0x01 + lsls r3, #RCC_USBEN //USBEN or USBRST + tst r0, r0 + beq .L_disable +.L_enable: + ldr r0, [r2, #RCC_APB1ENR2] + orrs r0, r3 + str r0, [r2, #RCC_APB1ENR2] //RCC->RCC_APB1ENR2 |= USBEN + ldr r0, [r2, #RCC_APB1RSTR2] + orrs r0, r3 + str r0, [r2, #RCC_APB1RSTR2] //RCC->APB1RSTR |= USBRST + bics r0, r3 + str r0, [r2, #RCC_APB1RSTR2] //RCC->APB1RSTR &= ~USBRST + +#if defined(USBD_PINS_REMAP) && (defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F070x6)) + ldr r0, [r2, #RCC_APB2ENR] + movs r3, #0x01 + orrs r0, r3 + str r0, [r2, #RCC_APB2ENR] //RCC->APB2ENR |= RCC_APB2ENR_SYSCFGCOMPEN + + ldr r2, =SYSCFG_BASE //SYSCFG->CFGR1 + ldr r0, [r2] + lsls r3, #SYSCFG_USBREMAP + orrs r0, r3 + str r0, [r2] //SYSCFG->CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP; // remap USB pins for small packages +#endif + +#if !defined(USBD_SOF_DISABLED) + movs r0, #0xBE // CTRM | ERRM | WKUPM | SUSPM | RESETM | SOFM +#else + movs r0, #0xBC // CTRM | ERRM | WKUPM | SUSPM | RESETM +#endif + lsls r0, #0x08 + strh r0, [r1] //set USB->CNTR + bx lr +.L_disable: + ldr r0, [r2, #RCC_APB1ENR2] + tst r0, r3 + beq .L_enable_end // usb is disabled + movs r0, #0x00 + strh r0, [r1, #USB_BCDR] //USB->BCDR disable USB I/O + ldr r0, [r2, #RCC_APB1RSTR2] + orrs r0, r3 + str r0, [r2, #RCC_APB1RSTR2] //RCC->APB1RSTR |= USBRST + ldr r0, [r2, #RCC_APB1ENR2] + bics r0, r3 + str r0, [r2, #RCC_APB1ENR2] //RCC->APB1ENR &= ~USBEN +.L_enable_end: + bx lr + .size _enable, . - _enable + + .thumb_func + .type _getinfo, %function +_getinfo: + movs r0, #USBD_HW_BC + ldr r2, =RCC_BASE + ldr r1, [r2, #RCC_APB1ENR2] + lsrs r1, #24 //USBEN -> CF + bcc .L_getinfo_end + adds r0, #USBD_HW_ENABLED + ldr r2, =USB_REGBASE + ldr r1, [r2, #USB_BCDR] + lsrs r1, #15 //DPPU -> CF + bcc .L_getinfo_end + adds r0, #USBD_HW_SPEED_FS +.L_getinfo_end: + bx lr + .size _getinfo, . - _getinfo + + .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: + push {r4, lr} + lsls r2, r0, #28 + lsrs r2, #26 + ldr r3, =USB_EPBASE + adds r3, r2 // epr -> r3 + movs r2, 0x30 // TX_STAT_MASK -> r2 + ldrh r4, [r3] + lsls r4, #21 + lsrs r4, #29 // EP_TYPE | EP_KIND -> R4 LSB + cmp r4, #0x04 // ISO ? + beq .L_eps_exit + cmp r0, #0x80 + blo .L_eps_rx +.L_eps_tx: + ldr r0, =TX_STALL //stall TX + cmp r1, #0x00 + bne .L_eps_reg_set +.L_eps_tx_unstall: + ldr r0, =DTX_USTALL //unstall dblbulk or iso TX (VALID and clr DTOG_TX & SWBUF_TX) + cmp r4, #0x01 // if doublebuffered bulk endpoint + beq .L_eps_reg_set + 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 + cmp r1, #0x00 + bne .L_eps_reg_set +.L_eps_rx_unstall: + ldr r0, =DRX_USTALL //unstall dblbulk or iso (VALID. clr DTOG_RX set SWBUF_RX) + cmp r4, #0x01 // if dblbulk + 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: + pop {r4, pc} + .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 +/* int32_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 or -1 on error + */ +_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, #1 + adds r4, r0 // *EPT -> R4 + ldrh r5, [r3] // reading epr +/* validating endpoint */ + movs r0, #0x37 + lsls r0, #0x08 + ands r0, r5 + lsrs r0, #0x08 + cmp r0, #0x34 // (OK) RX_VALID + ISO + beq .L_epr_iso + cmp r0, #0x31 // (OK) RX_VALID + DBLBULK + beq .L_epr_dbl + cmp r0, #0x20 // (OK) RX_NAKED + BULK + beq .L_epr_sngl + cmp r0, #0x22 // (OK) RX_NAKED + CTRL + beq .L_epr_sngl + cmp r0, #0x26 // (OK) RX_NAKED + INTR + beq .L_epr_sngl + movs r0, #0xFF // endpoint contains no valid data + sxtb r0, r0 + b .L_epr_exit +/* processing */ +.L_epr_dbl: + lsrs r0, r5, #8 + eors r0, r5 + lsrs r0, #7 // SW_RX ^ DTOG_RX -> CF + bcs .L_epr_notog // jmp if SW_RX != DTOG_RX (VALID) + ldr r0, =EP_NOTOG + ands r5, r0 + adds r5, #EP_RX_SWBUF + strh r5, [r3] // toggling SW_RX +.L_epr_notog: + ldrh r5, [r3] + lsls r5, #8 // shift SW_RX to DTOG_RX +.L_epr_iso: + lsrs r5, #15 // DTOG_RX -> CF + bcs .L_epr_sngl + subs r4, #0x04 // set RXADDR0 +.L_epr_sngl: + ldrh r0, [r4, #RXCOUNT] + lsrs r5, r0, #0x0A + lsls r5, #0x0A // r5 = r0 & ~0x03FF + strh r5, [r4, #RXCOUNT] + lsls r0, #22 + lsrs r0, #22 // r0 &= 0x3FF (RX count) + ldrh r5, [r4, #RXADDR] + ldr r4, =USB_PMABASE + adds r5, r4 // R5 now has a physical address + cmp r2, r0 + blo .L_epr_read + mov r2, r0 // if buffer is larger +.L_epr_read: + cmp r2, #1 + blo .L_epr_read_end + ldrh r4, [r5] + strb r4, [r1] + beq .L_epr_read_end + lsrs r4, #8 + strb r4, [r1, #1] + adds r1, #2 + adds r5, #2 + subs r2, #2 + bhi .L_epr_read +.L_epr_read_end: + ldrh r5, [r3] // reload EPR + lsls r1, r5, #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 r5, r2 + lsrs r2, #16 + ands r5, r2 + strh r5, [r3] // set ep to VALID state +.L_epr_exit: + pop {r4, r5, pc} + .size _ep_read, . - _ep_read + + + + .thumb_func + .type _ep_write, %function +/* int32_t ep_write(uint8_t ep, void *buf, uint16_t blen) + * R0 -> endpoint + * R1 -> *buffer + * R2 -> data length + * + */ +_ep_write: + push {r4, r5, r6, lr} + ldr r3, =USB_EPBASE + ldr r4, =USB_PMABASE + lsls r0, #28 + lsrs r0, #26 + adds r3, r0 // *EPR -> R3 + lsls r0, #1 + adds r4, r0 // TXADDR0 -> R4 + ldrh r5, [r3] // reading epr + movs r0, #0x73 + lsls r0, #4 + ands r0, r5 + lsrs r0, #4 + cmp r0, #0x43 // (OK) TX_VALID + ISO + beq .L_epw_iso + cmp r0, #0x12 // (OK) TX_NAK + DBLBULK + beq .L_epw_dbl + cmp r0, #0x02 // (OK) TX_NAK + BULK + beq .L_epw_sngl + cmp r0, #0x22 // (OK) TX_NAK + CONTROL + beq .L_epw_sngl + cmp r0, #0x62 // (OK) TX_NAK + INTERRUPT + beq .L_epw_sngl + movs r0, #0xFF + sxtb r0, r0 + b .L_epw_exit +.L_epw_dbl: + mvns r5, r5 + lsrs r5, #8 // ~SWBUF_TX -> DTOG_TX +.L_epw_iso: + lsrs r5, #7 // DTOG_TX -> CF + bcs .L_epw_sngl + adds r4, #4 // TXADDR1 -> R4 +.L_epw_sngl: + strh r2, [r4, #TXCOUNT] + mov r0, r2 // save count for return + ldrh r5, [r4, #TXADDR] + ldr r4, =USB_PMABASE + adds r5, r4 // PMA BUFFER -> R5 +.L_epw_write: + cmp r2, #1 + blo .L_epw_write_end + ldrb r4, [r1] + beq .L_epw_store + ldrb r6, [r1, #1] + lsls r6, #8 + orrs r4, r6 +.L_epw_store: + strh r4, [r5] + adds r5, #2 + adds r1, #2 + subs r2, #2 + bhi .L_epw_write +.L_epw_write_end: + ldrh r5, [r3] // reload EPR + lsls r1, r5, #21 + lsrs r1, #29 + cmp r1, #0x04 + beq .L_epw_exit // isochronous ep. do nothing + ldr r2, =TGL_SET(EP_TX_STAT, EP_TX_VAL) + cmp r1, #0x01 + bne .L_epw_setstate // NOT a doublebuffered bulk + ldr r2, =TGL_SET(EP_TX_SWBUF, EP_TX_SWBUF) + bics r5, r2 // clear TX_SWBUF +.L_epw_setstate: + eors r5, r2 + lsrs r2, #16 + ands r5, r2 + strh r5, [r3] +.L_epw_exit: + pop {r4, r5, r6, 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, #0x3C + movs r3, #1 + lsls r3, #10 //R3 MAX_PMA_SIZE + ldr r0, =USB_PMABASE +.L_gnp_chkaddr: + ldrh r4, [r0, r1] + tst r4, r4 + beq .L_gnp_nxtaddr + cmp r3, r4 + blo .L_gnp_nxtaddr + mov r3, r4 +.L_gnp_nxtaddr: + subs r1, #0x04 + bhs .L_gnp_chkaddr + subs r0, r3, r2 + blo .L_gnp_exit + cmp r0, #0x20 //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, #1 + adds r5, r4 +/* setup buffer table */ +/* TX or TX0 */ + 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 + bne .L_epc_txsetstate //if single buffered +.L_epc_txdbl: +/* TX1 */ + 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: +/* calculating RX_COUNT field. result in R3*/ + movs r3, r2 + cmp r2, #62 + bls .L_epc_rxbb + /* ep size must be 32-byte aligned if >= 64 */ + movs r3, #0x1F + adds r2, r3 + bics r2, r3 + lsrs r3, r2, #4 + adds r3, #0x3E +.L_epc_rxbb: + lsls r3, #9 + ldr r5, =USB_PMABASE + lsls r4, #1 + adds r5, r4 +/* setup buffer table */ + bl _get_next_pma + bcc .L_epc_fail +/* set RX or RX1 */ + strh r0, [r5, #RXADDR] + strh r3, [r5, #RXCOUNT] + ldr r0, =RX_USTALL +/* check if doublebuffered */ + cmp r1, 0x06 //if dblbulk + beq .L_epc_rxdbl + cmp r1, 0x01 // iso + bne .L_epc_rxsetstate +.L_epc_rxdbl: + bl _get_next_pma + bcc .L_epc_fail + strh r0, [r5, #RXADDR0] //store rxaddr0 + strh r3, [r5, #RXCOUNT0] //store rxcnt0 + ldr r0, =DRX_USTALL +.L_epc_rxsetstate: + ldr r5, =USB_EPBASE + lsrs r4, #1 + ldrh r3, [r5, r4] + eors r3, r0 + lsrs r0, #16 + ands r3, r0 + strh r3, [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 */ +#if !defined(USBD_SOF_DISABLED) + lsrs r1, r0, #10 //SOFM -> CF + bcs .L_ep_sofm +#endif + lsrs r1, r0, #16 //CTRM -> CF + bcs .L_ep_ctrm + lsrs r1, r0, #14 //ERRM -> CF + bcs .L_ep_errm + lsrs r1, r0, #13 //WKUPM -> CF + bcs .L_ep_wkupm + lsrs r1, r0, #12 //SUSPM -> CF + bcs .L_ep_suspm + lsrs r1, r0, #11 //RESETM -> CF + bcs .L_ep_resetm + /* exit with no callback */ + pop {r0, r1, r4 , r5} + bx lr + +.L_ep_ctrm: + movs r5, #0x80 // CTR_TX mask to R5 + ldr r0,=USB_EPBASE + lsrs r0, #2 + adds r0, r2 + lsls r0, #2 // R0 ep register address + ldrh r4, [r0] // R4 EPR valur + lsrs r3, r4, #8 // CTR_TX -> CF + bcc .L_ep_ctr_rx +/* CTR_TX event */ + movs r1, #usbd_evt_eptx + orrs r2, r5 // set endpoint tx + b .L_ep_clr_ctr +.L_ep_ctr_rx: +/* CTR_RX RX or SETUP */ + lsls r5, #0x08 // set mask to CRT_RX + movs r1, #usbd_evt_eprx + lsls r3, r4, #21 //SETUP -> CF + bcc .L_ep_clr_ctr + movs r1, #usbd_evt_epsetup +.L_ep_clr_ctr: + bics r4, r5 //clear CTR flag + ldr r5, =EP_NOTOG + ands r4, r5 + strh r4, [r0] // store + b .L_ep_callback +.L_ep_errm: + movs r1, #usbd_evt_error + movs r4, #ISTRBIT(13) + b .L_ep_clristr +#if !defined(USBD_SOF_DISABLED) +.L_ep_sofm: + movs r1, #usbd_evt_sof + movs r4, #ISTRBIT(9) + b .L_ep_clristr +#endif +.L_ep_wkupm: + ldrh r1, [r3, #USB_CNTR] //R1 USB->CNTR + movs r5, #0x08 + bics r1, r5 //clr FSUSP + strh r1, [r3, #USB_CNTR] //USB->CNTR R2 + movs r1, #usbd_evt_wkup + movs r4, #ISTRBIT(12) + b .L_ep_clristr + +.L_ep_suspm: + ldrh r1, [r3, #USB_CNTR] //R1 USB->CNTR + movs r5, #0x08 + orrs r1, r5 //set FSUSP + strh r1, [r3, #USB_CNTR] //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, #0x00 + 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 + bhs .L_ep_reset_loop + strh r4, [r3, #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 //USBD_STM32L052