Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of USBDevice by
USBDevice/USBHAL_KL25Z.cpp
- Committer:
- mbed_official
- Date:
- 2014-04-02
- Revision:
- 22:5b7d31d9d3f3
- Parent:
- 20:d38b72fed893
- Child:
- 23:c7639faed2eb
File content as of revision 22:5b7d31d9d3f3:
/* Copyright (c) 2010-2011 mbed.org, MIT License
*
* 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.
*/
#if defined(TARGET_KL25Z) | defined(TARGET_KL46Z) | defined(TARGET_K20D5M) | defined(TARGET_K64F)
#include "USBHAL.h"
USBHAL * USBHAL::instance;
static volatile int epComplete = 0;
// Convert physical endpoint number to register bit
#define EP(endpoint) (1<<(endpoint))
// Convert physical to logical
#define PHY_TO_LOG(endpoint) ((endpoint)>>1)
// Get endpoint direction
#define IN_EP(endpoint) ((endpoint) & 1U ? true : false)
#define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)
#define BD_OWN_MASK (1<<7)
#define BD_DATA01_MASK (1<<6)
#define BD_KEEP_MASK (1<<5)
#define BD_NINC_MASK (1<<4)
#define BD_DTS_MASK (1<<3)
#define BD_STALL_MASK (1<<2)
#define TX 1
#define RX 0
#define ODD 0
#define EVEN 1
// this macro waits a physical endpoint number
#define EP_BDT_IDX(ep, dir, odd) (((ep * 4) + (2 * dir) + (1 * odd)))
#define SETUP_TOKEN 0x0D
#define IN_TOKEN 0x09
#define OUT_TOKEN 0x01
#define TOK_PID(idx) ((bdt[idx].info >> 2) & 0x0F)
// for each endpt: 8 bytes
typedef struct BDT {
uint8_t info; // BD[0:7]
uint8_t dummy; // RSVD: BD[8:15]
uint16_t byte_count; // BD[16:32]
uint32_t address; // Addr
} BDT;
// there are:
// * 16 bidirectionnal endpt -> 32 physical endpt
// * as there are ODD and EVEN buffer -> 32*2 bdt
__attribute__((__aligned__(512))) BDT bdt[NUMBER_OF_PHYSICAL_ENDPOINTS * 2];
uint8_t * endpoint_buffer[(NUMBER_OF_PHYSICAL_ENDPOINTS - 2) * 2];
uint8_t * endpoint_buffer_iso[2*2];
static uint8_t set_addr = 0;
static uint8_t addr = 0;
static uint32_t Data1 = 0x55555555;
static uint32_t frameNumber() {
return((USB0->FRMNUML | (USB0->FRMNUMH << 8)) & 0x07FF);
}
uint32_t USBHAL::endpointReadcore(uint8_t endpoint, uint8_t *buffer) {
return 0;
}
USBHAL::USBHAL(void) {
// Disable IRQ
NVIC_DisableIRQ(USB0_IRQn);
#if defined(TARGET_K64F)
MPU->CESR=0;
#endif
// fill in callback array
epCallback[0] = &USBHAL::EP1_OUT_callback;
epCallback[1] = &USBHAL::EP1_IN_callback;
epCallback[2] = &USBHAL::EP2_OUT_callback;
epCallback[3] = &USBHAL::EP2_IN_callback;
epCallback[4] = &USBHAL::EP3_OUT_callback;
epCallback[5] = &USBHAL::EP3_IN_callback;
epCallback[6] = &USBHAL::EP4_OUT_callback;
epCallback[7] = &USBHAL::EP4_IN_callback;
epCallback[8] = &USBHAL::EP5_OUT_callback;
epCallback[9] = &USBHAL::EP5_IN_callback;
epCallback[10] = &USBHAL::EP6_OUT_callback;
epCallback[11] = &USBHAL::EP6_IN_callback;
epCallback[12] = &USBHAL::EP7_OUT_callback;
epCallback[13] = &USBHAL::EP7_IN_callback;
epCallback[14] = &USBHAL::EP8_OUT_callback;
epCallback[15] = &USBHAL::EP8_IN_callback;
epCallback[16] = &USBHAL::EP9_OUT_callback;
epCallback[17] = &USBHAL::EP9_IN_callback;
epCallback[18] = &USBHAL::EP10_OUT_callback;
epCallback[19] = &USBHAL::EP10_IN_callback;
epCallback[20] = &USBHAL::EP11_OUT_callback;
epCallback[21] = &USBHAL::EP11_IN_callback;
epCallback[22] = &USBHAL::EP12_OUT_callback;
epCallback[23] = &USBHAL::EP12_IN_callback;
epCallback[24] = &USBHAL::EP13_OUT_callback;
epCallback[25] = &USBHAL::EP13_IN_callback;
epCallback[26] = &USBHAL::EP14_OUT_callback;
epCallback[27] = &USBHAL::EP14_IN_callback;
epCallback[28] = &USBHAL::EP15_OUT_callback;
epCallback[29] = &USBHAL::EP15_IN_callback;
// choose usb src as PLL
SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK);
// enable OTG clock
SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK;
// Attach IRQ
instance = this;
NVIC_SetVector(USB0_IRQn, (uint32_t)&_usbisr);
NVIC_EnableIRQ(USB0_IRQn);
// USB Module Configuration
// Reset USB Module
USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
// Set BDT Base Register
USB0->BDTPAGE1 = (uint8_t)((uint32_t)bdt>>8);
USB0->BDTPAGE2 = (uint8_t)((uint32_t)bdt>>16);
USB0->BDTPAGE3 = (uint8_t)((uint32_t)bdt>>24);
// Clear interrupt flag
USB0->ISTAT = 0xff;
// USB Interrupt Enablers
USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK |
USB_INTEN_SOFTOKEN_MASK |
USB_INTEN_ERROREN_MASK |
USB_INTEN_USBRSTEN_MASK;
// Disable weak pull downs
USB0->USBCTRL &= ~(USB_USBCTRL_PDE_MASK | USB_USBCTRL_SUSP_MASK);
USB0->USBTRC0 |= 0x40;
}
USBHAL::~USBHAL(void) { }
void USBHAL::connect(void) {
// enable USB
USB0->CTL |= USB_CTL_USBENSOFEN_MASK;
// Pull up enable
USB0->CONTROL |= USB_CONTROL_DPPULLUPNONOTG_MASK;
}
void USBHAL::disconnect(void) {
// disable USB
USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK;
// Pull up disable
USB0->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
//Free buffers if required:
for (int i = 0; i<(NUMBER_OF_PHYSICAL_ENDPOINTS - 2) * 2; i++) {
free(endpoint_buffer[i]);
endpoint_buffer[i] = NULL;
}
free(endpoint_buffer_iso[2]);
endpoint_buffer_iso[2] = NULL;
free(endpoint_buffer_iso[0]);
endpoint_buffer_iso[0] = NULL;
}
void USBHAL::configureDevice(void) {
// not needed
}
void USBHAL::unconfigureDevice(void) {
// not needed
}
void USBHAL::setAddress(uint8_t address) {
// we don't set the address now otherwise the usb controller does not ack
// we set a flag instead
// see usbisr when an IN token is received
set_addr = 1;
addr = address;
}
bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flags) {
uint32_t handshake_flag = 0;
uint8_t * buf;
if (endpoint > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) {
return false;
}
uint32_t log_endpoint = PHY_TO_LOG(endpoint);
if ((flags & ISOCHRONOUS) == 0) {
handshake_flag = USB_ENDPT_EPHSHK_MASK;
if (IN_EP(endpoint)) {
if (endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, ODD)] == NULL)
endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, ODD)] = (uint8_t *) malloc (64*2);
buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, ODD)][0];
} else {
if (endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, ODD)] == NULL)
endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, ODD)] = (uint8_t *) malloc (64*2);
buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, ODD)][0];
}
} else {
if (IN_EP(endpoint)) {
if (endpoint_buffer_iso[2] == NULL)
endpoint_buffer_iso[2] = (uint8_t *) malloc (1023*2);
buf = &endpoint_buffer_iso[2][0];
} else {
if (endpoint_buffer_iso[0] == NULL)
endpoint_buffer_iso[0] = (uint8_t *) malloc (1023*2);
buf = &endpoint_buffer_iso[0][0];
}
}
// IN endpt -> device to host (TX)
if (IN_EP(endpoint)) {
USB0->ENDPOINT[log_endpoint].ENDPT |= handshake_flag | // ep handshaking (not if iso endpoint)
USB_ENDPT_EPTXEN_MASK; // en TX (IN) tran
bdt[EP_BDT_IDX(log_endpoint, TX, ODD )].address = (uint32_t) buf;
bdt[EP_BDT_IDX(log_endpoint, TX, EVEN)].address = 0;
}
// OUT endpt -> host to device (RX)
else {
USB0->ENDPOINT[log_endpoint].ENDPT |= handshake_flag | // ep handshaking (not if iso endpoint)
USB_ENDPT_EPRXEN_MASK; // en RX (OUT) tran.
bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].byte_count = maxPacket;
bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].address = (uint32_t) buf;
bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].info = BD_OWN_MASK | BD_DTS_MASK;
bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].info = 0;
}
Data1 |= (1 << endpoint);
return true;
}
// read setup packet
void USBHAL::EP0setup(uint8_t *buffer) {
uint32_t sz;
endpointReadResult(EP0OUT, buffer, &sz);
}
void USBHAL::EP0readStage(void) {
Data1 &= ~1UL; // set DATA0
bdt[0].info = (BD_DTS_MASK | BD_OWN_MASK);
}
void USBHAL::EP0read(void) {
uint32_t idx = EP_BDT_IDX(PHY_TO_LOG(EP0OUT), RX, 0);
bdt[idx].byte_count = MAX_PACKET_SIZE_EP0;
}
uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
uint32_t sz;
endpointReadResult(EP0OUT, buffer, &sz);
return sz;
}
void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
endpointWrite(EP0IN, buffer, size);
}
void USBHAL::EP0getWriteResult(void) {
}
void USBHAL::EP0stall(void) {
stallEndpoint(EP0OUT);
}
EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
endpoint = PHY_TO_LOG(endpoint);
uint32_t idx = EP_BDT_IDX(endpoint, RX, 0);
bdt[idx].byte_count = maximumSize;
return EP_PENDING;
}
EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_t *bytesRead) {
uint32_t n, sz, idx, setup = 0;
uint8_t not_iso;
uint8_t * ep_buf;
uint32_t log_endpoint = PHY_TO_LOG(endpoint);
if (endpoint > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) {
return EP_INVALID;
}
// if read on a IN endpoint -> error
if (IN_EP(endpoint)) {
return EP_INVALID;
}
idx = EP_BDT_IDX(log_endpoint, RX, 0);
sz = bdt[idx].byte_count;
not_iso = USB0->ENDPOINT[log_endpoint].ENDPT & USB_ENDPT_EPHSHK_MASK;
//for isochronous endpoint, we don't wait an interrupt
if ((log_endpoint != 0) && not_iso && !(epComplete & EP(endpoint))) {
return EP_PENDING;
}
if ((log_endpoint == 0) && (TOK_PID(idx) == SETUP_TOKEN)) {
setup = 1;
}
// non iso endpoint
if (not_iso) {
ep_buf = endpoint_buffer[idx];
} else {
ep_buf = endpoint_buffer_iso[0];
}
for (n = 0; n < sz; n++) {
buffer[n] = ep_buf[n];
}
if (((Data1 >> endpoint) & 1) == ((bdt[idx].info >> 6) & 1)) {
if (setup && (buffer[6] == 0)) // if no setup data stage,
Data1 &= ~1UL; // set DATA0
else
Data1 ^= (1 << endpoint);
}
if (((Data1 >> endpoint) & 1)) {
bdt[idx].info = BD_DTS_MASK | BD_DATA01_MASK | BD_OWN_MASK;
}
else {
bdt[idx].info = BD_DTS_MASK | BD_OWN_MASK;
}
USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
*bytesRead = sz;
epComplete &= ~EP(endpoint);
return EP_COMPLETED;
}
EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
uint32_t idx, n;
uint8_t * ep_buf;
if (endpoint > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) {
return EP_INVALID;
}
// if write on a OUT endpoint -> error
if (OUT_EP(endpoint)) {
return EP_INVALID;
}
idx = EP_BDT_IDX(PHY_TO_LOG(endpoint), TX, 0);
bdt[idx].byte_count = size;
// non iso endpoint
if (USB0->ENDPOINT[PHY_TO_LOG(endpoint)].ENDPT & USB_ENDPT_EPHSHK_MASK) {
ep_buf = endpoint_buffer[idx];
} else {
ep_buf = endpoint_buffer_iso[2];
}
for (n = 0; n < size; n++) {
ep_buf[n] = data[n];
}
if ((Data1 >> endpoint) & 1) {
bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK;
} else {
bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK | BD_DATA01_MASK;
}
Data1 ^= (1 << endpoint);
return EP_PENDING;
}
EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
if (epComplete & EP(endpoint)) {
epComplete &= ~EP(endpoint);
return EP_COMPLETED;
}
return EP_PENDING;
}
void USBHAL::stallEndpoint(uint8_t endpoint) {
USB0->ENDPOINT[PHY_TO_LOG(endpoint)].ENDPT |= USB_ENDPT_EPSTALL_MASK;
}
void USBHAL::unstallEndpoint(uint8_t endpoint) {
USB0->ENDPOINT[PHY_TO_LOG(endpoint)].ENDPT &= ~USB_ENDPT_EPSTALL_MASK;
}
bool USBHAL::getEndpointStallState(uint8_t endpoint) {
uint8_t stall = (USB0->ENDPOINT[PHY_TO_LOG(endpoint)].ENDPT & USB_ENDPT_EPSTALL_MASK);
return (stall) ? true : false;
}
void USBHAL::remoteWakeup(void) {
// [TODO]
}
void USBHAL::_usbisr(void) {
instance->usbisr();
}
void USBHAL::usbisr(void) {
uint8_t i;
uint8_t istat = USB0->ISTAT;
// reset interrupt
if (istat & USB_ISTAT_USBRST_MASK) {
// disable all endpt
for(i = 0; i < 16; i++) {
USB0->ENDPOINT[i].ENDPT = 0x00;
}
// enable control endpoint
realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0, 0);
realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0, 0);
Data1 = 0x55555555;
USB0->CTL |= USB_CTL_ODDRST_MASK;
USB0->ISTAT = 0xFF; // clear all interrupt status flags
USB0->ERRSTAT = 0xFF; // clear all error flags
USB0->ERREN = 0xFF; // enable error interrupt sources
USB0->ADDR = 0x00; // set default address
return;
}
// resume interrupt
if (istat & USB_ISTAT_RESUME_MASK) {
USB0->ISTAT = USB_ISTAT_RESUME_MASK;
}
// SOF interrupt
if (istat & USB_ISTAT_SOFTOK_MASK) {
USB0->ISTAT = USB_ISTAT_SOFTOK_MASK;
// SOF event, read frame number
SOF(frameNumber());
}
// stall interrupt
if (istat & 1<<7) {
if (USB0->ENDPOINT[0].ENDPT & USB_ENDPT_EPSTALL_MASK)
USB0->ENDPOINT[0].ENDPT &= ~USB_ENDPT_EPSTALL_MASK;
USB0->ISTAT |= USB_ISTAT_STALL_MASK;
}
// token interrupt
if (istat & 1<<3) {
uint32_t num = (USB0->STAT >> 4) & 0x0F;
uint32_t dir = (USB0->STAT >> 3) & 0x01;
uint32_t ev_odd = (USB0->STAT >> 2) & 0x01;
// setup packet
if ((num == 0) && (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == SETUP_TOKEN)) {
Data1 &= ~0x02;
bdt[EP_BDT_IDX(0, TX, EVEN)].info &= ~BD_OWN_MASK;
bdt[EP_BDT_IDX(0, TX, ODD)].info &= ~BD_OWN_MASK;
// EP0 SETUP event (SETUP data received)
EP0setupCallback();
} else {
// OUT packet
if (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == OUT_TOKEN) {
if (num == 0)
EP0out();
else {
epComplete |= (1 << EP(num));
if ((instance->*(epCallback[EP(num) - 2]))()) {
epComplete &= ~(1 << EP(num));
}
}
}
// IN packet
if (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == IN_TOKEN) {
if (num == 0) {
EP0in();
if (set_addr == 1) {
USB0->ADDR = addr & 0x7F;
set_addr = 0;
}
}
else {
epComplete |= (1 << (EP(num) + 1));
if ((instance->*(epCallback[EP(num) + 1 - 2]))()) {
epComplete &= ~(1 << (EP(num) + 1));
}
}
}
}
USB0->ISTAT = USB_ISTAT_TOKDNE_MASK;
}
// sleep interrupt
if (istat & 1<<4) {
USB0->ISTAT |= USB_ISTAT_SLEEP_MASK;
}
// error interrupt
if (istat & USB_ISTAT_ERROR_MASK) {
USB0->ERRSTAT = 0xFF;
USB0->ISTAT |= USB_ISTAT_ERROR_MASK;
}
}
#endif
