Tomas Cerskus / USBDevice

Fork of USBDevice by Tomas Cerskus

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHAL_STM32F4.cpp Source File

USBHAL_STM32F4.cpp

00001 /* Copyright (c) 2010-2011 mbed.org, MIT License
00002 *
00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004 * and associated documentation files (the "Software"), to deal in the Software without
00005 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
00006 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
00007 * Software is furnished to do so, subject to the following conditions:
00008 *
00009 * The above copyright notice and this permission notice shall be included in all copies or
00010 * substantial portions of the Software.
00011 *
00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017 */
00018 
00019 #if defined(TARGET_STM32F4XX) or defined(TARGET_NUCLEO_F401RE)
00020 
00021 #include "USBHAL.h"
00022 #include "USBRegs_STM32.h"
00023 #include "pinmap.h"
00024 #include "stm32f4xx_hal.h"
00025 
00026 
00027 
00028 USBHAL * USBHAL::instance;
00029 
00030 static volatile int epComplete = 0;
00031 
00032 static uint32_t bufferEnd = 0;
00033 static const uint32_t rxFifoSize = 512;
00034 static uint32_t rxFifoCount = 0;
00035 
00036 static uint32_t setupBuffer[MAX_PACKET_SIZE_EP0 >> 2];
00037 
00038 uint32_t USBHAL::endpointReadcore(uint8_t endpoint, uint8_t *buffer) {
00039     return 0;
00040 }
00041 
00042 USBHAL::USBHAL(void) {    
00043     NVIC_DisableIRQ(OTG_FS_IRQn);
00044     epCallback[0] = &USBHAL::EP1_OUT_callback;
00045     epCallback[1] = &USBHAL::EP1_IN_callback;
00046     epCallback[2] = &USBHAL::EP2_OUT_callback;
00047     epCallback[3] = &USBHAL::EP2_IN_callback;
00048     epCallback[4] = &USBHAL::EP3_OUT_callback;
00049     epCallback[5] = &USBHAL::EP3_IN_callback;
00050 
00051     // Enable power and clocking
00052     RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
00053 
00054 #if defined(TARGET_NUCLEO_F401RE)
00055     pin_function(PA_9, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0xFF));
00056     pin_function(PA_10, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_PULLUP, GPIO_AF10_OTG_FS));
00057     pin_function(PA_11, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS));
00058     pin_function(PA_12, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS));
00059 #elif
00060     pin_function(PA_8, STM_PIN_DATA(2, 10));
00061     pin_function(PA_9, STM_PIN_DATA(0, 0));
00062     pin_function(PA_10, STM_PIN_DATA(2, 10));
00063     pin_function(PA_11, STM_PIN_DATA(2, 10));
00064     pin_function(PA_12, STM_PIN_DATA(2, 10));
00065     
00066     // Set ID pin to open drain with pull-up resistor
00067     pin_mode(PA_10, OpenDrain);
00068     GPIOA->PUPDR &= ~(0x3 << 20);
00069     GPIOA->PUPDR |= 1 << 20;
00070 
00071     // Set VBUS pin to open drain
00072     pin_mode(PA_9, OpenDrain);
00073 #endif
00074 
00075     RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
00076     
00077     // Enable interrupts
00078     OTG_FS->GREGS.GAHBCFG |= (1 << 0);
00079 
00080     // Turnaround time to maximum value - too small causes packet loss
00081     OTG_FS->GREGS.GUSBCFG |= (0xF << 10);
00082 
00083     // Unmask global interrupts
00084     OTG_FS->GREGS.GINTMSK |= (1 << 3) | // SOF
00085                              (1 << 4) | // RX FIFO not empty
00086                              (1 << 12); // USB reset
00087 
00088     OTG_FS->DREGS.DCFG |= (0x3 << 0) | // Full speed
00089                           (1 << 2); // Non-zero-length status OUT handshake
00090 
00091     OTG_FS->GREGS.GCCFG |= (1 << 19) | // Enable VBUS sensing
00092                            (1 << 16); // Power Up
00093 
00094     instance = this;
00095     NVIC_SetVector(OTG_FS_IRQn, (uint32_t)&_usbisr);
00096     NVIC_SetPriority(OTG_FS_IRQn, 1);
00097 }
00098 
00099 USBHAL::~USBHAL(void) {
00100 }
00101 
00102 void USBHAL::connect(void) {
00103     NVIC_EnableIRQ(OTG_FS_IRQn);
00104 }
00105 
00106 void USBHAL::disconnect(void) {
00107     NVIC_DisableIRQ(OTG_FS_IRQn);
00108 }
00109 
00110 void USBHAL::configureDevice(void) {
00111     // Not needed
00112 }
00113 
00114 void USBHAL::unconfigureDevice(void) {
00115     // Not needed
00116 }
00117 
00118 void USBHAL::setAddress(uint8_t address) {
00119     OTG_FS->DREGS.DCFG |= (address << 4);
00120     EP0write(0, 0);
00121 }
00122 
00123 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket,
00124                              uint32_t flags) {
00125     uint32_t epIndex = endpoint >> 1;
00126 
00127     uint32_t type;
00128     switch (endpoint) {
00129         case EP0IN:  
00130         case EP0OUT:
00131             type = 0;
00132             break;   
00133         case EPISO_IN:
00134         case EPISO_OUT:
00135             type = 1; 
00136         case EPBULK_IN:
00137         case EPBULK_OUT:
00138             type = 2;  
00139             break;   
00140         case EPINT_IN:
00141         case EPINT_OUT:
00142             type = 3; 
00143             break;   
00144     }
00145 
00146     // Generic in or out EP controls
00147     uint32_t control = (maxPacket << 0) | // Packet size
00148                        (1 << 15) | // Active endpoint
00149                        (type << 18); // Endpoint type
00150 
00151     if (endpoint & 0x1) { // In Endpoint
00152         // Set up the Tx FIFO
00153         if (endpoint == EP0IN) {
00154             OTG_FS->GREGS.DIEPTXF0_HNPTXFSIZ = ((maxPacket >> 2) << 16) |
00155                                                (bufferEnd << 0);
00156         }
00157         else {
00158             OTG_FS->GREGS.DIEPTXF[epIndex - 1] = ((maxPacket >> 2) << 16) |
00159                                                  (bufferEnd << 0);
00160         }
00161         bufferEnd += maxPacket >> 2;
00162 
00163         // Set the In EP specific control settings
00164         if (endpoint != EP0IN) {
00165             control |= (1 << 28); // SD0PID
00166         }
00167         
00168         control |= (epIndex << 22) | // TxFIFO index
00169                    (1 << 27); // SNAK
00170         OTG_FS->INEP_REGS[epIndex].DIEPCTL = control;
00171 
00172         // Unmask the interrupt
00173         OTG_FS->DREGS.DAINTMSK |= (1 << epIndex);
00174     }
00175     else { // Out endpoint
00176         // Set the out EP specific control settings
00177         control |= (1 << 26); // CNAK
00178         OTG_FS->OUTEP_REGS[epIndex].DOEPCTL = control;
00179         
00180         // Unmask the interrupt
00181         OTG_FS->DREGS.DAINTMSK |= (1 << (epIndex + 16));
00182     }
00183     return true;
00184 }
00185 
00186 // read setup packet
00187 void USBHAL::EP0setup(uint8_t *buffer) {
00188     memcpy(buffer, setupBuffer, MAX_PACKET_SIZE_EP0);
00189 }
00190 
00191 void USBHAL::EP0readStage(void) {
00192 }
00193 
00194 void USBHAL::EP0read(void) {
00195 }
00196 
00197 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
00198     uint32_t* buffer32 = (uint32_t *) buffer;
00199     uint32_t length = rxFifoCount;
00200     for (uint32_t i = 0; i < length; i += 4) {
00201         buffer32[i >> 2] = OTG_FS->FIFO[0][0];
00202     }
00203                         
00204     rxFifoCount = 0;
00205     return length;
00206 }
00207 
00208 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
00209     endpointWrite(0, buffer, size);
00210 }
00211 
00212 void USBHAL::EP0getWriteResult(void) {
00213 }
00214 
00215 void USBHAL::EP0stall(void) {
00216     // If we stall the out endpoint here then we have problems transferring
00217     // and setup requests after the (stalled) get device qualifier requests.
00218     // TODO: Find out if this is correct behavior, or whether we are doing
00219     // something else wrong
00220     stallEndpoint(EP0IN);
00221 //    stallEndpoint(EP0OUT);
00222 }
00223 
00224 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
00225     uint32_t epIndex = endpoint >> 1;
00226     uint32_t size = (1 << 19) | // 1 packet
00227                     (maximumSize << 0); // Packet size
00228 //    if (endpoint == EP0OUT) {
00229         size |= (1 << 29); // 1 setup packet
00230 //    }
00231     OTG_FS->OUTEP_REGS[epIndex].DOEPTSIZ = size;
00232     OTG_FS->OUTEP_REGS[epIndex].DOEPCTL |= (1 << 31) | // Enable endpoint
00233                                            (1 << 26); // Clear NAK
00234 
00235     epComplete &= ~(1 << endpoint);
00236     return EP_PENDING;
00237 }
00238 
00239 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_t *bytesRead) {
00240     if (!(epComplete & (1 << endpoint))) {
00241         return EP_PENDING;
00242     }
00243 
00244     uint32_t* buffer32 = (uint32_t *) buffer;
00245     uint32_t length = rxFifoCount;
00246     for (uint32_t i = 0; i < length; i += 4) {
00247         buffer32[i >> 2] = OTG_FS->FIFO[endpoint >> 1][0];
00248     }
00249     rxFifoCount = 0;
00250     *bytesRead = length;
00251     return EP_COMPLETED;
00252 }
00253 
00254 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
00255     uint32_t epIndex = endpoint >> 1;
00256     OTG_FS->INEP_REGS[epIndex].DIEPTSIZ = (1 << 19) | // 1 packet
00257                                           (size << 0); // Size of packet
00258     OTG_FS->INEP_REGS[epIndex].DIEPCTL |= (1 << 31) | // Enable endpoint
00259                                           (1 << 26); // CNAK
00260     OTG_FS->DREGS.DIEPEMPMSK = (1 << epIndex);
00261 
00262     while ((OTG_FS->INEP_REGS[epIndex].DTXFSTS & 0XFFFF) < ((size + 3) >> 2));
00263 
00264     for (uint32_t i=0; i<(size + 3) >> 2; i++, data+=4) {
00265         OTG_FS->FIFO[epIndex][0] = *(uint32_t *)data;
00266     }
00267 
00268     epComplete &= ~(1 << endpoint);
00269 
00270     return EP_PENDING;
00271 }
00272 
00273 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
00274     if (epComplete & (1 << endpoint)) {
00275         epComplete &= ~(1 << endpoint);
00276         return EP_COMPLETED;
00277     }
00278 
00279     return EP_PENDING; 
00280 }
00281 
00282 void USBHAL::stallEndpoint(uint8_t endpoint) {
00283     if (endpoint & 0x1) { // In EP
00284         OTG_FS->INEP_REGS[endpoint >> 1].DIEPCTL |= (1 << 30) | // Disable
00285                                                     (1 << 21); // Stall
00286     }
00287     else {  // Out EP
00288         OTG_FS->DREGS.DCTL |= (1 << 9); // Set global out NAK
00289         OTG_FS->OUTEP_REGS[endpoint >> 1].DOEPCTL |= (1 << 30) | // Disable
00290                                                      (1 << 21); // Stall
00291     }
00292 }
00293 
00294 void USBHAL::unstallEndpoint(uint8_t endpoint) {
00295     
00296 }
00297 
00298 bool USBHAL::getEndpointStallState(uint8_t endpoint) {
00299     return false;
00300 }
00301 
00302 void USBHAL::remoteWakeup(void) {
00303 }
00304 
00305 
00306 void USBHAL::_usbisr(void) {
00307     instance->usbisr();
00308 }
00309 
00310 
00311 void USBHAL::usbisr(void) {
00312     if (OTG_FS->GREGS.GINTSTS & (1 << 12)) { // USB Reset
00313         // Set SNAK bits
00314         OTG_FS->OUTEP_REGS[0].DOEPCTL |= (1 << 27);
00315         OTG_FS->OUTEP_REGS[1].DOEPCTL |= (1 << 27);
00316         OTG_FS->OUTEP_REGS[2].DOEPCTL |= (1 << 27);
00317         OTG_FS->OUTEP_REGS[3].DOEPCTL |= (1 << 27);
00318 
00319         OTG_FS->DREGS.DIEPMSK = (1 << 0);
00320 
00321         bufferEnd = 0;
00322 
00323         // Set the receive FIFO size
00324         OTG_FS->GREGS.GRXFSIZ = rxFifoSize >> 2;
00325         bufferEnd += rxFifoSize >> 2;
00326 
00327         // Create the endpoints, and wait for setup packets on out EP0
00328         realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0, 0);
00329         realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0, 0);
00330         endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
00331 
00332         OTG_FS->GREGS.GINTSTS = (1 << 12);
00333     }
00334 
00335     if (OTG_FS->GREGS.GINTSTS & (1 << 4)) { // RX FIFO not empty
00336         uint32_t status = OTG_FS->GREGS.GRXSTSP;
00337 
00338         uint32_t endpoint = (status & 0xF) << 1;
00339         uint32_t length = (status >> 4) & 0x7FF;
00340         uint32_t type = (status >> 17) & 0xF;
00341 
00342         rxFifoCount = length;
00343 
00344         if (type == 0x6) {
00345             // Setup packet
00346             for (uint32_t i=0; i<length; i+=4) {
00347                 setupBuffer[i >> 2] = OTG_FS->FIFO[0][i >> 2];
00348             }
00349             rxFifoCount = 0;
00350         }
00351 
00352         if (type == 0x4) {
00353             // Setup complete
00354             EP0setupCallback();
00355             endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
00356         }
00357 
00358         if (type == 0x2) {
00359             // Out packet
00360             if (endpoint == EP0OUT) {
00361                 EP0out();
00362             }
00363             else {
00364                 epComplete |= (1 << endpoint);
00365                 if ((instance->*(epCallback[endpoint - 2]))()) {
00366                     epComplete &= (1 << endpoint);
00367                 }
00368             }
00369         }
00370 
00371         for (uint32_t i=0; i<rxFifoCount; i+=4) {
00372             (void) OTG_FS->FIFO[0][0];
00373         }
00374         OTG_FS->GREGS.GINTSTS = (1 << 4);
00375     }
00376 
00377     if (OTG_FS->GREGS.GINTSTS & (1 << 18)) { // In endpoint interrupt
00378         // Loop through the in endpoints
00379         for (uint32_t i=0; i<4; i++) {
00380             if (OTG_FS->DREGS.DAINT & (1 << i)) { // Interrupt is on endpoint
00381 
00382                 if (OTG_FS->INEP_REGS[i].DIEPINT & (1 << 7)) {// Tx FIFO empty
00383                     // If the Tx FIFO is empty on EP0 we need to send a further
00384                     // packet, so call EP0in()
00385                     if (i == 0) {
00386                         EP0in();
00387                     }
00388                     // Clear the interrupt
00389                     OTG_FS->INEP_REGS[i].DIEPINT = (1 << 7);
00390                     // Stop firing Tx empty interrupts
00391                     // Will get turned on again if another write is called
00392                     OTG_FS->DREGS.DIEPEMPMSK &= ~(1 << i);
00393                 }
00394 
00395                 // If the transfer is complete
00396                 if (OTG_FS->INEP_REGS[i].DIEPINT & (1 << 0)) { // Tx Complete
00397                     epComplete |= (1 << (1 + (i << 1)));
00398                     OTG_FS->INEP_REGS[i].DIEPINT = (1 << 0);
00399                 }
00400             }
00401         }
00402         OTG_FS->GREGS.GINTSTS = (1 << 18);
00403     }
00404 
00405     if (OTG_FS->GREGS.GINTSTS & (1 << 3)) { // Start of frame
00406         SOF((OTG_FS->GREGS.GRXSTSR >> 17) & 0xF);
00407         OTG_FS->GREGS.GINTSTS = (1 << 3);
00408     }
00409 }
00410 
00411 
00412 #endif