USB device stack, with KL25Z fixes for USB 3.0 hosts and sleep/resume interrupt handling

Dependents:   frdm_Slider_Keyboard idd_hw2_figlax_PanType idd_hw2_appachu_finger_chording idd_hw3_AngieWangAntonioDeLimaFernandesDanielLim_BladeSymphony ... more

Fork of USBDevice by mbed official

This is an overhauled version of the standard mbed USB device-side driver library, with bug fixes for KL25Z devices. It greatly improves reliability and stability of USB on the KL25Z, especially with devices using multiple endpoints concurrently.

I've had some nagging problems with the base mbed implementation for a long time, manifesting as occasional random disconnects that required rebooting the device. Recently (late 2015), I started implementing a USB device on the KL25Z that used multiple endpoints, and suddenly the nagging, occasional problems turned into frequent and predictable crashes. This forced me to delve into the USB stack and figure out what was really going on. Happily, the frequent crashes made it possible to track down and fix the problems. This new version is working very reliably in my testing - the random disconnects seem completely eradicated, even under very stressful conditions for the device.

Summary

  • Overall stability improvements
  • USB 3.0 host support
  • Stalled endpoint fixes
  • Sleep/resume notifications
  • Smaller memory footprint
  • General code cleanup

Update - 2/15/2016

My recent fixes introduced a new problem that made the initial connection fail most of the time on certain hosts. It's not clear if the common thread was a particular type of motherboard or USB chip set, or a specific version of Windows, or what, but several people ran into it. We tracked the problem down to the "stall" fixes in the earlier updates, which we now know weren't quite the right fixes after all. The latest update (2/15/2016) fixes this. It has new and improved "unstall" handling that so far works well with diverse hosts.

Race conditions and overall stability

The base mbed KL25Z implementation has a lot of problems with "race conditions" - timing problems that can happen when hardware interrupts occur at inopportune moments. The library shares a bunch of static variable data between interrupt handler context and regular application context. This isn't automatically a bad thing, but it does require careful coordination to make sure that the interrupt handler doesn't corrupt data that the other code was in the middle of updating when an interrupt occurs. The base mbed code, though, doesn't do any of the necessary coordination. This makes it kind of amazing that the base code worked at all for anyone, but I guess the interrupt rate is low enough in most applications that the glitch rate was below anyone's threshold to seriously investigate.

This overhaul adds the necessary coordination for the interrupt handlers to protect against these data corruptions. I think it's very solid now, and hopefully entirely free of the numerous race conditions in the old code. It's always hard to be certain that you've fixed every possible bug like this because they strike (effectively) at random, but I'm pretty confident: my test application was reliably able to trigger glitches in the base code in a matter of minutes, but the same application (with the overhauled library) now runs for days on end without dropping the connection.

Stalled endpoint fixes

USB has a standard way of handling communications errors called a "stall", which basically puts the connection into an error mode to let both sides know that they need to reset their internal states and sync up again. The original mbed version of the USB device library doesn't seem to have the necessary code to recover from this condition properly. The KL25Z hardware does some of the work, but it also seems to require the software to take some steps to "un-stall" the connection. (I keep saying "seems to" because the hardware reference material is very sketchy about all of this. Most of what I've figured out is from observing the device in action with a Windows host.) This new version adds code to do the necessary re-syncing and get the connection going again, automatically, and transparently to the user.

USB 3.0 Hosts

The original mbed code sometimes didn't work when connecting to hosts with USB 3.0 ports. This didn't affect every host, but it affected many of them. The common element seemed to be the Intel Haswell chip set on the host, but there may be other chip sets affected as well. In any case, the problem affected many PCs from the Windows 7 and 8 generation, as well as many Macs. It was possible to work around the problem by avoiding USB 3.0 ports - you could use a USB 2 port on the host, or plug a USB 2 hub between the host and device. But I wanted to just fix the problem and eliminate the need for such workarounds. This modified version of the library has such a fix, which so far has worked for everyone who's tried.

Sleep/resume notifications

This modified version also contains an innocuous change to the KL25Z USB HAL code to handle sleep and resume interrupts with calls to suspendStateChanged(). The original KL25Z code omitted these calls (and in fact didn't even enable the interrupts), but I think this was an unintentional oversight - the notifier function is part of the generic API, and other supported boards all implement it. I use this feature in my own application so that I can distinguish sleep mode from actual disconnects and handle the two conditions correctly.

Smaller memory footprint

The base mbed version of the code allocates twice as much memory for USB buffers as it really needed to. It looks like the original developers intended to implement the KL25Z USB hardware's built-in double-buffering mechanism, but they ultimately abandoned that effort. But they left in the double memory allocation. This version removes that and allocates only what's actually needed. The USB buffers aren't that big (128 bytes per endpoint), so this doesn't save a ton of memory, but even a little memory is pretty precious on this machine given that it only has 16K.

(I did look into adding the double-buffering support that the original developers abandoned, but after some experimentation I decided they were right to skip it. It just doesn't seem to mesh well with the design of the rest of the mbed USB code. I think it would take a major rewrite to make it work, and it doesn't seem worth the effort given that most applications don't need it - it would only benefit applications that are moving so much data through USB that they're pushing the limits of the CPU. And even for those, I think it would be a lot simpler to build a purely software-based buffer rotation mechanism.)

General code cleanup

The KL25Z HAL code in this version has greatly expanded commentary and a lot of general cleanup. Some of the hardware constants were given the wrong symbolic names (e.g., EVEN and ODD were reversed), and many were just missing (written as hard-coded numbers without explanation). I fixed the misnomers and added symbolic names for formerly anonymous numbers. Hopefully the next person who has to overhaul this code will at least have an easier time understanding what I thought I was doing!

Committer:
mjr
Date:
Fri Mar 17 22:01:47 2017 +0000
Revision:
54:2e181d51495a
Parent:
25:7c72828865f3
Comments

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 16:4f6df64750bd 1 /* Copyright (c) 2010-2011 mbed.org, MIT License
mbed_official 16:4f6df64750bd 2 *
mbed_official 16:4f6df64750bd 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
mbed_official 16:4f6df64750bd 4 * and associated documentation files (the "Software"), to deal in the Software without
mbed_official 16:4f6df64750bd 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
mbed_official 16:4f6df64750bd 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
mbed_official 16:4f6df64750bd 7 * Software is furnished to do so, subject to the following conditions:
mbed_official 16:4f6df64750bd 8 *
mbed_official 16:4f6df64750bd 9 * The above copyright notice and this permission notice shall be included in all copies or
mbed_official 16:4f6df64750bd 10 * substantial portions of the Software.
mbed_official 16:4f6df64750bd 11 *
mbed_official 16:4f6df64750bd 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
mbed_official 16:4f6df64750bd 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
mbed_official 16:4f6df64750bd 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
mbed_official 16:4f6df64750bd 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
mbed_official 16:4f6df64750bd 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
mbed_official 16:4f6df64750bd 17 */
mbed_official 16:4f6df64750bd 18
mbed_official 16:4f6df64750bd 19 #if defined(TARGET_STM32F4XX)
mbed_official 16:4f6df64750bd 20
mbed_official 16:4f6df64750bd 21 #include "USBHAL.h"
mbed_official 16:4f6df64750bd 22 #include "USBRegs_STM32.h"
mbed_official 16:4f6df64750bd 23 #include "pinmap.h"
mbed_official 16:4f6df64750bd 24
mbed_official 16:4f6df64750bd 25 USBHAL * USBHAL::instance;
mbed_official 16:4f6df64750bd 26
mbed_official 16:4f6df64750bd 27 static volatile int epComplete = 0;
mbed_official 16:4f6df64750bd 28
mbed_official 16:4f6df64750bd 29 static uint32_t bufferEnd = 0;
mbed_official 16:4f6df64750bd 30 static const uint32_t rxFifoSize = 512;
mbed_official 16:4f6df64750bd 31 static uint32_t rxFifoCount = 0;
mbed_official 16:4f6df64750bd 32
mbed_official 16:4f6df64750bd 33 static uint32_t setupBuffer[MAX_PACKET_SIZE_EP0 >> 2];
mbed_official 16:4f6df64750bd 34
mbed_official 16:4f6df64750bd 35 uint32_t USBHAL::endpointReadcore(uint8_t endpoint, uint8_t *buffer) {
mbed_official 16:4f6df64750bd 36 return 0;
mbed_official 16:4f6df64750bd 37 }
mbed_official 16:4f6df64750bd 38
mbed_official 25:7c72828865f3 39 USBHAL::USBHAL(void) {
mbed_official 16:4f6df64750bd 40 NVIC_DisableIRQ(OTG_FS_IRQn);
mbed_official 16:4f6df64750bd 41 epCallback[0] = &USBHAL::EP1_OUT_callback;
mbed_official 16:4f6df64750bd 42 epCallback[1] = &USBHAL::EP1_IN_callback;
mbed_official 16:4f6df64750bd 43 epCallback[2] = &USBHAL::EP2_OUT_callback;
mbed_official 16:4f6df64750bd 44 epCallback[3] = &USBHAL::EP2_IN_callback;
mbed_official 16:4f6df64750bd 45 epCallback[4] = &USBHAL::EP3_OUT_callback;
mbed_official 16:4f6df64750bd 46 epCallback[5] = &USBHAL::EP3_IN_callback;
mbed_official 16:4f6df64750bd 47
mbed_official 16:4f6df64750bd 48 // Enable power and clocking
mbed_official 16:4f6df64750bd 49 RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
mbed_official 16:4f6df64750bd 50
mbed_official 16:4f6df64750bd 51 pin_function(PA_8, STM_PIN_DATA(2, 10));
mbed_official 16:4f6df64750bd 52 pin_function(PA_9, STM_PIN_DATA(0, 0));
mbed_official 16:4f6df64750bd 53 pin_function(PA_10, STM_PIN_DATA(2, 10));
mbed_official 16:4f6df64750bd 54 pin_function(PA_11, STM_PIN_DATA(2, 10));
mbed_official 16:4f6df64750bd 55 pin_function(PA_12, STM_PIN_DATA(2, 10));
mbed_official 16:4f6df64750bd 56
mbed_official 16:4f6df64750bd 57 // Set ID pin to open drain with pull-up resistor
mbed_official 16:4f6df64750bd 58 pin_mode(PA_10, OpenDrain);
mbed_official 16:4f6df64750bd 59 GPIOA->PUPDR &= ~(0x3 << 20);
mbed_official 16:4f6df64750bd 60 GPIOA->PUPDR |= 1 << 20;
mbed_official 16:4f6df64750bd 61
mbed_official 16:4f6df64750bd 62 // Set VBUS pin to open drain
mbed_official 16:4f6df64750bd 63 pin_mode(PA_9, OpenDrain);
mbed_official 16:4f6df64750bd 64
mbed_official 16:4f6df64750bd 65 RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
mbed_official 25:7c72828865f3 66
mbed_official 16:4f6df64750bd 67 // Enable interrupts
mbed_official 16:4f6df64750bd 68 OTG_FS->GREGS.GAHBCFG |= (1 << 0);
mbed_official 16:4f6df64750bd 69
mbed_official 16:4f6df64750bd 70 // Turnaround time to maximum value - too small causes packet loss
mbed_official 16:4f6df64750bd 71 OTG_FS->GREGS.GUSBCFG |= (0xF << 10);
mbed_official 16:4f6df64750bd 72
mbed_official 16:4f6df64750bd 73 // Unmask global interrupts
mbed_official 16:4f6df64750bd 74 OTG_FS->GREGS.GINTMSK |= (1 << 3) | // SOF
mbed_official 16:4f6df64750bd 75 (1 << 4) | // RX FIFO not empty
mbed_official 16:4f6df64750bd 76 (1 << 12); // USB reset
mbed_official 16:4f6df64750bd 77
mbed_official 16:4f6df64750bd 78 OTG_FS->DREGS.DCFG |= (0x3 << 0) | // Full speed
mbed_official 16:4f6df64750bd 79 (1 << 2); // Non-zero-length status OUT handshake
mbed_official 16:4f6df64750bd 80
mbed_official 16:4f6df64750bd 81 OTG_FS->GREGS.GCCFG |= (1 << 19) | // Enable VBUS sensing
mbed_official 16:4f6df64750bd 82 (1 << 16); // Power Up
mbed_official 16:4f6df64750bd 83
mbed_official 16:4f6df64750bd 84 instance = this;
mbed_official 16:4f6df64750bd 85 NVIC_SetVector(OTG_FS_IRQn, (uint32_t)&_usbisr);
mbed_official 16:4f6df64750bd 86 NVIC_SetPriority(OTG_FS_IRQn, 1);
mbed_official 16:4f6df64750bd 87 }
mbed_official 16:4f6df64750bd 88
mbed_official 16:4f6df64750bd 89 USBHAL::~USBHAL(void) {
mbed_official 16:4f6df64750bd 90 }
mbed_official 16:4f6df64750bd 91
mbed_official 16:4f6df64750bd 92 void USBHAL::connect(void) {
mbed_official 16:4f6df64750bd 93 NVIC_EnableIRQ(OTG_FS_IRQn);
mbed_official 16:4f6df64750bd 94 }
mbed_official 16:4f6df64750bd 95
mbed_official 16:4f6df64750bd 96 void USBHAL::disconnect(void) {
mbed_official 16:4f6df64750bd 97 NVIC_DisableIRQ(OTG_FS_IRQn);
mbed_official 16:4f6df64750bd 98 }
mbed_official 16:4f6df64750bd 99
mbed_official 16:4f6df64750bd 100 void USBHAL::configureDevice(void) {
mbed_official 16:4f6df64750bd 101 // Not needed
mbed_official 16:4f6df64750bd 102 }
mbed_official 16:4f6df64750bd 103
mbed_official 16:4f6df64750bd 104 void USBHAL::unconfigureDevice(void) {
mbed_official 16:4f6df64750bd 105 // Not needed
mbed_official 16:4f6df64750bd 106 }
mbed_official 16:4f6df64750bd 107
mbed_official 16:4f6df64750bd 108 void USBHAL::setAddress(uint8_t address) {
mbed_official 16:4f6df64750bd 109 OTG_FS->DREGS.DCFG |= (address << 4);
mbed_official 16:4f6df64750bd 110 EP0write(0, 0);
mbed_official 16:4f6df64750bd 111 }
mbed_official 16:4f6df64750bd 112
mbed_official 16:4f6df64750bd 113 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket,
mbed_official 16:4f6df64750bd 114 uint32_t flags) {
mbed_official 16:4f6df64750bd 115 uint32_t epIndex = endpoint >> 1;
mbed_official 16:4f6df64750bd 116
mbed_official 16:4f6df64750bd 117 uint32_t type;
mbed_official 16:4f6df64750bd 118 switch (endpoint) {
mbed_official 25:7c72828865f3 119 case EP0IN:
mbed_official 16:4f6df64750bd 120 case EP0OUT:
mbed_official 16:4f6df64750bd 121 type = 0;
mbed_official 25:7c72828865f3 122 break;
mbed_official 16:4f6df64750bd 123 case EPISO_IN:
mbed_official 16:4f6df64750bd 124 case EPISO_OUT:
mbed_official 25:7c72828865f3 125 type = 1;
mbed_official 16:4f6df64750bd 126 case EPBULK_IN:
mbed_official 16:4f6df64750bd 127 case EPBULK_OUT:
mbed_official 25:7c72828865f3 128 type = 2;
mbed_official 25:7c72828865f3 129 break;
mbed_official 16:4f6df64750bd 130 case EPINT_IN:
mbed_official 16:4f6df64750bd 131 case EPINT_OUT:
mbed_official 25:7c72828865f3 132 type = 3;
mbed_official 25:7c72828865f3 133 break;
mbed_official 16:4f6df64750bd 134 }
mbed_official 16:4f6df64750bd 135
mbed_official 16:4f6df64750bd 136 // Generic in or out EP controls
mbed_official 16:4f6df64750bd 137 uint32_t control = (maxPacket << 0) | // Packet size
mbed_official 16:4f6df64750bd 138 (1 << 15) | // Active endpoint
mbed_official 16:4f6df64750bd 139 (type << 18); // Endpoint type
mbed_official 16:4f6df64750bd 140
mbed_official 16:4f6df64750bd 141 if (endpoint & 0x1) { // In Endpoint
mbed_official 16:4f6df64750bd 142 // Set up the Tx FIFO
mbed_official 16:4f6df64750bd 143 if (endpoint == EP0IN) {
mbed_official 16:4f6df64750bd 144 OTG_FS->GREGS.DIEPTXF0_HNPTXFSIZ = ((maxPacket >> 2) << 16) |
mbed_official 16:4f6df64750bd 145 (bufferEnd << 0);
mbed_official 16:4f6df64750bd 146 }
mbed_official 16:4f6df64750bd 147 else {
mbed_official 16:4f6df64750bd 148 OTG_FS->GREGS.DIEPTXF[epIndex - 1] = ((maxPacket >> 2) << 16) |
mbed_official 16:4f6df64750bd 149 (bufferEnd << 0);
mbed_official 16:4f6df64750bd 150 }
mbed_official 16:4f6df64750bd 151 bufferEnd += maxPacket >> 2;
mbed_official 16:4f6df64750bd 152
mbed_official 16:4f6df64750bd 153 // Set the In EP specific control settings
mbed_official 16:4f6df64750bd 154 if (endpoint != EP0IN) {
mbed_official 16:4f6df64750bd 155 control |= (1 << 28); // SD0PID
mbed_official 16:4f6df64750bd 156 }
mbed_official 25:7c72828865f3 157
mbed_official 16:4f6df64750bd 158 control |= (epIndex << 22) | // TxFIFO index
mbed_official 16:4f6df64750bd 159 (1 << 27); // SNAK
mbed_official 16:4f6df64750bd 160 OTG_FS->INEP_REGS[epIndex].DIEPCTL = control;
mbed_official 16:4f6df64750bd 161
mbed_official 16:4f6df64750bd 162 // Unmask the interrupt
mbed_official 16:4f6df64750bd 163 OTG_FS->DREGS.DAINTMSK |= (1 << epIndex);
mbed_official 16:4f6df64750bd 164 }
mbed_official 16:4f6df64750bd 165 else { // Out endpoint
mbed_official 16:4f6df64750bd 166 // Set the out EP specific control settings
mbed_official 16:4f6df64750bd 167 control |= (1 << 26); // CNAK
mbed_official 16:4f6df64750bd 168 OTG_FS->OUTEP_REGS[epIndex].DOEPCTL = control;
mbed_official 25:7c72828865f3 169
mbed_official 16:4f6df64750bd 170 // Unmask the interrupt
mbed_official 16:4f6df64750bd 171 OTG_FS->DREGS.DAINTMSK |= (1 << (epIndex + 16));
mbed_official 16:4f6df64750bd 172 }
mbed_official 16:4f6df64750bd 173 return true;
mbed_official 16:4f6df64750bd 174 }
mbed_official 16:4f6df64750bd 175
mbed_official 16:4f6df64750bd 176 // read setup packet
mbed_official 16:4f6df64750bd 177 void USBHAL::EP0setup(uint8_t *buffer) {
mbed_official 16:4f6df64750bd 178 memcpy(buffer, setupBuffer, MAX_PACKET_SIZE_EP0);
mbed_official 16:4f6df64750bd 179 }
mbed_official 16:4f6df64750bd 180
mbed_official 16:4f6df64750bd 181 void USBHAL::EP0readStage(void) {
mbed_official 16:4f6df64750bd 182 }
mbed_official 16:4f6df64750bd 183
mbed_official 16:4f6df64750bd 184 void USBHAL::EP0read(void) {
mbed_official 16:4f6df64750bd 185 }
mbed_official 16:4f6df64750bd 186
mbed_official 16:4f6df64750bd 187 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
mbed_official 16:4f6df64750bd 188 uint32_t* buffer32 = (uint32_t *) buffer;
mbed_official 16:4f6df64750bd 189 uint32_t length = rxFifoCount;
mbed_official 16:4f6df64750bd 190 for (uint32_t i = 0; i < length; i += 4) {
mbed_official 16:4f6df64750bd 191 buffer32[i >> 2] = OTG_FS->FIFO[0][0];
mbed_official 16:4f6df64750bd 192 }
mbed_official 25:7c72828865f3 193
mbed_official 16:4f6df64750bd 194 rxFifoCount = 0;
mbed_official 16:4f6df64750bd 195 return length;
mbed_official 16:4f6df64750bd 196 }
mbed_official 16:4f6df64750bd 197
mbed_official 16:4f6df64750bd 198 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
mbed_official 16:4f6df64750bd 199 endpointWrite(0, buffer, size);
mbed_official 16:4f6df64750bd 200 }
mbed_official 16:4f6df64750bd 201
mbed_official 16:4f6df64750bd 202 void USBHAL::EP0getWriteResult(void) {
mbed_official 16:4f6df64750bd 203 }
mbed_official 16:4f6df64750bd 204
mbed_official 16:4f6df64750bd 205 void USBHAL::EP0stall(void) {
mbed_official 16:4f6df64750bd 206 // If we stall the out endpoint here then we have problems transferring
mbed_official 16:4f6df64750bd 207 // and setup requests after the (stalled) get device qualifier requests.
mbed_official 16:4f6df64750bd 208 // TODO: Find out if this is correct behavior, or whether we are doing
mbed_official 16:4f6df64750bd 209 // something else wrong
mbed_official 16:4f6df64750bd 210 stallEndpoint(EP0IN);
mbed_official 16:4f6df64750bd 211 // stallEndpoint(EP0OUT);
mbed_official 16:4f6df64750bd 212 }
mbed_official 16:4f6df64750bd 213
mbed_official 16:4f6df64750bd 214 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
mbed_official 16:4f6df64750bd 215 uint32_t epIndex = endpoint >> 1;
mbed_official 16:4f6df64750bd 216 uint32_t size = (1 << 19) | // 1 packet
mbed_official 16:4f6df64750bd 217 (maximumSize << 0); // Packet size
mbed_official 16:4f6df64750bd 218 // if (endpoint == EP0OUT) {
mbed_official 16:4f6df64750bd 219 size |= (1 << 29); // 1 setup packet
mbed_official 16:4f6df64750bd 220 // }
mbed_official 16:4f6df64750bd 221 OTG_FS->OUTEP_REGS[epIndex].DOEPTSIZ = size;
mbed_official 16:4f6df64750bd 222 OTG_FS->OUTEP_REGS[epIndex].DOEPCTL |= (1 << 31) | // Enable endpoint
mbed_official 16:4f6df64750bd 223 (1 << 26); // Clear NAK
mbed_official 16:4f6df64750bd 224
mbed_official 16:4f6df64750bd 225 epComplete &= ~(1 << endpoint);
mbed_official 16:4f6df64750bd 226 return EP_PENDING;
mbed_official 16:4f6df64750bd 227 }
mbed_official 16:4f6df64750bd 228
mbed_official 16:4f6df64750bd 229 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_t *bytesRead) {
mbed_official 16:4f6df64750bd 230 if (!(epComplete & (1 << endpoint))) {
mbed_official 16:4f6df64750bd 231 return EP_PENDING;
mbed_official 16:4f6df64750bd 232 }
mbed_official 16:4f6df64750bd 233
mbed_official 16:4f6df64750bd 234 uint32_t* buffer32 = (uint32_t *) buffer;
mbed_official 16:4f6df64750bd 235 uint32_t length = rxFifoCount;
mbed_official 16:4f6df64750bd 236 for (uint32_t i = 0; i < length; i += 4) {
mbed_official 16:4f6df64750bd 237 buffer32[i >> 2] = OTG_FS->FIFO[endpoint >> 1][0];
mbed_official 16:4f6df64750bd 238 }
mbed_official 16:4f6df64750bd 239 rxFifoCount = 0;
mbed_official 16:4f6df64750bd 240 *bytesRead = length;
mbed_official 16:4f6df64750bd 241 return EP_COMPLETED;
mbed_official 16:4f6df64750bd 242 }
mbed_official 16:4f6df64750bd 243
mbed_official 16:4f6df64750bd 244 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
mbed_official 16:4f6df64750bd 245 uint32_t epIndex = endpoint >> 1;
mbed_official 16:4f6df64750bd 246 OTG_FS->INEP_REGS[epIndex].DIEPTSIZ = (1 << 19) | // 1 packet
mbed_official 16:4f6df64750bd 247 (size << 0); // Size of packet
mbed_official 16:4f6df64750bd 248 OTG_FS->INEP_REGS[epIndex].DIEPCTL |= (1 << 31) | // Enable endpoint
mbed_official 16:4f6df64750bd 249 (1 << 26); // CNAK
mbed_official 16:4f6df64750bd 250 OTG_FS->DREGS.DIEPEMPMSK = (1 << epIndex);
mbed_official 16:4f6df64750bd 251
mbed_official 16:4f6df64750bd 252 while ((OTG_FS->INEP_REGS[epIndex].DTXFSTS & 0XFFFF) < ((size + 3) >> 2));
mbed_official 16:4f6df64750bd 253
mbed_official 16:4f6df64750bd 254 for (uint32_t i=0; i<(size + 3) >> 2; i++, data+=4) {
mbed_official 16:4f6df64750bd 255 OTG_FS->FIFO[epIndex][0] = *(uint32_t *)data;
mbed_official 16:4f6df64750bd 256 }
mbed_official 16:4f6df64750bd 257
mbed_official 16:4f6df64750bd 258 epComplete &= ~(1 << endpoint);
mbed_official 16:4f6df64750bd 259
mbed_official 16:4f6df64750bd 260 return EP_PENDING;
mbed_official 16:4f6df64750bd 261 }
mbed_official 16:4f6df64750bd 262
mbed_official 16:4f6df64750bd 263 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
mbed_official 16:4f6df64750bd 264 if (epComplete & (1 << endpoint)) {
mbed_official 16:4f6df64750bd 265 epComplete &= ~(1 << endpoint);
mbed_official 16:4f6df64750bd 266 return EP_COMPLETED;
mbed_official 16:4f6df64750bd 267 }
mbed_official 16:4f6df64750bd 268
mbed_official 25:7c72828865f3 269 return EP_PENDING;
mbed_official 16:4f6df64750bd 270 }
mbed_official 16:4f6df64750bd 271
mbed_official 16:4f6df64750bd 272 void USBHAL::stallEndpoint(uint8_t endpoint) {
mbed_official 16:4f6df64750bd 273 if (endpoint & 0x1) { // In EP
mbed_official 16:4f6df64750bd 274 OTG_FS->INEP_REGS[endpoint >> 1].DIEPCTL |= (1 << 30) | // Disable
mbed_official 16:4f6df64750bd 275 (1 << 21); // Stall
mbed_official 16:4f6df64750bd 276 }
mbed_official 16:4f6df64750bd 277 else { // Out EP
mbed_official 16:4f6df64750bd 278 OTG_FS->DREGS.DCTL |= (1 << 9); // Set global out NAK
mbed_official 16:4f6df64750bd 279 OTG_FS->OUTEP_REGS[endpoint >> 1].DOEPCTL |= (1 << 30) | // Disable
mbed_official 16:4f6df64750bd 280 (1 << 21); // Stall
mbed_official 16:4f6df64750bd 281 }
mbed_official 16:4f6df64750bd 282 }
mbed_official 16:4f6df64750bd 283
mbed_official 16:4f6df64750bd 284 void USBHAL::unstallEndpoint(uint8_t endpoint) {
mbed_official 25:7c72828865f3 285
mbed_official 16:4f6df64750bd 286 }
mbed_official 16:4f6df64750bd 287
mbed_official 16:4f6df64750bd 288 bool USBHAL::getEndpointStallState(uint8_t endpoint) {
mbed_official 16:4f6df64750bd 289 return false;
mbed_official 16:4f6df64750bd 290 }
mbed_official 16:4f6df64750bd 291
mbed_official 16:4f6df64750bd 292 void USBHAL::remoteWakeup(void) {
mbed_official 16:4f6df64750bd 293 }
mbed_official 16:4f6df64750bd 294
mbed_official 16:4f6df64750bd 295
mbed_official 16:4f6df64750bd 296 void USBHAL::_usbisr(void) {
mbed_official 16:4f6df64750bd 297 instance->usbisr();
mbed_official 16:4f6df64750bd 298 }
mbed_official 16:4f6df64750bd 299
mbed_official 16:4f6df64750bd 300
mbed_official 16:4f6df64750bd 301 void USBHAL::usbisr(void) {
mbed_official 16:4f6df64750bd 302 if (OTG_FS->GREGS.GINTSTS & (1 << 12)) { // USB Reset
mbed_official 16:4f6df64750bd 303 // Set SNAK bits
mbed_official 16:4f6df64750bd 304 OTG_FS->OUTEP_REGS[0].DOEPCTL |= (1 << 27);
mbed_official 16:4f6df64750bd 305 OTG_FS->OUTEP_REGS[1].DOEPCTL |= (1 << 27);
mbed_official 16:4f6df64750bd 306 OTG_FS->OUTEP_REGS[2].DOEPCTL |= (1 << 27);
mbed_official 16:4f6df64750bd 307 OTG_FS->OUTEP_REGS[3].DOEPCTL |= (1 << 27);
mbed_official 16:4f6df64750bd 308
mbed_official 16:4f6df64750bd 309 OTG_FS->DREGS.DIEPMSK = (1 << 0);
mbed_official 16:4f6df64750bd 310
mbed_official 16:4f6df64750bd 311 bufferEnd = 0;
mbed_official 16:4f6df64750bd 312
mbed_official 16:4f6df64750bd 313 // Set the receive FIFO size
mbed_official 16:4f6df64750bd 314 OTG_FS->GREGS.GRXFSIZ = rxFifoSize >> 2;
mbed_official 16:4f6df64750bd 315 bufferEnd += rxFifoSize >> 2;
mbed_official 16:4f6df64750bd 316
mbed_official 16:4f6df64750bd 317 // Create the endpoints, and wait for setup packets on out EP0
mbed_official 16:4f6df64750bd 318 realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0, 0);
mbed_official 16:4f6df64750bd 319 realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0, 0);
mbed_official 16:4f6df64750bd 320 endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
mbed_official 16:4f6df64750bd 321
mbed_official 16:4f6df64750bd 322 OTG_FS->GREGS.GINTSTS = (1 << 12);
mbed_official 16:4f6df64750bd 323 }
mbed_official 16:4f6df64750bd 324
mbed_official 16:4f6df64750bd 325 if (OTG_FS->GREGS.GINTSTS & (1 << 4)) { // RX FIFO not empty
mbed_official 16:4f6df64750bd 326 uint32_t status = OTG_FS->GREGS.GRXSTSP;
mbed_official 16:4f6df64750bd 327
mbed_official 16:4f6df64750bd 328 uint32_t endpoint = (status & 0xF) << 1;
mbed_official 16:4f6df64750bd 329 uint32_t length = (status >> 4) & 0x7FF;
mbed_official 16:4f6df64750bd 330 uint32_t type = (status >> 17) & 0xF;
mbed_official 16:4f6df64750bd 331
mbed_official 16:4f6df64750bd 332 rxFifoCount = length;
mbed_official 16:4f6df64750bd 333
mbed_official 16:4f6df64750bd 334 if (type == 0x6) {
mbed_official 16:4f6df64750bd 335 // Setup packet
mbed_official 16:4f6df64750bd 336 for (uint32_t i=0; i<length; i+=4) {
mbed_official 16:4f6df64750bd 337 setupBuffer[i >> 2] = OTG_FS->FIFO[0][i >> 2];
mbed_official 16:4f6df64750bd 338 }
mbed_official 16:4f6df64750bd 339 rxFifoCount = 0;
mbed_official 16:4f6df64750bd 340 }
mbed_official 16:4f6df64750bd 341
mbed_official 16:4f6df64750bd 342 if (type == 0x4) {
mbed_official 16:4f6df64750bd 343 // Setup complete
mbed_official 16:4f6df64750bd 344 EP0setupCallback();
mbed_official 16:4f6df64750bd 345 endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
mbed_official 16:4f6df64750bd 346 }
mbed_official 16:4f6df64750bd 347
mbed_official 16:4f6df64750bd 348 if (type == 0x2) {
mbed_official 16:4f6df64750bd 349 // Out packet
mbed_official 16:4f6df64750bd 350 if (endpoint == EP0OUT) {
mbed_official 16:4f6df64750bd 351 EP0out();
mbed_official 16:4f6df64750bd 352 }
mbed_official 16:4f6df64750bd 353 else {
mbed_official 16:4f6df64750bd 354 epComplete |= (1 << endpoint);
mbed_official 16:4f6df64750bd 355 if ((instance->*(epCallback[endpoint - 2]))()) {
mbed_official 16:4f6df64750bd 356 epComplete &= (1 << endpoint);
mbed_official 16:4f6df64750bd 357 }
mbed_official 16:4f6df64750bd 358 }
mbed_official 16:4f6df64750bd 359 }
mbed_official 16:4f6df64750bd 360
mbed_official 16:4f6df64750bd 361 for (uint32_t i=0; i<rxFifoCount; i+=4) {
mbed_official 16:4f6df64750bd 362 (void) OTG_FS->FIFO[0][0];
mbed_official 16:4f6df64750bd 363 }
mbed_official 16:4f6df64750bd 364 OTG_FS->GREGS.GINTSTS = (1 << 4);
mbed_official 16:4f6df64750bd 365 }
mbed_official 16:4f6df64750bd 366
mbed_official 16:4f6df64750bd 367 if (OTG_FS->GREGS.GINTSTS & (1 << 18)) { // In endpoint interrupt
mbed_official 16:4f6df64750bd 368 // Loop through the in endpoints
mbed_official 16:4f6df64750bd 369 for (uint32_t i=0; i<4; i++) {
mbed_official 16:4f6df64750bd 370 if (OTG_FS->DREGS.DAINT & (1 << i)) { // Interrupt is on endpoint
mbed_official 16:4f6df64750bd 371
mbed_official 16:4f6df64750bd 372 if (OTG_FS->INEP_REGS[i].DIEPINT & (1 << 7)) {// Tx FIFO empty
mbed_official 16:4f6df64750bd 373 // If the Tx FIFO is empty on EP0 we need to send a further
mbed_official 16:4f6df64750bd 374 // packet, so call EP0in()
mbed_official 16:4f6df64750bd 375 if (i == 0) {
mbed_official 16:4f6df64750bd 376 EP0in();
mbed_official 16:4f6df64750bd 377 }
mbed_official 16:4f6df64750bd 378 // Clear the interrupt
mbed_official 16:4f6df64750bd 379 OTG_FS->INEP_REGS[i].DIEPINT = (1 << 7);
mbed_official 16:4f6df64750bd 380 // Stop firing Tx empty interrupts
mbed_official 16:4f6df64750bd 381 // Will get turned on again if another write is called
mbed_official 16:4f6df64750bd 382 OTG_FS->DREGS.DIEPEMPMSK &= ~(1 << i);
mbed_official 16:4f6df64750bd 383 }
mbed_official 16:4f6df64750bd 384
mbed_official 16:4f6df64750bd 385 // If the transfer is complete
mbed_official 16:4f6df64750bd 386 if (OTG_FS->INEP_REGS[i].DIEPINT & (1 << 0)) { // Tx Complete
mbed_official 16:4f6df64750bd 387 epComplete |= (1 << (1 + (i << 1)));
mbed_official 16:4f6df64750bd 388 OTG_FS->INEP_REGS[i].DIEPINT = (1 << 0);
mbed_official 16:4f6df64750bd 389 }
mbed_official 16:4f6df64750bd 390 }
mbed_official 16:4f6df64750bd 391 }
mbed_official 16:4f6df64750bd 392 OTG_FS->GREGS.GINTSTS = (1 << 18);
mbed_official 16:4f6df64750bd 393 }
mbed_official 16:4f6df64750bd 394
mbed_official 16:4f6df64750bd 395 if (OTG_FS->GREGS.GINTSTS & (1 << 3)) { // Start of frame
mbed_official 16:4f6df64750bd 396 SOF((OTG_FS->GREGS.GRXSTSR >> 17) & 0xF);
mbed_official 16:4f6df64750bd 397 OTG_FS->GREGS.GINTSTS = (1 << 3);
mbed_official 16:4f6df64750bd 398 }
mbed_official 16:4f6df64750bd 399 }
mbed_official 16:4f6df64750bd 400
mbed_official 16:4f6df64750bd 401
mbed_official 16:4f6df64750bd 402 #endif