Changed file extensions from .c to .cpp
Fork of USBMIDI by
usbcore.cpp
- Committer:
- KrissyHam
- Date:
- 2016-04-29
- Revision:
- 3:1c9f95100210
- Parent:
- usbcore.c@ 2:10d694d6ccdc
File content as of revision 3:1c9f95100210:
/* @license The MIT License
* Copyright (c) 2011 mux, simon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "usbcore.h"
#include "mbed.h"
// Serial Interface Engine
#define SIE_SET_ADDR (0xD0)
#define SIE_SET_STATUS (0xFE)
#define SIE_GET_STATUS (0xFE)
#define SIE_SET_MODE (0xF3)
#define SIE_CLR_BUFFER (0xF2)
#define SIE_VAL_BUFFER (0xFA)
#define SIE_SEL_EP (0x00)
#define SIE_SEL_CLR_EP (0x28)
#define SIE_SET_EP_STAT (0x40)
#define SIE_READ_ERROR (0xFB)
#define SIE_CONFIG_DEVICE (0xD8)
// EP status
#define EP_FE (1<<0) // Full/Empty
#define EP_ST (1<<1) // Stalled endpoint
#define EP_STP (1<<2) // Setup packet
#define EP_PO (1<<3) // packet overwritten
#define EP_EPN (1<<4) // EP NAKed
#define B_1_FULL (1<<5) // buffer 1 status
#define B_2_FULL (1<<6) // buffer 2 status
// USB device interrupts
#define DEV_FRAME (1<<0)
#define EP_FAST (1<<1)
#define EP_SLOW (1<<2)
#define DEV_STAT (1<<3)
#define RxENDPKT (1<<6)
#define TxENDPKT (1<<7)
#define EP_RLZED (1<<8)
#define CCEMPTY (0x10)
#define CDFULL (0x20)
// USB device status bits
#define STAT_CON (1<<0)
#define STAT_CON_CH (1<<1)
#define STAT_SUS (1<<2)
#define STAT_SUS_CH (1<<3)
#define STAT_RST (1<<4)
// end points interrupts
#define EP0RX_INT (1<<0)
#define EP0TX_INT (1<<1)
#define EP1RX_INT (1<<2)
#define EP1TX_INT (1<<3)
#define EP2RX_INT (1<<4)
#define EP2TX_INT (1<<5)
// USB control register
#define RD_EN (1<<0)
#define WR_EN (1<<1)
#define PKT_RDY (1<<11)
#define LOG_ENDPOINT(ep) ((ep>>1)<<2)
// configure state
static int configured = 0;
// USB interrupt handler
void USB_IRQHandler(void);
// Serial Interface Engine functions
void sie_command(uint32_t code) {
LPC_USB->USBDevIntClr = CCEMPTY; // clear CCEMPTY
LPC_USB->USBCmdCode = ((code<<16)|(0x05<<8)); // CMD_PHASE=Command
while (!(LPC_USB->USBDevIntSt & CCEMPTY)); // wait for CCEMPTY
}
void sie_write(uint32_t data) {
LPC_USB->USBDevIntClr = CCEMPTY; // clear CCEMPTY
LPC_USB->USBCmdCode = ((data<<16)|(0x01<<8)); // CMD_PHASE=Write
while (!(LPC_USB->USBDevIntSt & CCEMPTY)); // wait for CCEMPTY
}
uint8_t sie_read(uint32_t code) {
LPC_USB->USBDevIntClr = CDFULL; // clear CCEMPTY
LPC_USB->USBCmdCode = ((code<<16)|(0x02<<8)); // CMD_PHASE=Read
while (!(LPC_USB->USBDevIntSt & CDFULL)); // wait for CDFULL
return (uint8_t) LPC_USB->USBCmdData;
}
// end point functions
void ep_realize(uint8_t ep, uint32_t size) {
LPC_USB->USBDevIntClr = EP_RLZED; // clear EP_RLZED
LPC_USB->USBReEp |= (1<<ep);
LPC_USB->USBEpInd = ep; // set USBEpIn
LPC_USB->USBMaxPSize = size; // writing to EPn pointed to by USBEpInd
while (!(LPC_USB->USBDevIntSt & EP_RLZED)); // wait for EP_RLZED
LPC_USB->USBDevIntClr = EP_RLZED; // clear EP_RLZED
}
void ep_stall(uint8_t ep) {
sie_command(SIE_SET_EP_STAT+ep);
sie_write(1);
}
void ep_unstall(uint8_t ep) {
sie_command(SIE_SET_EP_STAT+ep);
sie_write(0);
}
// initializes a pointer to the endpoint buffer
uint8_t ep_select(uint8_t ep) {
sie_command(SIE_SEL_EP+ep);
return sie_read(SIE_SEL_EP+ep);
}
uint8_t ep_select_clear(uint8_t ep) {
LPC_USB->USBEpIntClr |= ep; // clear ep interrupt
while (!(LPC_USB->USBDevIntSt & CDFULL)); // wait for cmd finish
return LPC_USB->USBCmdData;
}
int ep_readable(uint8_t ep) {
uint8_t st = ep_select(ep);
return (st & EP_FE);
}
int ep_writable(uint8_t ep) {
uint8_t st = ep_select(ep);
return !(st & EP_FE);
}
int ep_read(uint8_t ep, uint8_t *tbuf) {
uint32_t *buf = (uint32_t*) tbuf;
LPC_USB->USBCtrl = LOG_ENDPOINT(ep)|RD_EN; // RD_EN bit and LOG_ENDPOINT
while (!(LPC_USB->USBRxPLen & PKT_RDY)); // wait for packet to be fetched
int len = LPC_USB->USBRxPLen & 0x3FF; // read and mask packet length
while (!(LPC_USB->USBDevIntSt & RxENDPKT)) {
*buf++ = LPC_USB->USBRxData;
}
LPC_USB->USBCtrl = 0;
LPC_USB->USBDevIntClr |= RxENDPKT;
sie_command(SIE_SEL_EP+ep); // select endpoint
sie_command(SIE_CLR_BUFFER); // clear RX buffer
return len;
}
void ep_write(uint8_t ep, uint8_t *tbuf, uint32_t len) {
uint32_t *buf = (uint32_t*) tbuf;
LPC_USB->USBCtrl = LOG_ENDPOINT(ep)|WR_EN; // RD_EN bit and LOG_ENDPOINT
LPC_USB->USBTxPLen |= (len & 0x3FF); // write and mask packet length
while (!(LPC_USB->USBDevIntSt & TxENDPKT)) {
LPC_USB->USBTxData = *buf++;
}
LPC_USB->USBCtrl = 0;
LPC_USB->USBDevIntClr |= TxENDPKT;
sie_command(SIE_SEL_EP+ep); // select endpoint
sie_command(SIE_VAL_BUFFER); // validate TX buffer
}
// USB device controller initialization
void usb_init() {
// USB D+/D- pinsel functions
LPC_PINCON->PINSEL1 &= 0xC3FFFFFF;
LPC_PINCON->PINSEL1 |= 0x14000000;
#if USB_UP_DEBUG
// USB_UP_LED pinsel function
LPC_PINCON->PINSEL3 &= 0xFFFFFFCF;
LPC_PINCON->PINSEL3 |= 0x00000010;
#endif
// USB connect pinsel function
LPC_PINCON->PINSEL4 &= 0xFFFCFFFF;
LPC_PINCON->PINSEL4 |= 0x00040000;
LPC_SC->PCONP |= (1UL<<31); // enable the USB controller
LPC_USB->USBClkCtrl |= ((1<<1)|(1<<4)); // enable the AHB and DEV clocks
while ((LPC_USB->USBClkSt & 0x12) != 0x12); // wait for the clocks to init
NVIC_SetVector(USB_IRQn, (uint32_t)&USB_IRQHandler);
NVIC_EnableIRQ(USB_IRQn); // enable USB interrupts
usb_reset();
usb_set_address(0); // default address
}
void usb_reset() {
ep_realize(EP0, MAX_EP0_PSIZE);
ep_realize(EP1, MAX_EP0_PSIZE);
LPC_USB->USBEpIntClr = 0xFFFFFFFF; // clear end points interrupts
LPC_USB->USBEpIntEn = 0xFFFFFFFF; // enable end points interrupts
LPC_USB->USBEpIntPri = 0x0; // route to EP_SLOW
LPC_USB->USBDevIntClr = 0xFFFFFFFF; // clear USB device interrupts
LPC_USB->USBDevIntEn = (EP_SLOW|DEV_STAT); // enable USB device interrupts
}
void usb_configure(uint8_t conf) {
sie_command(SIE_CONFIG_DEVICE);
sie_write(conf);
configured = 1;
}
int usb_configured() {
return configured;
}
void usb_set_address(uint8_t addr) {
sie_command(SIE_SET_ADDR);
sie_write(addr|0x80); // DEV_EN = 1
}
uint8_t usb_get_status() {
sie_command(SIE_GET_STATUS);
return sie_read(SIE_GET_STATUS);
}
void usb_connect() {
sie_command(SIE_GET_STATUS); // read current status
uint8_t st = sie_read(SIE_GET_STATUS);
sie_command(SIE_SET_STATUS); // set STAT_CON bit
sie_write(st|STAT_CON);
}
void USB_IRQHandler(void) {
if (LPC_USB->USBDevIntSt & DEV_STAT) { // DEV_STAT interrupt
LPC_USB->USBDevIntClr |= DEV_STAT;
if (usb_get_status() & STAT_RST) { // bus reset
usb_reset();
}
return;
}
if (LPC_USB->USBDevIntSt & EP_SLOW) { // EP_SLOW interrupt
if (LPC_USB->USBEpIntSt & EP0RX_INT) {
if (ep_select_clear(EP0RX_INT) & EP_STP) { // setup transfer
ep0_setup();
} else {
ep0_out();
}
}
if (LPC_USB->USBEpIntSt & EP0TX_INT) {
ep_select_clear(EP0TX_INT);
ep0_in();
}
if (LPC_USB->USBEpIntSt & EP2RX_INT) {
ep_select_clear(EP2TX_INT);
ep2_out();
}
if (LPC_USB->USBEpIntSt & EP2TX_INT) {
ep_select_clear(EP2TX_INT);
ep2_in();
}
// EP_SLOW should be cleared after clearing EPs interrupts
LPC_USB->USBDevIntClr |= EP_SLOW;
}
}
