From 44174a0ae621076694049b31086a8ee8a2085156 Mon Sep 17 00:00:00 2001 From: Cristian Maglie <c.maglie@arduino.cc> Date: Thu, 25 Jun 2015 19:13:16 +0200 Subject: [PATCH] USB device refactoring (WIP) --- cores/arduino/USB/CDC.cpp | 141 ++-- cores/arduino/USB/HID.cpp | 31 +- cores/arduino/USB/SAMD21_USBDevice.h | 197 +++++ cores/arduino/USB/USBAPI.h | 134 +-- cores/arduino/USB/USBCore.cpp | 1125 ++++++++++++++------------ cores/arduino/USB/USBCore.h | 12 +- cores/arduino/USB/USBDesc.h | 2 +- cores/arduino/USB/USB_device.h | 63 -- cores/arduino/USB/USB_host.h | 2 +- cores/arduino/USB/USB_interrupt.c | 23 - cores/arduino/USB/samd21_device.c | 349 -------- cores/arduino/USB/samd21_device.h | 108 --- cores/arduino/USB/samd21_host.c | 72 +- cores/arduino/USB/samd21_host.h | 24 +- 14 files changed, 1030 insertions(+), 1253 deletions(-) create mode 100644 cores/arduino/USB/SAMD21_USBDevice.h delete mode 100644 cores/arduino/USB/USB_device.h delete mode 100644 cores/arduino/USB/USB_interrupt.c delete mode 100644 cores/arduino/USB/samd21_device.c delete mode 100644 cores/arduino/USB/samd21_device.h diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp index 33c7b7e8..c0e61a89 100644 --- a/cores/arduino/USB/CDC.cpp +++ b/cores/arduino/USB/CDC.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2015 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,22 +16,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <Arduino.h> +#include <Reset.h> // Needed for auto-reset with 1200bps port touch + #include <stdlib.h> #include <stdio.h> #include <stdint.h> -// Include Atmel headers -#include "Arduino.h" -#include "sam.h" -#include "wiring_constants.h" -#include "USBCore.h" -#include "USB/USB_device.h" -#include "USBDesc.h" -#include "USBAPI.h" - -#include "Reset.h" - - #ifdef CDC_ENABLED #define CDC_SERIAL_BUFFER_SIZE 64 @@ -42,96 +33,93 @@ #define CDC_LINESTATE_READY (CDC_LINESTATE_RTS | CDC_LINESTATE_DTR) -struct ring_buffer -{ +struct ring_buffer { uint8_t buffer[CDC_SERIAL_BUFFER_SIZE]; volatile uint32_t head; volatile uint32_t tail; }; - ring_buffer cdc_rx_buffer = { { 0 }, 0, 0}; -typedef struct -{ - uint32_t dwDTERate; - uint8_t bCharFormat; - uint8_t bParityType; - uint8_t bDataBits; - uint8_t lineState; +typedef struct { + uint32_t dwDTERate; + uint8_t bCharFormat; + uint8_t bParityType; + uint8_t bDataBits; + uint8_t lineState; } LineInfo; _Pragma("pack(1)") static volatile LineInfo _usbLineInfo = { - 115200, // dWDTERate - 0x00, // bCharFormat - 0x00, // bParityType - 0x08, // bDataBits - 0x00 // lineState + 115200, // dWDTERate + 0x00, // bCharFormat + 0x00, // bParityType + 0x08, // bDataBits + 0x00 // lineState }; -static const CDCDescriptor _cdcInterface = -{ -#if (defined CDC_ENABLED) && defined(HID_ENABLED) +static const CDCDescriptor _cdcInterface = { + #if (defined CDC_ENABLED) && defined(HID_ENABLED) D_IAD(0, 2, CDC_COMMUNICATION_INTERFACE_CLASS, CDC_ABSTRACT_CONTROL_MODEL, 0), -#endif - // CDC communication interface - D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), - D_CDCCS( CDC_HEADER, CDC_V1_10 & 0xFF, (CDC_V1_10>>8) & 0x0FF ), // Header (1.10 bcd) - - D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported - D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE), // Communication interface is master, data interface is slave 0 - D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not) - D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10, 0x10), - - // CDC data interface - D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0), - D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,EPX_SIZE,0), - D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,EPX_SIZE,0) + #endif + + // CDC communication interface + D_INTERFACE(CDC_ACM_INTERFACE, 1, CDC_COMMUNICATION_INTERFACE_CLASS, CDC_ABSTRACT_CONTROL_MODEL, 0), + D_CDCCS(CDC_HEADER, CDC_V1_10 & 0xFF, (CDC_V1_10>>8) & 0x0FF), // Header (1.10 bcd) + + D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT, 6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported + D_CDCCS(CDC_UNION, CDC_ACM_INTERFACE, CDC_DATA_INTERFACE), // Communication interface is master, data interface is slave 0 + D_CDCCS(CDC_CALL_MANAGEMENT, 1, 1), // Device handles call management (not) + D_ENDPOINT(USB_ENDPOINT_IN(CDC_ENDPOINT_ACM), USB_ENDPOINT_TYPE_INTERRUPT, 0x10, 0x10), + + // CDC data interface + D_INTERFACE(CDC_DATA_INTERFACE, 2, CDC_DATA_INTERFACE_CLASS, 0, 0), + D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT), USB_ENDPOINT_TYPE_BULK, EPX_SIZE, 0), + D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ), USB_ENDPOINT_TYPE_BULK, EPX_SIZE, 0) }; _Pragma("pack()") -const void* WEAK CDC_GetInterface(void) +const void* CDC_GetInterface(void) { - return &_cdcInterface; + return &_cdcInterface; } -uint32_t WEAK CDC_GetInterfaceLength(void) +uint32_t CDC_GetInterfaceLength(void) { - return sizeof( _cdcInterface ); + return sizeof(_cdcInterface); } -bool WEAK CDC_Setup(Setup& setup) +bool CDC_Setup(Setup& setup) { - uint8_t r = setup.bRequest; uint8_t requestType = setup.bmRequestType; + uint8_t r = setup.bRequest; - if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) + if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) { - if (CDC_GET_LINE_CODING == r) + if (r == CDC_GET_LINE_CODING) { - USBD_SendControl(0,(void*)&_usbLineInfo,7); + USBDevice.sendControl((void*)&_usbLineInfo, 7); return true; } } - if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) + if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) { - if (CDC_SET_LINE_CODING == r) + if (r == CDC_SET_LINE_CODING) { - USBD_RecvControl((void*)&_usbLineInfo,7); + USBDevice.recvControl((void*)&_usbLineInfo, 7); } - if (CDC_SET_CONTROL_LINE_STATE == r) + if (r == CDC_SET_CONTROL_LINE_STATE) { _usbLineInfo.lineState = setup.wValueL; } - if (CDC_SET_LINE_CODING == r || CDC_SET_CONTROL_LINE_STATE == r) + if (r == CDC_SET_LINE_CODING || r == CDC_SET_CONTROL_LINE_STATE) { // auto-reset into the bootloader is triggered when the port, already // open at 1200 bps, is closed. We check DTR state to determine if host // port is open (bit 0 of lineState). - if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) + if (_usbLineInfo.dwDTERate == 1200 && (_usbLineInfo.lineState & 0x01) == 0) { initiateReset(250); } @@ -161,7 +149,7 @@ void Serial_::end(void) void Serial_::accept(void) { uint8_t buffer[CDC_SERIAL_BUFFER_SIZE]; - uint32_t len = USBD_Recv(CDC_ENDPOINT_OUT, (void*)&buffer, CDC_SERIAL_BUFFER_SIZE); + uint32_t len = usb.recv(CDC_ENDPOINT_OUT, &buffer, CDC_SERIAL_BUFFER_SIZE); noInterrupts(); ring_buffer *ringBuffer = &cdc_rx_buffer; @@ -173,7 +161,7 @@ void Serial_::accept(void) // and so we don't write the character or advance the head. uint32_t k = 0; i = (i + 1) % CDC_SERIAL_BUFFER_SIZE; - while (i != ringBuffer->tail && len>0) { + while ((i != ringBuffer->tail) && (len > 0)) { len--; ringBuffer->buffer[ringBuffer->head] = buffer[k++]; ringBuffer->head = i; @@ -185,6 +173,9 @@ void Serial_::accept(void) int Serial_::available(void) { ring_buffer *buffer = &cdc_rx_buffer; + if (buffer->head == buffer->tail) { + USB->DEVICE.DeviceEndpoint[2].EPINTENSET.reg = USB_DEVICE_EPINTENCLR_TRCPT(1); + } return (uint32_t)(CDC_SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % CDC_SERIAL_BUFFER_SIZE; } @@ -202,12 +193,22 @@ int Serial_::peek(void) } } + +// if the ringBuffer is empty: try to fill it +// if it's still empty: return -1 +// else return the last char +// so the buffer is filled only when needed int Serial_::read(void) { ring_buffer *buffer = &cdc_rx_buffer; // if the head isn't ahead of the tail, we don't have any characters if (buffer->head == buffer->tail) + { + if (usb.available(CDC_ENDPOINT_OUT)) + accept(); + } + if (buffer->head == buffer->tail) { return -1; } @@ -215,15 +216,15 @@ int Serial_::read(void) { unsigned char c = buffer->buffer[buffer->tail]; buffer->tail = (uint32_t)(buffer->tail + 1) % CDC_SERIAL_BUFFER_SIZE; - if (USBD_Available(CDC_ENDPOINT_OUT)) - accept(); +// if (usb.available(CDC_ENDPOINT_OUT)) +// accept(); return c; } } void Serial_::flush(void) { - USBD_Flush(CDC_ENDPOINT_IN); + usb.flush(CDC_ENDPOINT_IN); } size_t Serial_::write(const uint8_t *buffer, size_t size) @@ -239,13 +240,11 @@ size_t Serial_::write(const uint8_t *buffer, size_t size) // or locks up, or host virtual serial port hangs) // if (_usbLineInfo.lineState > 0) // Problem with Windows(R) { - uint32_t r = USBD_Send(CDC_ENDPOINT_IN, buffer, size); + uint32_t r = usb.send(CDC_ENDPOINT_IN, buffer, size); - if (r > 0) - { + if (r > 0) { return r; - } else - { + } else { setWriteError(); return 0; } @@ -282,6 +281,6 @@ Serial_::operator bool() return result; } -Serial_ SerialUSB; +Serial_ SerialUSB(USBDevice); #endif diff --git a/cores/arduino/USB/HID.cpp b/cores/arduino/USB/HID.cpp index f5d561e0..45208b2d 100644 --- a/cores/arduino/USB/HID.cpp +++ b/cores/arduino/USB/HID.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,13 +16,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "USBAPI.h" -#include "Reset.h" -#include "USBCore.h" -#include "USBDesc.h" -#include "sam.h" -#include "USB/USB_device.h" - +#include <Arduino.h> #ifdef HID_ENABLED @@ -143,14 +137,12 @@ _Pragma("pack()") uint8_t _hid_protocol = 1; uint8_t _hid_idle = 1; -#define WEAK __attribute__ ((weak)) - -const void* WEAK HID_GetInterface(void) +const void* HID_GetInterface(void) { return &_hidInterface; } -uint32_t WEAK HID_GetInterfaceLength(void) +uint32_t HID_GetInterfaceLength(void) { return sizeof( _hidInterface ); } @@ -160,12 +152,12 @@ uint32_t HID_SizeReportDescriptor(void) return sizeof(_hidReportDescriptor); } -uint32_t WEAK HID_GetDescriptor(void) +uint32_t HID_GetDescriptor(void) { - return USBD_SendControl(0,_hidReportDescriptor,sizeof(_hidReportDescriptor)); + return USBDevice.sendControl(_hidReportDescriptor, sizeof(_hidReportDescriptor)); } -void WEAK HID_SendReport(uint8_t id, const void* data, uint32_t len) +void HID_SendReport(uint8_t id, const void* data, uint32_t len) { uint8_t p[8]; const uint8_t *d = reinterpret_cast<const uint8_t *>(data); @@ -175,10 +167,10 @@ void WEAK HID_SendReport(uint8_t id, const void* data, uint32_t len) { p[i+1] = d[i]; } - USBD_Send(HID_ENDPOINT_INT, p, len+1); + USBDevice.send(HID_ENDPOINT_INT, p, len+1); } -bool WEAK HID_Setup(Setup& setup) +bool HID_Setup(Setup& setup) { uint8_t r = setup.bRequest; uint8_t requestType = setup.bmRequestType; @@ -197,8 +189,9 @@ bool WEAK HID_Setup(Setup& setup) } if (HID_GET_IDLE == r) { - UDD_Send(0, &_hid_idle, 1); - UDD_ClearIN(); + USBDevice.armSend(0, &_hid_idle, 1); + // RAM buffer is full, we can send data (IN) + USB->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.BK1RDY = 1; return true; } } diff --git a/cores/arduino/USB/SAMD21_USBDevice.h b/cores/arduino/USB/SAMD21_USBDevice.h new file mode 100644 index 00000000..203a1c78 --- /dev/null +++ b/cores/arduino/USB/SAMD21_USBDevice.h @@ -0,0 +1,197 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include <Arduino.h> + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> + +typedef uint8_t ep_t; + +class USBDevice_SAMD21G18x { +public: + USBDevice_SAMD21G18x() : usb(USB->DEVICE) { + // Empty + } + + // USB Device function mapping + // --------------------------- + + // Reset USB Device + void reset(); + + // Enable + inline void enable() { usb.CTRLA.bit.ENABLE = 1; } + inline void disable() { usb.CTRLA.bit.ENABLE = 0; } + + // USB mode (device/host) + inline void setUSBDeviceMode() { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_DEVICE_Val; } + inline void setUSBHostMode() { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_HOST_Val; } + + inline void runInStandby() { usb.CTRLA.bit.RUNSTDBY = 1; } + inline void noRunInStandby() { usb.CTRLA.bit.RUNSTDBY = 0; } + + // USB speed + inline void setFullSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val; } + inline void setLowSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_LS_Val; } + inline void setHiSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_HS_Val; } + inline void setHiSpeedTestMode() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_HSTM_Val; } + + // Authorize attach if Vbus is present + inline void attach() { usb.CTRLB.bit.DETACH = 0; } + inline void detach() { usb.CTRLB.bit.DETACH = 1; } + + // USB Interrupts + inline bool isEndOfResetInterrupt() { return usb.INTFLAG.bit.EORST; } + inline void ackEndOfResetInterrupt() { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; } + inline void enableEndOfResetInterrupt() { usb.INTENSET.bit.EORST = 1; } + inline void disableEndOfResetInterrupt() { usb.INTENCLR.bit.EORST = 1; } + + inline bool isStartOfFrameInterrupt() { return usb.INTFLAG.bit.SOF; } + inline void ackStartOfFrameInterrupt() { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF; } + inline void enableStartOfFrameInterrupt() { usb.INTENSET.bit.SOF = 1; } + inline void disableStartOfFrameInterrupt() { usb.INTENCLR.bit.SOF = 1; } + + // USB Address + inline void setAddress(uint32_t addr) { usb.DADD.bit.DADD = addr; usb.DADD.bit.ADDEN = 1; } + inline void unsetAddress() { usb.DADD.bit.DADD = 0; usb.DADD.bit.ADDEN = 0; } + + // Frame number + inline uint16_t frameNumber() { return usb.FNUM.bit.FNUM; } + + // Load calibration values + void calibrate(); + + // USB Device Endpoints function mapping + // ------------------------------------- + + // Config + inline void epBank0SetType(ep_t ep, uint8_t type) { usb.DeviceEndpoint[ep].EPCFG.bit.EPTYPE0 = type; } + inline void epBank1SetType(ep_t ep, uint8_t type) { usb.DeviceEndpoint[ep].EPCFG.bit.EPTYPE1 = type; } + + // Interrupts + inline uint16_t epInterruptSummary() { return usb.EPINTSMRY.reg; } + + inline bool epBank0IsSetupReceived(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.RXSTP; } + inline bool epBank0IsStalled(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.STALL & 1; } + inline bool epBank1IsStalled(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.STALL & 2; } + inline bool epBank0IsTransferComplete(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT & 1; } + inline bool epBank1IsTransferComplete(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT & 2; } + + inline void epBank0AckSetupReceived(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP; } + inline void epBank0AckStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL(1); } + inline void epBank1AckStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL(2); } + inline void epBank0AckTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(1); } + inline void epBank1AckTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(2); } + + inline void epBank0EnableSetupReceived(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.RXSTP = 1; } + inline void epBank0EnableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.STALL = 1; } + inline void epBank1EnableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.STALL = 2; } + inline void epBank0EnableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.TRCPT = 1; } + inline void epBank1EnableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.TRCPT = 2; } + + inline void epBank0DisableSetupReceived(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.RXSTP = 1; } + inline void epBank0DisableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.STALL = 1; } + inline void epBank1DisableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.STALL = 2; } + inline void epBank0DisableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.TRCPT = 1; } + inline void epBank1DisableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.TRCPT = 2; } + + // Status + inline bool epBank0IsReady(ep_t ep) { return usb.DeviceEndpoint[ep].EPSTATUS.bit.BK0RDY; } + inline bool epBank1IsReady(ep_t ep) { return usb.DeviceEndpoint[ep].EPSTATUS.bit.BK1RDY; } + inline void epBank0SetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.BK0RDY = 1; } + inline void epBank1SetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.BK1RDY = 1; } + inline void epBank0ResetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.BK0RDY = 1; } + inline void epBank1ResetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.BK1RDY = 1; } + + inline void epBank0SetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.STALLRQ = 1; } + inline void epBank1SetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.STALLRQ = 2; } + inline void epBank0ResetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.STALLRQ = 1; } + inline void epBank1ResetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.STALLRQ = 2; } + + // Packet + inline uint16_t epBank0ByteCount(ep_t ep) { return EP[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT; } + inline uint16_t epBank1ByteCount(ep_t ep) { return EP[ep].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT; } + inline void epBank0SetByteCount(ep_t ep, uint16_t bc) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = bc; } + inline void epBank1SetByteCount(ep_t ep, uint16_t bc) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = bc; } + inline void epBank0SetMultiPacketSize(ep_t ep, uint16_t s) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = s; } + inline void epBank1SetMultiPacketSize(ep_t ep, uint16_t s) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = s; } + + inline void epBank0SetAddress(ep_t ep, void *addr) { EP[ep].DeviceDescBank[0].ADDR.reg = (uint32_t)addr; } + inline void epBank1SetAddress(ep_t ep, void *addr) { EP[ep].DeviceDescBank[1].ADDR.reg = (uint32_t)addr; } + inline void epBank0SetSize(ep_t ep, uint16_t size) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.SIZE = EP_PCKSIZE_SIZE(size); } + inline void epBank1SetSize(ep_t ep, uint16_t size) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.SIZE = EP_PCKSIZE_SIZE(size); } + inline uint8_t EP_PCKSIZE_SIZE(uint16_t size) { + switch (size) { + case 8: return 0; + case 16: return 1; + case 32: return 2; + case 64: return 3; + case 128: return 4; + case 256: return 5; + case 512: return 6; + case 1023: return 7; + default: return 0; + } + } + + inline void epBank0DisableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.AUTO_ZLP = 0; } + inline void epBank1DisableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = 0; } + inline void epBank0EnableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.AUTO_ZLP = 1; } + inline void epBank1EnableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = 1; } + +private: + // USB Device registers + UsbDevice &usb; + + // Endpoints descriptors table + __attribute__((__aligned__(4))) UsbDeviceDescriptor EP[USB_EPT_NUM]; +}; + +void USBDevice_SAMD21G18x::reset() { + usb.CTRLA.bit.SWRST = 1; + memset(EP, 0, sizeof(EP)); + while (usb.SYNCBUSY.bit.SWRST) {} + usb.DESCADD.reg = (uint32_t)(&EP); +} + +void USBDevice_SAMD21G18x::calibrate() { + // Load Pad Calibration data from non-volatile memory + uint32_t *pad_transn_p = (uint32_t *) USB_FUSES_TRANSN_ADDR; + uint32_t *pad_transp_p = (uint32_t *) USB_FUSES_TRANSP_ADDR; + uint32_t *pad_trim_p = (uint32_t *) USB_FUSES_TRIM_ADDR; + + uint32_t pad_transn = (*pad_transn_p & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos; + uint32_t pad_transp = (*pad_transp_p & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos; + uint32_t pad_trim = (*pad_trim_p & USB_FUSES_TRIM_Msk ) >> USB_FUSES_TRIM_Pos; + + if (pad_transn == 0x1F) // maximum value (31) + pad_transn = 5; + if (pad_transp == 0x1F) // maximum value (31) + pad_transp = 29; + if (pad_trim == 0x7) // maximum value (7) + pad_trim = 3; + + usb.PADCAL.bit.TRANSN = pad_transn; + usb.PADCAL.bit.TRANSP = pad_transp; + usb.PADCAL.bit.TRIM = pad_trim; +} + diff --git a/cores/arduino/USB/USBAPI.h b/cores/arduino/USB/USBAPI.h index 1229c3b7..b2d9d510 100644 --- a/cores/arduino/USB/USBAPI.h +++ b/cores/arduino/USB/USBAPI.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2015 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,8 +16,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __USBAPI__ -#define __USBAPI__ +#pragma once #define HSTPIPCFG_PTYPE_BLK 1 #define HSTPIPCFG_PTOKEN_IN 2 @@ -25,17 +24,8 @@ #define HSTPIPCFG_PBK_1_BANK 4 #define HSTPIPCFG_PTYPE_INTRPT 5 - - -/* Define attribute */ -#if defined ( __CC_ARM ) /* Keil uVision 4 */ - #define WEAK (__attribute__ ((weak))) -#elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ - #define WEAK __weak -#elif defined ( __GNUC__ ) /* GCC CS */ - #define WEAK __attribute__ ((weak)) -#endif - +#define EP0 0 +#define EPX_SIZE 64 // 64 for Full Speed, EPT size max is 1024 #if defined __cplusplus @@ -43,31 +33,81 @@ #include "RingBuffer.h" //================================================================================ -//================================================================================ -// USB +// USB -class USBDevice_ -{ +// Low level API +typedef struct { + union { + uint8_t bmRequestType; + struct { + uint8_t direction : 5; + uint8_t type : 2; + uint8_t transferDirection : 1; + }; + }; + uint8_t bRequest; + uint8_t wValueL; + uint8_t wValueH; + uint16_t wIndex; + uint16_t wLength; +} Setup; + +class USBDeviceClass { public: - USBDevice_(); - bool configured(); + USBDeviceClass() {}; - bool attach(); - bool detach(); // Serial port goes down too... - void poll(); + // USB Device API void init(); + bool attach(); + bool detach(); + void setAddress(uint32_t addr); + + bool configured(); + bool connected(); + + // Setup API + bool handleClassInterfaceSetup(Setup &setup); + bool handleStandardSetup(Setup &setup); + bool sendDescriptor(Setup &setup); + + // Control EndPoint API + uint32_t sendControl(const void *data, uint32_t len); + uint32_t recvControl(void *data, uint32_t len); + bool sendConfiguration(uint32_t maxlen); + bool sendStringDescriptor(const uint8_t *string, uint8_t maxlen); + + // Generic EndPoint API + void initEP(uint32_t ep, uint32_t type); + void handleEndpoint(uint8_t ep); + + uint32_t send(uint32_t ep, const void *data, uint32_t len); + void sendZlp(uint32_t ep); + uint32_t recv(uint32_t ep, void *data, uint32_t len); + uint32_t recv(uint32_t ep); + uint32_t available(uint32_t ep); + void flush(uint32_t ep); + void stall(uint32_t ep); + + // private? + uint32_t armSend(uint32_t ep, const void *data, uint32_t len); + uint8_t armRecv(uint32_t ep, uint32_t len); + uint8_t armRecvCtrlOUT(uint32_t ep, uint32_t len); + + void ISRHandler(); + +private: + bool initialized; }; -extern USBDevice_ USBDevice; -//================================================================================ +extern USBDeviceClass USBDevice; + //================================================================================ // Serial over CDC (Serial1 is the physical port) class Serial_ : public Stream { -private: - RingBuffer *_cdc_rx_buffer; public: + Serial_(USBDeviceClass &_usb) : usb(_usb) { } void begin(uint32_t baud_count); void begin(unsigned long, uint8_t); void end(void); @@ -81,6 +121,9 @@ public: virtual size_t write(const uint8_t *buffer, size_t size); using Print::write; // pull in write(str) from Print operator bool(); +private: + USBDeviceClass &usb; + RingBuffer *_cdc_rx_buffer; }; extern Serial_ SerialUSB; @@ -175,26 +218,12 @@ public: }; extern Keyboard_ Keyboard; -//================================================================================ -//================================================================================ -// Low level API - -typedef struct -{ - uint8_t bmRequestType; - uint8_t bRequest; - uint8_t wValueL; - uint8_t wValueH; - uint16_t wIndex; - uint16_t wLength; -} Setup; - //================================================================================ //================================================================================ // HID 'Driver' -const void* WEAK HID_GetInterface(void); -uint32_t WEAK HID_GetInterfaceLength(void); +const void* HID_GetInterface(void); +uint32_t HID_GetInterfaceLength(void); uint32_t HID_SizeReportDescriptor(void); uint32_t HID_GetDescriptor(void); @@ -215,26 +244,9 @@ bool MSC_Data(uint8_t rx,uint8_t tx); // CDC 'Driver' const void* CDC_GetInterface(/*uint8_t* interfaceNum*/); -uint32_t WEAK CDC_GetInterfaceLength(void); +uint32_t CDC_GetInterfaceLength(void); uint32_t CDC_GetOtherInterface(uint8_t* interfaceNum); uint32_t CDC_GetDescriptor(uint32_t i); bool CDC_Setup(Setup& setup); -//================================================================================ -//================================================================================ - -uint32_t USBD_SendControl(uint8_t flags, const void* d, uint32_t len); -uint32_t USBD_RecvControl(void* d, uint32_t len); -uint32_t USBD_SendInterfaces(void); -bool USBD_ClassInterfaceRequest(Setup& setup); - -uint32_t USBD_Available(uint32_t ep); -uint32_t USBD_SendSpace(uint32_t ep); -uint32_t USBD_Send(uint32_t ep, const void* d, uint32_t len); -uint32_t USBD_Recv(uint32_t ep, void* data, uint32_t len); // non-blocking -uint32_t USBD_Recv(uint32_t ep); // non-blocking -void USBD_Flush(uint32_t ep); -uint32_t USBD_Connected(void); - #endif // __cplusplus -#endif // __USBAPI__ diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index 31b8380a..cfcf101a 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2015 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,14 +16,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "../Arduino.h" -#include "USBCore.h" -#include "USB/USB_device.h" // needed for USB PID define -#include "USBDesc.h" -#include "USBAPI.h" +#include <Arduino.h> -//#define TRACE_CORE(x) x -#define TRACE_CORE(x) +#include "SAMD21_USBDevice.h" + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> + +USBDevice_SAMD21G18x usbd; static char isRemoteWakeUpEnabled = 0; static char isEndpointHalt = 0; @@ -50,184 +51,56 @@ const uint8_t STRING_PRODUCT[] = USB_PRODUCT; # define USB_MANUFACTURER "Unknown" #endif -const uint8_t STRING_MANUFACTURER[12] = USB_MANUFACTURER; +const uint8_t STRING_MANUFACTURER[] = USB_MANUFACTURER; // DEVICE DESCRIPTOR #if (defined CDC_ENABLED) && defined(HID_ENABLED) -const DeviceDescriptor USB_DeviceDescriptor = - D_DEVICE(0xEF,0x02,0x01,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); +const DeviceDescriptor USB_DeviceDescriptor = D_DEVICE(0xEF, 0x02, 0x01, 64, USB_VID, USB_PID, 0x100, IMANUFACTURER, IPRODUCT, 0, 1); #elif defined(CDC_ENABLED) // CDC only -const DeviceDescriptor USB_DeviceDescriptor = - D_DEVICE(0x02,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); +const DeviceDescriptor USB_DeviceDescriptor = D_DEVICE(0x02, 0x00, 0x00, 64, USB_VID, USB_PID, 0x100, IMANUFACTURER, IPRODUCT, 0, 1); #else // HID only -const DeviceDescriptor USB_DeviceDescriptor = - D_DEVICE(0,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); +const DeviceDescriptor USB_DeviceDescriptor = D_DEVICE(0x00, 0x00, 0x00, 64, USB_VID, USB_PID, 0x100, IMANUFACTURER, IPRODUCT, 0, 1); #endif //================================================================== volatile uint32_t _usbConfiguration = 0; -volatile uint32_t _usbInitialized = 0; volatile uint32_t _usbSetInterface = 0; -//================================================================== - - -// Number of bytes, assumes a rx endpoint -uint32_t USBD_Available(uint32_t ep) -{ - return UDD_FifoByteCount(ep); -} - -// Non Blocking receive -// Return number of bytes read -uint32_t USBD_Recv(uint32_t ep, void* d, uint32_t len) -{ - if (!_usbConfiguration) - return -1; - - uint8_t *buffer; - uint8_t *data = (uint8_t *)d; - - len = min(UDD_FifoByteCount(ep), len); - - UDD_Recv_data(ep, len); - UDD_Recv(ep, &buffer); - for (uint32_t i=0; i<len; i++) { - data[i] = buffer[i]; - } - - if (len && !UDD_FifoByteCount(ep)) // release empty buffer - UDD_ReleaseRX(ep); - - return len; -} +static __attribute__((__aligned__(4))) /*__attribute__((__section__(".bss_hram0")))*/ +uint8_t udd_ep_out_cache_buffer[4][64]; -// Recv 1 byte if ready -uint32_t USBD_Recv(uint32_t ep) -{ - uint8_t c; - if (USBD_Recv(ep, &c, 1) != 1) - return -1; - else - return c; -} +static __attribute__((__aligned__(4))) /*__attribute__((__section__(".bss_hram0")))*/ +uint8_t udd_ep_in_cache_buffer[4][128]; -// Blocking Send of data to an endpoint -uint32_t USBD_Send(uint32_t ep, const void* d, uint32_t len) -{ - int r = len; - const uint8_t* data = (const uint8_t*)d; - - if (!_usbConfiguration) - { - TRACE_CORE(printf("pb conf\n\r");) - return -1; - } - UDD_Send(ep, data, len); - - /* Clear the transfer complete flag */ - udd_clear_IN_transf_cplt(ep); - /* Set the bank as ready */ - udd_IN_transfer_allowed(ep); - - /* Wait for transfer to complete */ - while (! udd_is_IN_transf_cplt(ep)); // need fire exit. - return r; -} - -uint32_t USBD_SendControl(uint8_t flags, const void* d, uint32_t len) -{ - const uint8_t* data = (const uint8_t*)d; - uint32_t length = len; - uint32_t sent = 0; - uint32_t pos = 0; - - TRACE_CORE(printf("=> USBD_SendControl TOTAL len=%lu\r\n", len);) - - while (len > 0) - { - sent = UDD_Send(EP0, data + pos, len); - TRACE_CORE(printf("=> USBD_SendControl sent=%lu\r\n", sent);) - pos += sent; - len -= sent; - } - - return length; -} +//================================================================== // Send a USB descriptor string. The string is stored as a // plain ASCII string but is sent out as UTF-16 with the // correct 2-byte prefix -static bool USB_SendStringDescriptor(const uint8_t *string, int wLength) +bool USBDeviceClass::sendStringDescriptor(const uint8_t *string, uint8_t maxlen) { - uint16_t buff[64]; + if (maxlen < 2) + return false; + + uint16_t buff[maxlen/2]; int l = 1; - wLength -= 2; - while (*string && wLength>0) + maxlen -= 2; + while (*string && maxlen>0) { buff[l++] = (uint8_t)(*string++); - wLength -= 2; + maxlen -= 2; } buff[0] = (3<<8) | (l*2); - return USBD_SendControl(0, (uint8_t*)buff, l*2); + return USBDevice.sendControl((uint8_t*)buff, l*2); } -uint32_t USBD_RecvControl(void* d, uint32_t len) -{ - uint8_t *buffer; - uint8_t *data = (uint8_t *)d; - uint32_t read = UDD_Recv_data(EP0, len); - if (read > len) - read = len; - UDD_Recv(EP0, &buffer); - while (!udd_is_OUT_transf_cplt(EP0)); - for (uint32_t i=0; i<read; i++) { - data[i] = buffer[i]; - } - udd_OUT_transfer_allowed(EP0); - return read; -} - -// Handle CLASS_INTERFACE requests -bool USBD_ClassInterfaceRequest(Setup& setup) -{ - uint8_t i = setup.wIndex; - - TRACE_CORE(printf("=> USBD_ClassInterfaceRequest\r\n");) - -#ifdef CDC_ENABLED - if (CDC_ACM_INTERFACE == i) - { - if( CDC_Setup(setup) == false ) - { - send_zlp(); - } - return true; - } -#endif - -#ifdef HID_ENABLED - if (HID_INTERFACE == i) - { - if( HID_Setup(setup) == true ) - { - send_zlp(); - } - return true; - } -#endif - - return false; -} - -// Construct a dynamic configuration descriptor -// This really needs dynamic endpoint allocation etc -// TODO -static bool USBD_SendConfiguration(uint32_t maxlen) +// Construct a dynamic configuration descriptor +// This really needs dynamic endpoint allocation etc +bool USBDeviceClass::sendConfiguration(uint32_t maxlen) { uint8_t cache_buffer[128]; uint8_t i; @@ -238,494 +111,728 @@ static bool USBD_SendConfiguration(uint32_t maxlen) num_interfaces[0] = 0; -#if (defined CDC_ENABLED) && defined(HID_ENABLED) - num_interfaces[0] += 3; - interfaces = (const uint8_t*) CDC_GetInterface(); - interfaces_length = CDC_GetInterfaceLength() + HID_GetInterfaceLength(); - if( maxlen > CDC_GetInterfaceLength() + HID_GetInterfaceLength() + sizeof(ConfigDescriptor) ) - { - maxlen = CDC_GetInterfaceLength() + HID_GetInterfaceLength() + sizeof(ConfigDescriptor); - } - -#else -#ifdef CDC_ENABLED - num_interfaces[0] += 2; +#if defined(CDC_ENABLED) && defined(HID_ENABLED) + num_interfaces[0] += 3; + interfaces = (const uint8_t*) CDC_GetInterface(); + interfaces_length = CDC_GetInterfaceLength() + HID_GetInterfaceLength(); + if (maxlen > CDC_GetInterfaceLength() + HID_GetInterfaceLength() + sizeof(ConfigDescriptor)) + { + maxlen = CDC_GetInterfaceLength() + HID_GetInterfaceLength() + sizeof(ConfigDescriptor); + } +#elif defined(CDC_ENABLED) + num_interfaces[0] += 2; interfaces = (const uint8_t*) CDC_GetInterface(); interfaces_length += CDC_GetInterfaceLength(); - if( maxlen > CDC_GetInterfaceLength()+ sizeof(ConfigDescriptor) ) + if (maxlen > CDC_GetInterfaceLength() + sizeof(ConfigDescriptor)) { - maxlen = CDC_GetInterfaceLength()+ sizeof(ConfigDescriptor); + maxlen = CDC_GetInterfaceLength() + sizeof(ConfigDescriptor); } -#endif - -#ifdef HID_ENABLED - num_interfaces[0] += 1; +#elif defined(HID_ENABLED) + num_interfaces[0] += 1; interfaces = (const uint8_t*) HID_GetInterface(); interfaces_length += HID_GetInterfaceLength(); - if( maxlen > HID_GetInterfaceLength()+ sizeof(ConfigDescriptor) ) + if (maxlen > HID_GetInterfaceLength() + sizeof(ConfigDescriptor)) { - maxlen = HID_GetInterfaceLength()+ sizeof(ConfigDescriptor); + maxlen = HID_GetInterfaceLength() + sizeof(ConfigDescriptor); } #endif -#endif _Pragma("pack(1)") - ConfigDescriptor config = D_CONFIG((uint16_t)(interfaces_length + sizeof(ConfigDescriptor)),num_interfaces[0]); + ConfigDescriptor config = D_CONFIG((uint16_t)(interfaces_length + sizeof(ConfigDescriptor)), num_interfaces[0]); _Pragma("pack()") - memcpy( cache_buffer, &config, sizeof(ConfigDescriptor) ); + memcpy(cache_buffer, &config, sizeof(ConfigDescriptor)); -#if (defined CDC_ENABLED) && defined(HID_ENABLED) - for ( i=0; i<CDC_GetInterfaceLength(); i++) - { - cache_buffer[i+sizeof(ConfigDescriptor)] = interfaces[i]; +#if defined(CDC_ENABLED) && defined(HID_ENABLED) + for (i=0; i<CDC_GetInterfaceLength(); i++) { + cache_buffer[i + sizeof(ConfigDescriptor)] = interfaces[i]; } interfaces = (const uint8_t*) HID_GetInterface(); - for ( i=0; i<HID_GetInterfaceLength(); i++) - { - cache_buffer[i+sizeof(ConfigDescriptor)+CDC_GetInterfaceLength()] = interfaces[i]; + for (i=0; i<HID_GetInterfaceLength(); i++) { + cache_buffer[i + sizeof(ConfigDescriptor) + CDC_GetInterfaceLength()] = interfaces[i]; } -#else -#ifdef HID_ENABLED - for ( i=0; i<interfaces_length; i++) - { - cache_buffer[i+sizeof(ConfigDescriptor)] = interfaces[i]; +#elif defined(HID_ENABLED) + for (i=0; i<interfaces_length; i++) { + cache_buffer[i + sizeof(ConfigDescriptor)] = interfaces[i]; } -#endif - -#ifdef CDC_ENABLED - for ( i=0; i<interfaces_length; i++) - { - cache_buffer[i+sizeof(ConfigDescriptor)] = interfaces[i]; +#elif defined(CDC_ENABLED) + for (i=0; i<interfaces_length; i++) { + cache_buffer[i + sizeof(ConfigDescriptor)] = interfaces[i]; } -#endif #endif - if (maxlen > sizeof(cache_buffer)) - { + if (maxlen > sizeof(cache_buffer)) { maxlen = sizeof(cache_buffer); } - USBD_SendControl(0,cache_buffer, maxlen ); - return true; + return sendControl(cache_buffer, maxlen); } -static bool USBD_SendDescriptor(Setup* pSetup) +bool USBDeviceClass::sendDescriptor(Setup &setup) { - uint8_t t = pSetup->wValueH; + uint8_t t = setup.wValueH; uint8_t desc_length = 0; - const uint8_t* desc_addr = 0; + const uint8_t *desc_addr = 0; - if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) + if (t == USB_CONFIGURATION_DESCRIPTOR_TYPE) { - TRACE_CORE(printf("=> USBD_SendDescriptor : USB_CONFIGURATION_DESCRIPTOR_TYPE length=%d\r\n", setup.wLength);) - return USBD_SendConfiguration(pSetup->wLength); + return USBDevice.sendConfiguration(setup.wLength); } -#ifdef HID_ENABLED - if (HID_REPORT_DESCRIPTOR_TYPE == t) +#if defined(HID_ENABLED) + if (t == HID_REPORT_DESCRIPTOR_TYPE) { - TRACE_CORE(puts("=> USBD_SendDescriptor : HID_REPORT_DESCRIPTOR_TYPE\r\n");) return HID_GetDescriptor(); } - if (HID_HID_DESCRIPTOR_TYPE == t) + + if (t == HID_HID_DESCRIPTOR_TYPE) { uint8_t tab[9] = D_HIDREPORT((uint8_t)HID_SizeReportDescriptor()); - - TRACE_CORE(puts("=> USBD_SendDescriptor : HID_HID_DESCRIPTOR_TYPE\r\n");) - - return USBD_SendControl(0, tab, sizeof(tab)); + return USBDevice.sendControl(tab, sizeof(tab)); } #endif - if (USB_DEVICE_DESCRIPTOR_TYPE == t) + if (t == USB_DEVICE_DESCRIPTOR_TYPE) { - TRACE_CORE(puts("=> USBD_SendDescriptor : USB_DEVICE_DESCRIPTOR_TYPE\r\n");) desc_addr = (const uint8_t*)&USB_DeviceDescriptor; - if( *desc_addr > pSetup->wLength ) { - desc_length = pSetup->wLength; - } + if (*desc_addr > setup.wLength) { + desc_length = setup.wLength; + } } else if (USB_STRING_DESCRIPTOR_TYPE == t) { - TRACE_CORE(puts("=> USBD_SendDescriptor : USB_STRING_DESCRIPTOR_TYPE\r\n");) - if (pSetup->wValueL == 0) { + if (setup.wValueL == 0) { desc_addr = (const uint8_t*)&STRING_LANGUAGE; } - else if (pSetup->wValueL == IPRODUCT) { - return USB_SendStringDescriptor(STRING_PRODUCT, pSetup->wLength); + else if (setup.wValueL == IPRODUCT) { + return sendStringDescriptor(STRING_PRODUCT, setup.wLength); } - else if (pSetup->wValueL == IMANUFACTURER) { - return USB_SendStringDescriptor(STRING_MANUFACTURER, pSetup->wLength); + else if (setup.wValueL == IMANUFACTURER) { + return sendStringDescriptor(STRING_MANUFACTURER, setup.wLength); } else { return false; } - if( *desc_addr > pSetup->wLength ) { - desc_length = pSetup->wLength; + if (*desc_addr > setup.wLength) { + desc_length = setup.wLength; } } - else - { - TRACE_CORE(printf("Device ERROR");) - } - - if (desc_addr == 0) + else { + } + + if (desc_addr == 0) { return false; } - if (desc_length == 0) - { + if (desc_length == 0) { desc_length = *desc_addr; } - TRACE_CORE(printf("=> USBD_SendDescriptor : desc_addr=%p desc_length=%d\r\n", desc_addr, desc_length);) - USBD_SendControl(0, desc_addr, desc_length); + sendControl(desc_addr, desc_length); return true; } -void EndpointHandler(uint8_t bEndpoint) +void USBDeviceClass::handleEndpoint(uint8_t ep) { -#ifdef CDC_ENABLED - if( bEndpoint == CDC_ENDPOINT_OUT ) +#if defined(CDC_ENABLED) + if (ep == CDC_ENDPOINT_OUT) { - udd_OUT_transfer_allowed(CDC_ENDPOINT_OUT); + // The RAM Buffer is empty: we can receive data + //usbd.epBank0ResetReady(CDC_ENDPOINT_OUT); // Handle received bytes - if (USBD_Available(CDC_ENDPOINT_OUT)) - { + if (available(CDC_ENDPOINT_OUT)) SerialUSB.accept(); - } } - if( bEndpoint == CDC_ENDPOINT_IN ) + if (ep == CDC_ENDPOINT_IN) { - udd_IN_stop_transfer(CDC_ENDPOINT_IN); - /* Clear the transfer complete flag */ - udd_clear_IN_transf_cplt(CDC_ENDPOINT_IN); - + // NAK on endpoint IN, the bank is not yet filled in. + usbd.epBank1ResetReady(CDC_ENDPOINT_IN); + usbd.epBank1AckTransferComplete(CDC_ENDPOINT_IN); } - if( bEndpoint == CDC_ENDPOINT_ACM ) + if (ep == CDC_ENDPOINT_ACM) { - udd_IN_stop_transfer(CDC_ENDPOINT_ACM); - /* Clear the transfer complete flag */ - udd_clear_IN_transf_cplt(CDC_ENDPOINT_ACM); + // NAK on endpoint IN, the bank is not yet filled in. + usbd.epBank1ResetReady(CDC_ENDPOINT_ACM); + usbd.epBank1AckTransferComplete(CDC_ENDPOINT_ACM); } #endif -#ifdef HID_ENABLED - /* Nothing to do in our example */ +#if defined(HID_ENABLED) + // Empty #endif } +void USBDeviceClass::init() +{ + // Enable USB clock + PM->APBBMASK.reg |= PM_APBBMASK_USB; + + // Set up the USB DP/DN pins + PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; + PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); + PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); + PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; + PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); + PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); + + // Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference) + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(6) | // Generic Clock Multiplexer 6 + GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source + GCLK_CLKCTRL_CLKEN; + while (GCLK->STATUS.bit.SYNCBUSY) + ; + + // Reset USB Device + usbd.reset(); + + usbd.calibrate(); + usbd.setUSBDeviceMode(); + usbd.runInStandby(); + usbd.setFullSpeed(); + + // Configure interrupts + NVIC_SetPriority((IRQn_Type) USB_IRQn, 0UL); + NVIC_EnableIRQ((IRQn_Type) USB_IRQn); + + usbd.enable(); + + initialized = true; +} -void USB_ISR(void) +bool USBDeviceClass::attach() { - uint16_t flags; - uint8_t i; - uint8_t ept_int; + if (!initialized) + return false; - ept_int = udd_endpoint_interrupt(); + usbd.attach(); + usbd.enableEndOfResetInterrupt(); + usbd.enableStartOfFrameInterrupt(); - /* Not endpoint interrupt */ - if (0 == ept_int) - { - udd_clear_wakeup_interrupt(); - udd_clear_eorsm_interrupt(); - udd_clear_suspend_interrupt(); + _usbConfiguration = 0; + return true; +} - // End of bus reset - if (Is_udd_reset()) - { - TRACE_CORE(printf(">>> End of Reset\r\n");) - // Reset USB address to 0 - udd_configure_address(0); - - // Configure EP 0 - UDD_InitEP(0, USB_ENDPOINT_TYPE_CONTROL); - udd_enable_setup_received_interrupt(0); - _usbConfiguration = 0; - udd_ack_reset(); +void USBDeviceClass::setAddress(uint32_t addr) +{ + usbd.epBank1SetByteCount(0, 0); + usbd.epBank1AckTransferComplete(0); + + // RAM buffer is full, we can send data (IN) + usbd.epBank1SetReady(0); + + // Wait for transfer to complete + while (!usbd.epBank1IsTransferComplete(0)) {} + + // Set USB address to addr + USB->DEVICE.DADD.bit.DADD = addr; // Address + USB->DEVICE.DADD.bit.ADDEN = 1; // Enable +} + +bool USBDeviceClass::detach() +{ + if (!initialized) + return false; + usbd.detach(); + return true; +} + +bool USBDeviceClass::configured() +{ + return _usbConfiguration != 0; +} + +bool USBDeviceClass::handleClassInterfaceSetup(Setup& setup) +{ + uint8_t i = setup.wIndex; + + #if defined(CDC_ENABLED) + if (CDC_ACM_INTERFACE == i) + { + if (CDC_Setup(setup) == false) { + sendZlp(0); } + return true; + } + #endif - if (Is_udd_sof()) - { - udd_ack_sof(); + #if defined(HID_ENABLED) + if (HID_INTERFACE == i) + { + if (HID_Setup(setup) == true) { + sendZlp(0); } + return true; + } + #endif + return false; +} + +void USBDeviceClass::initEP(uint32_t ep, uint32_t config) +{ + if (config == (USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0))) + { + usbd.epBank1SetSize(ep, 8); + usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[ep]); + usbd.epBank1SetType(ep, 4); // INTERRUPT IN } - else + else if (config == (USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0))) { - // Endpoint interrupt - flags = udd_read_endpoint_flag(0); + usbd.epBank0SetSize(ep, 64); + usbd.epBank0SetAddress(ep, &udd_ep_out_cache_buffer[ep]); + usbd.epBank0SetType(ep, 3); // BULK OUT + + // Release OUT EP + usbd.epBank0SetMultiPacketSize(ep, 64); + usbd.epBank0SetByteCount(ep, 0); + + // The RAM Buffer is empty: we can receive data + //usbd.epBank0ResetReady(ep); + } + else if (config == (USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0))) + { + usbd.epBank1SetSize(ep, 64); + usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[ep]); - // endpoint received setup interrupt - if (flags & USB_DEVICE_EPINTFLAG_RXSTP) - { - Setup *pSetupData; + // NAK on endpoint IN, the bank is not yet filled in. + usbd.epBank1ResetReady(ep); - /* Clear the Received Setup flag */ - udd_read_endpoint_flag(0) = USB_DEVICE_EPINTFLAG_RXSTP; + usbd.epBank1SetType(ep, 3); // BULK IN + } + else if (config == USB_ENDPOINT_TYPE_CONTROL) + { + // XXX: Needed? + usbd.epBank0DisableAutoZLP(ep); + usbd.epBank1DisableAutoZLP(ep); + + // Setup Control OUT + usbd.epBank0SetSize(ep, 64); + usbd.epBank0SetAddress(ep, &udd_ep_out_cache_buffer[0]); + usbd.epBank0SetType(ep, 1); // CONTROL OUT / SETUP + + // Setup Control IN + usbd.epBank1SetSize(ep, 64); + usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[0]); + usbd.epBank1SetType(ep, 1); // CONTROL IN + + // Release OUT EP + usbd.epBank0SetMultiPacketSize(ep, 64); + usbd.epBank0SetByteCount(ep, 0); + + // NAK on endpoint OUT, the bank is full. + usbd.epBank0SetReady(ep); + // NAK on endpoint IN, the bank is not yet filled in. + //usbd.epBank1ResetReady(ep); + } +} - UDD_Recv(EP0, (uint8_t**)&pSetupData); +void USBDeviceClass::flush(uint32_t ep) +{ + if (available(ep)) { + // RAM buffer is full, we can send data (IN) + usbd.epBank1SetReady(ep); - /* Clear the Bank 0 ready flag on Control OUT */ - udd_OUT_transfer_allowed(0); + // Clear the transfer complete flag + usbd.epBank1AckTransferComplete(ep); + } +} - bool ok = true; - if (REQUEST_STANDARD == (pSetupData->bmRequestType & REQUEST_TYPE)) - { - unsigned char data_to_be_send[2]; - - // Standard Requests - uint8_t r = pSetupData->bRequest; - if (GET_STATUS == r) - { - if( pSetupData->bmRequestType == 0 ) // device - { - // Send the device status - TRACE_CORE(puts(">>> EP0 Int: GET_STATUS\r\n");) - // Check current configuration for power mode (if device is configured) - // TODO - // Check if remote wake-up is enabled - // TODO - data_to_be_send[0]=0; - data_to_be_send[1]=0; - UDD_Send(0, data_to_be_send, 2); - } - // if( pSetupData->bmRequestType == 2 ) // Endpoint: - else - { - // Send the endpoint status - // Check if the endpoint if currently halted - if( isEndpointHalt == 1 ) - data_to_be_send[0]=1; - else - data_to_be_send[0]=0; - data_to_be_send[1]=0; - UDD_Send(0, data_to_be_send, 2); - } - } - else if (CLEAR_FEATURE == r) - { - // Check which is the selected feature - if( pSetupData->wValueL == 1) // DEVICEREMOTEWAKEUP - { - // Enable remote wake-up and send a ZLP - if( isRemoteWakeUpEnabled == 1 ) - data_to_be_send[0]=1; - else - data_to_be_send[0]=0; - data_to_be_send[1]=0; - UDD_Send(0, data_to_be_send, 2); - } - else // if( pSetupData->wValueL == 0) // ENDPOINTHALT - { - isEndpointHalt = 0; - send_zlp(); - } - } - else if (SET_FEATURE == r) - { - // Check which is the selected feature - if( pSetupData->wValueL == 1) // DEVICEREMOTEWAKEUP - { - // Enable remote wake-up and send a ZLP - isRemoteWakeUpEnabled = 1; - data_to_be_send[0] = 0; - UDD_Send(0, data_to_be_send, 1); - } - if( pSetupData->wValueL == 0) // ENDPOINTHALT - { - // Halt endpoint - isEndpointHalt = 1; - send_zlp(); - } - } - else if (SET_ADDRESS == r) - { - TRACE_CORE(puts(">>> EP0 Int: SET_ADDRESS\r\n");) - UDD_SetAddress(pSetupData->wValueL); - } - else if (GET_DESCRIPTOR == r) - { - TRACE_CORE(puts(">>> EP0 Int: GET_DESCRIPTOR\r\n");) - ok = USBD_SendDescriptor(pSetupData); - } - else if (SET_DESCRIPTOR == r) - { - TRACE_CORE(puts(">>> EP0 Int: SET_DESCRIPTOR\r\n");) - ok = false; - } - else if (GET_CONFIGURATION == r) - { - TRACE_CORE(puts(">>> EP0 Int: GET_CONFIGURATION\r\n");) - UDD_Send(0, (void*)&_usbConfiguration, 1); - } - else if (SET_CONFIGURATION == r) - { - if (REQUEST_DEVICE == (pSetupData->bmRequestType & REQUEST_RECIPIENT)) - { - TRACE_CORE(printf(">>> EP0 Int: SET_CONFIGURATION REQUEST_DEVICE %d\r\n", pSetupData->wValueL);) -#ifdef HID_ENABLED - UDD_InitEP( HID_ENDPOINT_INT, USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)); -#endif +void USBDeviceClass::stall(uint32_t ep) +{ + // TODO: test + // TODO: use .bit. notation -#ifdef CDC_ENABLED - UDD_InitEP( CDC_ENDPOINT_ACM, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0)); - UDD_InitEP( CDC_ENDPOINT_OUT, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0)); - UDD_InitEP( CDC_ENDPOINT_IN, USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)); -#endif - _usbConfiguration = pSetupData->wValueL; + // Stall endpoint + USB->DEVICE.DeviceEndpoint[ep].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ(2); +} -#ifdef CDC_ENABLED - // Enable interrupt for CDC reception from host (OUT packet) - udd_ept_enable_it_IN_transf_cplt(CDC_ENDPOINT_ACM); - udd_ept_enable_it_OUT_transf_cplt(CDC_ENDPOINT_OUT); -#endif - send_zlp(); - } - else - { - TRACE_CORE(puts(">>> EP0 Int: SET_CONFIGURATION failed!\r\n");) - ok = false; - } - } - else if (GET_INTERFACE == r) - { - TRACE_CORE(puts(">>> EP0 Int: GET_INTERFACE\r\n");) - UDD_Send(0, (void*)&_usbSetInterface, 1); - } - else if (SET_INTERFACE == r) - { - _usbSetInterface = pSetupData->wValueL; - TRACE_CORE(puts(">>> EP0 Int: SET_INTERFACE\r\n");) - send_zlp(); - } - } - else - { - TRACE_CORE(puts(">>> EP0 Int: ClassInterfaceRequest\r\n");) - ok = USBD_ClassInterfaceRequest(*pSetupData); - } +bool USBDeviceClass::connected() +{ + // Count frame numbers + uint8_t f = USB->DEVICE.FNUM.bit.FNUM; + //delay(3); + return f != USB->DEVICE.FNUM.bit.FNUM; +} - if (ok) - { - TRACE_CORE(puts(">>> EP0 Int: Send packet\r\n");) - UDD_ClearIN(); - } - else - { - TRACE_CORE(puts(">>> EP0 Int: Stall\r\n");) - UDD_Stall(0); - } - if( flags & USB_DEVICE_EPINTFLAG_STALL(2) ) - { - /* Clear the stall flag */ - udd_clear_stall_request(0); +uint32_t USBDeviceClass::recvControl(void *_data, uint32_t len) +{ + uint8_t *data = reinterpret_cast<uint8_t *>(_data); +// NO RXOUT ??????? - // Remove stall request - udd_remove_stall_request(0); - } - } // end if USB_DEVICE_EPINTFLAG_RXSTP + // The RAM Buffer is empty: we can receive data + usbd.epBank0ResetReady(0); - i=0; - ept_int &= 0xFE; // Remove endpoint number 0 (setup) - while (ept_int != 0) - { - // Check if endpoint has a pending interrupt - if ((ept_int & (1 << i)) != 0) - { - if( (udd_read_endpoint_flag(i) & USB_DEVICE_EPINTFLAG_TRCPT_Msk ) != 0 ) + //usbd.epBank0AckSetupReceived(0); + uint32_t read = armRecvCtrlOUT(0, len); + if (read > len) + read = len; + //while (!usbd.epBank0AckTransferComplete(0)) {} + uint8_t *buffer = udd_ep_out_cache_buffer[0]; + for (uint32_t i=0; i<len; i++) { + data[i] = buffer[i]; + } + + return read; +} + +// Number of bytes, assumes a rx endpoint +uint32_t USBDeviceClass::available(uint32_t ep) +{ + return usbd.epBank0ByteCount(ep); +} + +// Non Blocking receive +// Return number of bytes read +uint32_t USBDeviceClass::recv(uint32_t ep, void *_data, uint32_t len) +{ + if (!_usbConfiguration) + return -1; + + if (available(ep) < len) + len = available(ep); + + armRecv(ep, len); - { - EndpointHandler(i); - } - ept_int &= ~(1 << i); + usbd.epBank0DisableTransferComplete(ep); - if (ept_int != 0) - { + // NAK on endpoint OUT, the bank is full. + //usbd.epBank0SetReady(CDC_ENDPOINT_OUT); - TRACE_CORE("\n\r - "); - } - } - i++; - if( i> USB_EPT_NUM) break; // fire exit - } + uint8_t *buffer = udd_ep_out_cache_buffer[ep]; + uint8_t *data = reinterpret_cast<uint8_t *>(_data); + for (uint32_t i=0; i<len; i++) { + data[i] = buffer[i]; } + + // release empty buffer + if (len && !available(ep)) { + // The RAM Buffer is empty: we can receive data + usbd.epBank0ResetReady(ep); + + // Clear Transfer complete 0 flag + usbd.epBank0AckTransferComplete(ep); + } + + return len; } +// Recv 1 byte if ready +uint32_t USBDeviceClass::recv(uint32_t ep) +{ + uint8_t c; + if (recv(ep, &c, 1) != 1) { + return -1; + } else { + return c; + } +} +uint8_t USBDeviceClass::armRecvCtrlOUT(uint32_t ep, uint32_t len) +{ + /* get endpoint configuration from setting register */ + usbd.epBank0SetAddress(ep, &udd_ep_out_cache_buffer[ep]); + usbd.epBank0SetMultiPacketSize(ep, 8); + usbd.epBank0SetByteCount(ep, 0); + //usbd.epBank0ResetReady(0); + //while (!usbd.epBank0IsTransferComplete(ep)) {} + //while (usbd.epBank0IsReady(ep)) {} + + //usbd.epBank0SetByteCount(0, 0); + //usbd.epBank0SetMultiPacketSize(0, 8); + usbd.epBank0ResetReady(ep); + + // Wait OUT + while (!usbd.epBank0IsReady(ep)) {} + while (!usbd.epBank0IsTransferComplete(ep)) {} // XXX: while(USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT == 0); + return usbd.epBank0ByteCount(ep); +} -void USBD_Flush(uint32_t ep) +uint8_t USBDeviceClass::armRecv(uint32_t ep, uint32_t len) { - if (UDD_FifoByteCount(ep)) - { - UDD_ReleaseTX(ep); + usbd.epBank0SetSize(ep, 64); + usbd.epBank0SetAddress(ep, &udd_ep_out_cache_buffer[ep]); + usbd.epBank0SetMultiPacketSize(ep, 64); // XXX: Should be "len"? + uint16_t count = usbd.epBank0ByteCount(ep); + if (count >= 64) { + usbd.epBank0SetByteCount(ep, count - 64); + } else { + usbd.epBank0SetByteCount(ep, 0); } + // The RAM Buffer is empty: we can receive data + //usbd.epBank0ResetReady(ep); + + // Wait for transfer to complete + //while (!usbd.epBank0IsTransferComplete(ep)) {} + //while (usbd.epBank0IsReady(ep)) {} + // NAK on endpoint OUT, the bank is full. + //usbd.epBank0ResetReady(ep); + + return usbd.epBank0ByteCount(ep); } -// Counting frames -uint32_t USBD_Connected(void) +// Blocking Send of data to an endpoint +uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len) { - uint8_t f = UDD_GetFrameNumber(); + if (!_usbConfiguration) + return -1; + + armSend(ep, data, len); + + // Clear the transfer complete flag + usbd.epBank1AckTransferComplete(ep); - //delay(3); + // RAM buffer is full, we can send data (IN) + usbd.epBank1SetReady(ep); - return f != UDD_GetFrameNumber(); + // Wait for transfer to complete + while (!usbd.epBank1IsTransferComplete(ep)) { + ; // need fire exit. + } + return len; } +uint32_t USBDeviceClass::armSend(uint32_t ep, const void* data, uint32_t len) +{ + memcpy(&udd_ep_in_cache_buffer[ep], data, len); -//======================================================================= -//======================================================================= + // Get endpoint configuration from setting register + usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[ep]); + usbd.epBank1SetMultiPacketSize(ep, 0); + usbd.epBank1SetByteCount(ep, len); -USBDevice_ USBDevice; + return len; +} -USBDevice_::USBDevice_() +uint32_t USBDeviceClass::sendControl(const void* _data, uint32_t len) { - UDD_SetStack(&USB_ISR); + const uint8_t *data = reinterpret_cast<const uint8_t *>(_data); + uint32_t length = len; + uint32_t sent = 0; + uint32_t pos = 0; + + while (len > 0) + { + sent = armSend(EP0, data + pos, len); + pos += sent; + len -= sent; + } + + return length; } -bool USBDevice_::attach() +void USBDeviceClass::sendZlp(uint32_t ep) { - if (_usbInitialized != 0UL) - { - UDD_Attach(); - _usbConfiguration = 0; - return true; - } - else - { - return false; - } + // Set the byte count as zero + usbd.epBank1SetByteCount(ep, 0); } -bool USBDevice_::detach() +bool USBDeviceClass::handleStandardSetup(Setup &setup) { - if (_usbInitialized != 0UL) - { - UDD_Detach(); + switch (setup.bRequest) { + case GET_STATUS: + if (setup.bmRequestType == 0) // device + { + // Send the device status + // TODO: Check current configuration for power mode (if device is configured) + // TODO: Check if remote wake-up is enabled + uint8_t buff[] = { 0, 0 }; + armSend(0, buff, 2); + return true; + } + // if( setup.bmRequestType == 2 ) // Endpoint: + else + { + // Send the endpoint status + // Check if the endpoint if currently halted + uint8_t buff[] = { 0, 0 }; + if (isEndpointHalt == 1) + buff[0] = 1; + armSend(0, buff, 2); + return true; + } + + case CLEAR_FEATURE: + // Check which is the selected feature + if (setup.wValueL == 1) // DEVICEREMOTEWAKEUP + { + // Enable remote wake-up and send a ZLP + uint8_t buff[] = { 0, 0 }; + if (isRemoteWakeUpEnabled == 1) + buff[0] = 1; + armSend(0, buff, 2); + return true; + } + else // if( setup.wValueL == 0) // ENDPOINTHALT + { + isEndpointHalt = 0; + sendZlp(0); + return true; + } + + case SET_FEATURE: + // Check which is the selected feature + if (setup.wValueL == 1) // DEVICEREMOTEWAKEUP + { + // Enable remote wake-up and send a ZLP + isRemoteWakeUpEnabled = 1; + uint8_t buff[] = { 0 }; + armSend(0, buff, 1); + return true; + } + if (setup.wValueL == 0) // ENDPOINTHALT + { + // Halt endpoint + isEndpointHalt = 1; + sendZlp(0); + return true; + } + + case SET_ADDRESS: + setAddress(setup.wValueL); return true; - } - else - { + + case GET_DESCRIPTOR: + return sendDescriptor(setup); + + case SET_DESCRIPTOR: return false; + + case GET_CONFIGURATION: + armSend(0, (void*)&_usbConfiguration, 1); + return true; + + case SET_CONFIGURATION: + if (REQUEST_DEVICE == (setup.bmRequestType & REQUEST_RECIPIENT)) { + #if defined(HID_ENABLED) + initEP(HID_ENDPOINT_INT, USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)); + #endif + + #if defined(CDC_ENABLED) + initEP(CDC_ENDPOINT_ACM, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0)); + initEP(CDC_ENDPOINT_OUT, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0)); + initEP(CDC_ENDPOINT_IN, USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)); + #endif + _usbConfiguration = setup.wValueL; + + #if defined(CDC_ENABLED) + // Enable interrupt for CDC reception from host (OUT packet) + usbd.epBank1EnableTransferComplete(CDC_ENDPOINT_ACM); + usbd.epBank0EnableTransferComplete(CDC_ENDPOINT_OUT); + #endif + + sendZlp(0); + return true; + } else { + return false; + } + + case GET_INTERFACE: + armSend(0, (void*)&_usbSetInterface, 1); + return true; + + case SET_INTERFACE: + _usbSetInterface = setup.wValueL; + sendZlp(0); + return true; + + default: + return true; } } -bool USBDevice_::configured() +void USBDeviceClass::ISRHandler() { - return _usbConfiguration; -} + // End-Of-Reset + if (usbd.isEndOfResetInterrupt()) + { + // Configure EP 0 + initEP(0, USB_ENDPOINT_TYPE_CONTROL); -void USBDevice_::poll() -{ + // Enable Setup-Received interrupt + usbd.epBank0EnableSetupReceived(0); + + _usbConfiguration = 0; + + usbd.ackEndOfResetInterrupt(); + } + + // Start-Of-Frame + if (usbd.isStartOfFrameInterrupt()) + { + usbd.ackStartOfFrameInterrupt(); + } + + // Endpoint 0 Received Setup interrupt + if (usbd.epBank0IsSetupReceived(0)) + { + usbd.epBank0AckSetupReceived(0); + + Setup *setup = reinterpret_cast<Setup *>(udd_ep_out_cache_buffer[0]); + + /* Clear the Bank 0 ready flag on Control OUT */ + // The RAM Buffer is empty: we can receive data + usbd.epBank0ResetReady(0); + + bool ok; + if (REQUEST_STANDARD == (setup->bmRequestType & REQUEST_TYPE)) { + // Standard Requests + ok = handleStandardSetup(*setup); + } else { + // Class Interface Requests + ok = handleClassInterfaceSetup(*setup); + } + + if (ok) { + usbd.epBank1SetReady(0); + } else { + stall(0); + } + + // XXX: Should be really cleared? + if (usbd.epBank1IsStalled(0)) // XXX:(USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.STALL) + { + usbd.epBank1AckStalled(0); + + // Remove stall request + usbd.epBank1DisableStalled(0); + } + + } // end Received Setup handler + + uint8_t i=0; + uint8_t ept_int = usbd.epInterruptSummary() & 0xFE; // Remove endpoint number 0 (setup) + while (ept_int != 0) + { + // Check if endpoint has a pending interrupt + if ((ept_int & (1 << i)) != 0) + { + // Endpoint Transfer Complete (0/1) Interrupt + if (usbd.epBank0IsTransferComplete(i) || + usbd.epBank1IsTransferComplete(i)) + { + handleEndpoint(i); + } + ept_int &= ~(1 << i); + } + i++; + if (i > USB_EPT_NUM) + break; // fire exit + } } -void USBDevice_::init() -{ - UDD_Init(); - _usbInitialized=1UL; +/* + * USB Device instance + * ------------------- + */ + +// USBDevice class instance +USBDeviceClass USBDevice; + +// USB_Handler ISR +extern "C" void USB_Handler(void) { + USBDevice.ISRHandler(); } diff --git a/cores/arduino/USB/USBCore.h b/cores/arduino/USB/USBCore.h index 1441a649..d584fdfc 100644 --- a/cores/arduino/USB/USBCore.h +++ b/cores/arduino/USB/USBCore.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -31,6 +31,16 @@ #define GET_INTERFACE 10 #define SET_INTERFACE 11 +// bEndpointAddress in Endpoint Descriptor +#define USB_ENDPOINT_DIRECTION_MASK 0x80 +#define USB_ENDPOINT_OUT(addr) ((addr) | 0x00) +#define USB_ENDPOINT_IN(addr) ((addr) | 0x80) + +#define USB_ENDPOINT_TYPE_MASK 0x03 +#define USB_ENDPOINT_TYPE_CONTROL 0x00 +#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01 +#define USB_ENDPOINT_TYPE_BULK 0x02 +#define USB_ENDPOINT_TYPE_INTERRUPT 0x03 // bmRequestType #define REQUEST_HOSTTODEVICE 0x00 diff --git a/cores/arduino/USB/USBDesc.h b/cores/arduino/USB/USBDesc.h index 9b1cdf8c..655fb6d0 100644 --- a/cores/arduino/USB/USBDesc.h +++ b/cores/arduino/USB/USBDesc.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/cores/arduino/USB/USB_device.h b/cores/arduino/USB/USB_device.h deleted file mode 100644 index 6353f977..00000000 --- a/cores/arduino/USB/USB_device.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - Copyright (c) 2014 Arduino. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef USB_DEVICE_H_INCLUDED -#define USB_DEVICE_H_INCLUDED - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> -#include "USB/samd21_device.h" - - -// bEndpointAddress in Endpoint Descriptor -#define USB_ENDPOINT_DIRECTION_MASK 0x80 -#define USB_ENDPOINT_OUT(addr) ((addr) | 0x00) -#define USB_ENDPOINT_IN(addr) ((addr) | 0x80) - -#define USB_ENDPOINT_TYPE_MASK 0x03 -#define USB_ENDPOINT_TYPE_CONTROL 0x00 -#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01 -#define USB_ENDPOINT_TYPE_BULK 0x02 -#define USB_ENDPOINT_TYPE_INTERRUPT 0x03 - - -extern void UDD_ClearIN(void); -extern uint32_t UDD_FifoByteCount(uint32_t ep); -extern void UDD_ReleaseRX(uint32_t ep); -extern void UDD_ReleaseTX(uint32_t ep); -extern uint32_t UDD_Send(uint32_t ep, const void* data, uint32_t len); -extern uint8_t UDD_Recv_data(uint32_t ep, uint32_t len); -extern void UDD_Recv(uint32_t ep, uint8_t** data); -extern void UDD_Init(void); -extern void UDD_InitEP( uint32_t ul_ep, uint32_t ul_ep_cfg ); -extern void send_zlp (void); -extern void UDD_Attach(void); -extern void UDD_Detach(void); -extern void UDD_SetAddress(uint32_t addr); -extern void UDD_Stall(uint32_t ep); -extern uint32_t UDD_GetFrameNumber(void); -extern void UDD_SetStack(void (*pf_isr)(void)); - -#ifdef __cplusplus -} -#endif - -#endif /* USB_DEVICE_H_INCLUDED */ diff --git a/cores/arduino/USB/USB_host.h b/cores/arduino/USB/USB_host.h index e20738e8..390e3dd1 100644 --- a/cores/arduino/USB/USB_host.h +++ b/cores/arduino/USB/USB_host.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/cores/arduino/USB/USB_interrupt.c b/cores/arduino/USB/USB_interrupt.c deleted file mode 100644 index 3f1f05f6..00000000 --- a/cores/arduino/USB/USB_interrupt.c +++ /dev/null @@ -1,23 +0,0 @@ -/* -** Permission to use, copy, modify, and/or distribute this software for -** any purpose with or without fee is hereby granted, provided that the -** above copyright notice and this permission notice appear in all copies. -** -** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL -** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR -** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES -** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -** SOFTWARE. -*/ - -void (*gpf_isr)(void) = (0UL); - -void USB_Handler( void ) -{ - if (gpf_isr) - gpf_isr(); -} - diff --git a/cores/arduino/USB/samd21_device.c b/cores/arduino/USB/samd21_device.c deleted file mode 100644 index cff711f4..00000000 --- a/cores/arduino/USB/samd21_device.c +++ /dev/null @@ -1,349 +0,0 @@ -/* - Copyright (c) 2014 Arduino. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include <stdio.h> -#include <stdint.h> -#include <string.h> - -#include "variant.h" -#include "USB/USB_device.h" -#include "USB/samd21_device.h" -#include "sam.h" - -#ifdef __cplusplus -extern "C"{ -#endif // __cplusplus - -#ifdef SAMD_SERIES - -//#define TRACE_DEVICE(x) x -#define TRACE_DEVICE(x) - -__attribute__((__aligned__(4))) /*__attribute__((__section__(".bss_hram0")))*/ uint8_t udd_ep_out_cache_buffer[4][64]; -__attribute__((__aligned__(4))) /*__attribute__((__section__(".bss_hram0")))*/ uint8_t udd_ep_in_cache_buffer[4][128]; - -/** - * USB SRAM data containing pipe descriptor table - * The content of the USB SRAM can be : - * - modified by USB hardware interface to update pipe status. - * Thereby, it is read by software. - * - modified by USB software to control pipe. - * Thereby, it is read by hardware. - * This data section is volatile. - */ - __attribute__((__aligned__(4))) UsbDeviceDescriptor usb_endpoint_table[USB_EPT_NUM]; - - -extern void (*gpf_isr)(void); - - -void UDD_SetStack(void (*pf_isr)(void)) -{ - gpf_isr = pf_isr; -} - -// NVM Software Calibration Area Mapping -// USB TRANSN calibration value. Should be written to the USB PADCAL register. -#define NVM_USB_PAD_TRANSN_POS 45 -#define NVM_USB_PAD_TRANSN_SIZE 5 -// USB TRANSP calibration value. Should be written to the USB PADCAL register. -#define NVM_USB_PAD_TRANSP_POS 50 -#define NVM_USB_PAD_TRANSP_SIZE 5 -// USB TRIM calibration value. Should be written to the USB PADCAL register. -#define NVM_USB_PAD_TRIM_POS 55 -#define NVM_USB_PAD_TRIM_SIZE 3 - -void UDD_Init(void) -{ - uint32_t pad_transn; - uint32_t pad_transp; - uint32_t pad_trim; - uint32_t i; - - /* Enable USB clock */ - PM->APBBMASK.reg |= PM_APBBMASK_USB; - - /* Set up the USB DP/DN pins */ - PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; - PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); - PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); - PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; - PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); - PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); - - /* ---------------------------------------------------------------------------------------------- - * Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference) - */ - GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( 6 ) | // Generic Clock Multiplexer 6 - GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source - GCLK_CLKCTRL_CLKEN ; - - while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) - { - /* Wait for synchronization */ - } - - /* Reset */ - USB->DEVICE.CTRLA.bit.SWRST = 1; - while (USB->DEVICE.SYNCBUSY.bit.SWRST) { - /* Sync wait */ - } - - udd_enable(); - - /* Load Pad Calibration */ - pad_transn =( *((uint32_t *)(NVMCTRL_OTP4) // Non-Volatile Memory Controller - + (NVM_USB_PAD_TRANSN_POS / 32)) - >> (NVM_USB_PAD_TRANSN_POS % 32)) - & ((1 << NVM_USB_PAD_TRANSN_SIZE) - 1); - - if (pad_transn == 0x1F) { // maximum value (31) - pad_transn = 5; - } - - USB->DEVICE.PADCAL.bit.TRANSN = pad_transn; - - pad_transp =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_USB_PAD_TRANSP_POS / 32)) - >> (NVM_USB_PAD_TRANSP_POS % 32)) - & ((1 << NVM_USB_PAD_TRANSP_SIZE) - 1); - - if (pad_transp == 0x1F) { // maximum value (31) - pad_transp = 29; - } - - USB->DEVICE.PADCAL.bit.TRANSP = pad_transp; - - pad_trim =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_USB_PAD_TRIM_POS / 32)) - >> (NVM_USB_PAD_TRIM_POS % 32)) - & ((1 << NVM_USB_PAD_TRIM_SIZE) - 1); - - if (pad_trim == 0x7) { // maximum value (7) - pad_trim = 3; - } - - USB->DEVICE.PADCAL.bit.TRIM = pad_trim; - - /* Set the configuration */ - udd_force_device_mode(); - udd_device_run_in_standby(); - // Set address of USB SRAM - USB->DEVICE.DESCADD.reg = (uint32_t)(&usb_endpoint_table[0]); - // For USB_SPEED_FULL - udd_force_full_speed(); - memset(&usb_endpoint_table[0], 0, sizeof(usb_endpoint_table)); - - // Configure interrupts - NVIC_SetPriority((IRQn_Type) USB_IRQn, 0UL); - NVIC_EnableIRQ((IRQn_Type) USB_IRQn); -} - -void UDD_Attach(void) -{ - TRACE_DEVICE(printf("=> UDD_Attach\r\n");) - - // Authorize attach if Vbus is present - udd_attach_device(); - - // Enable USB line events - udd_enable_reset_interrupt(); - - // usefull for debug - udd_enable_sof_interrupt(); -} - -void UDD_Detach(void) -{ - TRACE_DEVICE(printf("=> UDD_Detach\r\n");) - udd_detach_device(); -} - -void send_zlp(void) -{ - /* Set the byte count as zero */ - usb_endpoint_table[0].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = 0; -} - - -void UDD_InitEP( uint32_t ul_ep_nb, uint32_t ul_ep_cfg ) -{ - TRACE_DEVICE(printf("=> UDD_InitEP : init EP %lu\r\n", (unsigned long)ul_ep_nb);) - - if( ul_ep_cfg == (USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)) ) - { - USB->DEVICE.DeviceEndpoint[ul_ep_nb].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(4); - /* Set maximum packet size as 8 bytes */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[1].PCKSIZE.bit.SIZE = 0; // 8 bytes - /* Configure the data buffer */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[ul_ep_nb]; - } - else if( ul_ep_cfg == (USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0)) ) - { - /* Configure BULK OUT endpoint for CDC Data interface*/ - USB->DEVICE.DeviceEndpoint[ul_ep_nb].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(3); - /* Set maximum packet size as 64 bytes */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.bit.SIZE = 0x3; // for 64 bytes - /* Configure the data buffer */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[ul_ep_nb]; - - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 64; - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; - // NACK if not ready - udd_OUT_transfer_allowed(ul_ep_nb); - } - else if( ul_ep_cfg == (USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0)) ) - { - /* Configure BULK IN endpoint for CDC Data interface */ - USB->DEVICE.DeviceEndpoint[ul_ep_nb].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(3); - /* Set maximum packet size as 64 bytes */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[1].PCKSIZE.bit.SIZE = 0x3; // for 64 bytes - /* Configure the data buffer */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[ul_ep_nb]; - // NACK if not ready - udd_IN_stop_transfer(ul_ep_nb); - } - else if( ul_ep_cfg == USB_ENDPOINT_TYPE_CONTROL ) - { - /* Configure CONTROL endpoint */ - USB->DEVICE.DeviceEndpoint[ul_ep_nb].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(1) | USB_DEVICE_EPCFG_EPTYPE1(1); - udd_OUT_stop_transfer(ul_ep_nb); - udd_IN_stop_transfer(ul_ep_nb); - - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.reg &= ~USB_DEVICE_PCKSIZE_AUTO_ZLP; - usb_endpoint_table[ul_ep_nb].DeviceDescBank[1].PCKSIZE.reg &= ~USB_DEVICE_PCKSIZE_AUTO_ZLP; - - /* Set maximum packet size as 64 bytes */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.bit.SIZE = 0x3; // for 64 bytes - usb_endpoint_table[ul_ep_nb].DeviceDescBank[1].PCKSIZE.bit.SIZE = 0x3; // for 64 bytes - - /* get endpoint configuration from setting register */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[0]; - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 8; - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; - - // NACK if not ready - udd_OUT_stop_transfer(ul_ep_nb); - udd_IN_stop_transfer(ul_ep_nb); - } -} - - -// Send packet. -void UDD_ClearIN(void) -{ - udd_IN_transfer_allowed(EP0); -} - - - -uint32_t UDD_Send(uint32_t ep, const void* data, uint32_t len) -{ - memcpy(&udd_ep_in_cache_buffer[ep], data, len); - - /* Get endpoint configuration from setting register */ - usb_endpoint_table[ep].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[ep]; - usb_endpoint_table[ep].DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = 0; - usb_endpoint_table[ep].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = len; - - return len; -} - -uint8_t UDD_Recv_data(uint32_t ep, uint32_t len) -{ - TRACE_DEVICE(printf("=> UDD_Recvdata : ep=%d\r\n", (char)ep);) - - if (len>64) len=64; - usb_endpoint_table[ep].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[ep]; - usb_endpoint_table[ep].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = len; - usb_endpoint_table[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; - udd_OUT_transfer_allowed(ep); - TRACE_DEVICE(printf("=> UDD_Recv_data : data=%lu\r\n", (unsigned long)data);) - - /* Wait for transfer to complete */ - while (!udd_is_OUT_transf_cplt(ep)); - /* Clear Transfer complete 0 flag */ - udd_clear_OUT_transf_cplt(ep); - - return udd_ep_out_cache_buffer[ep][0]; -} - -void UDD_Recv(uint32_t ep, uint8_t** ppData) -{ - *ppData = udd_ep_out_cache_buffer[ep]; -} - -void UDD_Stall(uint32_t ep) -{ - uint8_t ep_num = ep; - - // Stall endpoint - USB->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ(2); -} - -uint32_t UDD_FifoByteCount(uint32_t ep) -{ - return ((uint16_t)(usb_endpoint_table[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT)); -} - -void UDD_ReleaseRX(uint32_t ep) -{ - TRACE_DEVICE(puts("=> UDD_ReleaseRX\r\n");) - // The RAM Buffer is empty: we can receive data - udd_OUT_transfer_allowed(ep); - /* Clear Transfer complete 0 flag */ - udd_clear_OUT_transf_cplt(ep); -} - -void UDD_ReleaseTX(uint32_t ep) -{ - TRACE_DEVICE(printf("=> UDD_ReleaseTX ep=%lu\r\n", (unsigned long)ep);) - // The RAM Buffer is full: we can send data - udd_IN_transfer_allowed(ep); - /* Clear the transfer complete flag */ - udd_clear_IN_transf_cplt(ep); -} - -void UDD_SetAddress(uint32_t addr) -{ - TRACE_DEVICE(printf("=> UDD_SetAddress : setting address to %lu\r\n", (unsigned long)addr);) - - /* Set the byte count as zero */ - usb_endpoint_table[0].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = 0; - /* Clear the transfer complete flag */ - udd_clear_IN_transf_cplt(0); - /* Set the bank as ready */ - udd_IN_transfer_allowed(0); - - /* Wait for transfer to complete */ - while (!udd_is_IN_transf_cplt(EP0)) {} - - udd_configure_address(addr); -} - -uint32_t UDD_GetFrameNumber(void) -{ - return udd_frame_number(); -} - -#ifdef __cplusplus -} -#endif - -#endif /* SAMD_SERIES */ - diff --git a/cores/arduino/USB/samd21_device.h b/cores/arduino/USB/samd21_device.h deleted file mode 100644 index deded25b..00000000 --- a/cores/arduino/USB/samd21_device.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - Copyright (c) 2014 Arduino. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef SAMD21_DEVICE_H_INCLUDED -#define SAMD21_DEVICE_H_INCLUDED - -#ifdef __cplusplus -extern "C" { -#endif - -#define EP0 0 -#define EPX_SIZE 64// 64 for Full Speed, EPT size max is 1024 - -// Force device low speed mode -#define udd_force_low_speed() USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_SPDCONF_Msk; USB->DEVICE.CTRLB.reg |= USB_DEVICE_CTRLB_SPDCONF_1_Val -// Force full speed mode -#define udd_force_full_speed() USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_SPDCONF_Msk - -// Attaches to USB bus -#define udd_attach_device() USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH -#define udd_detach_device() USB->DEVICE.CTRLB.reg |= USB_DEVICE_CTRLB_DETACH - -// Manage reset event -// Set when a USB "End of Reset" has been detected -#define udd_enable_reset_interrupt() USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_EORST -#define udd_ack_reset() USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST -#define Is_udd_reset() (USB->DEVICE.INTFLAG.reg & USB_DEVICE_INTFLAG_EORST) - -// Manage start of frame (SOF) event -#define udd_enable_sof_interrupt() USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF -#define udd_ack_sof() USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF -#define Is_udd_sof() (USB->DEVICE.INTENSET.reg & USB_DEVICE_INTENSET_SOF) -#define udd_frame_number() ((USB->DEVICE.FNUM.reg & USB_DEVICE_FNUM_FNUM_Msk) >> USB_DEVICE_FNUM_FNUM_Pos) - -// configures the USB device address and enable it. -#define udd_configure_address(address) USB->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | address - -// Clear BK0RDY for know that the BANK0 ram buffer (udd_g_ep_table[ep].DeviceDescBank[0]) is empty and can receive data -#define udd_OUT_transfer_allowed(ep) USB->DEVICE.DeviceEndpoint[ep].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY -// Set BK1RDY for know that the BANK1 ram buffer (udd_g_ep_table[ep].DeviceDescBank[1]) is full and can send data -#define udd_IN_transfer_allowed(ep) USB->DEVICE.DeviceEndpoint[ep].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK1RDY - -// Stop OUT transfer -#define udd_OUT_stop_transfer(ep) USB->DEVICE.DeviceEndpoint[ep].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY -// Stop IN transfer -#define udd_IN_stop_transfer(ep) USB->DEVICE.DeviceEndpoint[ep].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY - -#define udd_read_endpoint_flag(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.reg -// Is transfer completed ? -#define udd_is_IN_transf_cplt(ep) (USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_TRCPT(2)) -#define udd_is_OUT_transf_cplt(ep) (USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_TRCPT(1)) -// Clear the transfer complete flag -#define udd_clear_IN_transf_cplt(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(2) -#define udd_clear_OUT_transf_cplt(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(1) -// Enable interrupt transfer complete -#define udd_ept_enable_it_IN_transf_cplt(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT(2) -#define udd_ept_enable_it_OUT_transf_cplt(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT(1) - -// Enables SETUP received interrupt -#define udd_enable_setup_received_interrupt(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTENSET.reg = USB_DEVICE_EPINTFLAG_RXSTP -// Clear the stall flag -#define udd_clear_stall_request(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL(2) -// Remove stall -#define udd_remove_stall_request(ep) USB->DEVICE.DeviceEndpoint[ep].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ(2) - -// Endpoint Interrupt Summary -#define udd_endpoint_interrupt() USB->DEVICE.EPINTSMRY.reg - -#define udd_clear_wakeup_interrupt() USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTENCLR_WAKEUP -#define udd_clear_eorsm_interrupt() USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTENCLR_EORSM -#define udd_clear_suspend_interrupt() USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTENCLR_SUSPEND - - - -// Force device mode -#define udd_force_device_mode() USB->DEVICE.CTRLA.reg &= ~USB_CTRLA_MODE -// Run in Standby -#define udd_device_run_in_standby() USB->DEVICE.CTRLA.reg |= USB_CTRLA_RUNSTDBY -// Force host mode -#define udd_force_host_mode() USB->DEVICE.CTRLA.reg |= USB_CTRLA_MODE - - -// Enable USB macro -#define udd_enable() USB->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE -// Disable USB macro -#define udd_disable() USB->DEVICE.CTRLA.reg &= ~USB_CTRLA_ENABLE - -#ifdef __cplusplus -} -#endif - -#endif /* SAMD21_DEVICE_H_INCLUDED */ - diff --git a/cores/arduino/USB/samd21_host.c b/cores/arduino/USB/samd21_host.c index 0ad32313..687cdcb0 100644 --- a/cores/arduino/USB/samd21_host.c +++ b/cores/arduino/USB/samd21_host.c @@ -1,20 +1,20 @@ -/* - Copyright (c) 2014 Arduino. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ +/* + Copyright (c) 2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ #include <stdio.h> @@ -22,9 +22,11 @@ #include <string.h> #include "../Arduino.h" -#include "../wiring_private.h" +#include "variant.h" #include "USB_host.h" #include "samd21_host.h" +#include "sam.h" +#include "wiring_digital.h" #define HOST_DEFINED #ifdef HOST_DEFINED @@ -67,20 +69,20 @@ void UHD_Init(void) uint32_t pad_trim; uint32_t i; - UHD_SetStack(&UHD_Handler); + UHD_SetStack(&UHD_Handler); /* Enable USB clock */ PM->APBBMASK.reg |= PM_APBBMASK_USB; /* Set up the USB DP/DM pins */ - pinPeripheral( PIN_USB_DM, PIO_COM ); - pinPeripheral( PIN_USB_DP, PIO_COM ); -// PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; -// PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); -// PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); -// PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; -// PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); -// PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); + pinPeripheral( PIN_USB_DM, PIO_COM ); + pinPeripheral( PIN_USB_DP, PIO_COM ); +// PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; +// PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); +// PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); +// PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; +// PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); +// PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); /* ---------------------------------------------------------------------------------------------- * Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference) @@ -102,9 +104,9 @@ void UHD_Init(void) } // uhd_enable(); - USB->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE | USB_CTRLA_MODE; + USB->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE | USB_CTRLA_MODE; uhd_force_host_mode(); - while (USB->HOST.SYNCBUSY.reg == USB_SYNCBUSY_ENABLE); + while (USB->HOST.SYNCBUSY.reg == USB_SYNCBUSY_ENABLE); /* Load Pad Calibration */ pad_transn = (*((uint32_t *)(NVMCTRL_OTP4) // Non-Volatile Memory Controller @@ -183,8 +185,8 @@ void UHD_Handler(void) { uint16_t flags; - if (USB->HOST.CTRLA.bit.MODE) { - /*host mode ISR */ + if (USB->HOST.CTRLA.bit.MODE) { + /*host mode ISR */ /* get interrupt flags */ flags = USB->HOST.INTFLAG.reg; @@ -305,7 +307,7 @@ uhd_vbus_state_t UHD_GetVBUSState(void) */ uint32_t UHD_Pipe0_Alloc(uint32_t ul_add, uint32_t ul_ep_size) { - if( USB->HOST.STATUS.reg & USB_HOST_STATUS_SPEED(1) ) + if( USB->HOST.STATUS.reg & USB_HOST_STATUS_SPEED(1) ) ul_ep_size = USB_PCKSIZE_SIZE_8_BYTES; // Low Speed else ul_ep_size = USB_PCKSIZE_SIZE_64_BYTES; // Full Speed @@ -356,7 +358,7 @@ uint32_t UHD_Pipe_Alloc(uint32_t ul_dev_addr, uint32_t ul_dev_ep, uint32_t ul_ty USB->HOST.HostPipe[ul_dev_ep].PSTATUSCLR.reg = USB_HOST_PSTATUSCLR_BK0RDY; } - if( USB->HOST.STATUS.reg & USB_HOST_STATUS_SPEED(1) ) + if( USB->HOST.STATUS.reg & USB_HOST_STATUS_SPEED(1) ) ul_maxsize = USB_PCKSIZE_SIZE_8_BYTES; // Low Speed else ul_maxsize = USB_PCKSIZE_SIZE_64_BYTES; // Full Speed @@ -373,7 +375,7 @@ uint32_t UHD_Pipe_Alloc(uint32_t ul_dev_addr, uint32_t ul_dev_ep, uint32_t ul_ty void UHD_Pipe_CountZero(uint32_t ul_pipe) { - usb_pipe_table[ul_pipe].HostDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; + usb_pipe_table[ul_pipe].HostDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; } /** @@ -448,7 +450,7 @@ void UHD_Pipe_Send(uint32_t ul_pipe, uint32_t ul_token_type) /* Start transfer */ if(ul_token_type == USB_HOST_PCFG_PTOKEN_SETUP ) { - USB->HOST.HostPipe[ul_pipe].PINTFLAG.reg = USB_HOST_PINTFLAG_TXSTP; + USB->HOST.HostPipe[ul_pipe].PINTFLAG.reg = USB_HOST_PINTFLAG_TXSTP; USB->HOST.HostPipe[ul_pipe].PSTATUSSET.reg = USB_HOST_PSTATUSSET_BK0RDY; } else if(ul_token_type == USB_HOST_PCFG_PTOKEN_IN ) diff --git a/cores/arduino/USB/samd21_host.h b/cores/arduino/USB/samd21_host.h index 5e2e2c89..d2d9c9e0 100644 --- a/cores/arduino/USB/samd21_host.h +++ b/cores/arduino/USB/samd21_host.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -28,18 +28,18 @@ extern __attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table #define USB_EP_DIR_IN 0x80 // USB_SETUP_DEVICE_TO_HOST #define USB_EP_DIR_OUT 0x00 // USB_SETUP_HOST_TO_DEVICE -#define USB_HOST_PTYPE_DIS USB_HOST_PCFG_PTYPE(0x0) // Pipe is disabled -#define USB_HOST_PTYPE_CTRL USB_HOST_PCFG_PTYPE(0x1) // Pipe is enabled and configured as CONTROL -#define USB_HOST_PTYPE_ISO USB_HOST_PCFG_PTYPE(0x2) // Pipe is enabled and configured as ISO -#define USB_HOST_PTYPE_BULK USB_HOST_PCFG_PTYPE(0x3) // Pipe is enabled and configured as BULK -#define USB_HOST_PTYPE_INT USB_HOST_PCFG_PTYPE(0x4) // Pipe is enabled and configured as INTERRUPT -#define USB_HOST_PTYPE_EXT USB_HOST_PCFG_PTYPE(0x5) // Pipe is enabled and configured as EXTENDED +#define USB_HOST_PTYPE_DIS USB_HOST_PCFG_PTYPE(0x0) // Pipe is disabled +#define USB_HOST_PTYPE_CTRL USB_HOST_PCFG_PTYPE(0x1) // Pipe is enabled and configured as CONTROL +#define USB_HOST_PTYPE_ISO USB_HOST_PCFG_PTYPE(0x2) // Pipe is enabled and configured as ISO +#define USB_HOST_PTYPE_BULK USB_HOST_PCFG_PTYPE(0x3) // Pipe is enabled and configured as BULK +#define USB_HOST_PTYPE_INT USB_HOST_PCFG_PTYPE(0x4) // Pipe is enabled and configured as INTERRUPT +#define USB_HOST_PTYPE_EXT USB_HOST_PCFG_PTYPE(0x5) // Pipe is enabled and configured as EXTENDED #define USB_HOST_NB_BK_1 1 -#define USB_HOST_PCFG_PTOKEN_SETUP USB_HOST_PCFG_PTOKEN(0x0) -#define USB_HOST_PCFG_PTOKEN_IN USB_HOST_PCFG_PTOKEN(0x1) -#define USB_HOST_PCFG_PTOKEN_OUT USB_HOST_PCFG_PTOKEN(0x2) +#define USB_HOST_PCFG_PTOKEN_SETUP USB_HOST_PCFG_PTOKEN(0x0) +#define USB_HOST_PCFG_PTOKEN_IN USB_HOST_PCFG_PTOKEN(0x1) +#define USB_HOST_PCFG_PTOKEN_OUT USB_HOST_PCFG_PTOKEN(0x2) #define USB_ERRORFLOW USB_HOST_STATUS_BK_ERRORFLOW #define USB_ERRORTIMEOUT USB_HOST_STATUS_PIPE_TOUTER @@ -84,7 +84,7 @@ extern __attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table #define Is_uhd_sof() (USB->HOST.INTFLAG.reg & USB_HOST_INTFLAG_HSOF) // USB address of pipes -#define uhd_configure_address(pipe_num, addr) usb_pipe_table[pipe_num].HostDescBank[0].CTRL_PIPE.bit.PDADDR = addr +#define uhd_configure_address(pipe_num, addr) usb_pipe_table[pipe_num].HostDescBank[0].CTRL_PIPE.bit.PDADDR = addr #define uhd_get_configured_address(pipe_num) usb_pipe_table[pipe_num].HostDescBank[0].CTRL_PIPE.bit.PDADDR // Pipes @@ -104,7 +104,7 @@ extern __attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table #define uhd_ack_out_ready(p) USB->HOST.HostPipe[p].PINTFLAG.reg = USB_HOST_PINTFLAG_TRCPT(1) #define Is_uhd_out_ready(p) ((USB->HOST.HostPipe[p].PINTFLAG.reg&USB_HOST_PINTFLAG_TRCPT(1)) == USB_HOST_PINTFLAG_TRCPT(1)) #define uhd_ack_nak_received(p) usb_pipe_table[p].HostDescBank[1].STATUS_BK.reg &= ~USB_HOST_STATUS_BK_ERRORFLOW -#define Is_uhd_nak_received(p) (usb_pipe_table[p].HostDescBank[1].STATUS_BK.reg & USB_HOST_STATUS_BK_ERRORFLOW) +#define Is_uhd_nak_received(p) (usb_pipe_table[p].HostDescBank[1].STATUS_BK.reg & USB_HOST_STATUS_BK_ERRORFLOW) // Endpoint Interrupt Summary #define uhd_endpoint_interrupt() USB->HOST.PINTSMRY.reg -- GitLab