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) {}
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 "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
|
||||
};
|
||||
|
|
|
@ -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));
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue