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

Fork of USBMIDI by Simon Ford

Committer:
simon
Date:
Sun Feb 20 13:10:05 2011 +0000
Revision:
1:ff74eabe02cd
Child:
2:10d694d6ccdc
First version, supporting most USB MIDI functionality

Who changed what in which revision?

UserRevisionLine numberNew contents of line
simon 1:ff74eabe02cd 1 /** @license The MIT License
simon 1:ff74eabe02cd 2 * Copyright (c) 2011 mux, simon
simon 1:ff74eabe02cd 3 *
simon 1:ff74eabe02cd 4 * Permission is hereby granted, free of charge, to any person obtaining a copy
simon 1:ff74eabe02cd 5 * of this software and associated documentation files (the "Software"), to deal
simon 1:ff74eabe02cd 6 * in the Software without restriction, including without limitation the rights
simon 1:ff74eabe02cd 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
simon 1:ff74eabe02cd 8 * copies of the Software, and to permit persons to whom the Software is
simon 1:ff74eabe02cd 9 * furnished to do so, subject to the following conditions:
simon 1:ff74eabe02cd 10 *
simon 1:ff74eabe02cd 11 * The above copyright notice and this permission notice shall be included in
simon 1:ff74eabe02cd 12 * all copies or substantial portions of the Software.
simon 1:ff74eabe02cd 13 *
simon 1:ff74eabe02cd 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
simon 1:ff74eabe02cd 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
simon 1:ff74eabe02cd 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
simon 1:ff74eabe02cd 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
simon 1:ff74eabe02cd 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
simon 1:ff74eabe02cd 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
simon 1:ff74eabe02cd 20 * THE SOFTWARE.
simon 1:ff74eabe02cd 21 */
simon 1:ff74eabe02cd 22
simon 1:ff74eabe02cd 23 #include "usbcore.h"
simon 1:ff74eabe02cd 24
simon 1:ff74eabe02cd 25 #include "mbed.h"
simon 1:ff74eabe02cd 26
simon 1:ff74eabe02cd 27 // Serial Interface Engine
simon 1:ff74eabe02cd 28 #define SIE_SET_ADDR (0xD0)
simon 1:ff74eabe02cd 29 #define SIE_SET_STATUS (0xFE)
simon 1:ff74eabe02cd 30 #define SIE_GET_STATUS (0xFE)
simon 1:ff74eabe02cd 31 #define SIE_SET_MODE (0xF3)
simon 1:ff74eabe02cd 32 #define SIE_CLR_BUFFER (0xF2)
simon 1:ff74eabe02cd 33 #define SIE_VAL_BUFFER (0xFA)
simon 1:ff74eabe02cd 34 #define SIE_SEL_EP (0x00)
simon 1:ff74eabe02cd 35 #define SIE_SEL_CLR_EP (0x28)
simon 1:ff74eabe02cd 36 #define SIE_SET_EP_STAT (0x40)
simon 1:ff74eabe02cd 37 #define SIE_READ_ERROR (0xFB)
simon 1:ff74eabe02cd 38 #define SIE_CONFIG_DEVICE (0xD8)
simon 1:ff74eabe02cd 39
simon 1:ff74eabe02cd 40 // EP status
simon 1:ff74eabe02cd 41 #define EP_FE (1<<0) // Full/Empty
simon 1:ff74eabe02cd 42 #define EP_ST (1<<1) // Stalled endpoint
simon 1:ff74eabe02cd 43 #define EP_STP (1<<2) // Setup packet
simon 1:ff74eabe02cd 44 #define EP_PO (1<<3) // packet overwritten
simon 1:ff74eabe02cd 45 #define EP_EPN (1<<4) // EP NAKed
simon 1:ff74eabe02cd 46 #define B_1_FULL (1<<5) // buffer 1 status
simon 1:ff74eabe02cd 47 #define B_2_FULL (1<<6) // buffer 2 status
simon 1:ff74eabe02cd 48
simon 1:ff74eabe02cd 49 // USB device interrupts
simon 1:ff74eabe02cd 50 #define DEV_FRAME (1<<0)
simon 1:ff74eabe02cd 51 #define EP_FAST (1<<1)
simon 1:ff74eabe02cd 52 #define EP_SLOW (1<<2)
simon 1:ff74eabe02cd 53 #define DEV_STAT (1<<3)
simon 1:ff74eabe02cd 54 #define RxENDPKT (1<<6)
simon 1:ff74eabe02cd 55 #define TxENDPKT (1<<7)
simon 1:ff74eabe02cd 56 #define EP_RLZED (1<<8)
simon 1:ff74eabe02cd 57 #define CCEMPTY (0x10)
simon 1:ff74eabe02cd 58 #define CDFULL (0x20)
simon 1:ff74eabe02cd 59
simon 1:ff74eabe02cd 60 // USB device status bits
simon 1:ff74eabe02cd 61 #define STAT_CON (1<<0)
simon 1:ff74eabe02cd 62 #define STAT_CON_CH (1<<1)
simon 1:ff74eabe02cd 63 #define STAT_SUS (1<<2)
simon 1:ff74eabe02cd 64 #define STAT_SUS_CH (1<<3)
simon 1:ff74eabe02cd 65 #define STAT_RST (1<<4)
simon 1:ff74eabe02cd 66
simon 1:ff74eabe02cd 67 // end points interrupts
simon 1:ff74eabe02cd 68 #define EP0RX_INT (1<<0)
simon 1:ff74eabe02cd 69 #define EP0TX_INT (1<<1)
simon 1:ff74eabe02cd 70 #define EP1RX_INT (1<<2)
simon 1:ff74eabe02cd 71 #define EP1TX_INT (1<<3)
simon 1:ff74eabe02cd 72 #define EP2RX_INT (1<<4)
simon 1:ff74eabe02cd 73 #define EP2TX_INT (1<<5)
simon 1:ff74eabe02cd 74
simon 1:ff74eabe02cd 75 // USB control register
simon 1:ff74eabe02cd 76 #define RD_EN (1<<0)
simon 1:ff74eabe02cd 77 #define WR_EN (1<<1)
simon 1:ff74eabe02cd 78 #define PKT_RDY (1<<11)
simon 1:ff74eabe02cd 79 #define LOG_ENDPOINT(ep) ((ep>>1)<<2)
simon 1:ff74eabe02cd 80
simon 1:ff74eabe02cd 81 // configure state
simon 1:ff74eabe02cd 82 static int configured = 0;
simon 1:ff74eabe02cd 83
simon 1:ff74eabe02cd 84 // USB interrupt handler
simon 1:ff74eabe02cd 85 void USB_IRQHandler(void);
simon 1:ff74eabe02cd 86
simon 1:ff74eabe02cd 87 // Serial Interface Engine functions
simon 1:ff74eabe02cd 88 void sie_command(uint32_t code) {
simon 1:ff74eabe02cd 89 LPC_USB->USBDevIntClr = CCEMPTY; // clear CCEMPTY
simon 1:ff74eabe02cd 90 LPC_USB->USBCmdCode = ((code<<16)|(0x05<<8)); // CMD_PHASE=Command
simon 1:ff74eabe02cd 91 while (!(LPC_USB->USBDevIntSt & CCEMPTY)); // wait for CCEMPTY
simon 1:ff74eabe02cd 92 }
simon 1:ff74eabe02cd 93
simon 1:ff74eabe02cd 94 void sie_write(uint32_t data) {
simon 1:ff74eabe02cd 95 LPC_USB->USBDevIntClr = CCEMPTY; // clear CCEMPTY
simon 1:ff74eabe02cd 96 LPC_USB->USBCmdCode = ((data<<16)|(0x01<<8)); // CMD_PHASE=Write
simon 1:ff74eabe02cd 97 while (!(LPC_USB->USBDevIntSt & CCEMPTY)); // wait for CCEMPTY
simon 1:ff74eabe02cd 98 }
simon 1:ff74eabe02cd 99
simon 1:ff74eabe02cd 100 uint8_t sie_read(uint32_t code) {
simon 1:ff74eabe02cd 101 LPC_USB->USBDevIntClr = CDFULL; // clear CCEMPTY
simon 1:ff74eabe02cd 102 LPC_USB->USBCmdCode = ((code<<16)|(0x02<<8)); // CMD_PHASE=Read
simon 1:ff74eabe02cd 103 while (!(LPC_USB->USBDevIntSt & CDFULL)); // wait for CDFULL
simon 1:ff74eabe02cd 104 return (uint8_t) LPC_USB->USBCmdData;
simon 1:ff74eabe02cd 105
simon 1:ff74eabe02cd 106 }
simon 1:ff74eabe02cd 107
simon 1:ff74eabe02cd 108 // end point functions
simon 1:ff74eabe02cd 109 void ep_realize(uint8_t ep, uint32_t size) {
simon 1:ff74eabe02cd 110 LPC_USB->USBDevIntClr = EP_RLZED; // clear EP_RLZED
simon 1:ff74eabe02cd 111 LPC_USB->USBReEp |= (1<<ep);
simon 1:ff74eabe02cd 112 LPC_USB->USBEpInd = ep; // set USBEpIn
simon 1:ff74eabe02cd 113 LPC_USB->USBMaxPSize = size; // writing to EPn pointed to by USBEpInd
simon 1:ff74eabe02cd 114 while (!(LPC_USB->USBDevIntSt & EP_RLZED)); // wait for EP_RLZED
simon 1:ff74eabe02cd 115 LPC_USB->USBDevIntClr = EP_RLZED; // clear EP_RLZED
simon 1:ff74eabe02cd 116 }
simon 1:ff74eabe02cd 117
simon 1:ff74eabe02cd 118 void ep_stall(uint8_t ep) {
simon 1:ff74eabe02cd 119 sie_command(SIE_SET_EP_STAT+ep);
simon 1:ff74eabe02cd 120 sie_write(1);
simon 1:ff74eabe02cd 121 }
simon 1:ff74eabe02cd 122
simon 1:ff74eabe02cd 123 void ep_unstall(uint8_t ep) {
simon 1:ff74eabe02cd 124 sie_command(SIE_SET_EP_STAT+ep);
simon 1:ff74eabe02cd 125 sie_write(0);
simon 1:ff74eabe02cd 126 }
simon 1:ff74eabe02cd 127
simon 1:ff74eabe02cd 128 // initializes a pointer to the endpoint buffer
simon 1:ff74eabe02cd 129 uint8_t ep_select(uint8_t ep) {
simon 1:ff74eabe02cd 130 sie_command(SIE_SEL_EP+ep);
simon 1:ff74eabe02cd 131 return sie_read(SIE_SEL_EP+ep);
simon 1:ff74eabe02cd 132 }
simon 1:ff74eabe02cd 133
simon 1:ff74eabe02cd 134 uint8_t ep_select_clear(uint8_t ep) {
simon 1:ff74eabe02cd 135 LPC_USB->USBEpIntClr |= ep; // clear ep interrupt
simon 1:ff74eabe02cd 136 while (!(LPC_USB->USBDevIntSt & CDFULL)); // wait for cmd finish
simon 1:ff74eabe02cd 137 return LPC_USB->USBCmdData;
simon 1:ff74eabe02cd 138 }
simon 1:ff74eabe02cd 139
simon 1:ff74eabe02cd 140 int ep_readable(uint8_t ep) {
simon 1:ff74eabe02cd 141 uint8_t st = ep_select(ep);
simon 1:ff74eabe02cd 142 return (st & EP_FE);
simon 1:ff74eabe02cd 143 }
simon 1:ff74eabe02cd 144
simon 1:ff74eabe02cd 145 int ep_writable(uint8_t ep) {
simon 1:ff74eabe02cd 146 uint8_t st = ep_select(ep);
simon 1:ff74eabe02cd 147 return !(st & EP_FE);
simon 1:ff74eabe02cd 148 }
simon 1:ff74eabe02cd 149
simon 1:ff74eabe02cd 150 int ep_read(uint8_t ep, uint8_t *tbuf) {
simon 1:ff74eabe02cd 151 uint32_t *buf = (uint32_t*) tbuf;
simon 1:ff74eabe02cd 152 LPC_USB->USBCtrl = LOG_ENDPOINT(ep)|RD_EN; // RD_EN bit and LOG_ENDPOINT
simon 1:ff74eabe02cd 153 while (!(LPC_USB->USBRxPLen & PKT_RDY)); // wait for packet to be fetched
simon 1:ff74eabe02cd 154 int len = LPC_USB->USBRxPLen & 0x3FF; // read and mask packet length
simon 1:ff74eabe02cd 155 while (!(LPC_USB->USBDevIntSt & RxENDPKT)) {
simon 1:ff74eabe02cd 156 *buf++ = LPC_USB->USBRxData;
simon 1:ff74eabe02cd 157 }
simon 1:ff74eabe02cd 158 LPC_USB->USBCtrl = 0;
simon 1:ff74eabe02cd 159 LPC_USB->USBDevIntClr |= RxENDPKT;
simon 1:ff74eabe02cd 160 sie_command(SIE_SEL_EP+ep); // select endpoint
simon 1:ff74eabe02cd 161 sie_command(SIE_CLR_BUFFER); // clear RX buffer
simon 1:ff74eabe02cd 162 return len;
simon 1:ff74eabe02cd 163 }
simon 1:ff74eabe02cd 164
simon 1:ff74eabe02cd 165 void ep_write(uint8_t ep, uint8_t *tbuf, uint32_t len) {
simon 1:ff74eabe02cd 166 uint32_t *buf = (uint32_t*) tbuf;
simon 1:ff74eabe02cd 167 LPC_USB->USBCtrl = LOG_ENDPOINT(ep)|WR_EN; // RD_EN bit and LOG_ENDPOINT
simon 1:ff74eabe02cd 168 LPC_USB->USBTxPLen |= (len & 0x3FF); // write and mask packet length
simon 1:ff74eabe02cd 169 while (!(LPC_USB->USBDevIntSt & TxENDPKT)) {
simon 1:ff74eabe02cd 170 LPC_USB->USBTxData = *buf++;
simon 1:ff74eabe02cd 171 }
simon 1:ff74eabe02cd 172 LPC_USB->USBCtrl = 0;
simon 1:ff74eabe02cd 173 LPC_USB->USBDevIntClr |= TxENDPKT;
simon 1:ff74eabe02cd 174 sie_command(SIE_SEL_EP+ep); // select endpoint
simon 1:ff74eabe02cd 175 sie_command(SIE_VAL_BUFFER); // validate TX buffer
simon 1:ff74eabe02cd 176 }
simon 1:ff74eabe02cd 177
simon 1:ff74eabe02cd 178 // USB device controller initialization
simon 1:ff74eabe02cd 179 void usb_init() {
simon 1:ff74eabe02cd 180 // USB D+/D- pinsel functions
simon 1:ff74eabe02cd 181 LPC_PINCON->PINSEL1 &= 0xC3FFFFFF;
simon 1:ff74eabe02cd 182 LPC_PINCON->PINSEL1 |= 0x14000000;
simon 1:ff74eabe02cd 183
simon 1:ff74eabe02cd 184 #if USB_UP_DEBUG
simon 1:ff74eabe02cd 185 // USB_UP_LED pinsel function
simon 1:ff74eabe02cd 186 LPC_PINCON->PINSEL3 &= 0xFFFFFFCF;
simon 1:ff74eabe02cd 187 LPC_PINCON->PINSEL3 |= 0x00000010;
simon 1:ff74eabe02cd 188 #endif
simon 1:ff74eabe02cd 189
simon 1:ff74eabe02cd 190 // USB connect pinsel function
simon 1:ff74eabe02cd 191 LPC_PINCON->PINSEL4 &= 0xFFFCFFFF;
simon 1:ff74eabe02cd 192 LPC_PINCON->PINSEL4 |= 0x00040000;
simon 1:ff74eabe02cd 193 LPC_SC->PCONP |= (1UL<<31); // enable the USB controller
simon 1:ff74eabe02cd 194 LPC_USB->USBClkCtrl |= ((1<<1)|(1<<4)); // enable the AHB and DEV clocks
simon 1:ff74eabe02cd 195 while ((LPC_USB->USBClkSt & 0x12) != 0x12); // wait for the clocks to init
simon 1:ff74eabe02cd 196
simon 1:ff74eabe02cd 197 NVIC_SetVector(USB_IRQn, (uint32_t)&USB_IRQHandler);
simon 1:ff74eabe02cd 198 NVIC_EnableIRQ(USB_IRQn); // enable USB interrupts
simon 1:ff74eabe02cd 199
simon 1:ff74eabe02cd 200 usb_reset();
simon 1:ff74eabe02cd 201 usb_set_address(0); // default address
simon 1:ff74eabe02cd 202 }
simon 1:ff74eabe02cd 203
simon 1:ff74eabe02cd 204 void usb_reset() {
simon 1:ff74eabe02cd 205 ep_realize(EP0, MAX_EP0_PSIZE);
simon 1:ff74eabe02cd 206 ep_realize(EP1, MAX_EP0_PSIZE);
simon 1:ff74eabe02cd 207 LPC_USB->USBEpIntClr = 0xFFFFFFFF; // clear end points interrupts
simon 1:ff74eabe02cd 208 LPC_USB->USBEpIntEn = 0xFFFFFFFF; // enable end points interrupts
simon 1:ff74eabe02cd 209 LPC_USB->USBEpIntPri = 0x0; // route to EP_SLOW
simon 1:ff74eabe02cd 210 LPC_USB->USBDevIntClr = 0xFFFFFFFF; // clear USB device interrupts
simon 1:ff74eabe02cd 211 LPC_USB->USBDevIntEn = (EP_SLOW|DEV_STAT); // enable USB device interrupts
simon 1:ff74eabe02cd 212 }
simon 1:ff74eabe02cd 213
simon 1:ff74eabe02cd 214 void usb_configure(uint8_t conf) {
simon 1:ff74eabe02cd 215 sie_command(SIE_CONFIG_DEVICE);
simon 1:ff74eabe02cd 216 sie_write(conf);
simon 1:ff74eabe02cd 217 configured = 1;
simon 1:ff74eabe02cd 218 }
simon 1:ff74eabe02cd 219
simon 1:ff74eabe02cd 220 int usb_configured() {
simon 1:ff74eabe02cd 221 return configured;
simon 1:ff74eabe02cd 222 }
simon 1:ff74eabe02cd 223
simon 1:ff74eabe02cd 224 void usb_set_address(uint8_t addr) {
simon 1:ff74eabe02cd 225 sie_command(SIE_SET_ADDR);
simon 1:ff74eabe02cd 226 sie_write(addr|0x80); // DEV_EN = 1
simon 1:ff74eabe02cd 227 }
simon 1:ff74eabe02cd 228
simon 1:ff74eabe02cd 229 uint8_t usb_get_status() {
simon 1:ff74eabe02cd 230 sie_command(SIE_GET_STATUS);
simon 1:ff74eabe02cd 231 return sie_read(SIE_GET_STATUS);
simon 1:ff74eabe02cd 232 }
simon 1:ff74eabe02cd 233
simon 1:ff74eabe02cd 234 void usb_connect() {
simon 1:ff74eabe02cd 235 sie_command(SIE_GET_STATUS); // read current status
simon 1:ff74eabe02cd 236 uint8_t st = sie_read(SIE_GET_STATUS);
simon 1:ff74eabe02cd 237
simon 1:ff74eabe02cd 238 sie_command(SIE_SET_STATUS); // set STAT_CON bit
simon 1:ff74eabe02cd 239 sie_write(st|STAT_CON);
simon 1:ff74eabe02cd 240 }
simon 1:ff74eabe02cd 241
simon 1:ff74eabe02cd 242 void USB_IRQHandler(void) {
simon 1:ff74eabe02cd 243 if (LPC_USB->USBDevIntSt & DEV_STAT) { // DEV_STAT interrupt
simon 1:ff74eabe02cd 244 LPC_USB->USBDevIntClr |= DEV_STAT;
simon 1:ff74eabe02cd 245 if (usb_get_status() & STAT_RST) { // bus reset
simon 1:ff74eabe02cd 246 usb_reset();
simon 1:ff74eabe02cd 247 }
simon 1:ff74eabe02cd 248 return;
simon 1:ff74eabe02cd 249 }
simon 1:ff74eabe02cd 250
simon 1:ff74eabe02cd 251 if (LPC_USB->USBDevIntSt & EP_SLOW) { // EP_SLOW interrupt
simon 1:ff74eabe02cd 252 if (LPC_USB->USBEpIntSt & EP0RX_INT) {
simon 1:ff74eabe02cd 253 if (ep_select_clear(EP0RX_INT) & EP_STP) { // setup transfer
simon 1:ff74eabe02cd 254 ep0_setup();
simon 1:ff74eabe02cd 255 } else {
simon 1:ff74eabe02cd 256 ep0_out();
simon 1:ff74eabe02cd 257 }
simon 1:ff74eabe02cd 258 }
simon 1:ff74eabe02cd 259
simon 1:ff74eabe02cd 260 if (LPC_USB->USBEpIntSt & EP0TX_INT) {
simon 1:ff74eabe02cd 261 ep_select_clear(EP0TX_INT);
simon 1:ff74eabe02cd 262 ep0_in();
simon 1:ff74eabe02cd 263 }
simon 1:ff74eabe02cd 264
simon 1:ff74eabe02cd 265 if (LPC_USB->USBEpIntSt & EP2RX_INT) {
simon 1:ff74eabe02cd 266 ep_select_clear(EP2TX_INT);
simon 1:ff74eabe02cd 267 ep2_out();
simon 1:ff74eabe02cd 268 }
simon 1:ff74eabe02cd 269
simon 1:ff74eabe02cd 270 if (LPC_USB->USBEpIntSt & EP2TX_INT) {
simon 1:ff74eabe02cd 271 ep_select_clear(EP2TX_INT);
simon 1:ff74eabe02cd 272 ep2_in();
simon 1:ff74eabe02cd 273 }
simon 1:ff74eabe02cd 274
simon 1:ff74eabe02cd 275 // EP_SLOW should be cleared after clearing EPs interrupts
simon 1:ff74eabe02cd 276 LPC_USB->USBDevIntClr |= EP_SLOW;
simon 1:ff74eabe02cd 277 }
simon 1:ff74eabe02cd 278 }