- Tx FIFO management fixed

This commit is contained in:
Wiesner András 2024-04-11 10:57:31 +02:00
parent 627e038dbb
commit 0adc9c8664
5 changed files with 20 additions and 180 deletions

View File

@ -62,7 +62,7 @@ typedef struct {
// ----------------
#define USB_CDC_PCKT_BUFSIZE (120)
#define USB_CDC_PCKT_BUFSIZE (128)
// ----------------

View File

@ -178,11 +178,9 @@ void usbdrv_preload_endpoint_config(uint8_t ep, uint8_t dir, const USBDRV_EpConf
if (dir == USB_OUT) {
gs.ep_OUT[ep] = *cfg;
gs.ep_OUT[ep].is_configured = true;
gs.ep_OUT[ep].task_commenced = USB_EPEVT_IDLE;
} else {
gs.ep_IN[ep] = *cfg;
gs.ep_IN[ep].is_configured = true;
gs.ep_IN[ep].task_commenced = USB_EPEVT_IDLE;
}
}
@ -400,7 +398,7 @@ void usbdrv_set_rx_fifo_size(uint16_t size) {
// stall endpoint
void usbdrv_stall_endpoint(uint8_t ep, uint8_t dir, bool stall) {
USB_OTG_INEndpointTypeDef *inep = USBINEP + ep;
USB_OTG_OUTEndpointTypeDef *outep = USBOUTEP + ep;
// USB_OTG_OUTEndpointTypeDef *outep = USBOUTEP + ep;
if (stall) {
if (dir == USB_IN) {
@ -418,10 +416,6 @@ void usbdrv_stall_endpoint(uint8_t ep, uint8_t dir, bool stall) {
// flush trnasmit FIFO
usbdrv_flush_tx_fifo(ep);
// signal that the endpoint is stalled
gs.ep_IN[ep].task_commenced = USB_EPEVT_STALLED;
} else {
if (dir == USB_IN) {
if (ep != 0) { // special treatment for EP0
@ -429,9 +423,6 @@ void usbdrv_stall_endpoint(uint8_t ep, uint8_t dir, bool stall) {
}
CLEAR_BIT(inep->DIEPCTL, USB_OTG_DIEPCTL_STALL); // clear endpoint stall
}
// signal that the endpoint stalling is over
gs.ep_IN[ep].task_commenced = USB_EPEVT_IDLE;
}
}
@ -476,24 +467,24 @@ 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);*/
// endpoint is already armed
// if (gs.ep_IN[ep].task_commenced == USB_EPEVT_ARMED) {
// return;
// }
// gs.ep_IN[ep].task_commenced = USB_EPEVT_ARMED;
// transmission may only be commenced if last transmission has concluded
if (READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA)) {
return 0;
}
// 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
uint16_t writeSize = MIN(freeSize, len); // limit transmit size to free size
// calculate packet count based on max packet size
uint16_t mps = gs.ep_IN[ep].max_packet_size;
uint16_t packet_count = 1; // for ZLPs
if (writeSize > 0) { // if length is nonzero
if (writeSize > 0) { // if length is nonzero
packet_count = writeSize / mps + (((writeSize % mps) > 0) ? 1 : 0);
}
// TODO: ZLP ending
// set zlp_next if transmission size is integer multiple of max packet size
gs.ep_IN[ep].zlp_next = (writeSize > 0) && ((writeSize % mps) == 0);
// program DIEPTSIZ with transfer length (TODO: currently only a single transfer!)
USBINEP[ep].DIEPTSIZ = (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | writeSize;
@ -533,12 +524,8 @@ uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) {
// arm OUT endpoint
void usbdrv_arm_OUT_endpoint(uint8_t ep, uint8_t size) {
// if (gs.ep_OUT[ep].task_commenced == USB_EPEVT_IDLE) { // only effective if endpointis not armed (no double arming!)
// gs.ep_OUT[ep].task_commenced = USB_EPEVT_ARMED; // step in armed state
USBOUTEP[ep].DOEPTSIZ |= USB_OTG_DOEPTSIZ_PKTCNT | size; // program DIEPTSIZ with maximum (expected) transfer length and set PCKTCNT to make ready for reception
SET_BIT(USBOUTEP[ep].DOEPCTL, USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK); // enable endpoint and clear NAK
//}
}
// ----------------
@ -618,11 +605,6 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
case USB_FSM_SETUP_OPERATE: { // expect SETUP transactions first, then everything else as well
switch (evt_code) {
case USB_EVT_RECEPTION_DONE: { // reception done
// for (uint32_t i = 0; i < 100000; i++) {
// __NOP();
// }
USBDRV_EventData evt_data = {0};
usbdrv_process_rx_fifo_top(&evt_data); // process rx fifo top
@ -641,11 +623,6 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
} else if (evt_data.rx.pckt_status == USB_PCKT_STATUS_OUT_TRANSFER_CPLT) {
stage = UST_DATA;
// OUT transaction has fired
if (gs.ep_OUT[0].task_commenced == USB_EPEVT_ARMED) {
gs.ep_OUT[0].task_commenced = USB_EPEVT_IDLE;
}
USBMSG("--DATA\n");
}
@ -681,11 +658,6 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
SET_BIT(USBOUTEP[ep].DOEPINT, USB_OTG_DOEPINT_XFRC);
USBMSG("OUT\n");
// reset commenced task state
if (gs.ep_OUT[ep].task_commenced == USB_EPEVT_ARMED) {
gs.ep_OUT[ep].task_commenced = USB_EPEVT_IDLE;
}
usbdrv_arm_OUT_endpoint(ep, gs.ep_OUT[ep].max_packet_size);
}
}
@ -707,32 +679,25 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TOC)) { // timeout done
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TOC);
USBMSG("TO\n");
gs.ep_IN[ep].task_commenced = USB_EPEVT_IDLE;
}
if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_XFRC)) { // IN transaction done
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_XFRC);
// reset commenced task state
if (gs.ep_IN[ep].task_commenced == USB_EPEVT_ARMED) {
gs.ep_IN[ep].task_commenced = USB_EPEVT_IDLE;
// see if a ZLP transmission was queued
if (gs.ep_IN[ep].zlp_next) {
usbdrv_arm_IN_endpoint(ep, NULL, 0); // send ZLP
} else { // no ZLP
USBMSG("IN [%d]\n", ep);
cbcpd.code = USB_CBC_IN_DONE;
usbcore_process_nonsetup_event(&cbcpd);
}
USBMSG("IN [%d]\n", ep);
cbcpd.code = USB_CBC_IN_DONE;
usbcore_process_nonsetup_event(&cbcpd);
}
if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_ITTXFE)) { // IN endpoint IN token received with Tx FIFO empty interrupt
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_ITTXFE);
// reset stalled state
if (gs.ep_IN[ep].task_commenced == USB_EPEVT_STALLED) {
usbdrv_stall_endpoint(ep, USB_IN, false);
}
// USBMSG("IN FIFOEMPTY [%d]\n", ep);
cbcpd.code = USB_CBC_IN_FIFOEMPTY;

