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 Mike R

Files at this revision

API Documentation at this revision

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;