From 4b4c63f797e739d47320f8ba9990dc25f93b62c3 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Sun, 9 Jun 2019 21:50:30 +0200 Subject: [PATCH 1/6] usbus: Allow setting USB thread flags outside IRQ --- sys/usb/usbus/usbus.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/sys/usb/usbus/usbus.c b/sys/usb/usbus/usbus.c index 830b8fa156fa..321d526589ea 100644 --- a/sys/usb/usbus/usbus.c +++ b/sys/usb/usbus/usbus.c @@ -168,6 +168,21 @@ static inline uint32_t _get_ep_bitflag(usbdev_ep_t *ep) : 0x00) + ep->num); } +static void _set_ep_event(usbus_t *usbus, usbdev_ep_t *ep) +{ + if (irq_is_in()) { + usbus->ep_events |= _get_ep_bitflag(ep); + } + else { + unsigned state = irq_disable(); + usbus->ep_events |= _get_ep_bitflag(ep); + irq_restore(state); + } + + thread_flags_set((thread_t *)thread_get(usbus->pid), + USBUS_THREAD_FLAG_USBDEV_EP); +} + static uint32_t _get_and_reset_ep_events(usbus_t *usbus) { unsigned state = irq_disable(); @@ -316,16 +331,14 @@ static void _event_cb(usbdev_t *usbdev, usbdev_event_t event) } } + /* USB generic endpoint callback */ static void _event_ep_cb(usbdev_ep_t *ep, usbdev_event_t event) { usbus_t *usbus = (usbus_t *)ep->dev->context; if (event == USBDEV_EVENT_ESR) { - assert(irq_is_in()); - usbus->ep_events |= _get_ep_bitflag(ep); - thread_flags_set((thread_t *)thread_get(usbus->pid), - USBUS_THREAD_FLAG_USBDEV_EP); + _set_ep_event(usbus, ep); } else { usbus_handler_t *handler = _ep_to_handler(usbus, ep); From ab05e63175bb26b7bd4a01553b266230c2807b76 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Wed, 27 Feb 2019 20:03:18 +0100 Subject: [PATCH 2/6] nrf52: Add USB device peripheral driver --- cpu/nrf52/include/nrfusb.h | 78 +++++ cpu/nrf52/periph/usbdev.c | 657 +++++++++++++++++++++++++++++++++++++ 2 files changed, 735 insertions(+) create mode 100644 cpu/nrf52/include/nrfusb.h create mode 100644 cpu/nrf52/periph/usbdev.c diff --git a/cpu/nrf52/include/nrfusb.h b/cpu/nrf52/include/nrfusb.h new file mode 100644 index 000000000000..d69967ff4b6d --- /dev/null +++ b/cpu/nrf52/include/nrfusb.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2019 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup cpu_nrf52_nrfusb NRF usb peripheral implementation + * @ingroup cpu_nrf52 + * @brief Minimal driver for the NRF52840 usb peripheral + * + * @{ + * + * @file + * @brief USB interface functions for the nrf52840 class devices + * + * @author Koen Zandberg + */ + +#ifndef NRFUSB_H +#define NRFUSB_H + +#include +#include +#include "periph/usbdev.h" +#include "cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Number of USB peripherals on the MCU + */ +#define NRF_USB_NUM_PERIPH 1 + +/** + * USB endpoint buffer space + */ +#define NRF_USB_BUF_SPACE USBDEV_EP_BUF_SPACE + +/** + * Number of USB IN and OUT endpoints + */ +#define NRF_USB_NUM_EP USBDEV_NUM_ENDPOINTS + +/** + * @brief nrfusb setup packet state tracker for endpoint 0 handling + */ +typedef enum { + NRFUSB_SETUP_READY, /**< Ready for a new setup request */ + NRFUSB_SETUP_READ, /**< Read request received */ + NRFUSB_SETUP_WRITE, /**< Write request received */ + NRFUSB_SETUP_ACKOUT, /**< Expecting an ACK on the out endpoint */ + NRFUSB_SETUP_ACKIN, /**< Expecting an ACK on the in endpoint */ +} nrfusb_setup_state_t; + +/** + * @brief nrf usb peripheral device context + */ +typedef struct { + usbdev_t usbdev; /**< Inherited usbdev struct */ + usbdev_ep_t ep_ins[NRF_USB_NUM_EP]; /**< IN type endpoints */ + usbdev_ep_t ep_outs[ NRF_USB_NUM_EP]; /**< OUT type endpoints */ + NRF_USBD_Type *device; /**< Ptr to the device registers */ + size_t used; /**< Number of bytes from the + buffer that are used */ + uint8_t buffer[NRF_USB_BUF_SPACE]; /**< Buffer space for endpoint data */ + nrfusb_setup_state_t sstate; /**< Setup request state machine */ +} nrfusb_t; + +#ifdef __cplusplus +} +#endif +#endif /* NRFUSB_H */ +/** @} */ diff --git a/cpu/nrf52/periph/usbdev.c b/cpu/nrf52/periph/usbdev.c new file mode 100644 index 000000000000..faecf7f6e90a --- /dev/null +++ b/cpu/nrf52/periph/usbdev.c @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2018 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_nrf52_nrfusb + * @{ + * @file + * @brief USB interface functions + * + * @file + * @brief Low level USB interface functions for the nrf52840 class + * devices + * + * @author Koen Zandberg + * @} + */ +#include +#include +#include + +#include "cpu.h" +#include "nrfusb.h" +#include "periph/usbdev.h" +#include "usb.h" +#include "usb/descriptor.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static nrfusb_t _usbdevs[NRF_USB_NUM_PERIPH]; + +static void _init(usbdev_t *usbdev); +static int _get(usbdev_t *usbdev, usbopt_t opt, void *value, size_t max_len); +static int _set(usbdev_t *usbdev, usbopt_t opt, const void *value, size_t value_len); +static usbdev_ep_t *_new_ep(usbdev_t *dev, usb_ep_type_t type, usb_ep_dir_t dir, size_t buf_len); +static void _esr(usbdev_t *usbdev); +static void _ep_init(usbdev_ep_t *ep); +static int _ep_get(usbdev_ep_t *ep, usbopt_ep_t opt, void *value, size_t max_len); +static int _ep_set(usbdev_ep_t *ep, usbopt_ep_t opt, const void *value, size_t value_len); +static int _ep_ready(usbdev_ep_t *ep, size_t len); +static void _ep_esr(usbdev_ep_t *ep); + +static const usbdev_driver_t _driver = { + .init = _init, + .new_ep = _new_ep, + .get = _get, + .set = _set, + .esr = _esr, + .ep_init = _ep_init, + .ep_get = _ep_get, + .ep_set = _ep_set, + .ep_esr = _ep_esr, + .ready = _ep_ready, +}; + +static inline usbdev_ep_t *_get_ep_in(nrfusb_t *usbdev, unsigned num) +{ + return &usbdev->ep_ins[num]; +} + +static inline usbdev_ep_t *_get_ep_out(nrfusb_t *usbdev, unsigned num) +{ + return &usbdev->ep_outs[num]; +} + +static inline usbdev_ep_t *_get_ep(nrfusb_t *usbdev, + unsigned num, usb_ep_dir_t dir) +{ + return dir == USB_EP_DIR_IN ? _get_ep_in(usbdev, num) + : _get_ep_out(usbdev, num); +} +static inline void _enable_errata_199(void) +{ + /* Contains the workaround as described in nRF52840 Errata 199 */ + *(volatile uint32_t *)0x40027C1C = 0x00000082; +} + +static inline void _disable_errata_199(void) +{ + /* Contains the workaround as described in nRF52840 Errata 199 */ + *(volatile uint32_t *)0x40027C1C = 0x00000000; +} + +/* Contains the sequence as described in nRF52840 Errata 187 */ +static inline void poweron(nrfusb_t *usbdev) +{ + /* Apply magic */ + *(volatile uint32_t *)0x4006EC00 = 0x00009375; + *(volatile uint32_t *)0x4006ED14 = 0x00000003; + *(volatile uint32_t *)0x4006EC00 = 0x00009375; + + /* Enable the peripheral */ + usbdev->device->ENABLE = USBD_ENABLE_ENABLE_Msk; + /* Waiting for peripheral to enable, this should take a few μs */ + while (!(usbdev->device->EVENTCAUSE & USBD_EVENTCAUSE_READY_Msk)) {} + + usbdev->device->EVENTCAUSE &= ~USBD_EVENTCAUSE_READY_Msk; + + /* Apply more magic */ + *(volatile uint32_t *)0x4006EC00 = 0x00009375; + *(volatile uint32_t *)0x4006ED14 = 0x00000000; + *(volatile uint32_t *)0x4006EC00 = 0x00009375; + + /* Enable peripheral a second time */ + usbdev->device->ENABLE = USBD_ENABLE_ENABLE_Msk; +} + +static inline void poweroff(nrfusb_t *usbdev) +{ + usbdev->device->ENABLE = 0x00; +} + +static void usb_attach(nrfusb_t *usbdev) +{ + DEBUG("nrfusb: Enabling pull-up\n"); + usbdev->device->USBPULLUP = 0x01; +} + +static void usb_detach(nrfusb_t *usbdev) +{ + DEBUG("nrfusb: Disabling pull-up\n"); + usbdev->device->USBPULLUP = 0x00; +} + +static void _ep_set_address(usbdev_ep_t *ep) +{ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + if (ep->dir == USB_EP_DIR_OUT) { + usbdev->device->EPOUT[ep->num].PTR = (uint32_t)ep->buf; + } + else { + usbdev->device->EPIN[ep->num].PTR = (uint32_t)ep->buf; + } +} + +static void _copy_setup(usbdev_ep_t *ep) +{ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + usb_setup_t *setup = (usb_setup_t*)ep->buf; + setup->type = usbdev->device->BMREQUESTTYPE; + setup->request = usbdev->device->BREQUEST; + setup->value = usbdev->device->WVALUEL | usbdev->device->WVALUEH << 8; + setup->index = usbdev->device->WINDEXL | usbdev->device->WINDEXH << 8; + setup->length = usbdev->device->WLENGTHL | usbdev->device->WLENGTHH << 8; + usbdev->sstate = usb_setup_is_read(setup) ? NRFUSB_SETUP_READ + : NRFUSB_SETUP_WRITE; + if (setup->request == USB_SETUP_REQ_SET_ADDRESS) { + DEBUG("nrfusb: set address call\n"); + usbdev->sstate = NRFUSB_SETUP_READY; + } +} + +static int _ep_set_size(usbdev_ep_t *ep) +{ + /* TODO: validate size */ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + if (ep->dir == USB_EP_DIR_OUT) { + usbdev->device->EPOUT[ep->num].MAXCNT = (uint32_t)ep->len; + } + return 1; +} + +static void _ep_enable(usbdev_ep_t *ep) +{ + DEBUG("Enabling endpoint %u dir %s\n", ep->num, ep->dir == USB_EP_DIR_OUT ? "OUT" : "IN"); + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + if (ep->dir == USB_EP_DIR_OUT) { + usbdev->device->EPOUTEN |= 1 << ep->num; + } + else { + usbdev->device->EPINEN |= 1 << ep->num; + } +} + +static void _ep_disable(usbdev_ep_t *ep) +{ + /* TODO: validate size */ + DEBUG("disabling endpoint %u dir %s\n", ep->num, ep->dir == USB_EP_DIR_OUT ? "OUT" : "IN"); + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + if (ep->dir == USB_EP_DIR_OUT) { + usbdev->device->EPOUTEN &= ~(1 << ep->num); + } + else { + usbdev->device->EPINEN &= ~(1 << ep->num); + } +} + +static void _ep_set_stall(usbdev_ep_t *ep, usbopt_enable_t enable) +{ + /* TODO: validate size */ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + uint32_t val = (ep->num & USBD_EPSTALL_EP_Msk) | + (ep->dir == USB_EP_DIR_IN ? USBD_EPSTALL_IO_Msk : 0) | + (enable ? USBD_EPSTALL_STALL_Msk : 0); + usbdev->device->EPSTALL = val; +} + +static usbopt_enable_t _ep_get_stall(usbdev_ep_t *ep) +{ + /* TODO: validate size */ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + if (ep->dir == USB_EP_DIR_OUT) { + return usbdev->device->HALTED.EPOUT[ep->num] ? USBOPT_ENABLE + : USBOPT_DISABLE; + } + else { + return usbdev->device->HALTED.EPIN[ep->num] ? USBOPT_ENABLE + : USBOPT_DISABLE; + } +} + +static size_t _ep_get_available(usbdev_ep_t *ep) +{ + /* TODO: validate size */ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + if (ep->dir == USB_EP_DIR_OUT) { + return usbdev->device->SIZE.EPOUT[ep->num]; + } + else { + return usbdev->device->EPIN[ep->num].AMOUNT; + } +} + +static void _ep_dma_out(usbdev_ep_t *ep) +{ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + assert(ep->dir == USB_EP_DIR_OUT); + _enable_errata_199(); + usbdev->device->TASKS_STARTEPOUT[ep->num] = 1; + /* Block while waiting for dma to finish */ + while (!(usbdev->device->EVENTS_ENDEPOUT[ep->num])) {} + + usbdev->device->EVENTS_ENDEPOUT[ep->num] = 0; + _disable_errata_199(); +} + +static void _ep_dma_in(usbdev_ep_t *ep) +{ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + assert(ep->dir == USB_EP_DIR_IN); + _enable_errata_199(); + usbdev->device->TASKS_STARTEPIN[ep->num] = 1; + /* Block while waiting for dma to finish */ + while (!(usbdev->device->EVENTS_ENDEPIN[ep->num])) {} + + usbdev->device->EVENTS_ENDEPIN[ep->num] = 0; + _disable_errata_199(); +} + +usbdev_t *usbdev_get_ctx(unsigned num) +{ + assert(num < NRF_USB_NUM_PERIPH); + return &_usbdevs[num].usbdev; +} + +void usbdev_init_lowlevel(void) +{ + for (size_t i = 0; i < NRF_USB_NUM_PERIPH; i++) { + _usbdevs[i].usbdev.driver = &_driver; + _usbdevs[i].device = NRF_USBD; + } +} + +static void _init(usbdev_t *dev) +{ + DEBUG("nrfusb: initializing\n"); + nrfusb_t *usbdev = (nrfusb_t*)dev; + poweron(usbdev); + usbdev->used = 0; + usbdev->sstate = NRFUSB_SETUP_READY; + + /* Enable a set of interrupts */ + usbdev->device->INTEN = USBD_INTEN_USBRESET_Msk | USBD_INTEN_EPDATA_Msk; + NVIC_EnableIRQ(USBD_IRQn); +} + +static int _get(usbdev_t *usbdev, usbopt_t opt, void *value, size_t max_len) +{ + (void)usbdev; + (void)max_len; + int res = -ENOTSUP; + switch (opt) { + case USBOPT_MAX_VERSION: + assert(max_len == sizeof(usb_version_t)); + *(usb_version_t *)value = USB_VERSION_20; + res = sizeof(usb_version_t); + break; + case USBOPT_MAX_SPEED: + assert(max_len == sizeof(usb_speed_t)); + *(usb_speed_t *)value = USB_SPEED_FULL; + res = sizeof(usb_speed_t); + break; + default: + DEBUG("unhandled get call: 0x%x\n", opt); + break; + } + return res; +} + +static int _set(usbdev_t *dev, usbopt_t opt, + const void *value, size_t value_len) +{ + nrfusb_t *usbdev = (nrfusb_t*)dev; + (void)value_len; + int res = -ENOTSUP; + switch (opt) { + case USBOPT_ATTACH: + assert(value_len == sizeof(usbopt_enable_t)); + if (*((usbopt_enable_t *)value)) { + usb_attach(usbdev); + } + else { + usb_detach(usbdev); + } + res = sizeof(usbopt_enable_t); + break; + default: + DEBUG("Unhandled set call: 0x%x\n", opt); + break; + } + return res; +} + +static usbdev_ep_t *_new_ep(usbdev_t *dev, usb_ep_type_t type, usb_ep_dir_t dir, size_t buf_len) +{ + nrfusb_t *usbdev = (nrfusb_t*)dev; + /* The IP supports all types for all endpoints */ + usbdev_ep_t *res = NULL; + + /* Always return endpoint 0 for control types */ + if (type == USB_EP_TYPE_CONTROL) { + res = _get_ep(usbdev, 0, dir); + res->num = 0; + } + else if (type == USB_EP_TYPE_INTERRUPT || type == USB_EP_TYPE_BULK) { + /* Find the first unassigned ep with proper dir */ + for (unsigned idx = 1; idx < NRF_USB_NUM_EP && !res; idx++) { + usbdev_ep_t *ep = _get_ep(usbdev, idx, dir); + if (ep->type == USB_EP_TYPE_NONE) { + res = ep; + res->num = idx; + } + } + } + if (res) { + res->dev = dev; + res->dir = dir; + DEBUG("nrfusb: Allocated new ep (%d %s)\n", res->num, res->dir == USB_EP_DIR_OUT ? "OUT" : "IN"); + if (usbdev->used + buf_len < NRF_USB_BUF_SPACE) { + res->buf = usbdev->buffer + usbdev->used; + res->len = buf_len; + if (_ep_set_size(res) < 0) { + return NULL; + } + usbdev->used += buf_len; + _ep_set_address(res); + res->type = type; + res->dev = dev; + } + else { + DEBUG("nrfusb: error allocating buffer space\n"); + } + } + return res; +} + +static void _ep_enable_irq(usbdev_ep_t *ep) +{ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + if (ep->dir == USB_EP_DIR_IN) { + if (ep->num == 0) { + usbdev->device->INTENSET = USBD_INTENSET_EP0DATADONE_Msk; + } + } + else { + if (ep->num == 0) { + usbdev->device->INTENSET = USBD_INTENSET_EP0SETUP_Msk; + } + } +} + +static void _ep_disable_irq(usbdev_ep_t *ep) +{ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + if (ep->dir == USB_EP_DIR_IN) { + if (ep->num == 0) { + usbdev->device->INTENCLR = USBD_INTENCLR_EP0DATADONE_Msk; + } + } + else { + if (ep->num == 0) { + usbdev->device->INTENCLR = USBD_INTENCLR_EP0SETUP_Msk; + } + } +} + +static void _ep_init(usbdev_ep_t *ep) +{ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + _ep_set_size(ep); + _ep_set_address(ep); + if (ep->num == 0) { + usbdev->device->EVENTS_EP0SETUP = 0; + } + if (ep->dir == USB_EP_DIR_OUT) { + usbdev->device->EVENTS_ENDEPOUT[ep->num] = 0; + usbdev->device->EPDATASTATUS = 1 << ep->num; + } + else { + usbdev->device->EPDATASTATUS = 1 << ep->num; + } + _ep_enable_irq(ep); +} + +static int _ep_get(usbdev_ep_t *ep, usbopt_ep_t opt, + void *value, size_t max_len) +{ + (void)max_len; + int res = -ENOTSUP; + switch (opt) { + case USBOPT_EP_STALL: + assert(max_len == sizeof(usbopt_enable_t)); + *(usbopt_enable_t *)value = _ep_get_stall(ep); + res = sizeof(usbopt_enable_t); + break; + case USBOPT_EP_AVAILABLE: + assert(max_len == sizeof(size_t)); + *(size_t *)value = _ep_get_available(ep); + res = sizeof(size_t); + break; + default: + DEBUG("Unhandled get call: 0x%x\n", opt); + break; + } + return res; +} + +static int _ep_set(usbdev_ep_t *ep, usbopt_ep_t opt, + const void *value, size_t value_len) +{ + (void)value_len; + int res = -ENOTSUP; + switch (opt) { + case USBOPT_EP_ENABLE: + assert(value_len == sizeof(usbopt_enable_t)); + if (*((usbopt_enable_t *)value)) { + _ep_enable(ep); + _ep_init(ep); + } + else { + _ep_disable(ep); + } + res = sizeof(usbopt_enable_t); + break; + case USBOPT_EP_STALL: + assert(value_len == sizeof(usbopt_enable_t)); + _ep_set_stall(ep, *(usbopt_enable_t *)value); + res = sizeof(usbopt_enable_t); + break; + case USBOPT_EP_READY: + assert(value_len == sizeof(usbopt_enable_t)); + if (*((usbopt_enable_t *)value)) { + _ep_ready(ep, 0); + res = sizeof(usbopt_enable_t); + } + break; + default: + DEBUG("Unhandled set call: 0x%x\n", opt); + break; + } + return res; +} + +static int _ep0_ready(usbdev_ep_t *ep, size_t len) +{ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + if (ep->dir == USB_EP_DIR_IN) { + if (len == 0 && usbdev->sstate == NRFUSB_SETUP_WRITE) { + usbdev->device->TASKS_EP0STATUS = 1; + usbdev->usbdev.epcb(_get_ep_in(usbdev, 0), USBDEV_EVENT_ESR); + usbdev->sstate = NRFUSB_SETUP_ACKIN; + } + else { + usbdev->device->EPIN[0].PTR = (uint32_t)ep->buf; + usbdev->device->EPIN[0].MAXCNT = (uint32_t)len; + usbdev->device->TASKS_STARTEPIN[0] = 1; + } + } + else { + /* USB_EP_DIR_OUT */ + if (len == 0) { + if (usbdev->sstate == NRFUSB_SETUP_READ) { + usbdev->device->TASKS_EP0STATUS = 1; + usbdev->sstate = NRFUSB_SETUP_ACKOUT; + usbdev->usbdev.epcb(_get_ep_out(usbdev, 0), USBDEV_EVENT_ESR); + } + else if (usbdev->sstate == NRFUSB_SETUP_READY) { + return 0; + } + } + else { + usbdev->device->TASKS_STARTEPOUT[ep->num] = 1; + } + } + return len; +} + +static int _ep_ready(usbdev_ep_t *ep, size_t len) +{ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + if (ep->num == 0) { + /* Endpoint 0 requires special handling as per datasheet sec 6.35.9 */ + return _ep0_ready(ep, len); + } + if (ep->dir == USB_EP_DIR_IN) { + usbdev->device->EPIN[ep->num].PTR = (uint32_t)ep->buf; + usbdev->device->EPIN[ep->num].MAXCNT = (uint32_t)len; + _ep_dma_in(ep); + } + else { + /* Write nonzero value to EPOUT to indicate ready */ + usbdev->device->SIZE.EPOUT[ep->num] = 1; + } + return len; +} + +static void _esr(usbdev_t *dev) +{ + nrfusb_t *usbdev = (nrfusb_t*)dev; + if (usbdev->device->EVENTS_USBRESET) { + DEBUG("nrfusb: reset condition\n"); + usbdev->device->EVENTS_USBRESET = 0; + usbdev->sstate = NRFUSB_SETUP_READY; + usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_RESET); + usbdev->device->INTENSET = USBD_INTENSET_USBRESET_Msk; + } +} + +static signed _ep0_esr(usbdev_ep_t *ep) +{ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + signed event = -1; + if (ep->dir == USB_EP_DIR_OUT) { + if (usbdev->sstate == NRFUSB_SETUP_ACKOUT) { + usbdev->sstate = NRFUSB_SETUP_READY; + event = USBDEV_EVENT_TR_COMPLETE; + } + else if (usbdev->device->EVENTS_EP0SETUP) { + usbdev->device->EVENTS_EP0SETUP = 0; + event = USBDEV_EVENT_TR_COMPLETE; + /* Copy setup request info to buffer */ + _copy_setup(ep); + if ((uint8_t)usbdev->device->BREQUEST == 0x05) { + event = 0; + } + } + } + else { + if (usbdev->sstate == NRFUSB_SETUP_ACKIN) { + usbdev->sstate = NRFUSB_SETUP_READY; + event = USBDEV_EVENT_TR_COMPLETE; + } + else if (usbdev->device->EVENTS_EP0DATADONE) { + usbdev->device->EVENTS_EP0DATADONE = 0; + event = USBDEV_EVENT_TR_COMPLETE; + } + } + return event; +} + +static void _ep_esr(usbdev_ep_t *ep) +{ + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + signed event = -1; + if (ep->num == 0) { + event = _ep0_esr(ep); + } + else { + if (ep->dir == USB_EP_DIR_IN) { + if (usbdev->device->EPDATASTATUS & 1 << ep->num) { + usbdev->device->EPDATASTATUS = 1 << (ep->num); + usbdev->device->EVENTS_EPDATA = 0; + usbdev->device->INTENSET = USBD_INTENSET_EPDATA_Msk; + + event = USBDEV_EVENT_TR_COMPLETE; + } + } + else { + if (usbdev->device->EPDATASTATUS & 1 << (ep->num + 16)) { + /* start dma to transfer payload to memory */ + _ep_dma_out(ep); + + usbdev->device->EPDATASTATUS = 1 << (ep->num + 16); + event = USBDEV_EVENT_TR_COMPLETE; + } + } + } + if (event) { + ep->dev->epcb(ep, event); + } + _ep_enable_irq(ep); +} + +void isr_usbd(void) +{ + /* Only one usb peripheral possible at the moment */ + nrfusb_t *usbdev = &_usbdevs[0]; + /* Generic USB peripheral events */ + if (usbdev->device->EVENTS_USBRESET && + (usbdev->device->INTEN & USBD_INTEN_USBRESET_Msk)) { + usbdev->device->INTENCLR = USBD_INTENCLR_USBRESET_Msk; + usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_ESR); + } + else { + /* Endpoint specific isr handling*/ + /* Endpoint 0 SETUP data received requests */ + if (usbdev->device->EVENTS_EP0SETUP && + (usbdev->device->INTEN & USBD_INTEN_EP0SETUP_Msk)) { + usbdev->usbdev.epcb(_get_ep_out(usbdev, 0), USBDEV_EVENT_ESR); + _ep_disable_irq(_get_ep_out(usbdev, 0)); + } + if (usbdev->device->EVENTS_EP0DATADONE && + (usbdev->device->INTEN & USBD_INTEN_EP0DATADONE_Msk)) { + usbdev->usbdev.epcb(_get_ep_in(usbdev, 0), USBDEV_EVENT_ESR); + _ep_disable_irq(_get_ep_in(usbdev, 0)); + } + if (usbdev->device->EVENTS_EPDATA && usbdev->device->EPDATASTATUS) { + usbdev->device->EVENTS_EPDATA = 0; + uint32_t epdatastatus = usbdev->device->EPDATASTATUS; + while (epdatastatus) { + unsigned epnum = bitarithm_lsb(epdatastatus); + if (epnum > 16) { + usbdev_ep_t *ep = _get_ep_out(usbdev, epnum - 16); + if (ep->type != USB_EP_TYPE_NONE) { + /* OUT type endpoint */ + usbdev->usbdev.epcb(ep, + USBDEV_EVENT_ESR); + } + } + else { + usbdev_ep_t *ep = _get_ep_in(usbdev, epnum); + if (ep->type != USB_EP_TYPE_NONE) { + usbdev->usbdev.epcb(ep, + USBDEV_EVENT_ESR); + } + } + epdatastatus &= ~(1 << epnum); + } + } + } + cortexm_isr_end(); +} From cc5320d626c88d4914f684da891f765fdb664c9a Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Sun, 9 Jun 2019 22:01:35 +0200 Subject: [PATCH 3/6] nrf52840dk: Add usbdev feature --- boards/nrf52840dk/Makefile.features | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/nrf52840dk/Makefile.features b/boards/nrf52840dk/Makefile.features index 4ab48c7cbc2e..9cd78c754fe6 100644 --- a/boards/nrf52840dk/Makefile.features +++ b/boards/nrf52840dk/Makefile.features @@ -3,3 +3,4 @@ include $(RIOTBOARD)/common/nrf52xxxdk/Makefile.features # Various other features (if any) FEATURES_PROVIDED += radio_nrf802154 FEATURES_PROVIDED += periph_pwm +FEATURES_PROVIDED += periph_usbdev From 7ca573aace2d74bec481058ce0a69a5bace7156f Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Sun, 9 Jun 2019 22:01:54 +0200 Subject: [PATCH 4/6] nrf52840-mdk: add usbdev feature --- boards/nrf52840-mdk/Makefile.features | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boards/nrf52840-mdk/Makefile.features b/boards/nrf52840-mdk/Makefile.features index 2d67b5507b24..72d4df594287 100644 --- a/boards/nrf52840-mdk/Makefile.features +++ b/boards/nrf52840-mdk/Makefile.features @@ -1,7 +1,8 @@ # Put defined MCU peripherals here (in alphabetical order) +FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_uart -FEATURES_PROVIDED += periph_i2c +FEATURES_PROVIDED += periph_usbdev # Various other features (if any) FEATURES_PROVIDED += radio_nrf802154 From e745078f76c59b2ebaed70d5861d1b7cb7230aaf Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Sun, 9 Jun 2019 22:02:11 +0200 Subject: [PATCH 5/6] particle-mesh: add usbdev feature --- boards/common/particle-mesh/Makefile.features | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/common/particle-mesh/Makefile.features b/boards/common/particle-mesh/Makefile.features index 26f1bcc71f3b..72d4df594287 100644 --- a/boards/common/particle-mesh/Makefile.features +++ b/boards/common/particle-mesh/Makefile.features @@ -2,6 +2,7 @@ FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_uart +FEATURES_PROVIDED += periph_usbdev # Various other features (if any) FEATURES_PROVIDED += radio_nrf802154 From 98aa643d7e6abc4e9f70e586ce2de3a6359a72b5 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Sun, 9 Jun 2019 22:04:39 +0200 Subject: [PATCH 6/6] PHYTEC reel: add usbdev feature --- boards/reel/Makefile.features | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/reel/Makefile.features b/boards/reel/Makefile.features index cf9d2b4ceb34..490b6451237d 100644 --- a/boards/reel/Makefile.features +++ b/boards/reel/Makefile.features @@ -2,5 +2,6 @@ FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_uart +FEATURES_PROVIDED += periph_usbdev include $(RIOTBOARD)/common/nrf52/Makefile.features