diff --git a/demos/LPC/LPC_11U35_USBDFU/main.c b/demos/LPC/LPC_11U35_USBDFU/main.c index c8def05c..f44bfe9c 100644 --- a/demos/LPC/LPC_11U35_USBDFU/main.c +++ b/demos/LPC/LPC_11U35_USBDFU/main.c @@ -41,10 +41,6 @@ static void jump_to_application(void) { while (1) {} } -#define IAP_LOCATION 0x1fff1ff1 -typedef void (*IAP)(uint32_t [], uint32_t []); -const IAP iap_entry = (IAP)IAP_LOCATION; - /* * Application entry point. */ @@ -57,66 +53,16 @@ int main(void) { */ chSysInit(); - memset(fw_buffer, 0, FW_BUFFER_SIZE); - dfu_need_flush = 0; - /* * Normal main() thread activity, in this demo it does nothing except * increasing the minutes counter. */ - while (true) { - uint32_t iap_command[5]; - uint32_t iap_result[4]; + usbDisconnectBus(&USBD1); + chThdSleepMilliseconds(1500); + usbStart(&USBD1, &usbcfg); + usbConnectBus(&USBD1); - usbDisconnectBus(&USBD1); - chThdSleepMilliseconds(1500); - usbStart(&USBD1, &usbcfg); - usbConnectBus(&USBD1); - - while(1){ - if (dfu_need_flush) { - if (global_offset == APP_BASE) { - do { - iap_command[0] = 50; // Prep Sector - iap_command[1] = 3; // Start Sec - iap_command[2] = 15; // Stop Sec - iap_entry(iap_command, iap_result); - } while(iap_result[0]); - // Erase All Flash (3-15) - do { - iap_command[0] = 52; // Erase Sector - iap_command[1] = 3; // Start Sec - iap_command[2] = 15; // Stop Sec - iap_command[3] = 48000; // 48MHz - iap_entry(iap_command, iap_result); - } while(iap_result[0]); - } - uint32_t start_sector = global_offset / 4096; - uint32_t end_sector = (global_offset + FW_BUFFER_SIZE) / 4096; - iap_command[0] = 50; // Prep Sector - iap_command[1] = start_sector; // Start Sec - iap_command[2] = end_sector; // Stop Sec - iap_entry(iap_command, iap_result); - // Copy the buffer - iap_command[0] = 51; - iap_command[1] = global_offset; - iap_command[2] = (uint32_t)fw_buffer; - iap_command[3] = FW_BUFFER_SIZE; - iap_command[4] = 48000; - iap_entry(iap_command, iap_result); - global_offset += FW_BUFFER_SIZE; - - dfu_need_flush = 0; - memset(fw_buffer, 0, FW_BUFFER_SIZE); - buffer_fill = 0; - if (currentState == STATE_DFU_DNLOAD_SYNC || currentState == STATE_DFU_DNBUSY) - currentState = STATE_DFU_DNLOAD_IDLE; - if (currentState == STATE_DFU_MANIFEST_SYNC) { - currentState = STATE_DFU_MANIFEST_WAIT_RESET; - chThdSleepMilliseconds(2000); - jump_to_application(); - } - } - } + while(1){ + chThdSleepSeconds(600); } } diff --git a/demos/LPC/LPC_11U35_USBDFU/source/dfu_target.c b/demos/LPC/LPC_11U35_USBDFU/source/dfu_target.c new file mode 100644 index 00000000..e049c6ff --- /dev/null +++ b/demos/LPC/LPC_11U35_USBDFU/source/dfu_target.c @@ -0,0 +1,115 @@ +#include "dfu_target.h" +#include "usbdfu.h" +#include "ch.h" +#include "hal.h" +#include + +#define IAP_LOCATION 0x1fff1ff1 +typedef void (*IAP)(uint32_t [], uint32_t []); +const IAP iap_entry = (IAP)IAP_LOCATION; + +#define INTERNAL_CHUNK_SIZE 1024 + +static uint8_t iap_buffer[INTERNAL_CHUNK_SIZE]; +static size_t buffer_size = 0; +static size_t buffer_base = 0; +static size_t last_chunk_size = 0; +static size_t preped_flash = 0; + +size_t target_get_max_fw_size(void) { + return (0x10000 - 0x2000); +} + +uint16_t target_get_timeout(void) { + if (last_chunk_size != 0 && (buffer_size + last_chunk_size) < INTERNAL_CHUNK_SIZE) { + return 5; + } + if (preped_flash == 0) { + return 50; + } + return 0; +} + +void target_flash_unlock(void) { + chSysLock(); +} + +static inline bool write_buffer(void) { + uint32_t iap_command[5] = {0,0,0,0,0}; + uint32_t iap_result[4] = {0,0,0,0}; + + if (((size_t)buffer_base % INTERNAL_CHUNK_SIZE) != 0) { + return false; + } + + uint32_t sector = (size_t)buffer_base / 4096; + iap_command[0] = 50; // Prep Sector + iap_command[1] = sector; // Start Sec + iap_command[2] = sector; // Stop Sec + iap_entry(iap_command, iap_result); + + // Copy the buffer + iap_command[0] = 51; // Copy RAM -> Flash + iap_command[1] = (size_t) buffer_base; + iap_command[2] = (size_t) iap_buffer; + iap_command[3] = INTERNAL_CHUNK_SIZE; + iap_command[4] = 48000; + iap_entry(iap_command, iap_result); + return iap_result[0] == 0; +} + +bool target_flash_write(uint8_t* dst, uint8_t* src, size_t len) { + last_chunk_size = len; + size_t copied = 0; + while(copied < len) { // Stuff remain in the thing + if (buffer_size == 0) { // If buffer is empty, then we update base + buffer_base = (size_t)dst + copied; + } + + size_t copy_size = len - copied; + if (copy_size > (INTERNAL_CHUNK_SIZE - buffer_size)) { + copy_size = INTERNAL_CHUNK_SIZE - buffer_size; + } + memcpy(&iap_buffer[buffer_size], (src + copied), copy_size); + buffer_size += copy_size; + copied += copy_size; + if (buffer_size == INTERNAL_CHUNK_SIZE) { + if (!write_buffer()) + return false; + buffer_size = 0; + } + } + return true; +} + +bool target_prepare_flash(void) { + uint32_t iap_command[5] = {0,0,0,0,0}; + uint32_t iap_result[4] = {0,0,0,0}; + iap_command[0] = 50; // Prep Sector + iap_command[1] = APP_BASE / 0x1000; // Start Sec + iap_command[2] = 15; // Stop Sec + iap_entry(iap_command, iap_result); + if (iap_result[0] != 0) { + return false; + } + + iap_command[0] = 52; // Erase Sector + iap_command[1] = APP_BASE / 0x1000; // Start Sec + iap_command[2] = 15; // Stop Sec + iap_command[3] = 48000; // 48MHz + iap_entry(iap_command, iap_result); + preped_flash = 1; + + return iap_result[0] == 0; +} + +void target_flash_lock(void) { + chSysUnlock(); +} + +void target_complete_programming(void) { + if (buffer_size > 0) { + memset(&iap_buffer[buffer_size], 0, INTERNAL_CHUNK_SIZE - buffer_size); + write_buffer(); + } +} diff --git a/demos/LPC/LPC_11U35_USBDFU/source/dfu_target.h b/demos/LPC/LPC_11U35_USBDFU/source/dfu_target.h new file mode 100644 index 00000000..a411b2b2 --- /dev/null +++ b/demos/LPC/LPC_11U35_USBDFU/source/dfu_target.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include +#include + +size_t target_get_max_fw_size(void); +uint16_t target_get_timeout(void); +void target_flash_unlock(void); +bool target_flash_write(uint8_t* dst, uint8_t* src, size_t len); +bool target_prepare_flash(void); +void target_flash_lock(void); +void target_complete_programming(void); \ No newline at end of file diff --git a/demos/LPC/LPC_11U35_USBDFU/source/usbdfu.c b/demos/LPC/LPC_11U35_USBDFU/source/usbdfu.c index cbbaf9c7..06d91fc5 100644 --- a/demos/LPC/LPC_11U35_USBDFU/source/usbdfu.c +++ b/demos/LPC/LPC_11U35_USBDFU/source/usbdfu.c @@ -1,11 +1,8 @@ #include "hal.h" #include "usbdfu.h" - +#include "dfu_target.h" uint8_t fw_buffer[FW_BUFFER_SIZE]; -volatile uint8_t dfu_need_flush = 0; -volatile uint32_t buffer_fill = 0; -volatile uint32_t global_offset = APP_BASE; /* * USB Device Descriptor. */ @@ -52,8 +49,8 @@ static const uint8_t dfu_configuration_descriptor_data[27] = { USB_DESC_BYTE (9), /* bLength. */ USB_DESC_BYTE (0x21), /* bDescriptorType (DFU_FCUNTION). */ USB_DESC_BYTE (0b1011), /* bmAttributes (DETACH | DOWNLOAD) */ - USB_DESC_WORD ( 1500), /* Timeout. */ - USB_DESC_WORD (64 ), + USB_DESC_WORD ( 1000), /* DetachTimeout. */ + USB_DESC_WORD ( 64), USB_DESC_BCD (0x0110) }; @@ -79,9 +76,9 @@ static const uint8_t dfu_string1[] = { * Device Description string. */ static const uint8_t dfu_string2[] = { - USB_DESC_BYTE(8), /* bLength. */ + USB_DESC_BYTE(12), /* bLength. */ USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - 'D', 0, 'F', 0, 'U', 0 + 'S', 0, 'F', 0, 'D', 0, 'F', 0, 'U', 0 }; /* @@ -114,7 +111,6 @@ static const USBDescriptor *get_descriptor(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t lang) { - (void)usbp; (void)lang; switch (dtype) { @@ -129,87 +125,171 @@ static const USBDescriptor *get_descriptor(USBDriver *usbp, return NULL; } -static void usb_event(USBDriver *usbp, usbevent_t event) { -} - -static void sof_handler(USBDriver *usbp) { - (void)usbp; -} - volatile enum dfu_state currentState = STATE_DFU_IDLE; -size_t currentAddress = 0; -static enum { - LASTOP_IDLE, - LASTOP_DNLOAD, - LASTOP_UPLOAD -} lastOperation; +volatile enum dfu_status currentStatus = DFU_STATUS_OK; +size_t current_dfu_offset = 0; +size_t dfu_download_size = 0; -static uint8_t status_response_buffer[6] = { - DFU_STATUS_OK, // Status (0) - 100, 0x00, 0x00, - 0x00, // Next State (4) - 0 -}; +static void dfu_on_download_request(USBDriver *usbp) { + (void)usbp; + uint8_t *dest = (uint8_t*)(APP_BASE + current_dfu_offset); + + bool ok = true; + target_flash_unlock(); + if (current_dfu_offset == 0) { + ok = target_prepare_flash(); + } + if (ok) { + ok = target_flash_write(dest, fw_buffer, dfu_download_size); + } + target_flash_lock(); + + if (ok) { + current_dfu_offset += dfu_download_size; + currentState = STATE_DFU_DNLOAD_IDLE; + } else { + currentState = STATE_DFU_ERROR; + currentStatus = DFU_STATUS_ERR_VERIFY; + } +} + +static void dfu_on_download_complete(USBDriver *usbp) { + (void)usbp; + currentState = STATE_DFU_MANIFEST_SYNC; +} + +static void dfu_on_manifest_request(USBDriver *usbp) { + (void)usbp; + target_complete_programming(); + currentState = STATE_DFU_MANIFEST_WAIT_RESET; +} + +static void dfu_on_detach_complete(USBDriver *usbp) { + (void)usbp; + __asm__ __volatile__("dsb"); + SCB->AIRCR = 0x05FA0004; // System Reset + __asm__ __volatile__("dsb"); + while(1){}; +} + +static inline void dfu_status_req(USBDriver *usbp) { + static uint8_t status_response_buffer[6] = {}; + uint32_t pollTime = 10; + usbcallback_t cb = NULL; + + switch(currentState) { + case STATE_DFU_DNLOAD_SYNC: { + currentState = STATE_DFU_DNBUSY; + pollTime = target_get_timeout(); + cb = &dfu_on_download_request; + break; + } + case STATE_DFU_MANIFEST_SYNC: { + currentState = STATE_DFU_MANIFEST; + cb = &dfu_on_manifest_request; + break; + } + case STATE_DFU_MANIFEST_WAIT_RESET: { + cb = &dfu_on_detach_complete; + break; + } + + default: + break; + } + + // Response Construction + status_response_buffer[0] = (uint8_t) currentStatus; + status_response_buffer[1] = (uint8_t) (pollTime & 0xFFU); + status_response_buffer[2] = (uint8_t) ((pollTime >> 8U) & 0xFFU); + status_response_buffer[3] = (uint8_t) ((pollTime >> 16U) & 0xFFU); + status_response_buffer[4] = (uint8_t) currentState; + status_response_buffer[5] = 0; // No Index + + usbSetupTransfer(usbp, status_response_buffer, 6, cb); +} static bool request_handler(USBDriver *usbp) { - if((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) { - uint16_t transfer_size = (((uint16_t)usbp->setup[7]) << 8) | usbp->setup[6]; - uint16_t block_cnt = (((uint16_t)usbp->setup[4]) << 8) | usbp->setup[3]; - switch (usbp->setup[1]) { - case DFU_GETSTATUS: - if (currentState == STATE_DFU_DNLOAD_SYNC) { - currentState = STATE_DFU_DNBUSY; - } - status_response_buffer[4] = currentState; - usbSetupTransfer(usbp, (uint8_t *)status_response_buffer, 6, NULL); - return true; - case DFU_GETSTATE: - usbSetupTransfer(usbp, (uint8_t *)¤tState, 1, NULL); - return true; - case DFU_UPLOAD: - if (lastOperation != LASTOP_UPLOAD) { - lastOperation = LASTOP_UPLOAD; - currentAddress = APP_BASE; - } - if ((currentAddress + transfer_size) > MAX_FLASH_ADDR) { - transfer_size = MAX_FLASH_ADDR - currentAddress; - usbSetupTransfer(usbp, (uint8_t *)currentAddress, transfer_size, NULL); - lastOperation = LASTOP_IDLE; - currentState = STATE_DFU_IDLE; - } else { - usbSetupTransfer(usbp, (uint8_t *)currentAddress, transfer_size, NULL); - currentAddress += transfer_size; - currentState = STATE_DFU_UPLOAD_IDLE; - } - return true; - case DFU_ABORT: - lastOperation = LASTOP_IDLE; - currentState = STATE_DFU_IDLE; - return true; - case DFU_DNLOAD: - if (lastOperation != LASTOP_DNLOAD) { - lastOperation = LASTOP_DNLOAD; - global_offset = APP_BASE; - buffer_fill = 0; - dfu_need_flush = 0; - } - if (transfer_size) { - usbSetupTransfer(usbp, &fw_buffer[buffer_fill], transfer_size, NULL); - buffer_fill += transfer_size; - if (buffer_fill < FW_BUFFER_SIZE) { - currentState = STATE_DFU_DNLOAD_IDLE; - } else { - currentState = STATE_DFU_DNLOAD_SYNC; - dfu_need_flush = 1; - } - } else { - if (buffer_fill > 0) - dfu_need_flush = 1; - currentState = STATE_DFU_MANIFEST_SYNC; - lastOperation = LASTOP_IDLE; - } - return true; + struct usb_setup* setup = (struct usb_setup*) usbp->setup; + if((setup->bmRequestType & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) { + switch (setup->bRequest) { + case DFU_GETSTATUS: { + dfu_status_req(usbp); + return true; } + case DFU_GETSTATE: { + usbSetupTransfer(usbp, (uint8_t *)¤tState, 1, NULL); + return true; + } + case DFU_UPLOAD: { + switch (currentState) { + case STATE_DFU_IDLE: { + current_dfu_offset = 0; + __attribute__((fallthrough)); + } + case STATE_DFU_UPLOAD_IDLE: { + uint16_t copy_len = setup->wLength; + size_t fw_size = target_get_max_fw_size(); + if (current_dfu_offset + setup->wLength > fw_size) { + copy_len = fw_size - current_dfu_offset; + currentState = STATE_DFU_IDLE; + } else { + currentState = STATE_DFU_UPLOAD_IDLE; + } + usbSetupTransfer(usbp, (uint8_t *)(APP_BASE + current_dfu_offset), copy_len, NULL ); + current_dfu_offset += copy_len; + break; + } + default: + usbSetupTransfer(usbp, NULL, 0, NULL); + break; + } + return true; + } + case DFU_CLRSTATUS: { + currentStatus = DFU_STATUS_OK; + if (currentState != STATE_DFU_ERROR) { + usbSetupTransfer(usbp, NULL, 0, NULL); + break; + } + __attribute__((fallthrough)); + } + case DFU_ABORT: { + currentState = STATE_DFU_IDLE; + usbSetupTransfer(usbp, NULL, 0, NULL); + return true; + } + case DFU_DETACH: { + usbSetupTransfer(usbp, NULL, 0, &dfu_on_detach_complete); + return true; + } + case DFU_DNLOAD: { + switch (currentState) { + case STATE_DFU_IDLE: { + current_dfu_offset = 0; + dfu_download_size = setup->wLength; + currentState = STATE_DFU_DNLOAD_SYNC; + usbSetupTransfer(usbp, &fw_buffer[0], dfu_download_size, NULL); + break; + } + case STATE_DFU_DNLOAD_IDLE: { + if (setup->wLength > 0) { + dfu_download_size = setup->wLength; + usbSetupTransfer(usbp, &fw_buffer[0], dfu_download_size, NULL); + currentState = STATE_DFU_DNLOAD_SYNC; + } else { + usbSetupTransfer(usbp, NULL, 0, &dfu_on_download_complete); + } + break; + } + default: { + usbSetupTransfer(usbp, NULL, 0, NULL); + break; + } + } + return true; + } + } } return false; } @@ -218,8 +298,8 @@ static bool request_handler(USBDriver *usbp) { * USB driver configuration. */ const USBConfig usbcfg = { - usb_event, + NULL, get_descriptor, request_handler, - sof_handler + NULL }; diff --git a/demos/LPC/LPC_11U35_USBDFU/source/usbdfu.h b/demos/LPC/LPC_11U35_USBDFU/source/usbdfu.h index a8b1cfa5..f47c5806 100644 --- a/demos/LPC/LPC_11U35_USBDFU/source/usbdfu.h +++ b/demos/LPC/LPC_11U35_USBDFU/source/usbdfu.h @@ -1,23 +1,18 @@ #pragma once #include "stdint.h" +#include "hal.h" extern const USBConfig usbcfg; #define MAX_FLASH_ADDR 0x10000 #define FLASH_BASE 0x0 -#define BL_SIZE 0x3000 +#define BL_SIZE 0x2000 #define APP_BASE (FLASH_BASE + BL_SIZE) #define FLASH_PAGE_SIZE 4096 -#define FW_BUFFER_SIZE 1024 -extern uint8_t fw_buffer[FW_BUFFER_SIZE]; -extern volatile uint8_t dfu_need_flush; -extern volatile uint32_t buffer_fill; -extern volatile uint32_t global_offset; -extern size_t currentAddress; -extern volatile enum dfu_state currentState; +#define FW_BUFFER_SIZE 256 enum dfu_req { DFU_DETACH, @@ -63,3 +58,10 @@ enum dfu_status { DFU_STATUS_ERR_STALLEDPKT, }; +struct usb_setup { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} __attribute__((packed)); \ No newline at end of file diff --git a/os/hal/ports/LPC/LLD/USB/hal_usb_lld.c b/os/hal/ports/LPC/LLD/USB/hal_usb_lld.c index 149c679c..e78bc1df 100644 --- a/os/hal/ports/LPC/LLD/USB/hal_usb_lld.c +++ b/os/hal/ports/LPC/LLD/USB/hal_usb_lld.c @@ -132,7 +132,7 @@ static void usb_packet_transmit(USBDriver *usbp, usbep_t ep, size_t n) } /* Get EP command/status List, update the length field and data pointer. */ - USB_EPLIST->entry[ep * 4 + 2] &= ~0x3FFFFFF; + USB_EPLIST->entry[ep * 4 + 2] &= ~(0x3FFFFFF | EPLIST_ENTRY_STALL | EPLIST_ENTRY_ACTIVE); USB_EPLIST->entry[ep * 4 + 2] |= EPLIST_ENTRY_NBYTES(n) | EPLIST_ADDR(usbp->epn_buffer[ep * 2 + 1]); if (n > 0) @@ -145,21 +145,28 @@ static size_t usb_packet_receive(USBDriver *usbp, usbep_t ep) { const USBEndpointConfig *epcp = usbp->epc[ep]; USBOutEndpointState *osp = usbp->epc[ep]->out_state; uint32_t n = (USB_EPLIST->entry[4 * ep] & EPLIST_ENTRY_NBYTES_MASK) >> EPLIST_ENTRY_NBYTES_POS; - n = epcp->out_maxsize - n; + const size_t xfer_size = (osp->rxsize > epcp->out_maxsize) ? epcp->out_maxsize : osp->rxsize; + n = xfer_size - n; if (osp->rxbuf != NULL && n > 0) { memcpy(osp->rxbuf, usbp->epn_buffer[ep * 2], n); osp->rxbuf += n; } - // ReSetup for recieve - USB_EPLIST->entry[4 * ep] &= ~0x3FFFFFF; - USB_EPLIST->entry[4 * ep] |= EPLIST_ENTRY_NBYTES(epcp->out_maxsize) | - EPLIST_ADDR(usbp->epn_buffer[ep * 2]); - if (osp->rxpkts > 0) osp->rxpkts -= 1; osp->rxcnt += n; osp->rxsize -= n; + + size_t next_xfer = (osp->rxsize > epcp->out_maxsize) ? epcp->out_maxsize : osp->rxsize; + USB_EPLIST->entry[4 * ep] &= ~(0x3FFFFFF | EPLIST_ENTRY_STALL | EPLIST_ENTRY_ACTIVE); + if (next_xfer > 0) { + // ReSetup for recieve + USB_EPLIST->entry[4 * ep] |= EPLIST_ENTRY_NBYTES(next_xfer) | + EPLIST_ADDR(usbp->epn_buffer[ep * 2]) | EPLIST_ENTRY_ACTIVE; + } else { + USB_EPLIST->entry[4 * ep] |= EPLIST_ENTRY_STALL; + } + return n; } @@ -174,10 +181,9 @@ OSAL_IRQ_HANDLER(LPC_USB_IRQ_VECTOR) { OSAL_IRQ_PROLOGUE(); USBDriver *usbp = &USBD1; - uint32_t isr = LPC_USB->INTSTAT; - #define devstat (LPC_USB->DEVCMDSTAT) + uint32_t isr = (LPC_USB->INTSTAT & LPC_USB->INTEN); LPC_USB->INTSTAT &= 0xFFFFFFFF; // Clear Flags - + #define devstat (LPC_USB->DEVCMDSTAT) // SOF if (isr & USB_INT_FRAME_INT) { @@ -212,13 +218,13 @@ OSAL_IRQ_HANDLER(LPC_USB_IRQ_VECTOR) { } else { // OUT endpoint, receive USBOutEndpointState *osp = usbp->epc[ep]->out_state; - osalSysLockFromISR(); - size_t n = usb_packet_receive(usbp, ep); - osalSysUnlockFromISR(); - if ((n < usbp->epc[0]->out_maxsize) || (osp->rxpkts == 0)) { + if (osp->rxsize > 0) { + osalSysLockFromISR(); + usb_packet_receive(usbp, ep); + osalSysUnlockFromISR(); + } + if (osp->rxsize == 0) { // TODO: Check if this is correct _usb_isr_invoke_out_cb(usbp, ep); - } else { - USB_EPLIST->entry[4 * ep] |= EPLIST_ENTRY_ACTIVE; } } } @@ -356,9 +362,9 @@ void usb_lld_reset(USBDriver *usbp) { LPC_USB->DATABUFSTART = LPC_USB_SRAM_START & USB_DATABUFSTART_MASK; // Clear Existing Interrupts - LPC_USB->INTSTAT = USB_INT_DEV_INT | USB_INT_FRAME_INT | USB_INT_EP_ALL_INT; + LPC_USB->INTSTAT |= USB_INT_DEV_INT | USB_INT_FRAME_INT | USB_INT_EP_ALL_INT; // Setup Interrupt Masks - LPC_USB->INTEN = USB_INT_DEV_INT | USB_INT_EP_ALL_INT; + LPC_USB->INTEN = USB_INT_DEV_INT | 0b11; // SOF only if there is a handler registered. if ((usbp)->config->sof_cb != NULL) { LPC_USB->INTEN |= USB_INT_FRAME_INT; @@ -425,32 +431,31 @@ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) { case USB_EP_MODE_TYPE_INTR: break; default: - while(1) {} + break; } - if (epcp->out_state != NULL) { - while(epcp->out_maxsize > 1023); + if (epcp->out_state != NULL || ep == 0) { uint32_t ep_mem = usb_ep_malloc(usbp, epcp->out_maxsize, 64); usbp->epn_buffer[(2 * ep)] = (void *)ep_mem; + USB_EPLIST->entry[(4 * ep)] = usbep_cfg | EPLIST_ADDR(ep_mem) | EPLIST_ENTRY_NBYTES(epcp->out_maxsize); + + LPC_USB->INTEN |= USB_INT_EP((ep * 2)); } if (ep == 0) { - while(usbp->setup_buffer != NULL){} // Allocate Setup Bytes uint32_t ep_mem = usb_ep_malloc(usbp, 8, 64); usbp->setup_buffer = (void *)ep_mem; USB_EPLIST->entry[1] = EPLIST_ADDR(ep_mem); - LPC_USB->INTEN |= USB_INT_EP(ep * 2); } - if (epcp->in_state != NULL) { - while(epcp->in_maxsize > 1023); + if (epcp->in_state != NULL || ep == 0) { uint32_t ep_mem = usb_ep_malloc(usbp, epcp->in_maxsize, 64); usbp->epn_buffer[(2 * ep) + 1] = (void *)ep_mem; USB_EPLIST->entry[(4 * ep) + 2] = usbep_cfg | EPLIST_ADDR(ep_mem) | EPLIST_ENTRY_NBYTES(epcp->in_maxsize); - LPC_USB->INTEN |= USB_INT_EP((ep * 2) + 1); + LPC_USB->INTEN |= USB_INT_EP(((ep * 2) + 1)); } } @@ -469,10 +474,10 @@ void usb_lld_disable_endpoints(USBDriver *usbp) { while (LPC_USB->EPSKIP) {} for (int i = 1; i < 5; ++i) // 4 EPs needs to be disabled, EP0 can't { - USB_EPLIST->entry[i * 2] &= ~EP_STATUS_ACTIVE; - USB_EPLIST->entry[i * 2] |= EP_STATUS_DISABLED; - USB_EPLIST->entry[i * 2 + 2] &= ~EP_STATUS_ACTIVE; - USB_EPLIST->entry[i * 2 + 2] |= EP_STATUS_DISABLED; + USB_EPLIST->entry[i * 4] &= ~EP_STATUS_ACTIVE; + USB_EPLIST->entry[i * 4] |= EP_STATUS_DISABLED; + USB_EPLIST->entry[i * 4 + 2] &= ~EP_STATUS_ACTIVE; + USB_EPLIST->entry[i * 4 + 2] |= EP_STATUS_DISABLED; } } @@ -491,9 +496,9 @@ void usb_lld_disable_endpoints(USBDriver *usbp) { usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) { if (usbp != &USBD1) return EP_STATUS_DISABLED; - if (USB_EPLIST->entry[ep * 2] & EPLIST_ENTRY_DISABLE) { + if (USB_EPLIST->entry[ep * 4] & EPLIST_ENTRY_DISABLE) { return EP_STATUS_DISABLED; - } else if (USB_EPLIST->entry[ep * 2] & EPLIST_ENTRY_STALL) { + } else if (USB_EPLIST->entry[ep * 4] & EPLIST_ENTRY_STALL) { return EP_STATUS_STALLED; } else { return EP_STATUS_ACTIVE; @@ -515,9 +520,9 @@ usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) { usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) { if (usbp != &USBD1) return EP_STATUS_DISABLED; - if (USB_EPLIST->entry[ep * 2 + 2] & EPLIST_ENTRY_DISABLE) { + if (USB_EPLIST->entry[ep * 4 + 2] & EPLIST_ENTRY_DISABLE) { return EP_STATUS_DISABLED; - } else if (USB_EPLIST->entry[ep * 2 + 2] & EPLIST_ENTRY_STALL) { + } else if (USB_EPLIST->entry[ep * 4 + 2] & EPLIST_ENTRY_STALL) { return EP_STATUS_STALLED; } else { return EP_STATUS_ACTIVE; @@ -546,11 +551,8 @@ void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) { USB_EPLIST->entry[0] &= ~(EPLIST_ENTRY_STALL | EPLIST_ENTRY_ACTIVE); // EP0OUT USB_EPLIST->entry[2] &= ~(EPLIST_ENTRY_STALL | EPLIST_ENTRY_ACTIVE); // EP0IN LPC_USB->DEVCMDSTAT |= USB_DEVCMDSTAT_SETUP; // Clear SETUP - LPC_USB->DEVCMDSTAT &= ~(USB_DEVCMDSTAT_INTONNAK_CO | USB_DEVCMDSTAT_INTONNAK_CI); memcpy(buf, usbp->setup_buffer, 8); USB_EPLIST->entry[1] = EPLIST_ADDR(usbp->setup_buffer); - } else { - while(1){} } } } @@ -567,19 +569,28 @@ void usb_lld_start_out(USBDriver *usbp, usbep_t ep) { USBOutEndpointState *osp = usbp->epc[ep]->out_state; const USBEndpointConfig *epcp = usbp->epc[ep]; - if (osp->rxsize == 0) /* Special case for zero sized packets.*/ - osp->rxpkts = 1; - else - osp->rxpkts = (uint16_t)((osp->rxsize + usbp->epc[ep]->out_maxsize - 1) / - usbp->epc[ep]->out_maxsize); + size_t rx_size = 0; - USB_EPLIST->entry[ep * 4] &= ~0x3FFFFFF; + if (osp->rxsize == 0) { /* Special case for zero sized packets.*/ + osp->rxpkts = 1; + rx_size = 0; + } else { + osp->rxpkts = (uint16_t)((osp->rxsize + epcp->out_maxsize - 1) / + epcp->out_maxsize); + if (osp->rxsize > epcp->out_maxsize) { + rx_size = epcp->out_maxsize; + } else { + rx_size = osp->rxsize; + } + } + + USB_EPLIST->entry[ep * 4] &= ~(0x3FFFFFF | EPLIST_ENTRY_STALL | EPLIST_ENTRY_ACTIVE); USB_EPLIST->entry[ep * 4] |= EPLIST_ENTRY_ACTIVE | - EPLIST_ENTRY_NBYTES(epcp->out_maxsize) | + EPLIST_ENTRY_NBYTES(rx_size) | EPLIST_ADDR(usbp->epn_buffer[ep * 2]); - LPC_USB->DEVCMDSTAT |= USB_DEVCMDSTAT_INTONNAK_CO; - LPC_USB->DEVCMDSTAT &= ~USB_DEVCMDSTAT_INTONNAK_CI; + if (ep == 0) + LPC_USB->DEVCMDSTAT |= USB_DEVCMDSTAT_INTONNAK_CO; } /**