- auto ZLP reconsidered and removed, ZLP is always appended to transfers featuring a size divisible by max packet size

- EEM tweaked
This commit is contained in:
Wiesner András 2024-05-01 18:33:22 +02:00
parent 6406222be3
commit f6e3d48476
6 changed files with 28 additions and 200 deletions

View File

@ -14,16 +14,14 @@
static USB_EemState eems = {0};
static uint8_t netbBuf[USB_EEM_FIFO_SIZE]; // Network bound FIFO memory
// static uint8_t netbBuf[USB_EEM_FIFO_SIZE]; // Network bound FIFO memory
static uint8_t hostbBuf[USB_EEM_FIFO_SIZE]; // Host bound FIFO memory
#define EEM_EVENT_QUEUE_LENGTH (16)
#define EEM_FRAME_QUEUE_LENGTH (24)
#define EEM_FRAME_QUEUE_LENGTH (8)
#define EEM_PCKT_SIZE (64)
#define EEM_TRANSFER_UNIT (128)
static uint8_t transferBuffer[EEM_TRANSFER_UNIT]; // transfer buffer
void usb_eem_thread(void *);
void usb_eem_init(uint8_t data_ep) {
@ -37,7 +35,7 @@ void usb_eem_init(uint8_t data_ep) {
eems.eventQueue = osMessageQueueNew(EEM_EVENT_QUEUE_LENGTH, sizeof(uint8_t), NULL);
// create network bound and host bound FIFOs
bfifo_create(&(eems.hostbFifo), netbBuf, USB_EEM_FIFO_SIZE);
// bfifo_create(&(eems.hostbFifo), netbBuf, USB_EEM_FIFO_SIZE);
bfifo_create(&(eems.netbFifo), hostbBuf, USB_EEM_FIFO_SIZE);
// create queue for hostbound frames
@ -47,6 +45,9 @@ void usb_eem_init(uint8_t data_ep) {
eems.hostbState = EEM_IDLE;
eems.netbState = EEM_IDLE;
// turn network bound autoarm on
eems.netbAutoArm = true;
// no EchoResponse is queued
eems.echoRespQueued = false;
@ -81,6 +82,11 @@ int usb_eem_process_and_return(USB_CallbackEvent *cbevt) {
if ((cbevt->ep == eems.data_ep)) { // verify endpoint
bfifo_push(&(eems.netbFifo), cbevt->data, cbevt->size); // store portion of netbound packet
usb_eem_push_event(EEM_EVT_NETBOUND_PCKT_RECEIVED); // push notification
if (bfifo_get_free(&eems.netbFifo) < EEM_PCKT_SIZE) { // don't autoarm if OUT no more packets can be stored
eems.netbAutoArm = false;
cbevt->arm_out_endpoint = false;
}
}
break;
@ -101,7 +107,7 @@ int usb_eem_process_and_return(USB_CallbackEvent *cbevt) {
// MSG("---\n");
// }
} else { // no data is waiting for transmission
usbcore_schedule_transmission(eems.data_ep, NULL, 0); // send ZLP
//usbcore_schedule_transmission(eems.data_ep, NULL, 0); // send ZLP
}
// if FIFO is empty or flushed, then send notification
@ -208,6 +214,12 @@ void usb_eem_process_networkbound() {
// pop data from the packet
bfifo_pop(bf, eems.netbFrameSize, 0);
// if free size is greater then the size of a single USB packet, then arm the endpoint
if ((eems.netbAutoArm == false) && (bfifo_get_free(bf) > EEM_PCKT_SIZE)) {
eems.netbAutoArm = true;
usbcore_schedule_reception(eems.data_ep, EEM_PCKT_SIZE);
}
// MSG("PKT OK! %u\n", eems.netbFrameSize);
eems.netbState = EEM_IDLE;
@ -217,11 +229,6 @@ void usb_eem_process_networkbound() {
}
void usb_eem_process_hostbound() {
// see if there are some packets waiting for transmission
if (osMessageQueueGetCount(eems.hostbFrameQ) == 0) {
return; // no packets
}
/*// check that forward buffer is indeed empty
BFifo * bf = &eems.hostbFifo;
if (bfifo_get_used(bf) > 0) {
@ -240,6 +247,11 @@ void usb_eem_process_hostbound() {
// release frame
dynmem_free(oldEemFrame);
// see if there are some packets waiting for transmission
if (osMessageQueueGetCount(eems.hostbFrameQ) == 0) {
return; // no packets
}
// at this point, we can safely pop from the frame queue, popping will not block,
// and the forward queue is certainly empty

View File

@ -9,7 +9,7 @@
#include <etherlib/etherlib.h>
#define USB_EEM_FIFO_SIZE (2048)
#define USB_EEM_FIFO_SIZE (8192)
typedef enum {
EEM_ECHO = 0, // Echo
@ -44,11 +44,12 @@ typedef struct {
EthInterface * intf; // interface for packet interception and injection
uint8_t data_ep; // bulk data in and out endpoint pair
osMessageQueueId_t eventQueue; // event queue
BFifo hostbFifo; // Hostbound FIFO
// BFifo hostbFifo; // Hostbound FIFO
BFifo netbFifo; // Network bound FIFO
USB_EemFsmState netbState; // state of host bound operations
uint16_t netbFrameSize; // size of network bound packet
uint16_t netbSizeLeft; // number of bytes expected from the host sending into current network bound packet
bool netbAutoArm; // signal, that the netbound endpoint should be autoarmed or not
USB_EemFsmState hostbState; // state of network bound operations
osMessageQueueId_t hostbFrameQ; // queue for hostbound message pointers
USB_EemFrame * hostbFrame; // hostbound frame

3
usb.c
View File

@ -215,7 +215,6 @@ void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) {
cbevt.subtype = USB_CBEVST_IN_REQ;
}
cbevt.dir = USB_IN;
cbevt.enable_autozlp = true; // by default, enable auto ZLP
break;
}
@ -233,8 +232,6 @@ void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) {
if (cbevt.arm_out_endpoint) {
usbdrv_autoarm_OUT_endpoint(cbcpd->ep);
}
} else if (cbevt.dir == USB_IN) {
usbdrv_enable_autozlp(cbcpd->ep, cbevt.enable_autozlp); // handle auto ZLP setting
}
}
}

View File

@ -29,7 +29,6 @@ typedef struct {
const uint8_t * reply_data; // reply data
uint8_t reply_size; // reply size
bool arm_out_endpoint; // automatically arm OUT endpoint at the end of the current transmission
bool enable_autozlp; // enable automatic ZLP transmission based on transfer size
} USB_CallbackEvent;
#endif /* CORE_USB_USB_CALLBACK_EVENT */

View File

@ -284,7 +284,6 @@ void usbdrv_build_fifo() {
if (cfg->is_configured) {
cfg->fifo_size = CEIL4(MAX(USB_MIN_GROSS_TX_FIFO_SIZE, 2 * cfg->max_packet_size)); // correct FIFO size if necessary
cfg->fifo_address = next_fifo_addr; // store FIFO address
cfg->auto_zlp = true; // turn on automatic ZLP appending
cfg->zlp_next = false;
// cfg->txp = false; // no transfer is in progress
next_fifo_addr += cfg->fifo_size; // advance next address
@ -488,14 +487,8 @@ void usbdrv_fetch_received_data(uint8_t ep, uint16_t len) {
// write data to specific endpoint FIFO
uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) {
/*WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_XFRSIZ, len);
WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_PKTCNT, 1);*/
// determine if a transmission is in progress or not
bool txp = READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA);
/*if (txp) {
return 0;
}*/
uint16_t mps = gs.ep_IN[ep].max_packet_size; // fetch maximum packet size
@ -600,10 +593,6 @@ void usbdrv_autoarm_OUT_endpoint(uint8_t ep) {
gs.ep_OUT[ep].autoarm = true;
}
void usbdrv_enable_autozlp(uint8_t ep, bool en) {
gs.ep_IN[ep].auto_zlp = en;
}
// ----------------
void usbdrv_set_address(uint8_t addr) {
@ -774,7 +763,7 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
// gs.ep_IN[ep].txp = false;
// see if a ZLP transmission was queued
if (/*gs.ep_IN[ep].auto_zlp && */ gs.ep_IN[ep].zlp_next) {
if (gs.ep_IN[ep].zlp_next) {
usbdrv_arm_IN_endpoint(ep, NULL, 0); // send ZLP
} else { // no ZLP
USBMSG("IN [%d]\n", ep);
@ -889,170 +878,3 @@ void OTG_FS_IRQHandler() {
return;
}
// ---------------
// uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) {
// /*WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_XFRSIZ, len);
// WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_PKTCNT, 1);*/
// // determine if a transmission is in progress or not
// if (gs.ep_IN[ep].txp) {
// return 0;
// }
// // determine if a transmission is in progress or not
// // bool txp = READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA); // transmission in progress
// // transmission may only be commenced if last transmission has concluded
// /*if (READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA)) {
// return 0;
// }*/
// uint16_t mps = gs.ep_IN[ep].max_packet_size; // fetch maximum packet size
// // determine final write size
// uint32_t freeSize = 0;
// // if (len > 0) { // only poll DTXFSTS if (len > 0) (see datasheet)
// freeSize = USBINEP[ep].DTXFSTS * sizeof(uint32_t); // get free transmit buffer size
// //}
// // if (gs.ep_IN[ep].txp && (freeSize == 0)) {
// // return 0;
// // }
// uint16_t writeSize = MIN(freeSize, len); // limit transmit size to free size
// // if transmission is in progress, then remaining transmission bytes also limits transmission size
// if (gs.ep_IN[ep].txp) {
// uint16_t bytesLeft = USBINEP[ep].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ;
// writeSize = MIN(writeSize, bytesLeft);
// // if this was the last write, then disable Tx empty interrupt
// if (bytesLeft <= mps) {
// USBD->DIEPEMPMSK &= ~((uint32_t)(1 << ep));
// } else { // if not, turn it back on
// USBD->DIEPEMPMSK |= ((uint32_t)(1 << ep));
// }
// } else { // if no transmission was in progress, then setup endpoint for transmission
// // calculate packet count based on max packet size
// uint16_t packet_count = 1; // for ZLPs
// if (writeSize > 0) { // if length is nonzero
// packet_count = len / mps + (((len % mps) > 0) ? 1 : 0); // a transfer may contain multiple packets
// }
// // set zlp_next if transfer size is integer multiple of max packet size and auto ZLP is on
// gs.ep_IN[ep].zlp_next = gs.ep_IN[ep].auto_zlp && (len > 0) && ((len % mps) == 0);
// // program DIEPTSIZ with transfer length
// USBINEP[ep].DIEPTSIZ = /*(packet_count << USB_OTG_DIEPTSIZ_MULCNT_Pos) |*/ (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | len;
// // enable endpoint and cancel responding NAK
// SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK);
// // enable FIFO empty interrupt, only if further write operations will follow
// // DO NOT enable this interrupt source when dealing with EP0!
// if ((ep != 0) && (writeSize < len)) {
// USBD->DIEPEMPMSK |= (1 << ep);
// }
// // set transfer in progress
// gs.ep_IN[ep].txp = true;
// }
// // disable ALL USB interrupts to prevent access to specific registers (see errata)
// CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
// // push full dwords
// volatile uint32_t *p = (uint32_t *)USBFIFO(ep);
// uint32_t floorlen_dwords = writeSize >> 2;
// for (uint16_t i = 0; i < floorlen_dwords; i++) {
// uint16_t i0 = 4 * i;
// uint32_t dword = data[i0] | (data[i0 + 1] << 8) | (data[i0 + 2] << 16) | (data[i0 + 3] << 24);
// p[i] = dword;
// }
// // push the remaining partial dword
// uint8_t rem_bytes = writeSize & 0b11;
// if (rem_bytes > 0) {
// uint32_t rem_dword = 0;
// uint16_t rem_start = writeSize - rem_bytes;
// for (int16_t i = writeSize - 1; i >= rem_start; i--) {
// rem_dword = (rem_dword << 8) | data[i];
// }
// *p = rem_dword;
// }
// // unmask USB interrupts
// SET_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
// // return with written size
// return writeSize;
// }
// EZ MŰKÖDIK, DE CSAK RÖVID TRANSFEREKRE
// uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) {
// /*WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_XFRSIZ, len);
// WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_PKTCNT, 1);*/
// // determine if a transmission is in progress or not
// bool txp = READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA);
// if (txp) {
// return 0;
// }
// uint16_t mps = gs.ep_IN[ep].max_packet_size; // fetch maximum packet size
// // determine final write size
// uint32_t freeSize = USBINEP[ep].DTXFSTS * sizeof(uint32_t); // get free transmit buffer size
// uint16_t writeSize = MIN(freeSize, len); // limit transmit size to free size
// // calculate packet count based on max packet size
// uint16_t packet_count = 1; // for ZLPs
// if (writeSize > 0) { // if length is nonzero
// packet_count = writeSize / mps + (((writeSize % mps) > 0) ? 1 : 0); // a transfer may contain multiple packets
// }
// // set zlp_next if transfer size is integer multiple of max packet size and auto ZLP is on
// gs.ep_IN[ep].zlp_next = gs.ep_IN[ep].auto_zlp && (writeSize > 0) && ((writeSize % mps) == 0);
// // program DIEPTSIZ with transfer length
// USBINEP[ep].DIEPTSIZ = /*(packet_count << USB_OTG_DIEPTSIZ_MULCNT_Pos) |*/ (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | writeSize;
// // enable endpoint and cancel responding NAK
// SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK);
// // set transfer in progress
// //gs.ep_IN[ep].txp = true;
// // disable ALL USB interrupts to prevent access to specific registers (see errata)
// CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
// // push full dwords
// volatile uint32_t *p = (uint32_t *)USBFIFO(ep);
// uint32_t floorlen_dwords = writeSize >> 2;
// for (uint16_t i = 0; i < floorlen_dwords; i++) {
// uint16_t i0 = 4 * i;
// uint32_t dword = data[i0] | (data[i0 + 1] << 8) | (data[i0 + 2] << 16) | (data[i0 + 3] << 24);
// p[i] = dword;
// }
// // push the remaining partial dword
// uint8_t rem_bytes = writeSize & 0b11;
// if (rem_bytes > 0) {
// uint32_t rem_dword = 0;
// uint16_t rem_start = writeSize - rem_bytes;
// for (int16_t i = writeSize - 1; i >= rem_start; i--) {
// rem_dword = (rem_dword << 8) | data[i];
// }
// *p = rem_dword;
// }
// // unmask USB interrupts
// SET_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
// // return with written size
// return writeSize;
// }

View File

@ -35,10 +35,8 @@ typedef struct {
uint8_t is_configured; // the endpoint is in use
uint16_t fifo_address; // address in the FIFO
uint16_t fifo_size; // FIFO size
bool8_t auto_zlp; // automatically insert ZLP packets
bool8_t zlp_next; // indicates, that ZLP should be transmitted at the end of the current transfer (for IN endpoints)
bool8_t autoarm; // automatically arm endpoint (for OUT endpoints)
//bool8_t txp; // transfer in progress
} USBDRV_EpConfig;
typedef enum {
@ -155,7 +153,6 @@ uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len);
#define USBDRV_ARM_IN_ZLP(ep) usbdrv_arm_IN_endpoint((ep), NULL, 0)
uint32_t usbdrv_arm_OUT_endpoint(uint8_t ep, uint8_t size); // arm OUT endpoint, returned with the actual armed size (capped by the max packet size on that endpoint)
void usbdrv_autoarm_OUT_endpoint(uint8_t ep); // automatically re-arm OUT endpoint at the and of the current OUT transfer
void usbdrv_enable_autozlp(uint8_t ep, bool en); // enable or disable automatic ZLP appending to the transaction
bool usbdrv_get_endpoint_interrupt_flag(uint8_t ep, uint8_t dir); // get endpoint interrupt flag