A library to send and receive MIDI messages over USB using the default USB-MIDI drivers on Win/Mac

Dependents:   USBMIDI_HelloWorld USBMIDI_DrumExample USBMIDI_MonoSynth MIDI_Interface_ver_1 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers usbcore.c Source File

usbcore.c

00001 /* @license The MIT License
00002  * Copyright (c) 2011 mux, simon
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy
00005  * of this software and associated documentation files (the "Software"), to deal
00006  * in the Software without restriction, including without limitation the rights
00007  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  * copies of the Software, and to permit persons to whom the Software is
00009  * furnished to do so, subject to the following conditions:
00010  *  
00011  * The above copyright notice and this permission notice shall be included in
00012  * all copies or substantial portions of the Software.
00013  *  
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00020  * THE SOFTWARE.
00021  */
00022 
00023 #include "usbcore.h"
00024 
00025 #include "mbed.h"
00026 
00027 // Serial Interface Engine
00028 #define SIE_SET_ADDR    (0xD0)
00029 #define SIE_SET_STATUS  (0xFE)
00030 #define SIE_GET_STATUS  (0xFE)
00031 #define SIE_SET_MODE    (0xF3)
00032 #define SIE_CLR_BUFFER  (0xF2)
00033 #define SIE_VAL_BUFFER  (0xFA)
00034 #define SIE_SEL_EP      (0x00)
00035 #define SIE_SEL_CLR_EP  (0x28)
00036 #define SIE_SET_EP_STAT (0x40)
00037 #define SIE_READ_ERROR  (0xFB)
00038 #define SIE_CONFIG_DEVICE (0xD8)
00039 
00040 // EP status
00041 #define EP_FE           (1<<0) // Full/Empty
00042 #define EP_ST           (1<<1) // Stalled endpoint
00043 #define EP_STP          (1<<2) // Setup packet
00044 #define EP_PO           (1<<3) // packet overwritten
00045 #define EP_EPN          (1<<4) // EP NAKed
00046 #define B_1_FULL        (1<<5) // buffer 1 status
00047 #define B_2_FULL        (1<<6) // buffer 2 status
00048 
00049 // USB device interrupts
00050 #define DEV_FRAME       (1<<0)
00051 #define EP_FAST         (1<<1)
00052 #define EP_SLOW         (1<<2)
00053 #define DEV_STAT        (1<<3)
00054 #define RxENDPKT        (1<<6)
00055 #define TxENDPKT        (1<<7)
00056 #define EP_RLZED        (1<<8)
00057 #define CCEMPTY         (0x10)
00058 #define CDFULL          (0x20)
00059 
00060 // USB device status bits
00061 #define STAT_CON        (1<<0)
00062 #define STAT_CON_CH     (1<<1)
00063 #define STAT_SUS        (1<<2)
00064 #define STAT_SUS_CH     (1<<3)
00065 #define STAT_RST        (1<<4)
00066 
00067 // end points interrupts
00068 #define EP0RX_INT       (1<<0)
00069 #define EP0TX_INT       (1<<1)
00070 #define EP1RX_INT       (1<<2)
00071 #define EP1TX_INT       (1<<3)
00072 #define EP2RX_INT       (1<<4)
00073 #define EP2TX_INT       (1<<5)
00074 
00075 // USB control register
00076 #define RD_EN           (1<<0)
00077 #define WR_EN           (1<<1)
00078 #define PKT_RDY         (1<<11)
00079 #define LOG_ENDPOINT(ep) ((ep>>1)<<2)
00080 
00081 // configure state
00082 static int configured = 0;
00083 
00084 // USB interrupt handler
00085 void USB_IRQHandler(void);
00086 
00087 // Serial Interface Engine functions
00088 void sie_command(uint32_t code) {
00089     LPC_USB->USBDevIntClr = CCEMPTY;                // clear CCEMPTY     
00090     LPC_USB->USBCmdCode   = ((code<<16)|(0x05<<8)); // CMD_PHASE=Command 
00091     while (!(LPC_USB->USBDevIntSt & CCEMPTY));      // wait for CCEMPTY 
00092 }
00093 
00094 void sie_write(uint32_t data) {
00095     LPC_USB->USBDevIntClr = CCEMPTY;                // clear CCEMPTY     
00096     LPC_USB->USBCmdCode   = ((data<<16)|(0x01<<8)); // CMD_PHASE=Write   
00097     while (!(LPC_USB->USBDevIntSt & CCEMPTY));      // wait for CCEMPTY  
00098 }
00099 
00100 uint8_t sie_read(uint32_t code) {
00101     LPC_USB->USBDevIntClr = CDFULL;                 // clear CCEMPTY     
00102     LPC_USB->USBCmdCode   = ((code<<16)|(0x02<<8)); // CMD_PHASE=Read    
00103     while (!(LPC_USB->USBDevIntSt & CDFULL));       // wait for CDFULL   
00104     return (uint8_t) LPC_USB->USBCmdData;
00105 
00106 }
00107 
00108 // end point functions
00109 void ep_realize(uint8_t ep, uint32_t size) {
00110     LPC_USB->USBDevIntClr = EP_RLZED;           // clear EP_RLZED
00111     LPC_USB->USBReEp    |= (1<<ep);
00112     LPC_USB->USBEpInd    = ep;                  // set USBEpIn
00113     LPC_USB->USBMaxPSize = size;                // writing to EPn pointed to by USBEpInd
00114     while (!(LPC_USB->USBDevIntSt & EP_RLZED)); // wait for EP_RLZED
00115     LPC_USB->USBDevIntClr = EP_RLZED;           // clear EP_RLZED
00116 }
00117 
00118 void ep_stall(uint8_t ep) {
00119     sie_command(SIE_SET_EP_STAT+ep);
00120     sie_write(1);
00121 }
00122 
00123 void ep_unstall(uint8_t ep) {
00124     sie_command(SIE_SET_EP_STAT+ep);
00125     sie_write(0);
00126 }
00127 
00128 // initializes a pointer to the endpoint buffer
00129 uint8_t ep_select(uint8_t ep) {
00130     sie_command(SIE_SEL_EP+ep);
00131     return sie_read(SIE_SEL_EP+ep);
00132 }
00133 
00134 uint8_t ep_select_clear(uint8_t ep) {
00135     LPC_USB->USBEpIntClr |= ep;                 // clear ep interrupt   
00136     while (!(LPC_USB->USBDevIntSt & CDFULL));   // wait for cmd finish 
00137     return LPC_USB->USBCmdData;
00138 }
00139 
00140 int ep_readable(uint8_t ep) {
00141     uint8_t st = ep_select(ep);
00142     return (st & EP_FE);
00143 }
00144 
00145 int ep_writable(uint8_t ep) {
00146     uint8_t st = ep_select(ep);
00147     return !(st & EP_FE);
00148 }
00149 
00150 int ep_read(uint8_t ep, uint8_t *tbuf) {
00151     uint32_t *buf = (uint32_t*) tbuf;
00152     LPC_USB->USBCtrl = LOG_ENDPOINT(ep)|RD_EN;  // RD_EN bit and LOG_ENDPOINT   
00153     while (!(LPC_USB->USBRxPLen & PKT_RDY));    // wait for packet to be fetched
00154     int len = LPC_USB->USBRxPLen & 0x3FF;       // read and mask packet length  
00155     while (!(LPC_USB->USBDevIntSt & RxENDPKT)) {
00156         *buf++ = LPC_USB->USBRxData;
00157     }
00158     LPC_USB->USBCtrl = 0;
00159     LPC_USB->USBDevIntClr |= RxENDPKT;
00160     sie_command(SIE_SEL_EP+ep);     // select endpoint   
00161     sie_command(SIE_CLR_BUFFER);    // clear RX buffer   
00162     return len;
00163 }
00164 
00165 void ep_write(uint8_t ep, uint8_t *tbuf, uint32_t len) {
00166     uint32_t *buf = (uint32_t*) tbuf;
00167     LPC_USB->USBCtrl   = LOG_ENDPOINT(ep)|WR_EN; // RD_EN bit and LOG_ENDPOINT  
00168     LPC_USB->USBTxPLen |= (len & 0x3FF);         // write and mask packet length
00169     while (!(LPC_USB->USBDevIntSt & TxENDPKT)) {
00170         LPC_USB->USBTxData = *buf++;
00171     }
00172     LPC_USB->USBCtrl = 0;
00173     LPC_USB->USBDevIntClr |= TxENDPKT;
00174     sie_command(SIE_SEL_EP+ep);     // select endpoint   
00175     sie_command(SIE_VAL_BUFFER);    // validate TX buffer
00176 }
00177 
00178 // USB device controller initialization
00179 void usb_init() {
00180     // USB D+/D- pinsel functions
00181     LPC_PINCON->PINSEL1 &=   0xC3FFFFFF;
00182     LPC_PINCON->PINSEL1 |=   0x14000000;
00183 
00184 #if USB_UP_DEBUG
00185     // USB_UP_LED pinsel function
00186     LPC_PINCON->PINSEL3 &=   0xFFFFFFCF;
00187     LPC_PINCON->PINSEL3 |=   0x00000010;
00188 #endif    
00189 
00190     // USB connect pinsel function
00191     LPC_PINCON->PINSEL4 &=   0xFFFCFFFF;
00192     LPC_PINCON->PINSEL4 |=   0x00040000;
00193     LPC_SC->PCONP       |=   (1UL<<31);         // enable the USB controller
00194     LPC_USB->USBClkCtrl |=   ((1<<1)|(1<<4));   // enable the AHB and DEV clocks
00195     while ((LPC_USB->USBClkSt & 0x12) != 0x12); // wait for the clocks to init
00196 
00197     NVIC_SetVector(USB_IRQn, (uint32_t)&USB_IRQHandler);
00198     NVIC_EnableIRQ(USB_IRQn);    // enable USB interrupts
00199 
00200     usb_reset();
00201     usb_set_address(0);          // default address
00202 }
00203 
00204 void usb_reset() {
00205     ep_realize(EP0, MAX_EP0_PSIZE);
00206     ep_realize(EP1, MAX_EP0_PSIZE);
00207     LPC_USB->USBEpIntClr  = 0xFFFFFFFF;         // clear end points interrupts
00208     LPC_USB->USBEpIntEn   = 0xFFFFFFFF;         // enable end points interrupts
00209     LPC_USB->USBEpIntPri  = 0x0;                // route to EP_SLOW
00210     LPC_USB->USBDevIntClr = 0xFFFFFFFF;         // clear USB device interrupts 
00211     LPC_USB->USBDevIntEn  = (EP_SLOW|DEV_STAT); // enable USB device interrupts
00212 }
00213 
00214 void usb_configure(uint8_t conf) {
00215     sie_command(SIE_CONFIG_DEVICE);
00216     sie_write(conf);
00217     configured = 1;
00218 }
00219 
00220 int usb_configured() {
00221     return configured;
00222 }
00223 
00224 void usb_set_address(uint8_t addr) {
00225     sie_command(SIE_SET_ADDR);
00226     sie_write(addr|0x80);       // DEV_EN = 1
00227 }
00228 
00229 uint8_t usb_get_status() {
00230     sie_command(SIE_GET_STATUS);
00231     return sie_read(SIE_GET_STATUS);
00232 }
00233 
00234 void usb_connect() {
00235     sie_command(SIE_GET_STATUS); // read current status
00236     uint8_t st = sie_read(SIE_GET_STATUS);
00237 
00238     sie_command(SIE_SET_STATUS); // set STAT_CON bit
00239     sie_write(st|STAT_CON);
00240 }
00241 
00242 void USB_IRQHandler(void) {
00243     if (LPC_USB->USBDevIntSt & DEV_STAT) { // DEV_STAT interrupt
00244         LPC_USB->USBDevIntClr |= DEV_STAT;
00245         if (usb_get_status() & STAT_RST) { // bus reset
00246             usb_reset();
00247         }
00248         return;
00249     }
00250 
00251     if (LPC_USB->USBDevIntSt & EP_SLOW) {  // EP_SLOW interrupt
00252         if (LPC_USB->USBEpIntSt & EP0RX_INT) {
00253             if (ep_select_clear(EP0RX_INT) & EP_STP) { // setup transfer
00254                 ep0_setup();
00255             } else {
00256                 ep0_out();
00257             }
00258         }
00259 
00260         if (LPC_USB->USBEpIntSt & EP0TX_INT) {
00261             ep_select_clear(EP0TX_INT);
00262             ep0_in();
00263         }
00264 
00265         if (LPC_USB->USBEpIntSt & EP2RX_INT) {
00266             ep_select_clear(EP2TX_INT);
00267             ep2_out();
00268         }
00269 
00270         if (LPC_USB->USBEpIntSt & EP2TX_INT) {
00271             ep_select_clear(EP2TX_INT);
00272             ep2_in();
00273         }
00274 
00275         // EP_SLOW should be cleared after clearing EPs interrupts
00276         LPC_USB->USBDevIntClr |= EP_SLOW;
00277     }
00278 }