Merge pull request #243 from Codetector1374/LPC_Port
[HAL/LPC] Update USB HAL Driver to resolve an issue where sometimes it causes control EP to stall
This commit is contained in:
commit
11478d784b
|
@ -41,10 +41,6 @@ static void jump_to_application(void) {
|
||||||
while (1) {}
|
while (1) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IAP_LOCATION 0x1fff1ff1
|
|
||||||
typedef void (*IAP)(uint32_t [], uint32_t []);
|
|
||||||
const IAP iap_entry = (IAP)IAP_LOCATION;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Application entry point.
|
* Application entry point.
|
||||||
*/
|
*/
|
||||||
|
@ -57,66 +53,16 @@ int main(void) {
|
||||||
*/
|
*/
|
||||||
chSysInit();
|
chSysInit();
|
||||||
|
|
||||||
memset(fw_buffer, 0, FW_BUFFER_SIZE);
|
|
||||||
dfu_need_flush = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Normal main() thread activity, in this demo it does nothing except
|
* Normal main() thread activity, in this demo it does nothing except
|
||||||
* increasing the minutes counter.
|
* increasing the minutes counter.
|
||||||
*/
|
*/
|
||||||
while (true) {
|
usbDisconnectBus(&USBD1);
|
||||||
uint32_t iap_command[5];
|
chThdSleepMilliseconds(1500);
|
||||||
uint32_t iap_result[4];
|
usbStart(&USBD1, &usbcfg);
|
||||||
|
usbConnectBus(&USBD1);
|
||||||
|
|
||||||
usbDisconnectBus(&USBD1);
|
while(1){
|
||||||
chThdSleepMilliseconds(1500);
|
chThdSleepSeconds(600);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
#include "dfu_target.h"
|
||||||
|
#include "usbdfu.h"
|
||||||
|
#include "ch.h"
|
||||||
|
#include "hal.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
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);
|
|
@ -1,11 +1,8 @@
|
||||||
#include "hal.h"
|
#include "hal.h"
|
||||||
#include "usbdfu.h"
|
#include "usbdfu.h"
|
||||||
|
#include "dfu_target.h"
|
||||||
|
|
||||||
uint8_t fw_buffer[FW_BUFFER_SIZE];
|
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.
|
* USB Device Descriptor.
|
||||||
*/
|
*/
|
||||||
|
@ -52,8 +49,8 @@ static const uint8_t dfu_configuration_descriptor_data[27] = {
|
||||||
USB_DESC_BYTE (9), /* bLength. */
|
USB_DESC_BYTE (9), /* bLength. */
|
||||||
USB_DESC_BYTE (0x21), /* bDescriptorType (DFU_FCUNTION). */
|
USB_DESC_BYTE (0x21), /* bDescriptorType (DFU_FCUNTION). */
|
||||||
USB_DESC_BYTE (0b1011), /* bmAttributes (DETACH | DOWNLOAD) */
|
USB_DESC_BYTE (0b1011), /* bmAttributes (DETACH | DOWNLOAD) */
|
||||||
USB_DESC_WORD ( 1500), /* Timeout. */
|
USB_DESC_WORD ( 1000), /* DetachTimeout. */
|
||||||
USB_DESC_WORD (64 ),
|
USB_DESC_WORD ( 64),
|
||||||
USB_DESC_BCD (0x0110)
|
USB_DESC_BCD (0x0110)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -79,9 +76,9 @@ static const uint8_t dfu_string1[] = {
|
||||||
* Device Description string.
|
* Device Description string.
|
||||||
*/
|
*/
|
||||||
static const uint8_t dfu_string2[] = {
|
static const uint8_t dfu_string2[] = {
|
||||||
USB_DESC_BYTE(8), /* bLength. */
|
USB_DESC_BYTE(12), /* bLength. */
|
||||||
USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */
|
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 dtype,
|
||||||
uint8_t dindex,
|
uint8_t dindex,
|
||||||
uint16_t lang) {
|
uint16_t lang) {
|
||||||
|
|
||||||
(void)usbp;
|
(void)usbp;
|
||||||
(void)lang;
|
(void)lang;
|
||||||
switch (dtype) {
|
switch (dtype) {
|
||||||
|
@ -129,87 +125,171 @@ static const USBDescriptor *get_descriptor(USBDriver *usbp,
|
||||||
return NULL;
|
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;
|
volatile enum dfu_state currentState = STATE_DFU_IDLE;
|
||||||
size_t currentAddress = 0;
|
volatile enum dfu_status currentStatus = DFU_STATUS_OK;
|
||||||
static enum {
|
size_t current_dfu_offset = 0;
|
||||||
LASTOP_IDLE,
|
size_t dfu_download_size = 0;
|
||||||
LASTOP_DNLOAD,
|
|
||||||
LASTOP_UPLOAD
|
|
||||||
} lastOperation;
|
|
||||||
|
|
||||||
static uint8_t status_response_buffer[6] = {
|
static void dfu_on_download_request(USBDriver *usbp) {
|
||||||
DFU_STATUS_OK, // Status (0)
|
(void)usbp;
|
||||||
100, 0x00, 0x00,
|
uint8_t *dest = (uint8_t*)(APP_BASE + current_dfu_offset);
|
||||||
0x00, // Next State (4)
|
|
||||||
0
|
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) {
|
static bool request_handler(USBDriver *usbp) {
|
||||||
if((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) {
|
struct usb_setup* setup = (struct usb_setup*) usbp->setup;
|
||||||
uint16_t transfer_size = (((uint16_t)usbp->setup[7]) << 8) | usbp->setup[6];
|
if((setup->bmRequestType & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) {
|
||||||
uint16_t block_cnt = (((uint16_t)usbp->setup[4]) << 8) | usbp->setup[3];
|
switch (setup->bRequest) {
|
||||||
switch (usbp->setup[1]) {
|
case DFU_GETSTATUS: {
|
||||||
case DFU_GETSTATUS:
|
dfu_status_req(usbp);
|
||||||
if (currentState == STATE_DFU_DNLOAD_SYNC) {
|
return true;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -218,8 +298,8 @@ static bool request_handler(USBDriver *usbp) {
|
||||||
* USB driver configuration.
|
* USB driver configuration.
|
||||||
*/
|
*/
|
||||||
const USBConfig usbcfg = {
|
const USBConfig usbcfg = {
|
||||||
usb_event,
|
NULL,
|
||||||
get_descriptor,
|
get_descriptor,
|
||||||
request_handler,
|
request_handler,
|
||||||
sof_handler
|
NULL
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,23 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
extern const USBConfig usbcfg;
|
extern const USBConfig usbcfg;
|
||||||
|
|
||||||
|
|
||||||
#define MAX_FLASH_ADDR 0x10000
|
#define MAX_FLASH_ADDR 0x10000
|
||||||
#define FLASH_BASE 0x0
|
#define FLASH_BASE 0x0
|
||||||
#define BL_SIZE 0x3000
|
#define BL_SIZE 0x2000
|
||||||
#define APP_BASE (FLASH_BASE + BL_SIZE)
|
#define APP_BASE (FLASH_BASE + BL_SIZE)
|
||||||
#define FLASH_PAGE_SIZE 4096
|
#define FLASH_PAGE_SIZE 4096
|
||||||
|
|
||||||
#define FW_BUFFER_SIZE 1024
|
#define FW_BUFFER_SIZE 256
|
||||||
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;
|
|
||||||
|
|
||||||
enum dfu_req {
|
enum dfu_req {
|
||||||
DFU_DETACH,
|
DFU_DETACH,
|
||||||
|
@ -63,3 +58,10 @@ enum dfu_status {
|
||||||
DFU_STATUS_ERR_STALLEDPKT,
|
DFU_STATUS_ERR_STALLEDPKT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct usb_setup {
|
||||||
|
uint8_t bmRequestType;
|
||||||
|
uint8_t bRequest;
|
||||||
|
uint16_t wValue;
|
||||||
|
uint16_t wIndex;
|
||||||
|
uint16_t wLength;
|
||||||
|
} __attribute__((packed));
|
|
@ -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. */
|
/* 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) |
|
USB_EPLIST->entry[ep * 4 + 2] |= EPLIST_ENTRY_NBYTES(n) |
|
||||||
EPLIST_ADDR(usbp->epn_buffer[ep * 2 + 1]);
|
EPLIST_ADDR(usbp->epn_buffer[ep * 2 + 1]);
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
|
@ -145,21 +145,28 @@ static size_t usb_packet_receive(USBDriver *usbp, usbep_t ep) {
|
||||||
const USBEndpointConfig *epcp = usbp->epc[ep];
|
const USBEndpointConfig *epcp = usbp->epc[ep];
|
||||||
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
|
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
|
||||||
uint32_t n = (USB_EPLIST->entry[4 * ep] & EPLIST_ENTRY_NBYTES_MASK) >> EPLIST_ENTRY_NBYTES_POS;
|
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) {
|
if (osp->rxbuf != NULL && n > 0) {
|
||||||
memcpy(osp->rxbuf, usbp->epn_buffer[ep * 2], n);
|
memcpy(osp->rxbuf, usbp->epn_buffer[ep * 2], n);
|
||||||
osp->rxbuf += 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)
|
if (osp->rxpkts > 0)
|
||||||
osp->rxpkts -= 1;
|
osp->rxpkts -= 1;
|
||||||
osp->rxcnt += n;
|
osp->rxcnt += n;
|
||||||
osp->rxsize -= 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;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,10 +181,9 @@ OSAL_IRQ_HANDLER(LPC_USB_IRQ_VECTOR) {
|
||||||
OSAL_IRQ_PROLOGUE();
|
OSAL_IRQ_PROLOGUE();
|
||||||
USBDriver *usbp = &USBD1;
|
USBDriver *usbp = &USBD1;
|
||||||
|
|
||||||
uint32_t isr = LPC_USB->INTSTAT;
|
uint32_t isr = (LPC_USB->INTSTAT & LPC_USB->INTEN);
|
||||||
#define devstat (LPC_USB->DEVCMDSTAT)
|
|
||||||
LPC_USB->INTSTAT &= 0xFFFFFFFF; // Clear Flags
|
LPC_USB->INTSTAT &= 0xFFFFFFFF; // Clear Flags
|
||||||
|
#define devstat (LPC_USB->DEVCMDSTAT)
|
||||||
|
|
||||||
// SOF
|
// SOF
|
||||||
if (isr & USB_INT_FRAME_INT) {
|
if (isr & USB_INT_FRAME_INT) {
|
||||||
|
@ -212,13 +218,13 @@ OSAL_IRQ_HANDLER(LPC_USB_IRQ_VECTOR) {
|
||||||
} else {
|
} else {
|
||||||
// OUT endpoint, receive
|
// OUT endpoint, receive
|
||||||
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
|
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
|
||||||
osalSysLockFromISR();
|
if (osp->rxsize > 0) {
|
||||||
size_t n = usb_packet_receive(usbp, ep);
|
osalSysLockFromISR();
|
||||||
osalSysUnlockFromISR();
|
usb_packet_receive(usbp, ep);
|
||||||
if ((n < usbp->epc[0]->out_maxsize) || (osp->rxpkts == 0)) {
|
osalSysUnlockFromISR();
|
||||||
|
}
|
||||||
|
if (osp->rxsize == 0) { // TODO: Check if this is correct
|
||||||
_usb_isr_invoke_out_cb(usbp, ep);
|
_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;
|
LPC_USB->DATABUFSTART = LPC_USB_SRAM_START & USB_DATABUFSTART_MASK;
|
||||||
|
|
||||||
// Clear Existing Interrupts
|
// 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
|
// 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.
|
// SOF only if there is a handler registered.
|
||||||
if ((usbp)->config->sof_cb != NULL) {
|
if ((usbp)->config->sof_cb != NULL) {
|
||||||
LPC_USB->INTEN |= USB_INT_FRAME_INT;
|
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:
|
case USB_EP_MODE_TYPE_INTR:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
while(1) {}
|
break;
|
||||||
}
|
}
|
||||||
if (epcp->out_state != NULL) {
|
if (epcp->out_state != NULL || ep == 0) {
|
||||||
while(epcp->out_maxsize > 1023);
|
|
||||||
uint32_t ep_mem = usb_ep_malloc(usbp, epcp->out_maxsize, 64);
|
uint32_t ep_mem = usb_ep_malloc(usbp, epcp->out_maxsize, 64);
|
||||||
usbp->epn_buffer[(2 * ep)] = (void *)ep_mem;
|
usbp->epn_buffer[(2 * ep)] = (void *)ep_mem;
|
||||||
|
|
||||||
USB_EPLIST->entry[(4 * ep)] = usbep_cfg | EPLIST_ADDR(ep_mem)
|
USB_EPLIST->entry[(4 * ep)] = usbep_cfg | EPLIST_ADDR(ep_mem)
|
||||||
| EPLIST_ENTRY_NBYTES(epcp->out_maxsize);
|
| EPLIST_ENTRY_NBYTES(epcp->out_maxsize);
|
||||||
|
|
||||||
|
LPC_USB->INTEN |= USB_INT_EP((ep * 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ep == 0) {
|
if (ep == 0) {
|
||||||
while(usbp->setup_buffer != NULL){}
|
|
||||||
// Allocate Setup Bytes
|
// Allocate Setup Bytes
|
||||||
uint32_t ep_mem = usb_ep_malloc(usbp, 8, 64);
|
uint32_t ep_mem = usb_ep_malloc(usbp, 8, 64);
|
||||||
usbp->setup_buffer = (void *)ep_mem;
|
usbp->setup_buffer = (void *)ep_mem;
|
||||||
USB_EPLIST->entry[1] = EPLIST_ADDR(ep_mem);
|
USB_EPLIST->entry[1] = EPLIST_ADDR(ep_mem);
|
||||||
LPC_USB->INTEN |= USB_INT_EP(ep * 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (epcp->in_state != NULL) {
|
if (epcp->in_state != NULL || ep == 0) {
|
||||||
while(epcp->in_maxsize > 1023);
|
|
||||||
uint32_t ep_mem = usb_ep_malloc(usbp, epcp->in_maxsize, 64);
|
uint32_t ep_mem = usb_ep_malloc(usbp, epcp->in_maxsize, 64);
|
||||||
usbp->epn_buffer[(2 * ep) + 1] = (void *)ep_mem;
|
usbp->epn_buffer[(2 * ep) + 1] = (void *)ep_mem;
|
||||||
USB_EPLIST->entry[(4 * ep) + 2] = usbep_cfg | EPLIST_ADDR(ep_mem)
|
USB_EPLIST->entry[(4 * ep) + 2] = usbep_cfg | EPLIST_ADDR(ep_mem)
|
||||||
| EPLIST_ENTRY_NBYTES(epcp->in_maxsize);
|
| 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) {}
|
while (LPC_USB->EPSKIP) {}
|
||||||
for (int i = 1; i < 5; ++i) // 4 EPs needs to be disabled, EP0 can't
|
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 * 4] &= ~EP_STATUS_ACTIVE;
|
||||||
USB_EPLIST->entry[i * 2] |= EP_STATUS_DISABLED;
|
USB_EPLIST->entry[i * 4] |= EP_STATUS_DISABLED;
|
||||||
USB_EPLIST->entry[i * 2 + 2] &= ~EP_STATUS_ACTIVE;
|
USB_EPLIST->entry[i * 4 + 2] &= ~EP_STATUS_ACTIVE;
|
||||||
USB_EPLIST->entry[i * 2 + 2] |= EP_STATUS_DISABLED;
|
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) {
|
usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) {
|
||||||
if (usbp != &USBD1)
|
if (usbp != &USBD1)
|
||||||
return EP_STATUS_DISABLED;
|
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;
|
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;
|
return EP_STATUS_STALLED;
|
||||||
} else {
|
} else {
|
||||||
return EP_STATUS_ACTIVE;
|
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) {
|
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) {
|
||||||
if (usbp != &USBD1)
|
if (usbp != &USBD1)
|
||||||
return EP_STATUS_DISABLED;
|
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;
|
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;
|
return EP_STATUS_STALLED;
|
||||||
} else {
|
} else {
|
||||||
return EP_STATUS_ACTIVE;
|
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[0] &= ~(EPLIST_ENTRY_STALL | EPLIST_ENTRY_ACTIVE); // EP0OUT
|
||||||
USB_EPLIST->entry[2] &= ~(EPLIST_ENTRY_STALL | EPLIST_ENTRY_ACTIVE); // EP0IN
|
USB_EPLIST->entry[2] &= ~(EPLIST_ENTRY_STALL | EPLIST_ENTRY_ACTIVE); // EP0IN
|
||||||
LPC_USB->DEVCMDSTAT |= USB_DEVCMDSTAT_SETUP; // Clear SETUP
|
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);
|
memcpy(buf, usbp->setup_buffer, 8);
|
||||||
USB_EPLIST->entry[1] = EPLIST_ADDR(usbp->setup_buffer);
|
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;
|
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
|
||||||
const USBEndpointConfig *epcp = usbp->epc[ep];
|
const USBEndpointConfig *epcp = usbp->epc[ep];
|
||||||
|
|
||||||
if (osp->rxsize == 0) /* Special case for zero sized packets.*/
|
size_t rx_size = 0;
|
||||||
osp->rxpkts = 1;
|
|
||||||
else
|
|
||||||
osp->rxpkts = (uint16_t)((osp->rxsize + usbp->epc[ep]->out_maxsize - 1) /
|
|
||||||
usbp->epc[ep]->out_maxsize);
|
|
||||||
|
|
||||||
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 |
|
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]);
|
EPLIST_ADDR(usbp->epn_buffer[ep * 2]);
|
||||||
|
|
||||||
LPC_USB->DEVCMDSTAT |= USB_DEVCMDSTAT_INTONNAK_CO;
|
if (ep == 0)
|
||||||
LPC_USB->DEVCMDSTAT &= ~USB_DEVCMDSTAT_INTONNAK_CI;
|
LPC_USB->DEVCMDSTAT |= USB_DEVCMDSTAT_INTONNAK_CO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue