Pinscape Controller version 1 fork. This is a fork to allow for ongoing bug fixes to the original controller version, from before the major changes for the expansion board project.
Dependencies: FastIO FastPWM SimpleDMA mbed
Fork of Pinscape_Controller by
Revision 57:20d54f25065a, committed 2016-02-11
- Comitter:
- mjr
- Date:
- Thu Feb 11 22:18:30 2016 +0000
- Parent:
- 56:c435f370f511
- Child:
- 58:480c2c786c71
- Commit message:
- Add USBHAL_KL25Z buffer cleanup
Changed in this revision
USBDevice/USBDevice/USBHAL_KL25Z.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- a/USBDevice/USBDevice/USBHAL_KL25Z.cpp Thu Feb 11 20:24:50 2016 +0000 +++ b/USBDevice/USBDevice/USBHAL_KL25Z.cpp Thu Feb 11 22:18:30 2016 +0000 @@ -114,8 +114,16 @@ // * 16 bidirectional logical endpoints -> 32 physical endpoints // * 2 BDT entries per endpoint (EVEN/ODD) -> 64 BDT entries __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]; + +// Transfer buffers. We allocate the transfer buffers and point the +// SIE hardware to them via the BDT. We disable hardware SIE's +// double-buffering (EVEN/ODD) scheme, so we only allocate one buffer +// per physical endpoint. +uint8_t *endpoint_buffer[NUMBER_OF_PHYSICAL_ENDPOINTS]; + +// Allocated size of each endpoint buffer +size_t epMaxPacket[NUMBER_OF_PHYSICAL_ENDPOINTS]; + // SET ADDRESS mode tracking. The address assignment has to be done in a // specific order and with specific timing defined by the USB setup protocol @@ -139,7 +147,7 @@ // endpoint's bit is at (1 << endpoint number). A 1 bit signifies that // the last read or write has completed (and hasn't had its result // consumed yet). -static volatile int epComplete = 0; +static volatile uint32_t epComplete = 0; static uint32_t frameNumber() { return((USB0->FRMNUML | (USB0->FRMNUMH << 8)) & 0x07FF); @@ -229,28 +237,33 @@ USBHAL::~USBHAL(void) { } -void USBHAL::connect(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) { +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 buffers + for (int i = 0 ; i < NUMBER_OF_PHYSICAL_ENDPOINTS ; i++) + { + if (endpoint_buffer[i] != NULL) + { + free(endpoint_buffer[i]); + endpoint_buffer[i] = NULL; + epMaxPacket[i] = 0; + } } - free(endpoint_buffer_iso[2]); - endpoint_buffer_iso[2] = NULL; - free(endpoint_buffer_iso[0]); - endpoint_buffer_iso[0] = NULL; } void USBHAL::configureDevice(void) { @@ -269,56 +282,74 @@ addr = address; } -bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flags) { - uint32_t handshake_flag = 0; - uint8_t * buf; +bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flags) +{ + // validate the endpoint number + if (endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) + return false; - if (endpoint > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) { - return false; - } - + // get the logical endpoint 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, EVEN)] == NULL) - endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, EVEN)] = (uint8_t *) malloc (64*2); - buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, EVEN)][0]; - } else { - if (endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, EVEN)] == NULL) - endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, EVEN)] = (uint8_t *) malloc (64*2); - buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, EVEN)][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]; - } + // For bulk and interrupt endpoints, the hardware maximum packet size is 64 bytes, + // and we use packet handshaking. Set these defaults. + uint32_t hwMaxPacket = 64; + uint32_t handshake_flag = USB_ENDPT_EPHSHK_MASK; + + // If it's to be an isochronous endpoint, the hardware maximum packet size + // increases to 1023 bytes, and we don't use handshaking. + if (flags & ISOCHRONOUS) { + handshake_flag = 0; + hwMaxPacket = 1023; } - // 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, EVEN )].address = (uint32_t) buf; + // limit the requested max packet size to the hardware limit + if (maxPacket > hwMaxPacket) + maxPacket = hwMaxPacket; + + // if the endpoint buffer hasn't been allocated yet or was previously + // allocated at a smaller size, allocate a new buffer + uint8_t *buf = endpoint_buffer[endpoint]; + + if (buf == NULL || epMaxPacket[endpoint] < maxPacket) + { + // free any previous buffer + if (buf != 0) + free(buf); + + // allocate at the new size + endpoint_buffer[endpoint] = buf = (uint8_t *)malloc(maxPacket); + + // set the new max packet size + epMaxPacket[endpoint] = maxPacket; + } + + // set the endpoint register flags and BDT entry + if (IN_EP(endpoint)) + { + // IN endpt -> device to host (TX) + USB0->ENDPOINT[log_endpoint].ENDPT |= handshake_flag | USB_ENDPT_EPTXEN_MASK; // en TX (IN) tran + bdt[EP_BDT_IDX(log_endpoint, TX, EVEN)].address = (uint32_t) buf; bdt[EP_BDT_IDX(log_endpoint, TX, ODD )].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. + else + { + // OUT endpt -> host to device (RX) + USB0->ENDPOINT[log_endpoint].ENDPT |= handshake_flag | USB_ENDPT_EPRXEN_MASK; // en RX (OUT) tran. + bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].address = (uint32_t) buf; + bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].address = 0; + + // set up the first read bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].byte_count = maxPacket; - bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].address = (uint32_t) buf; bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].info = BD_OWN_MASK | BD_DTS_MASK; bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].info = 0; } + // Set DATA1 on the endpoint. For RX endpoints, we just queued up our first + // read, which will always be a DATA0 packet, so the next read will use DATA1. + // For TX endpoints, we always flip the bit *before* sending the packet, so + // (counterintuitively) we need to set the DATA1 bit now to send DATA0 in the + // next packet. So in either case, we want DATA1 initially. Data1 |= (1 << endpoint); return true; @@ -364,101 +395,87 @@ 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; +EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_t *bytesRead) +{ + // validate the endpoint number and direction + if (endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS || !OUT_EP(endpoint)) + return EP_INVALID; + // get the logical endpoint uint32_t log_endpoint = PHY_TO_LOG(endpoint); - if (endpoint > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) { - return EP_INVALID; - } + // get the BDT entry + uint32_t idx = EP_BDT_IDX(log_endpoint, RX, 0); + bool iso = (USB0->ENDPOINT[log_endpoint].ENDPT & USB_ENDPT_EPHSHK_MASK) == 0; - // if read on a IN endpoint -> error - if (IN_EP(endpoint)) { - return EP_INVALID; - } + // If it's not isochronous, check to see if we've received data, and + // return PENDING if not. Isochronous endpoints don't use the TOKNE + // interrupt (they use SOF instead), so the 'complete' flag doesn't + // apply if it's an iso endpoint. + if ((log_endpoint != 0) && !iso && !(epComplete & EP(endpoint))) + return EP_PENDING; + + // note if we have a SETUP token + bool setup = (log_endpoint == 0 && TOK_PID(idx) == SETUP_TOKEN); - idx = EP_BDT_IDX(log_endpoint, RX, 0); - sz = bdt[idx].byte_count; - not_iso = USB0->ENDPOINT[log_endpoint].ENDPT & USB_ENDPT_EPHSHK_MASK; + // get the received data buffer and size + uint8_t *ep_buf = endpoint_buffer[endpoint]; + uint32_t sz = bdt[idx].byte_count; - //for isochronous endpoint, we don't wait an interrupt - if ((log_endpoint != 0) && not_iso && !(epComplete & EP(endpoint))) { - return EP_PENDING; - } + // copy the data from the hardware receive buffer to the caller's buffer + *bytesRead = sz; + for (uint32_t n = 0 ; n < sz ; n++) + buffer[n] = ep_buf[n]; - if ((log_endpoint == 0) && (TOK_PID(idx) == SETUP_TOKEN)) { - setup = 1; + // figure the DATA0/DATA1 bit for the next packet + if (((Data1 >> endpoint) & 1) == ((bdt[idx].info >> 6) & 1)) { + if (setup && (buffer[6] == 0)) // if SETUP with no data stage, + Data1 &= ~1UL; // the next packet is always DATA0 + else + Data1 ^= (1 << endpoint); // for all other cases, toggle from the last packet } - // 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]; - } + // hand off the BDT to the SIE to start the next read + bdt[idx].byte_count = epMaxPacket[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; - 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); - } + // clear the "suspend busy" flag to allow continued token processing + USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; - 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; - + // clear the 'completed' flag - we're now awaiting the next packet epComplete &= ~EP(endpoint); + + // read completed 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) { +EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) +{ + // validate the endpoint number and direction + if (endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS || !IN_EP(endpoint)) return EP_INVALID; - } - // if write on a OUT endpoint -> error - if (OUT_EP(endpoint)) { - return EP_INVALID; - } + // get the BDT + uint32_t idx = EP_BDT_IDX(PHY_TO_LOG(endpoint), TX, 0); - idx = EP_BDT_IDX(PHY_TO_LOG(endpoint), TX, 0); - bdt[idx].byte_count = size; - + // get the endpoint buffer + uint8_t *ep_buf = endpoint_buffer[endpoint]; - // 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++) { + // copy the data to the BDT buffer + bdt[idx].byte_count = size; + for (uint32_t n = 0 ; n < size ; n++) ep_buf[n] = data[n]; - } - if ((Data1 >> endpoint) & 1) { + // figure the DATA0/DATA1 mode and hand the BDT to the SIE to do the send + if ((Data1 >> endpoint) & 1) bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK; - } else { + else bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK | BD_DATA01_MASK; - } + // toggle DATA0/DATA1 Data1 ^= (1 << endpoint); return EP_PENDING;