|
| 1 | +/* |
| 2 | + Copyright (c) 2015 Arduino LLC. All right reserved. |
| 3 | +
|
| 4 | + This library is free software; you can redistribute it and/or |
| 5 | + modify it under the terms of the GNU Lesser General Public |
| 6 | + License as published by the Free Software Foundation; either |
| 7 | + version 2.1 of the License, or (at your option) any later version. |
| 8 | +
|
| 9 | + This library is distributed in the hope that it will be useful, |
| 10 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| 12 | + See the GNU Lesser General Public License for more details. |
| 13 | +
|
| 14 | + You should have received a copy of the GNU Lesser General Public |
| 15 | + License along with this library; if not, write to the Free Software |
| 16 | + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 17 | +*/ |
| 18 | + |
| 19 | +#pragma once |
| 20 | + |
| 21 | +#include <Arduino.h> |
| 22 | + |
| 23 | +#include <stdlib.h> |
| 24 | +#include <stdio.h> |
| 25 | +#include <stdint.h> |
| 26 | + |
| 27 | +typedef uint8_t ep_t; |
| 28 | + |
| 29 | +class USBDevice_SAMR21G18x { |
| 30 | +public: |
| 31 | + USBDevice_SAMR21G18x() : usb(USB->DEVICE) { |
| 32 | + // Empty |
| 33 | + } |
| 34 | + |
| 35 | + // USB Device function mapping |
| 36 | + // --------------------------- |
| 37 | + |
| 38 | + // Reset USB Device |
| 39 | + void reset(); |
| 40 | + |
| 41 | + // Enable |
| 42 | + inline void enable() { usb.CTRLA.bit.ENABLE = 1; } |
| 43 | + inline void disable() { usb.CTRLA.bit.ENABLE = 0; } |
| 44 | + |
| 45 | + // USB mode (device/host) |
| 46 | + inline void setUSBDeviceMode() { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_DEVICE_Val; } |
| 47 | + inline void setUSBHostMode() { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_HOST_Val; } |
| 48 | + |
| 49 | + inline void runInStandby() { usb.CTRLA.bit.RUNSTDBY = 1; } |
| 50 | + inline void noRunInStandby() { usb.CTRLA.bit.RUNSTDBY = 0; } |
| 51 | + |
| 52 | + // USB speed |
| 53 | + inline void setFullSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val; } |
| 54 | + inline void setLowSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_LS_Val; } |
| 55 | + inline void setHiSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_HS_Val; } |
| 56 | + inline void setHiSpeedTestMode() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_HSTM_Val; } |
| 57 | + |
| 58 | + // Authorize attach if Vbus is present |
| 59 | + inline void attach() { usb.CTRLB.bit.DETACH = 0; } |
| 60 | + inline void detach() { usb.CTRLB.bit.DETACH = 1; } |
| 61 | + |
| 62 | + // USB Interrupts |
| 63 | + inline bool isEndOfResetInterrupt() { return usb.INTFLAG.bit.EORST; } |
| 64 | + inline void ackEndOfResetInterrupt() { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; } |
| 65 | + inline void enableEndOfResetInterrupt() { usb.INTENSET.bit.EORST = 1; } |
| 66 | + inline void disableEndOfResetInterrupt() { usb.INTENCLR.bit.EORST = 1; } |
| 67 | + |
| 68 | + inline bool isStartOfFrameInterrupt() { return usb.INTFLAG.bit.SOF; } |
| 69 | + inline void ackStartOfFrameInterrupt() { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF; } |
| 70 | + inline void enableStartOfFrameInterrupt() { usb.INTENSET.bit.SOF = 1; } |
| 71 | + inline void disableStartOfFrameInterrupt() { usb.INTENCLR.bit.SOF = 1; } |
| 72 | + |
| 73 | + // USB Address |
| 74 | + inline void setAddress(uint32_t addr) { usb.DADD.bit.DADD = addr; usb.DADD.bit.ADDEN = 1; } |
| 75 | + inline void unsetAddress() { usb.DADD.bit.DADD = 0; usb.DADD.bit.ADDEN = 0; } |
| 76 | + |
| 77 | + // Frame number |
| 78 | + inline uint16_t frameNumber() { return usb.FNUM.bit.FNUM; } |
| 79 | + |
| 80 | + // Load calibration values |
| 81 | + void calibrate(); |
| 82 | + |
| 83 | + // USB Device Endpoints function mapping |
| 84 | + // ------------------------------------- |
| 85 | + |
| 86 | + // Config |
| 87 | + inline void epBank0SetType(ep_t ep, uint8_t type) { usb.DeviceEndpoint[ep].EPCFG.bit.EPTYPE0 = type; } |
| 88 | + inline void epBank1SetType(ep_t ep, uint8_t type) { usb.DeviceEndpoint[ep].EPCFG.bit.EPTYPE1 = type; } |
| 89 | + |
| 90 | + // Interrupts |
| 91 | + inline uint16_t epInterruptSummary() { return usb.EPINTSMRY.reg; } |
| 92 | + |
| 93 | + inline bool epBank0IsSetupReceived(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.RXSTP; } |
| 94 | + inline bool epBank0IsStalled(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.STALL0; } |
| 95 | + inline bool epBank1IsStalled(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.STALL1; } |
| 96 | + inline bool epBank0IsTransferComplete(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT0; } |
| 97 | + inline bool epBank1IsTransferComplete(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT1; } |
| 98 | + |
| 99 | + inline void epBank0AckSetupReceived(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP; } |
| 100 | + inline void epBank0AckStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL(1); } |
| 101 | + inline void epBank1AckStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL(2); } |
| 102 | + inline void epBank0AckTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(1); } |
| 103 | + inline void epBank1AckTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(2); } |
| 104 | + |
| 105 | + inline void epBank0EnableSetupReceived(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.RXSTP = 1; } |
| 106 | + inline void epBank0EnableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.STALL0 = 1; } |
| 107 | + inline void epBank1EnableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.STALL1 = 1; } |
| 108 | + inline void epBank0EnableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.TRCPT0 = 1; } |
| 109 | + inline void epBank1EnableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.TRCPT1 = 1; } |
| 110 | + |
| 111 | + inline void epBank0DisableSetupReceived(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.RXSTP = 1; } |
| 112 | + inline void epBank0DisableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.STALL0 = 1; } |
| 113 | + inline void epBank1DisableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.STALL1 = 1; } |
| 114 | + inline void epBank0DisableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.TRCPT0 = 1; } |
| 115 | + inline void epBank1DisableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.TRCPT1 = 1; } |
| 116 | + |
| 117 | + // Status |
| 118 | + inline bool epBank0IsReady(ep_t ep) { return usb.DeviceEndpoint[ep].EPSTATUS.bit.BK0RDY; } |
| 119 | + inline bool epBank1IsReady(ep_t ep) { return usb.DeviceEndpoint[ep].EPSTATUS.bit.BK1RDY; } |
| 120 | + inline void epBank0SetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.BK0RDY = 1; } |
| 121 | + inline void epBank1SetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.BK1RDY = 1; } |
| 122 | + inline void epBank0ResetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.BK0RDY = 1; } |
| 123 | + inline void epBank1ResetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.BK1RDY = 1; } |
| 124 | + |
| 125 | + inline void epBank0SetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.STALLRQ0 = 1; } |
| 126 | + inline void epBank1SetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.STALLRQ1 = 1; } |
| 127 | + inline void epBank0ResetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.STALLRQ0 = 1; } |
| 128 | + inline void epBank1ResetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.STALLRQ1 = 1; } |
| 129 | + |
| 130 | + // Packet |
| 131 | + inline uint16_t epBank0ByteCount(ep_t ep) { return EP[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT; } |
| 132 | + inline uint16_t epBank1ByteCount(ep_t ep) { return EP[ep].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT; } |
| 133 | + inline void epBank0SetByteCount(ep_t ep, uint16_t bc) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = bc; } |
| 134 | + inline void epBank1SetByteCount(ep_t ep, uint16_t bc) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = bc; } |
| 135 | + inline void epBank0SetMultiPacketSize(ep_t ep, uint16_t s) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = s; } |
| 136 | + inline void epBank1SetMultiPacketSize(ep_t ep, uint16_t s) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = s; } |
| 137 | + |
| 138 | + inline void epBank0SetAddress(ep_t ep, void *addr) { EP[ep].DeviceDescBank[0].ADDR.reg = (uint32_t)addr; } |
| 139 | + inline void epBank1SetAddress(ep_t ep, void *addr) { EP[ep].DeviceDescBank[1].ADDR.reg = (uint32_t)addr; } |
| 140 | + inline void epBank0SetSize(ep_t ep, uint16_t size) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.SIZE = EP_PCKSIZE_SIZE(size); } |
| 141 | + inline void epBank1SetSize(ep_t ep, uint16_t size) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.SIZE = EP_PCKSIZE_SIZE(size); } |
| 142 | + inline uint8_t EP_PCKSIZE_SIZE(uint16_t size) { |
| 143 | + switch (size) { |
| 144 | + case 8: return 0; |
| 145 | + case 16: return 1; |
| 146 | + case 32: return 2; |
| 147 | + case 64: return 3; |
| 148 | + case 128: return 4; |
| 149 | + case 256: return 5; |
| 150 | + case 512: return 6; |
| 151 | + case 1023: return 7; |
| 152 | + default: return 0; |
| 153 | + } |
| 154 | + } |
| 155 | + |
| 156 | + inline void epBank0DisableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.AUTO_ZLP = 0; } |
| 157 | + inline void epBank1DisableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = 0; } |
| 158 | + inline void epBank0EnableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.AUTO_ZLP = 1; } |
| 159 | + inline void epBank1EnableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = 1; } |
| 160 | + |
| 161 | +private: |
| 162 | + // USB Device registers |
| 163 | + UsbDevice &usb; |
| 164 | + |
| 165 | + // Endpoints descriptors table |
| 166 | + __attribute__((__aligned__(4))) UsbDeviceDescriptor EP[USB_EPT_NUM]; |
| 167 | +}; |
| 168 | + |
| 169 | +void USBDevice_SAMR21G18x::reset() { |
| 170 | + usb.CTRLA.bit.SWRST = 1; |
| 171 | + memset(EP, 0, sizeof(EP)); |
| 172 | + while (usb.SYNCBUSY.bit.SWRST) {} |
| 173 | + usb.DESCADD.reg = (uint32_t)(&EP); |
| 174 | +} |
| 175 | + |
| 176 | +void USBDevice_SAMR21G18x::calibrate() { |
| 177 | + // Load Pad Calibration data from non-volatile memory |
| 178 | + uint32_t *pad_transn_p = (uint32_t *) USB_FUSES_TRANSN_ADDR; |
| 179 | + uint32_t *pad_transp_p = (uint32_t *) USB_FUSES_TRANSP_ADDR; |
| 180 | + uint32_t *pad_trim_p = (uint32_t *) USB_FUSES_TRIM_ADDR; |
| 181 | + |
| 182 | + uint32_t pad_transn = (*pad_transn_p & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos; |
| 183 | + uint32_t pad_transp = (*pad_transp_p & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos; |
| 184 | + uint32_t pad_trim = (*pad_trim_p & USB_FUSES_TRIM_Msk ) >> USB_FUSES_TRIM_Pos; |
| 185 | + |
| 186 | + if (pad_transn == 0x1F) // maximum value (31) |
| 187 | + pad_transn = 5; |
| 188 | + if (pad_transp == 0x1F) // maximum value (31) |
| 189 | + pad_transp = 29; |
| 190 | + if (pad_trim == 0x7) // maximum value (7) |
| 191 | + pad_trim = 3; |
| 192 | + |
| 193 | + usb.PADCAL.bit.TRANSN = pad_transn; |
| 194 | + usb.PADCAL.bit.TRANSP = pad_transp; |
| 195 | + usb.PADCAL.bit.TRIM = pad_trim; |
| 196 | +} |
| 197 | + |
0 commit comments