diff --git a/os/common/ext/CMSIS/LPC/LPC11Uxx.h b/os/common/ext/CMSIS/LPC/LPC11Uxx.h index ad143ea8..a5e228d2 100644 --- a/os/common/ext/CMSIS/LPC/LPC11Uxx.h +++ b/os/common/ext/CMSIS/LPC/LPC11Uxx.h @@ -1,4 +1,3 @@ - /****************************************************************************************************//** * @file LPC11Uxx.h * @@ -492,43 +491,55 @@ typedef struct { /*!< (@ 0x40048000) SYSCON Structure #define SYSCON_SYSPLLCTRL_PSEL_POS (5U) #define SYSCON_SYSPLLCTRL_PSEL_MASK (0x03U << SYSPLLCTRL_PSEL_POS) // SYSCON_SYSPLLSTAT -#define SYSCON_SYSPLLSTAT_LOCK 0x1 +#define SYSCON_SYSPLLSTAT_LOCK 0x1U // SYSCON_SYSPLLCLKSEL #define SYSCON_SYSPLLCLKSEL_IRC (0x00U << 0) #define SYSCON_SYSPLLCLKSEL_SYSOSC (0x01U << 0) -#define SYSCON_SYSPLLCLKUEN_ENA 0x01 +#define SYSCON_SYSPLLCLKUEN_ENA 0x01U + +#define SYSCON_USBPLLCLKSEL_IRC (0U << 0U) +#define SYSCON_USBPLLCLKSEL_SYSOSC (1U << 0U) + +#define SYSCON_USBPLLCLKUEN_ENA 0x01U #define SYSCON_MAINCLKSEL_IRC (0x00U << 0) #define SYSCON_MAINCLKSEL_PLLIN (0x01U << 0) #define SYSCON_MAINCLKSEL_WATCHDOG (0x02U << 0) #define SYSCON_MAINCLKSEL_PLLOUT (0x03U << 0) -#define SYSCON_MAINCLKUEN_ENA 0x01 +#define SYSCON_MAINCLKUEN_ENA 0x01U -#define SYSAHBCLKCTRL_SYS (1U << 0) -#define SYSAHBCLKCTRL_ROM (1U << 1) -#define SYSAHBCLKCTRL_RAM0 (1U << 2) -#define SYSAHBCLKCTRL_FLASHREG (1U << 3) -#define SYSAHBCLKCTRL_FLASHARRAY (1U << 4) -#define SYSAHBCLKCTRL_I2C (1U << 5) -#define SYSAHBCLKCTRL_GPIO (1U << 6) -#define SYSAHBCLKCTRL_CT16B0 (1U << 7) -#define SYSAHBCLKCTRL_CT16B1 (1U << 8) -#define SYSAHBCLKCTRL_CT32B0 (1U << 9) -#define SYSAHBCLKCTRL_CT32B1 (1U << 10) -#define SYSAHBCLKCTRL_SSP0 (1U << 11) -#define SYSAHBCLKCTRL_USART (1U << 12) -#define SYSAHBCLKCTRL_ADC (1U << 13) -#define SYSAHBCLKCTRL_USB (1U << 14) -#define SYSAHBCLKCTRL_WWDT (1U << 15) -#define SYSAHBCLKCTRL_IOCON (1U << 16) -#define SYSAHBCLKCTRL_SSP1 (1U << 18) -#define SYSAHBCLKCTRL_PINT (1U << 19) -#define SYSAHBCLKCTRL_GROUP0INT (1U << 23) -#define SYSAHBCLKCTRL_GROUP1INT (1U << 24) -#define SYSAHBCLKCTRL_RAM1 (1U << 26) -#define SYSAHBCLKCTRL_USBRAM (1U << 27) +#define SYSCON_SYSAHBCLKCTRL_SYS (1U << 0) +#define SYSCON_SYSAHBCLKCTRL_ROM (1U << 1) +#define SYSCON_SYSAHBCLKCTRL_RAM0 (1U << 2) +#define SYSCON_SYSAHBCLKCTRL_FLASHREG (1U << 3) +#define SYSCON_SYSAHBCLKCTRL_FLASHARRAY (1U << 4) +#define SYSCON_SYSAHBCLKCTRL_I2C (1U << 5) +#define SYSCON_SYSAHBCLKCTRL_GPIO (1U << 6) +#define SYSCON_SYSAHBCLKCTRL_CT16B0 (1U << 7) +#define SYSCON_SYSAHBCLKCTRL_CT16B1 (1U << 8) +#define SYSCON_SYSAHBCLKCTRL_CT32B0 (1U << 9) +#define SYSCON_SYSAHBCLKCTRL_CT32B1 (1U << 10) +#define SYSCON_SYSAHBCLKCTRL_SSP0 (1U << 11) +#define SYSCON_SYSAHBCLKCTRL_USART (1U << 12) +#define SYSCON_SYSAHBCLKCTRL_ADC (1U << 13) +#define SYSCON_SYSAHBCLKCTRL_USB (1U << 14) +#define SYSCON_SYSAHBCLKCTRL_WWDT (1U << 15) +#define SYSCON_SYSAHBCLKCTRL_IOCON (1U << 16) +#define SYSCON_SYSAHBCLKCTRL_SSP1 (1U << 18) +#define SYSCON_SYSAHBCLKCTRL_PINT (1U << 19) +#define SYSCON_SYSAHBCLKCTRL_GROUP0INT (1U << 23) +#define SYSCON_SYSAHBCLKCTRL_GROUP1INT (1U << 24) +#define SYSCON_SYSAHBCLKCTRL_RAM1 (1U << 26) +#define SYSCON_SYSAHBCLKCTRL_USBRAM (1U << 27) + +#define SYSCON_USBCLKSEL_USBPLLOUT (0U << 0U) +#define SYSCON_USBCLKSEL_MAINCLK (1U << 0U) + +#define SYSCON_USBCLKUEN_ENA 0x01U + +#define SYSCON_USBCLKDIV_MASK #define SYSCON_PDRUNCFG_IRCOUT_PD (1U << 0U) #define SYSCON_PDRUNCFG_IRC_PD (1U << 1U) @@ -608,6 +619,38 @@ typedef struct { /*!< (@ 0x40080000) USB Structure __I uint32_t EPTOGGLE; /*!< (@ 0x40080034) USB Endpoint toggle register */ } LPC_USB_Type; +#define USB_DEVCMDSTAT_DEVADDR_POS 0U +#define USB_DEVCMDSTAT_DEVADDR_MASK (0x7FU << USB_DEVCMDSTAT_DEVADDR_POS) +#define USB_DEVCMDSTAT_DEV_EN (1U << 7U) +#define USB_DEVCMDSTAT_SETUP (1U << 8U) +#define USB_DEVCMDSTAT_PLL_ON (1U << 9U) +#define USB_DEVCMDSTAT_LPM_SUP (1U << 11U) +#define USB_DEVCMDSTAT_INTONNAK_AO (1U << 12U) +#define USB_DEVCMDSTAT_INTONNAK_AI (1U << 13U) +#define USB_DEVCMDSTAT_INTONNAK_CO (1U << 14U) +#define USB_DEVCMDSTAT_INTONNAK_CI (1U << 15U) +#define USB_DEVCMDSTAT_DCON (1U << 16U) +#define USB_DEVCMDSTAT_DSUP (1U << 17U) +#define USB_DEVCMDSTAT_LPM_SUS (1U << 19U) +#define USB_DEVCMDSTAT_LPM_REWP (1U << 20U) +#define USB_DEVCMDSTAT_DCON_C (1U << 24U) +#define USB_DEVCMDSTAT_DSUS_C (1U << 25U) +#define USB_DEVCMDSTAT_DRES_C (1U << 26U) + +#define USB_INFO_FRAME_NR_POS 0U +#define USB_INFO_FRAME_NR_MASK (0x7FFU << USB_INFO_FRAME_NR_POS) + +#define USB_EPLISTSTART_POS (8U) +#define USB_EPLISTSTART_MASK (0xFFFFFF << USB_EPLISTSTART_POS) + +#define USB_DATABUFSTART_POS (22U) +#define USB_DATABUFSTART_MASK (0x3FF << USB_DATABUFSTART_POS) + +#define USB_INT_EPn_INT (1U) +#define USB_INT_EP(ep) (1U << (ep)) +#define USB_INT_EP_ALL_INT (0x3FF) +#define USB_INT_FRAME_INT (1U << 30U) +#define USB_INT_DEV_INT (1U << 31U) // ------------------------------------------------------------------------------------------------ // ----- GPIO_PORT ----- diff --git a/os/common/startup/ARMCMx/compilers/GCC/ld/LPC11U35_401.ld b/os/common/startup/ARMCMx/compilers/GCC/ld/LPC11U35_401.ld index a6757a2c..8e3a2b3f 100644 --- a/os/common/startup/ARMCMx/compilers/GCC/ld/LPC11U35_401.ld +++ b/os/common/startup/ARMCMx/compilers/GCC/ld/LPC11U35_401.ld @@ -36,7 +36,7 @@ MEMORY { flash5 : org = 0x00000000, len = 0 flash6 : org = 0x00000000, len = 0 flash7 : org = 0x00000000, len = 0 - ram0 : org = 0x10000000, len = 8k + ram0 : org = 0x10000200, len = 7680 ram1 : org = 0x00000000, len = 0 ram2 : org = 0x00000000, len = 0 ram3 : org = 0x00000000, len = 0 diff --git a/os/hal/ports/LPC/LLD/GPIO/hal_pal_lld.c b/os/hal/ports/LPC/LLD/GPIO/hal_pal_lld.c index 23c22d4a..13d90fbe 100644 --- a/os/hal/ports/LPC/LLD/GPIO/hal_pal_lld.c +++ b/os/hal/ports/LPC/LLD/GPIO/hal_pal_lld.c @@ -57,7 +57,7 @@ */ void _pal_lld_init(void) { // Enable GPIO / IOCON CLK - LPC_SYSCON->SYSAHBCLKCTRL |= SYSAHBCLKCTRL_GPIO | SYSAHBCLKCTRL_IOCON; + LPC_SYSCON->SYSAHBCLKCTRL |= SYSCON_SYSAHBCLKCTRL_GPIO | SYSCON_SYSAHBCLKCTRL_IOCON; } /** @@ -94,12 +94,16 @@ void _pal_lld_setgroupmode(ioportid_t port, * @notapi */ void _pal_lld_setpadmode(ioportid_t port, iopadid_t pad, iomode_t mode) { - ((uint32_t *)LPC_IOCON)[(PAL_IOPORTS_WIDTH * LPC_IOPORT_NUM(port)) + pad] - = mode & MODE_IOCONF_MASK; + while (pad > 0x1F){} + uint32_t* base = (uint32_t*)0x40044000; + if (LPC_IOPORT_NUM(port) == 1) { + base = (uint32_t*)0x40044060; + } + base[pad & 0x1F] = (mode & MODE_IOCONF_MASK); if (mode & MODE_DIR_MASK) { - LPC_GPIO->DIR[LPC_IOPORT_NUM(port)] |= 1U << pad; + LPC_GPIO->DIR[LPC_IOPORT_NUM(port)] |= (uint32_t) 1U << pad; } else { - LPC_GPIO->DIR[LPC_IOPORT_NUM(port)] &= ~(1U << pad); + LPC_GPIO->DIR[LPC_IOPORT_NUM(port)] &= ~(((uint32_t)1U) << pad); } } diff --git a/os/hal/ports/LPC/LLD/GPIO/hal_pal_lld.h b/os/hal/ports/LPC/LLD/GPIO/hal_pal_lld.h index 1477c3ed..682ba868 100644 --- a/os/hal/ports/LPC/LLD/GPIO/hal_pal_lld.h +++ b/os/hal/ports/LPC/LLD/GPIO/hal_pal_lld.h @@ -71,13 +71,13 @@ * @brief Decodes a port identifier from a line identifier. */ #define PAL_PORT(line) \ - (((uint32_t)(line)) & 0xFFFFFFE0U) + (((uint32_t)(line)) & 0xFFFFFF00U) /** * @brief Decodes a pad identifier from a line identifier. */ #define PAL_PAD(line) \ - (((uint32_t)(line) & 0x0000001FU)) + (((uint32_t)(line) & 0x000000FFU)) /** * @brief Value identifying an invalid line. @@ -128,11 +128,17 @@ typedef uint32_t iomode_t; #define MODE_MODE_PULL_UP (0x2U << MODE_MODE_POS) #define MODE_MODE_REPEATER (0x3U << MODE_MODE_POS) +#define MODE_AD_POS (7U) +#define MODE_AD_MASK (1U << MODE_AD_POS) +#define MODE_AD_ANALOG (0U << MODE_AD_POS) +#define MODE_AD_DIGITAL (1U << MODE_AD_POS) + #define MODE_DIR_POS 31U #define MODE_DIR_MASK (0x1U << MODE_DIR_POS) #define MODE_DIR_IN (0U << MODE_DIR_POS) #define MODE_DIR_OUT (1U << MODE_DIR_POS) + /** * @brief Type of an I/O line. */ @@ -160,8 +166,8 @@ typedef uint32_t iopadid_t; * @details Low level drivers can define multiple ports, it is suggested to * use this naming convention. */ -#define LPC_IOPORT_ID(x) (x << 5U) -#define LPC_IOPORT_NUM(x) (x >> 5U) +#define LPC_IOPORT_ID(x) ((x) << 8U) +#define LPC_IOPORT_NUM(x) ((x) >> 8U) #define IOPORT0 LPC_IOPORT_ID(0) #define IOPORT1 LPC_IOPORT_ID(1) @@ -379,5 +385,4 @@ extern "C" { #endif /* HAL_USE_PAL == TRUE */ #endif /* HAL_PAL_LLD_H */ - /** @} */ diff --git a/os/hal/ports/LPC/LLD/USB/driver.mk b/os/hal/ports/LPC/LLD/USB/driver.mk new file mode 100644 index 00000000..d070430a --- /dev/null +++ b/os/hal/ports/LPC/LLD/USB/driver.mk @@ -0,0 +1,5 @@ +PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/USB/hal_usb_lld.c + +PLATFORMINC += $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/USB + + diff --git a/os/hal/ports/LPC/LLD/USB/hal_usb_lld.c b/os/hal/ports/LPC/LLD/USB/hal_usb_lld.c new file mode 100644 index 00000000..149c679c --- /dev/null +++ b/os/hal/ports/LPC/LLD/USB/hal_usb_lld.c @@ -0,0 +1,676 @@ +/* + ChibiOS - Copyright (C) 2020 Yaotian Feng / Codetector + + 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. +*/ + +/** + * @file hal_usb_lld.c + * @brief LPC11Uxx USB subsystem low level driver source. + * + * @addtogroup USB + * @{ + */ + +#include "hal.h" +#include + +#if (HAL_USE_USB == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define roundup2(x, m) (((x) + (m) - 1) & ~((m) - 1)) + +#define LPC_USB_SRAM_START 0x20004000 + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief USB- driver identifier. + */ +#if (LPC_USB_USE_USB1 == TRUE) || defined(__DOXYGEN__) +USBDriver USBD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief EP0 state. + * @note It is an union because IN and OUT endpoints are never used at the + * same time for EP0. + */ +static union { + /** + * @brief IN EP0 state. + */ + USBInEndpointState in; + /** + * @brief OUT EP0 state. + */ + USBOutEndpointState out; +} ep0_state; + +/** + * @brief EP0 initialization structure. + */ +static const USBEndpointConfig ep0config = { + USB_EP_MODE_TYPE_CTRL, + _usb_ep0setup, + _usb_ep0in, + _usb_ep0out, + 0x40, + 0x40, + &ep0_state.in, + &ep0_state.out, + 0, + NULL, +}; + +static struct { + uint32_t entry[20]; +} *USB_EPLIST = (void*)LPC_USB_SRAM_START; + +#define EPLIST_ENTRY_BUFFER_RSHIFT 6U +#define EPLIST_ENTRY_BUFFER_POS 0U +#define EPLIST_ENTRY_BUFFER_MASK (0xFFFF << EPLIST_ENTRY_BUFFER_POS) +#define EPLIST_ADDR(ADDR) \ + ((((uint32_t)(ADDR)) >> EPLIST_ENTRY_BUFFER_RSHIFT) & EPLIST_ENTRY_BUFFER_MASK) +#define EPLIST_ENTRY_NBYTES_POS 16U +#define EPLIST_ENTRY_NBYTES_MASK (0x3FF << EPLIST_ENTRY_NBYTES_POS) +#define EPLIST_ENTRY_NBYTES(BYTES) \ + (((BYTES) << EPLIST_ENTRY_NBYTES_POS) & EPLIST_ENTRY_NBYTES_MASK) +#define EPLIST_ENTRY_ACTIVE (1U << 31U) +#define EPLIST_ENTRY_DISABLE (1U << 30U) +#define EPLIST_ENTRY_STALL (1U << 29U) +#define EPLIST_ENTRY_TOGGLE_RESET (1U << 28U) +#define EPLIST_ENTRY_RFTV (1U << 27U) +#define EPLIST_ENTRY_EPTYPE (1U << 26U) +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static size_t usb_ep_malloc(USBDriver *usbp, size_t size, size_t alignment) { + size_t current = usbp->epmem_next; + if ((current & (alignment - 1)) != 0) { // Alignment issue + current = (current + alignment) & (~(alignment - 1)); + } + const size_t epmo = current; + usbp->epmem_next = current + size; + osalDbgAssert(usbp->epmem_next <= (LPC_USB_SRAM_START + 0x800), "UBSSRAM exhausted"); + return epmo; +} + +static void usb_packet_transmit(USBDriver *usbp, usbep_t ep, size_t n) +{ + const USBEndpointConfig * const epc = usbp->epc[ep]; + USBInEndpointState * const isp = epc->in_state; + + if (n > epc->in_maxsize) { + n = epc->in_maxsize; + } + + if (ep == 0) { + // When EP0 IN is received, set ACTIVE bit on both EP0 IN + // and OUT. + USB_EPLIST->entry[0] |= EPLIST_ENTRY_ACTIVE; + } + + /* Get EP command/status List, update the length field and data pointer. */ + USB_EPLIST->entry[ep * 4 + 2] &= ~0x3FFFFFF; + USB_EPLIST->entry[ep * 4 + 2] |= EPLIST_ENTRY_NBYTES(n) | + EPLIST_ADDR(usbp->epn_buffer[ep * 2 + 1]); + if (n > 0) + memcpy(usbp->epn_buffer[ep*2 + 1], isp->txbuf, n); + isp->txlastpktlen = n; + USB_EPLIST->entry[ep * 4 + 2] |= EPLIST_ENTRY_ACTIVE; +} + +static size_t usb_packet_receive(USBDriver *usbp, usbep_t ep) { + const USBEndpointConfig *epcp = usbp->epc[ep]; + USBOutEndpointState *osp = usbp->epc[ep]->out_state; + uint32_t n = (USB_EPLIST->entry[4 * ep] & EPLIST_ENTRY_NBYTES_MASK) >> EPLIST_ENTRY_NBYTES_POS; + n = epcp->out_maxsize - n; + if (osp->rxbuf != NULL && n > 0) { + memcpy(osp->rxbuf, usbp->epn_buffer[ep * 2], n); + osp->rxbuf += n; + } + + // ReSetup for recieve + USB_EPLIST->entry[4 * ep] &= ~0x3FFFFFF; + USB_EPLIST->entry[4 * ep] |= EPLIST_ENTRY_NBYTES(epcp->out_maxsize) | + EPLIST_ADDR(usbp->epn_buffer[ep * 2]); + + if (osp->rxpkts > 0) + osp->rxpkts -= 1; + osp->rxcnt += n; + osp->rxsize -= n; + return n; +} + + +/*===========================================================================*/ +/* Driver interrupt handlers and threads. */ +/*===========================================================================*/ +#ifndef LPC_USB_IRQ_VECTOR +#error "LPC_USB_IRQ_VECTOR not defined" +#endif +OSAL_IRQ_HANDLER(LPC_USB_IRQ_VECTOR) { + OSAL_IRQ_PROLOGUE(); + USBDriver *usbp = &USBD1; + + uint32_t isr = LPC_USB->INTSTAT; + #define devstat (LPC_USB->DEVCMDSTAT) + LPC_USB->INTSTAT &= 0xFFFFFFFF; // Clear Flags + + + // SOF + if (isr & USB_INT_FRAME_INT) { + _usb_isr_invoke_sof_cb(usbp); + } + + if (isr & USB_INT_DEV_INT) { + if (devstat & USB_DEVCMDSTAT_DSUS_C) { + if (devstat & USB_DEVCMDSTAT_DCON) { + if (devstat & USB_DEVCMDSTAT_DSUP) { + // Suspend + _usb_suspend(usbp); + } else { + // Wakeup + _usb_wakeup(usbp); + } + } + } + + if (devstat & USB_DEVCMDSTAT_DRES_C) { + LPC_USB->DEVCMDSTAT |= USB_DEVCMDSTAT_DRES_C; + _usb_reset(usbp); + } + } // USB_INT_DEV_INT + + for (int ep = 0; ep < 5; ++ep) + { + // EP0 OUT (Setup) + if (isr & (USB_INT_EPn_INT << (2 * ep))) { + if (devstat & USB_DEVCMDSTAT_SETUP) { + _usb_isr_invoke_setup_cb(usbp, ep); + } else { + // OUT endpoint, receive + USBOutEndpointState *osp = usbp->epc[ep]->out_state; + osalSysLockFromISR(); + size_t n = usb_packet_receive(usbp, ep); + osalSysUnlockFromISR(); + if ((n < usbp->epc[0]->out_maxsize) || (osp->rxpkts == 0)) { + _usb_isr_invoke_out_cb(usbp, ep); + } else { + USB_EPLIST->entry[4 * ep] |= EPLIST_ENTRY_ACTIVE; + } + } + } + + // EP0 IN + if (isr & (USB_INT_EPn_INT << (2 * ep + 1))) { + USBInEndpointState *isp = usbp->epc[ep]->in_state; + size_t n = isp->txlastpktlen; + isp->txcnt += n; + if (isp->txcnt < isp->txsize) { + isp->txbuf += n; + osalSysLockFromISR(); + usb_packet_transmit(usbp, ep, isp->txsize - isp->txcnt); + osalSysUnlockFromISR(); + } else { + // IN callback + _usb_isr_invoke_in_cb(usbp, ep); + } + } + } + + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level USB driver initialization. + * + * @notapi + */ + void usb_lld_init(void) { + +#if LPC_USB_USE_USB1 == TRUE + /* Driver initialization.*/ + usbObjectInit(&USBD1); + // Enable Clock + LPC_SYSCON->SYSAHBCLKCTRL |= + ( + SYSCON_SYSAHBCLKCTRL_USB | SYSCON_SYSAHBCLKCTRL_USBRAM | + SYSCON_SYSAHBCLKCTRL_RAM0 + ); + + USBD1.epmem_next = (0x50 + LPC_USB_SRAM_START); + +#if defined(LPC_MAINCLK_FREQUENCY) && LPC_MAINCLK_FREQUENCY == 48000000U +// TODO: Implement proper PLL support + LPC_SYSCON->PDRUNCFG &= ~SYSCON_PDRUNCFG_USBPLL_PD; + LPC_SYSCON->USBPLLCLKSEL = SYSCON_USBPLLCLKSEL_SYSOSC; + LPC_SYSCON->USBPLLCLKUEN = 0; + LPC_SYSCON->USBPLLCLKUEN = SYSCON_USBPLLCLKUEN_ENA; + LPC_SYSCON->USBPLLCTRL = LPC_SYSCON->SYSPLLCTRL; // BIG HACK. Steal Main PLL CFG + while(LPC_SYSCON->USBPLLSTAT == 0){} + LPC_SYSCON->USBCLKSEL = SYSCON_USBCLKSEL_USBPLLOUT; + LPC_SYSCON->USBCLKDIV = 1; // Divide By 1 +#else // LPC_MAINCLK_FREQUENCY +#error "USB Currently requires LPC_MAINCLK_FREQUENCY = 48MHz" +#endif // LPC_MAINCLK_FREQUENCY + + +#endif // LPC_USB_USE_USB1 == TRUE +} + +/** + * @brief Configures and activates the USB peripheral. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_start(USBDriver *usbp) { + + if (usbp->state == USB_STOP) { + /* Enables the peripheral.*/ +#if LPC_USB_USE_USB1 == TRUE + if (&USBD1 == usbp) { + // USB Transiver Powerup + LPC_SYSCON->PDRUNCFG &= ~SYSCON_PDRUNCFG_USBPAD_PD; + + // Enable Vector + #if !defined(LPC_USB_USB1_IRQ_PRIORITY) + #error "LPC_USB_USB1_IRQ_PRIORITY is not defined" + #endif + nvicEnableVector(USB_IRQn, LPC_USB_USB1_IRQ_PRIORITY); + } +#endif + usb_lld_reset(usbp); + } + /* Configures the peripheral.*/ + +} + +/** + * @brief Deactivates the USB peripheral. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_stop(USBDriver *usbp) { + + if (usbp->state == USB_READY) { + /* Resets the peripheral.*/ + + /* Disables the peripheral.*/ +#if LPC_USB_USE_USB1 == TRUE + if (&USBD1 == usbp) { + nvicDisableVector(USB_IRQn); + LPC_USB->INTEN = 0; + LPC_SYSCON->PDRUNCFG |= SYSCON_PDRUNCFG_USBPAD_PD; + LPC_USB->DEVCMDSTAT &= ~USB_DEVCMDSTAT_DEV_EN; + } +#endif + } +} + +/** + * @brief USB low level reset routine. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_reset(USBDriver *usbp) { + /* Post reset initialization.*/ + // cfg Interrupt routing to IRQ + LPC_USB->INTROUTING = 0; + LPC_USB->EPINUSE = 0; + LPC_USB->EPSKIP = 0; + LPC_USB->EPBUFCFG = 0; + // Points USB Buffers to correct places + LPC_USB->EPLISTSTART = LPC_USB_SRAM_START & USB_EPLISTSTART_MASK; + LPC_USB->DATABUFSTART = LPC_USB_SRAM_START & USB_DATABUFSTART_MASK; + + // Clear Existing Interrupts + LPC_USB->INTSTAT = USB_INT_DEV_INT | USB_INT_FRAME_INT | USB_INT_EP_ALL_INT; + // Setup Interrupt Masks + LPC_USB->INTEN = USB_INT_DEV_INT | USB_INT_EP_ALL_INT; + // SOF only if there is a handler registered. + if ((usbp)->config->sof_cb != NULL) { + LPC_USB->INTEN |= USB_INT_FRAME_INT; + } + + + // Reset Allocator + usbp->epmem_next = (0x50 + LPC_USB_SRAM_START); + + usbp->setup_buffer = NULL; + for (int i = 0; i < 10; ++i) + { + usbp->epn_buffer[i] = NULL; + } + + // Disable all endpoints + for (int i = 0; i < 16; ++i) + { + USB_EPLIST->entry[i + 4] = EPLIST_ENTRY_DISABLE; + } + + /* EP0 initialization.*/ + usbp->epc[0] = &ep0config; + usb_lld_init_endpoint(usbp, 0); + + LPC_USB->DEVCMDSTAT |= USB_DEVCMDSTAT_DEV_EN; // USB Start Running +} + +/** + * @brief Sets the USB address. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_set_address(USBDriver *usbp) { + LPC_USB->DEVCMDSTAT &= ~USB_DEVCMDSTAT_DEVADDR_MASK; + LPC_USB->DEVCMDSTAT |= (USB_DEVCMDSTAT_DEV_EN | + (usbp->address & USB_DEVCMDSTAT_DEVADDR_MASK)); +} + +/** + * @brief Enables an endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) { + if(ep > USB_MAX_ENDPOINTS) + return; + + const USBEndpointConfig *epcp = usbp->epc[ep]; + uint32_t usbep_cfg = 0; + switch(epcp->ep_mode & USB_EP_MODE_TYPE) { + case USB_EP_MODE_TYPE_CTRL: + break; + case USB_EP_MODE_TYPE_ISOC: + usbep_cfg |= EPLIST_ENTRY_EPTYPE; + break; + case USB_EP_MODE_TYPE_BULK: + break; + case USB_EP_MODE_TYPE_INTR: + break; + default: + while(1) {} + } + if (epcp->out_state != NULL) { + while(epcp->out_maxsize > 1023); + uint32_t ep_mem = usb_ep_malloc(usbp, epcp->out_maxsize, 64); + usbp->epn_buffer[(2 * ep)] = (void *)ep_mem; + USB_EPLIST->entry[(4 * ep)] = usbep_cfg | EPLIST_ADDR(ep_mem) + | EPLIST_ENTRY_NBYTES(epcp->out_maxsize); + } + + if (ep == 0) { + while(usbp->setup_buffer != NULL){} + // Allocate Setup Bytes + uint32_t ep_mem = usb_ep_malloc(usbp, 8, 64); + usbp->setup_buffer = (void *)ep_mem; + USB_EPLIST->entry[1] = EPLIST_ADDR(ep_mem); + LPC_USB->INTEN |= USB_INT_EP(ep * 2); + } + + if (epcp->in_state != NULL) { + while(epcp->in_maxsize > 1023); + uint32_t ep_mem = usb_ep_malloc(usbp, epcp->in_maxsize, 64); + usbp->epn_buffer[(2 * ep) + 1] = (void *)ep_mem; + USB_EPLIST->entry[(4 * ep) + 2] = usbep_cfg | EPLIST_ADDR(ep_mem) + | EPLIST_ENTRY_NBYTES(epcp->in_maxsize); + LPC_USB->INTEN |= USB_INT_EP((ep * 2) + 1); + } +} + +/** + * @brief Disables all the active endpoints except the endpoint zero. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_disable_endpoints(USBDriver *usbp) { + if (usbp != &USBD1) + return; + LPC_USB->EPSKIP = 0xFFFFFFFF; + LPC_USB->INTEN &= (~USB_INT_EP_ALL_INT) | USB_INT_EP(0) | USB_INT_EP(1); + while (LPC_USB->EPSKIP) {} + for (int i = 1; i < 5; ++i) // 4 EPs needs to be disabled, EP0 can't + { + USB_EPLIST->entry[i * 2] &= ~EP_STATUS_ACTIVE; + USB_EPLIST->entry[i * 2] |= EP_STATUS_DISABLED; + USB_EPLIST->entry[i * 2 + 2] &= ~EP_STATUS_ACTIVE; + USB_EPLIST->entry[i * 2 + 2] |= EP_STATUS_DISABLED; + } +} + +/** + * @brief Returns the status of an OUT endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return The endpoint status. + * @retval EP_STATUS_DISABLED The endpoint is not active. + * @retval EP_STATUS_STALLED The endpoint is stalled. + * @retval EP_STATUS_ACTIVE The endpoint is active. + * + * @notapi + */ +usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) { + if (usbp != &USBD1) + return EP_STATUS_DISABLED; + if (USB_EPLIST->entry[ep * 2] & EPLIST_ENTRY_DISABLE) { + return EP_STATUS_DISABLED; + } else if (USB_EPLIST->entry[ep * 2] & EPLIST_ENTRY_STALL) { + return EP_STATUS_STALLED; + } else { + return EP_STATUS_ACTIVE; + } +} + +/** + * @brief Returns the status of an IN endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return The endpoint status. + * @retval EP_STATUS_DISABLED The endpoint is not active. + * @retval EP_STATUS_STALLED The endpoint is stalled. + * @retval EP_STATUS_ACTIVE The endpoint is active. + * + * @notapi + */ +usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) { + if (usbp != &USBD1) + return EP_STATUS_DISABLED; + if (USB_EPLIST->entry[ep * 2 + 2] & EPLIST_ENTRY_DISABLE) { + return EP_STATUS_DISABLED; + } else if (USB_EPLIST->entry[ep * 2 + 2] & EPLIST_ENTRY_STALL) { + return EP_STATUS_STALLED; + } else { + return EP_STATUS_ACTIVE; + } +} + +/** + * @brief Reads a setup packet from the dedicated packet buffer. + * @details This function must be invoked in the context of the @p setup_cb + * callback in order to read the received setup packet. + * @pre In order to use this function the endpoint must have been + * initialized as a control endpoint. + * @post The endpoint is ready to accept another packet. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @param[out] buf buffer where to copy the packet data + * + * @notapi + */ +void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) { + if (usbp == &USBD1) { + if (ep == 0) { + while(usbp->setup_buffer == 0){} + /* Check/Clear STALL on both EP0 IN and OUT when SETUP is received. */ + USB_EPLIST->entry[0] &= ~(EPLIST_ENTRY_STALL | EPLIST_ENTRY_ACTIVE); // EP0OUT + USB_EPLIST->entry[2] &= ~(EPLIST_ENTRY_STALL | EPLIST_ENTRY_ACTIVE); // EP0IN + LPC_USB->DEVCMDSTAT |= USB_DEVCMDSTAT_SETUP; // Clear SETUP + LPC_USB->DEVCMDSTAT &= ~(USB_DEVCMDSTAT_INTONNAK_CO | USB_DEVCMDSTAT_INTONNAK_CI); + memcpy(buf, usbp->setup_buffer, 8); + USB_EPLIST->entry[1] = EPLIST_ADDR(usbp->setup_buffer); + } else { + while(1){} + } + } +} + +/** + * @brief Starts a receive operation on an OUT endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_start_out(USBDriver *usbp, usbep_t ep) { + USBOutEndpointState *osp = usbp->epc[ep]->out_state; + const USBEndpointConfig *epcp = usbp->epc[ep]; + + if (osp->rxsize == 0) /* Special case for zero sized packets.*/ + osp->rxpkts = 1; + else + osp->rxpkts = (uint16_t)((osp->rxsize + usbp->epc[ep]->out_maxsize - 1) / + usbp->epc[ep]->out_maxsize); + + USB_EPLIST->entry[ep * 4] &= ~0x3FFFFFF; + USB_EPLIST->entry[ep * 4] |= EPLIST_ENTRY_ACTIVE | + EPLIST_ENTRY_NBYTES(epcp->out_maxsize) | + EPLIST_ADDR(usbp->epn_buffer[ep * 2]); + + LPC_USB->DEVCMDSTAT |= USB_DEVCMDSTAT_INTONNAK_CO; + LPC_USB->DEVCMDSTAT &= ~USB_DEVCMDSTAT_INTONNAK_CI; +} + +/** + * @brief Starts a transmit operation on an IN endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_start_in(USBDriver *usbp, usbep_t ep) { + USBInEndpointState * const isp = usbp->epc[ep]->in_state; + usb_packet_transmit(usbp, ep, isp->txsize); +} + +/** + * @brief Brings an OUT endpoint in the stalled state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) { + if (usbp != &USBD1) + return; + const uint32_t skip_flag = 1U << (ep * 2); + if (USB_EPLIST->entry[ep * 4] & EPLIST_ENTRY_ACTIVE) { + LPC_USB->EPSKIP = skip_flag; + } + while(LPC_USB->EPSKIP & skip_flag) {} // Wait for not active + USB_EPLIST->entry[ep*4] |= EPLIST_ENTRY_STALL; +} + +/** + * @brief Brings an IN endpoint in the stalled state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) { + if (usbp != &USBD1) + return; + const uint32_t skip_flag = 1U << (ep * 2 + 1); + if (USB_EPLIST->entry[ep * 4 + 2] & EPLIST_ENTRY_ACTIVE) { + LPC_USB->EPSKIP = skip_flag; + } + while(LPC_USB->EPSKIP & skip_flag) {} // Wait for not active + USB_EPLIST->entry[ep * 4 + 2] |= EPLIST_ENTRY_STALL; +} + +/** + * @brief Brings an OUT endpoint in the active state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) { + if (usbp != &USBD1) + return; + const uint32_t skip_flag = 1U << (ep * 2); + if (USB_EPLIST->entry[ep * 4] & EPLIST_ENTRY_ACTIVE) { + LPC_USB->EPSKIP = skip_flag; + } + while(LPC_USB->EPSKIP & skip_flag) {} // Wait for not active + USB_EPLIST->entry[ep*4] &= ~EPLIST_ENTRY_STALL; +} + +/** + * @brief Brings an IN endpoint in the active state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) { + if (usbp != &USBD1) + return; + const uint32_t skip_flag = 1U << (ep * 2 + 1); + if (USB_EPLIST->entry[ep * 4 + 2] & EPLIST_ENTRY_ACTIVE) { + LPC_USB->EPSKIP = skip_flag; + } + while(LPC_USB->EPSKIP & skip_flag) {} // Wait for not active + USB_EPLIST->entry[ep * 4 + 2] &= ~EPLIST_ENTRY_STALL; +} + +#endif /* HAL_USE_USB == TRUE */ + +/** @} */ diff --git a/os/hal/ports/LPC/LLD/USB/hal_usb_lld.h b/os/hal/ports/LPC/LLD/USB/hal_usb_lld.h new file mode 100644 index 00000000..4cc3ee77 --- /dev/null +++ b/os/hal/ports/LPC/LLD/USB/hal_usb_lld.h @@ -0,0 +1,408 @@ +/* + ChibiOS - Copyright (C) 2020 Yaotian Feng / Codetector + + 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. +*/ + +/** + * @file hal_usb_lld.h + * @brief LPC11Uxx USB subsystem low level driver header. + * + * @addtogroup USB + * @{ + */ + +#ifndef HAL_USB_LLD_H +#define HAL_USB_LLD_H + +#if (HAL_USE_USB == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Maximum endpoint address. + */ +#define USB_MAX_ENDPOINTS 5 + +/** + * @brief Status stage handling method. + */ +#define USB_EP0_STATUS_STAGE USB_EP0_STATUS_STAGE_SW + +/** + * @brief The address can be changed immediately upon packet reception. + */ +#define USB_SET_ADDRESS_MODE USB_LATE_SET_ADDRESS + +/** + * @brief Method for set address acknowledge. + */ +#define USB_SET_ADDRESS_ACK_HANDLING USB_SET_ADDRESS_ACK_SW + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name PLC11Uxx configuration options + * @{ + */ +/** + * @brief USB driver enable switch. + * @details If set to @p TRUE the support for USB0 is included. + * @note The default is @p FALSE. + */ +#if !defined(LPC_USB_USE_USB1) || defined(__DOXYGEN__) +#define LPC_USB_USE_USB1 FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of an IN endpoint state structure. + */ +typedef struct { + /** + * @brief Requested transmit transfer size. + */ + size_t txsize; + /** + * @brief Transmitted bytes so far. + */ + size_t txcnt; + /** + * @brief Pointer to the transmission linear buffer. + */ + const uint8_t *txbuf; +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + thread_reference_t thread; +#endif + /* End of the mandatory fields.*/ + uint16_t txlastpktlen; +} USBInEndpointState; + +/** + * @brief Type of an OUT endpoint state structure. + */ +typedef struct { + /** + * @brief Requested receive transfer size. + */ + size_t rxsize; + /** + * @brief Received bytes so far. + */ + size_t rxcnt; + /** + * @brief Pointer to the receive linear buffer. + */ + uint8_t *rxbuf; +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + thread_reference_t thread; +#endif + /* End of the mandatory fields.*/ + uint16_t rxpkts; +} USBOutEndpointState; + +/** + * @brief Type of an USB endpoint configuration structure. + * @note Platform specific restrictions may apply to endpoints. + */ +typedef struct { + /** + * @brief Type and mode of the endpoint. + */ + uint32_t ep_mode; + /** + * @brief Setup packet notification callback. + * @details This callback is invoked when a setup packet has been + * received. + * @post The application must immediately call @p usbReadPacket() in + * order to access the received packet. + * @note This field is only valid for @p USB_EP_MODE_TYPE_CTRL + * endpoints, it should be set to @p NULL for other endpoint + * types. + */ + usbepcallback_t setup_cb; + /** + * @brief IN endpoint notification callback. + * @details This field must be set to @p NULL if the IN endpoint is not + * used. + */ + usbepcallback_t in_cb; + /** + * @brief OUT endpoint notification callback. + * @details This field must be set to @p NULL if the OUT endpoint is not + * used. + */ + usbepcallback_t out_cb; + /** + * @brief IN endpoint maximum packet size. + * @details This field must be set to zero if the IN endpoint is not + * used. + */ + uint16_t in_maxsize; + /** + * @brief OUT endpoint maximum packet size. + * @details This field must be set to zero if the OUT endpoint is not + * used. + */ + uint16_t out_maxsize; + /** + * @brief @p USBEndpointState associated to the IN endpoint. + * @details This structure maintains the state of the IN endpoint. + */ + USBInEndpointState *in_state; + /** + * @brief @p USBEndpointState associated to the OUT endpoint. + * @details This structure maintains the state of the OUT endpoint. + */ + USBOutEndpointState *out_state; + /* End of the mandatory fields.*/ + + /** + * @brief Reserved field, not currently used. + * @note Initialize this field to 1 in order to be forward compatible. + */ + uint16_t ep_buffers; + /** + * @brief Pointer to a buffer for setup packets. + * @details Setup packets require a dedicated 8-bytes buffer, set this + * field to @p NULL for non-control endpoints. + */ + uint8_t *setup_buf; +} USBEndpointConfig; + +/** + * @brief Type of an USB driver configuration structure. + */ +typedef struct { + /** + * @brief USB events callback. + * @details This callback is invoked when an USB driver event is registered. + */ + usbeventcb_t event_cb; + /** + * @brief Device GET_DESCRIPTOR request callback. + * @note This callback is mandatory and cannot be set to @p NULL. + */ + usbgetdescriptor_t get_descriptor_cb; + /** + * @brief Requests hook callback. + * @details This hook allows to be notified of standard requests or to + * handle non standard requests. + */ + usbreqhandler_t requests_hook_cb; + /** + * @brief Start Of Frame callback. + */ + usbcallback_t sof_cb; + /* End of the mandatory fields.*/ +} USBConfig; + +/** + * @brief Structure representing an USB driver. + */ +struct USBDriver { + /** + * @brief Driver state. + */ + usbstate_t state; + /** + * @brief Current configuration data. + */ + const USBConfig *config; + /** + * @brief Bit map of the transmitting IN endpoints. + */ + uint16_t transmitting; + /** + * @brief Bit map of the receiving OUT endpoints. + */ + uint16_t receiving; + /** + * @brief Active endpoints configurations. + */ + const USBEndpointConfig *epc[USB_MAX_ENDPOINTS + 1]; + /** + * @brief Fields available to user, it can be used to associate an + * application-defined handler to an IN endpoint. + * @note The base index is one, the endpoint zero does not have a + * reserved element in this array. + */ + void *in_params[USB_MAX_ENDPOINTS]; + /** + * @brief Fields available to user, it can be used to associate an + * application-defined handler to an OUT endpoint. + * @note The base index is one, the endpoint zero does not have a + * reserved element in this array. + */ + void *out_params[USB_MAX_ENDPOINTS]; + /** + * @brief Endpoint 0 state. + */ + usbep0state_t ep0state; + /** + * @brief Next position in the buffer to be transferred through endpoint 0. + */ + uint8_t *ep0next; + /** + * @brief Number of bytes yet to be transferred through endpoint 0. + */ + size_t ep0n; + /** + * @brief Endpoint 0 end transaction callback. + */ + usbcallback_t ep0endcb; + /** + * @brief Setup packet buffer. + */ + uint8_t setup[8]; + /** + * @brief Current USB device status. + */ + uint16_t status; + /** + * @brief Assigned USB address. + */ + uint8_t address; + /** + * @brief Current USB device configuration. + */ + uint8_t configuration; + /** + * @brief State of the driver when a suspend happened. + */ + usbstate_t saved_state; +#if defined(USB_DRIVER_EXT_FIELDS) + USB_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + + /** + * @brief Offset of the next chunk of usb_ep_malloc + */ + size_t epmem_next; + void* setup_buffer; + void* epn_buffer[10]; // OUT = 2n, IN = 2n +1 +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Returns the current frame number. + * + * @param[in] usbp pointer to the @p USBDriver object + * @return The current frame number. + * + * @notapi + */ +#define usb_lld_get_frame_number(usbp) \ + ((LPC_USB->INFO & USB_INFO_FRAME_NR_MASK) >> USB_INFO_FRAME_NR_POS) + +/** + * @brief Returns the exact size of a receive transaction. + * @details The received size can be different from the size specified in + * @p usbStartReceiveI() because the last packet could have a size + * different from the expected one. + * @pre The OUT endpoint must have been configured in transaction mode + * in order to use this function. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return Received data size. + * + * @notapi + */ +#define usb_lld_get_transaction_size(usbp, ep) \ + ((usbp)->epc[ep]->out_state->rxcnt) + +/** + * @brief Connects the USB device. + * + * @api + */ +#define usb_lld_connect_bus(usbp) \ + (LPC_USB->DEVCMDSTAT |= USB_DEVCMDSTAT_DCON) + +/** + * @brief Disconnect the USB device. + * + * @api + */ +#define usb_lld_disconnect_bus(usbp) \ + (LPC_USB->DEVCMDSTAT &= ~USB_DEVCMDSTAT_DCON) + +/** + * @brief Start of host wake-up procedure. + * + * @notapi + */ +#define usb_lld_wakeup_host(usbp) \ + (LPC_USB->DEVCMDSTAT &= ~USB_DEVCMDSTAT_DSUP) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (LPC_USB_USE_USB1 == TRUE) && !defined(__DOXYGEN__) +extern USBDriver USBD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void usb_lld_init(void); + void usb_lld_start(USBDriver *usbp); + void usb_lld_stop(USBDriver *usbp); + void usb_lld_reset(USBDriver *usbp); + void usb_lld_set_address(USBDriver *usbp); + void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep); + void usb_lld_disable_endpoints(USBDriver *usbp); + usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep); + usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep); + void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf); + void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep); + void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep); + void usb_lld_start_out(USBDriver *usbp, usbep_t ep); + void usb_lld_start_in(USBDriver *usbp, usbep_t ep); + void usb_lld_stall_out(USBDriver *usbp, usbep_t ep); + void usb_lld_stall_in(USBDriver *usbp, usbep_t ep); + void usb_lld_clear_out(USBDriver *usbp, usbep_t ep); + void usb_lld_clear_in(USBDriver *usbp, usbep_t ep); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_USB == TRUE */ + +#endif /* HAL_USB_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/LPC/LPC11Uxx/lpc_registry.h b/os/hal/ports/LPC/LPC11Uxx/lpc_registry.h index 251c1e6d..46b49f34 100644 --- a/os/hal/ports/LPC/LPC11Uxx/lpc_registry.h +++ b/os/hal/ports/LPC/LPC11Uxx/lpc_registry.h @@ -37,6 +37,9 @@ defined(__DOXYGEN__) #if defined(LPC11Uxx) || defined(__DOXYGEN__) +/* USB attributes.*/ +#define LPC_HAS_USB TRUE +#define LPC_USB_IRQ_VECTOR Vector98 #endif diff --git a/os/hal/ports/LPC/LPC11Uxx/platform.mk b/os/hal/ports/LPC/LPC11Uxx/platform.mk index 321e2f77..43ba4a11 100644 --- a/os/hal/ports/LPC/LPC11Uxx/platform.mk +++ b/os/hal/ports/LPC/LPC11Uxx/platform.mk @@ -8,6 +8,7 @@ PLATFORMINC = ${CHIBIOS}/os/hal/ports/common/ARMCMx \ include $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/STM/driver.mk include $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/GPIO/driver.mk +include $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/USB/driver.mk # Shared variables ALLCSRC += $(PLATFORMSRC)