View File

@ -26,9 +26,7 @@ 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
// management variables
uint8_t task_commenced; // task commenced on endpoint
bool8_t zlp_next; // indicates, that ZLP should be transmitted at the end of the current transfer
} USBDRV_EpConfig;
typedef enum {

View File

@ -1,51 +0,0 @@
#include "gen_queue.h"
#include <memory.h>
#include <stdbool.h>
Queue *q_create(uint32_t length, uint32_t elemSize, uint8_t *mem) {
Queue *q = (Queue *)mem;
q->length = length;
q->elemSize = elemSize;
q->readIdx = 0;
q->writeIdx = 0;
memset(q->elements, 0, length * elemSize);
return q;
}
void q_clear(Queue *q) {
q->readIdx = 0;
q->writeIdx = 0;
memset(q->elements, 0, q->length * q->elemSize);
}
uint32_t q_avail(const Queue *q) {
return q->writeIdx - q->readIdx;
}
#define MQ_NEXT(size, current) (((current) + 1) % (size))
bool q_push(Queue *q, const void *src) {
if (MQ_NEXT(q->length, q->writeIdx) == q->readIdx) { // cannot push, queue is full
return false;
}
// can push
memcpy(q->elements + q->writeIdx * q->elemSize, src, q->elemSize);
// advance write pointer
q->writeIdx = MQ_NEXT(q->length, q->writeIdx);
return true;
}
void q_top(Queue *q, void *dest) {
memcpy(dest, q->elements + q->readIdx, q->elemSize);
}
void q_pop(Queue *q) {
if (q_avail(q) > 0) { // if there's something to pop
q->readIdx = MQ_NEXT(q->length, q->readIdx);
}
}

View File

@ -1,72 +0,0 @@
#ifndef CORE_USB_UTILS_GE_QUEUE
#define CORE_USB_UTILS_GE_QUEUE
#include <stdbool.h>
#include <stdint.h>
/**
* Generic Queue.
*/
typedef struct {
uint32_t writeIdx; ///< Next block to write
uint32_t readIdx; ///< Next block to read
uint32_t length; ///< Size of circular buffer
uint32_t elemSize; ///< Element size
uint8_t elements[]; ///< Array of packets
} Queue;
/**
* Create Queue.
* @param length length of circular buffer
* @param elemSize element size
* @param mem backing memory, should be DWORD-aligned!
* @return pointer to Queue instance OR NULL on failure
*/
Queue *q_create(uint32_t length, uint32_t elemSize, uint8_t *mem);
/**
* Create Queue based on storage type.
*/
#define Q_CREATE_T(length, T, mem) q_create((length), sizeof(T), (mem))
/**
* @brief Calculate required memory size for allocating a new queue fitting
* length elements of type T.
*/
#define Q_REQ_MEM_SIZE_T(length, T) (sizeof(Queue) + (length * sizeof(T)))
/**
* Clear circular buffer.
* @param q pointer to Queue
*/
void q_clear(Queue *q);
/**
* Get number of available elements.
* @param q pointer to Queue
* @return number of available elements
*/
uint32_t q_avail(const Queue *q);
/**
* Push element to the Queue.
* @param q pointer to Queue
* @param raw pointer to raw packet
* @return true on success, false on failure (e.g.: queue full)
*/
bool q_push(Queue *q, const void *src);
/**
* Get top element.
* @param q pointer to Queue
* @return top element (COPY, NOT POINTER!)
*/
void q_top(Queue *q, void *dest);
/**
* Pop top element.
* @param q pointer to Queue
*/
void q_pop(Queue *q);
#endif /* CORE_USB_UTILS_GE_QUEUE */