USBDevice for STM support

Dependents:   Nucleo_Usb_JoyMouse Nucleo_usbmouse ELEC350_1-referral-2018-usb-hid USBJoystick_HelloWorld2_wip ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHAL_Maxim.cpp Source File

USBHAL_Maxim.cpp

00001 /*******************************************************************************
00002  * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a
00005  * copy of this software and associated documentation files (the "Software"),
00006  * to deal in the Software without restriction, including without limitation
00007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008  * and/or sell copies of the Software, and to permit persons to whom the
00009  * Software is furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included
00012  * in all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00016  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00017  * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00018  * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020  * OTHER DEALINGS IN THE SOFTWARE.
00021  *
00022  * Except as contained in this notice, the name of Maxim Integrated
00023  * Products, Inc. shall not be used except as stated in the Maxim Integrated
00024  * Products, Inc. Branding Policy.
00025  *
00026  * The mere transfer of this software does not imply any licenses
00027  * of trade secrets, proprietary technology, copyrights, patents,
00028  * trademarks, maskwork rights, or any other form of intellectual
00029  * property whatsoever. Maxim Integrated Products, Inc. retains all
00030  * ownership rights.
00031  *******************************************************************************
00032  */
00033 
00034 #if defined(TARGET_Maxim)
00035 
00036 #include "USBHAL.h"
00037 #include "usb_regs.h"
00038 #include "clkman_regs.h"
00039 
00040 #define CONNECT_INTS    (MXC_F_USB_DEV_INTEN_BRST | MXC_F_USB_DEV_INTEN_SETUP | MXC_F_USB_DEV_INTEN_EP_IN | MXC_F_USB_DEV_INTEN_EP_OUT | MXC_F_USB_DEV_INTEN_DMA_ERR)
00041 
00042 USBHAL *USBHAL::instance;
00043 
00044 typedef struct {
00045     volatile uint32_t buf0_desc;
00046     volatile uint32_t buf0_address;
00047     volatile uint32_t buf1_desc;
00048     volatile uint32_t buf1_address;
00049 } ep_buffer_t;
00050 
00051 typedef struct {
00052     ep_buffer_t out_buffer;
00053     ep_buffer_t in_buffer;
00054 } ep0_buffer_t;
00055 
00056 typedef struct {
00057     ep0_buffer_t ep0;
00058     ep_buffer_t ep[MXC_USB_NUM_EP - 1];
00059 } ep_buffer_descriptor_t;
00060 
00061 // Static storage for endpoint buffer descriptor table. Must be 512 byte aligned for DMA.
00062 #ifdef __IAR_SYSTEMS_ICC__
00063 #pragma data_alignment = 512
00064 #else
00065 __attribute__ ((aligned (512))) 
00066 #endif
00067 ep_buffer_descriptor_t ep_buffer_descriptor;
00068 
00069 // static storage for temporary data buffers. Must be 32 byte aligned.
00070 #ifdef __IAR_SYSTEMS_ICC__
00071 #pragma data_alignment = 4
00072 #else
00073 __attribute__ ((aligned (4))) 
00074 #endif
00075 static uint8_t aligned_buffer[NUMBER_OF_LOGICAL_ENDPOINTS][MXC_USB_MAX_PACKET];
00076 
00077 // control packet state
00078 static enum {
00079     CTRL_NONE = 0,
00080     CTRL_SETUP,
00081     CTRL_OUT,
00082     CTRL_IN,
00083 } control_state;
00084 
00085 USBHAL::USBHAL(void)
00086 {
00087     NVIC_DisableIRQ(USB_IRQn);
00088 
00089 #if defined(TARGET_MAX32600)
00090     // The PLL must be enabled for USB
00091     MBED_ASSERT(MXC_CLKMAN->clk_config & MXC_F_CLKMAN_CLK_CONFIG_PLL_ENABLE);
00092 
00093     // Enable the USB clock
00094     MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_USB_GATE_N;
00095 #elif defined(TARGET_MAX32620)
00096     // Enable the USB clock
00097     MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_USB_CLOCK_ENABLE;
00098 #endif
00099 
00100     // reset the device
00101     MXC_USB->cn = 0;
00102     MXC_USB->cn = MXC_F_USB_CN_USB_EN;
00103     MXC_USB->dev_inten = 0;
00104     MXC_USB->dev_cn = 0;
00105     MXC_USB->dev_cn = MXC_F_USB_DEV_CN_URST;
00106     MXC_USB->dev_cn = 0;
00107 
00108     // fill in callback arrays
00109     epCallback[EP0OUT] = NULL;
00110     epCallback[EP0IN]  = NULL;
00111     epCallback[EP1OUT] = &USBHAL::EP1_OUT_callback;
00112     epCallback[EP1IN ] = &USBHAL::EP1_IN_callback;
00113     epCallback[EP2OUT] = &USBHAL::EP2_OUT_callback;
00114     epCallback[EP2IN ] = &USBHAL::EP2_IN_callback;
00115     epCallback[EP3OUT] = &USBHAL::EP3_OUT_callback;
00116     epCallback[EP3IN ] = &USBHAL::EP3_IN_callback;
00117     epCallback[EP4OUT] = &USBHAL::EP4_OUT_callback;
00118     epCallback[EP4IN ] = &USBHAL::EP4_IN_callback;
00119     epCallback[EP5OUT] = &USBHAL::EP5_OUT_callback;
00120     epCallback[EP5IN ] = &USBHAL::EP5_IN_callback;
00121     epCallback[EP6OUT] = &USBHAL::EP6_OUT_callback;
00122     epCallback[EP6IN ] = &USBHAL::EP6_IN_callback;
00123     epCallback[EP7OUT] = &USBHAL::EP7_OUT_callback;
00124     epCallback[EP7IN ] = &USBHAL::EP7_IN_callback;
00125 
00126     // clear driver state
00127     control_state = CTRL_NONE;
00128 
00129     // set the descriptor location
00130     MXC_USB->ep_base = (uint32_t)&ep_buffer_descriptor;
00131 
00132     // enable VBUS interrupts
00133     MXC_USB->dev_inten = MXC_F_USB_DEV_INTEN_NO_VBUS | MXC_F_USB_DEV_INTEN_VBUS;
00134 
00135     // attach IRQ handler and enable interrupts
00136     instance = this;
00137     NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
00138     NVIC_EnableIRQ(USB_IRQn);
00139 }
00140 
00141 USBHAL::~USBHAL(void)
00142 {
00143     MXC_USB->dev_cn = MXC_F_USB_DEV_CN_URST;
00144     MXC_USB->dev_cn = 0;
00145     MXC_USB->cn = 0;
00146 }
00147 
00148 void USBHAL::connect(void)
00149 {
00150     // enable interrupts
00151     MXC_USB->dev_inten |= CONNECT_INTS;
00152 
00153     // allow interrupts on ep0
00154     MXC_USB->ep[0] |= MXC_F_USB_EP_INT_EN;
00155 
00156     // pullup enable
00157     MXC_USB->dev_cn |= (MXC_F_USB_DEV_CN_CONNECT | MXC_F_USB_DEV_CN_FIFO_MODE);
00158 }
00159 
00160 void USBHAL::disconnect(void)
00161 {
00162     // disable interrupts
00163     MXC_USB->dev_inten &= ~CONNECT_INTS;
00164 
00165     // disable pullup
00166     MXC_USB->dev_cn &= ~MXC_F_USB_DEV_CN_CONNECT;
00167 }
00168 
00169 void USBHAL::configureDevice(void)
00170 {
00171     // do nothing
00172 }
00173 
00174 void USBHAL::unconfigureDevice(void)
00175 {
00176     // reset endpoints
00177     for (int i = 0; i < MXC_USB_NUM_EP; i++) {
00178         // Disable endpoint and clear the data toggle
00179         MXC_USB->ep[i] &= ~MXC_F_USB_EP_DIR;
00180         MXC_USB->ep[i] |= MXC_F_USB_EP_DT;
00181     }
00182 }
00183 
00184 void USBHAL::setAddress(uint8_t address)
00185 {
00186     // do nothing
00187 }
00188 
00189 void USBHAL::remoteWakeup(void)
00190 {
00191     // do nothing
00192 }
00193 
00194 static ep_buffer_t *get_desc(uint8_t endpoint)
00195 {
00196     uint8_t epnum = EP_NUM(endpoint);
00197     ep_buffer_t *desc;
00198 
00199     if (epnum == 0) {
00200         if (IN_EP(endpoint)) {
00201             desc = &ep_buffer_descriptor.ep0.in_buffer;
00202         } else {
00203             desc = &ep_buffer_descriptor.ep0.out_buffer;
00204         }
00205     } else {
00206         desc = &ep_buffer_descriptor.ep[epnum - 1];
00207     }
00208 
00209     return desc;
00210 }
00211 
00212 void USBHAL::EP0setup(uint8_t *buffer)
00213 {
00214     // Setup packet is fixed at 8 bytes
00215     // Setup registers cannot be read in byte mode
00216     uint32_t *ptr32 = (uint32_t*)buffer;
00217     ptr32[0] = (uint32_t)MXC_USB->setup0;
00218     ptr32[1] = (uint32_t)MXC_USB->setup1;
00219 }
00220 
00221 void USBHAL::EP0read(void)
00222 {
00223     if (control_state == CTRL_IN) {
00224         // This is the status stage. ACK.
00225         MXC_USB->ep[0] |= MXC_F_USB_EP_ST_ACK;
00226         control_state = CTRL_NONE;
00227         return;
00228     }
00229 
00230     control_state = CTRL_OUT;
00231 
00232     endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
00233 }
00234 
00235 void USBHAL::EP0readStage(void)
00236 {
00237     // do nothing
00238 }
00239 
00240 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer)
00241 {
00242     uint32_t size;
00243 
00244     if (MXC_USB->out_owner & 1) {
00245         return 0;
00246     }
00247 
00248     // get the packet length and contents
00249     ep_buffer_t *desc = get_desc(EP0OUT);
00250     size = desc->buf0_desc;
00251     memcpy(buffer, aligned_buffer[0], size);
00252 
00253     return size;
00254 }
00255 
00256 void USBHAL::EP0write(uint8_t *buffer, uint32_t size)
00257 {
00258     if ((size == 0) && (control_state != CTRL_IN)) {
00259         // This is a status stage ACK. Handle in hardware.
00260         MXC_USB->ep[0] |= MXC_F_USB_EP_ST_ACK;
00261         control_state = CTRL_NONE;
00262         return;
00263     }
00264 
00265     control_state = CTRL_IN;
00266 
00267     endpointWrite(EP0IN, buffer, size);
00268 }
00269 
00270 void USBHAL::EP0stall(void)
00271 {
00272     stallEndpoint(0);
00273 }
00274 
00275 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize)
00276 {
00277     uint8_t epnum = EP_NUM(endpoint);
00278 
00279     if ((endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) || IN_EP(endpoint)) {
00280         return EP_INVALID;
00281     }
00282 
00283     if (maximumSize > MXC_USB_MAX_PACKET) {
00284         return EP_INVALID;
00285     }
00286     
00287     uint32_t mask = (1 << epnum);
00288     if (MXC_USB->out_owner & mask) {
00289         return EP_INVALID;
00290     }
00291 
00292     ep_buffer_t *desc = get_desc(endpoint);
00293     desc->buf0_desc = maximumSize;
00294     desc->buf0_address = (uint32_t)aligned_buffer[epnum];
00295 
00296     MXC_USB->out_owner = mask;
00297 
00298     return EP_PENDING;
00299 }
00300 
00301 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead)
00302 {
00303     if ((endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) || IN_EP(endpoint)) {
00304         return EP_INVALID;
00305     }
00306 
00307     uint32_t mask = (1 << EP_NUM(endpoint));
00308     if (MXC_USB->out_owner & mask) {
00309         return EP_PENDING;
00310     }
00311 
00312     // get the packet length and contents
00313     ep_buffer_t *desc = get_desc(endpoint);
00314     *bytesRead = desc->buf0_desc;
00315     memcpy(data, aligned_buffer[EP_NUM(endpoint)], *bytesRead);
00316 
00317     return EP_COMPLETED;
00318 }
00319 
00320 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size)
00321 {
00322     uint8_t epnum = EP_NUM(endpoint);
00323 
00324     if ((endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) || OUT_EP(endpoint)) {
00325         return EP_INVALID;
00326     }
00327 
00328     if (size > MXC_USB_MAX_PACKET) {
00329         return EP_INVALID;
00330     }
00331 
00332     uint32_t mask = (1 << epnum);
00333     if (MXC_USB->in_owner & mask) {
00334         return EP_INVALID;
00335     }
00336 
00337     memcpy(aligned_buffer[epnum], data, size);
00338 
00339     ep_buffer_t *desc = get_desc(endpoint);
00340     desc->buf0_desc = size;
00341     desc->buf0_address = (uint32_t)aligned_buffer[epnum];
00342 
00343     // start the DMA
00344     MXC_USB->in_owner = mask;
00345 
00346     return EP_PENDING;
00347 }
00348 
00349 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint)
00350 {
00351     uint32_t mask = (1 << EP_NUM(endpoint));
00352     if (MXC_USB->in_owner & mask) {
00353         return EP_PENDING;
00354     }
00355 
00356     return EP_COMPLETED;
00357 }
00358 
00359 void USBHAL::stallEndpoint(uint8_t endpoint)
00360 {
00361     uint8_t epnum = EP_NUM(endpoint);
00362 
00363     if (epnum == 0) {
00364         MXC_USB->ep[epnum] |= MXC_F_USB_EP_ST_STALL;
00365     }
00366 
00367     MXC_USB->ep[epnum] |= MXC_F_USB_EP_STALL;
00368 }
00369 
00370 void USBHAL::unstallEndpoint(uint8_t endpoint)
00371 {
00372     MXC_USB->ep[EP_NUM(endpoint)] &= ~MXC_F_USB_EP_STALL;
00373 }
00374 
00375 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options)
00376 {
00377     uint8_t epnum = EP_NUM(endpoint);
00378     uint32_t ep_ctrl;
00379 
00380     if (epnum >= NUMBER_OF_PHYSICAL_ENDPOINTS) {
00381         return false;
00382     }
00383 
00384     if (IN_EP(endpoint)) {
00385         ep_ctrl = (MXC_V_USB_EP_DIR_IN << MXC_F_USB_EP_DIR_POS);
00386     } else {
00387         ep_ctrl = (MXC_S_USB_EP_DIR_OUT << MXC_F_USB_EP_DIR_POS);
00388     }
00389 
00390     ep_ctrl |= (MXC_F_USB_EP_DT | MXC_F_USB_EP_INT_EN);
00391 
00392     MXC_USB->ep[epnum] = ep_ctrl;
00393 
00394     return true;
00395 }
00396 
00397 bool USBHAL::getEndpointStallState(unsigned char endpoint)
00398 {
00399     return !!(MXC_USB->ep[endpoint] & MXC_F_USB_EP_STALL);
00400 }
00401 
00402 void USBHAL::_usbisr(void)
00403 {
00404     instance->usbisr();
00405 }
00406 
00407 void USBHAL::usbisr(void)
00408 {
00409     // get and clear irqs
00410     uint32_t irq_flags = MXC_USB->dev_intfl;
00411     MXC_USB->dev_intfl = irq_flags;
00412 
00413     // process only enabled interrupts
00414     irq_flags &= MXC_USB->dev_inten;
00415 
00416     // suspend 
00417     if (irq_flags & MXC_F_USB_DEV_INTFL_SUSP) {
00418         suspendStateChanged(1);
00419     }
00420 
00421     // bus reset
00422     if (irq_flags & MXC_F_USB_DEV_INTFL_BRST) {
00423 
00424         // reset endpoints
00425         for (int i = 0; i < MXC_USB_NUM_EP; i++) {
00426             // Disable endpoint and clear the data toggle
00427             MXC_USB->ep[i] &= ~MXC_F_USB_EP_DIR;
00428             MXC_USB->ep[i] |= MXC_F_USB_EP_DT;
00429         }
00430 
00431         // clear driver state
00432         control_state = CTRL_NONE;
00433 
00434         busReset();
00435 
00436         // no need to process events after reset
00437         return;
00438     }
00439 
00440     // Setup packet
00441     if (irq_flags & MXC_F_USB_DEV_INTFL_SETUP) {
00442         control_state = CTRL_SETUP;
00443         EP0setupCallback();
00444     }
00445 
00446     // IN packets
00447     if (irq_flags & MXC_F_USB_DEV_INTFL_EP_IN) {
00448         // get and clear IN irqs
00449         uint32_t in_irqs = MXC_USB->in_int;
00450         MXC_USB->in_int = in_irqs;
00451 
00452         if (in_irqs & 1) {
00453             EP0in();
00454         }
00455 
00456         for (uint8_t epnum = 1; epnum < NUMBER_OF_LOGICAL_ENDPOINTS; epnum++) {
00457             uint32_t irq_mask = (1 << epnum);
00458             if (in_irqs & irq_mask) {
00459                 uint8_t endpoint = (epnum << 1) | DIR_IN;
00460                 (instance->*(epCallback[endpoint]))();
00461             }
00462         }
00463     }
00464 
00465     // OUT packets
00466     if (irq_flags & MXC_F_USB_DEV_INTFL_EP_OUT) {
00467         // get and clear OUT irqs
00468         uint32_t out_irqs = MXC_USB->out_int;
00469         MXC_USB->out_int = out_irqs;
00470 
00471         if (out_irqs & 1) {
00472             EP0out();
00473         }
00474 
00475         for (uint8_t epnum = 1; epnum < NUMBER_OF_LOGICAL_ENDPOINTS; epnum++) {
00476             uint32_t irq_mask = (1 << epnum);
00477             if (out_irqs & irq_mask) {
00478                 uint8_t endpoint = (epnum << 1) | DIR_OUT;
00479                 (instance->*(epCallback[endpoint]))();
00480             }
00481         }
00482     }
00483 }
00484 
00485 #endif