- Tx FIFO management fixed
This commit is contained in:
parent
627e038dbb
commit
0adc9c8664
@ -62,7 +62,7 @@ typedef struct {
|
|||||||
|
|
||||||
// ----------------
|
// ----------------
|
||||||
|
|
||||||
#define USB_CDC_PCKT_BUFSIZE (120)
|
#define USB_CDC_PCKT_BUFSIZE (128)
|
||||||
|
|
||||||
// ----------------
|
// ----------------
|
||||||
|
|
||||||
|
71
usb_driver.c
71
usb_driver.c
@ -178,11 +178,9 @@ void usbdrv_preload_endpoint_config(uint8_t ep, uint8_t dir, const USBDRV_EpConf
|
|||||||
if (dir == USB_OUT) {
|
if (dir == USB_OUT) {
|
||||||
gs.ep_OUT[ep] = *cfg;
|
gs.ep_OUT[ep] = *cfg;
|
||||||
gs.ep_OUT[ep].is_configured = true;
|
gs.ep_OUT[ep].is_configured = true;
|
||||||
gs.ep_OUT[ep].task_commenced = USB_EPEVT_IDLE;
|
|
||||||
} else {
|
} else {
|
||||||
gs.ep_IN[ep] = *cfg;
|
gs.ep_IN[ep] = *cfg;
|
||||||
gs.ep_IN[ep].is_configured = true;
|
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
|
// stall endpoint
|
||||||
void usbdrv_stall_endpoint(uint8_t ep, uint8_t dir, bool stall) {
|
void usbdrv_stall_endpoint(uint8_t ep, uint8_t dir, bool stall) {
|
||||||
USB_OTG_INEndpointTypeDef *inep = USBINEP + ep;
|
USB_OTG_INEndpointTypeDef *inep = USBINEP + ep;
|
||||||
USB_OTG_OUTEndpointTypeDef *outep = USBOUTEP + ep;
|
// USB_OTG_OUTEndpointTypeDef *outep = USBOUTEP + ep;
|
||||||
|
|
||||||
if (stall) {
|
if (stall) {
|
||||||
if (dir == USB_IN) {
|
if (dir == USB_IN) {
|
||||||
@ -418,10 +416,6 @@ void usbdrv_stall_endpoint(uint8_t ep, uint8_t dir, bool stall) {
|
|||||||
|
|
||||||
// flush trnasmit FIFO
|
// flush trnasmit FIFO
|
||||||
usbdrv_flush_tx_fifo(ep);
|
usbdrv_flush_tx_fifo(ep);
|
||||||
|
|
||||||
// signal that the endpoint is stalled
|
|
||||||
gs.ep_IN[ep].task_commenced = USB_EPEVT_STALLED;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (dir == USB_IN) {
|
if (dir == USB_IN) {
|
||||||
if (ep != 0) { // special treatment for EP0
|
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
|
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_XFRSIZ, len);
|
||||||
WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_PKTCNT, 1);*/
|
WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_PKTCNT, 1);*/
|
||||||
|
|
||||||
// endpoint is already armed
|
// transmission may only be commenced if last transmission has concluded
|
||||||
// if (gs.ep_IN[ep].task_commenced == USB_EPEVT_ARMED) {
|
if (READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA)) {
|
||||||
// return;
|
return 0;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// gs.ep_IN[ep].task_commenced = USB_EPEVT_ARMED;
|
|
||||||
|
|
||||||
// determine final write size
|
// determine final write size
|
||||||
uint32_t freeSize = USBINEP[ep].DTXFSTS * sizeof(uint32_t); // get free transmit buffer 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
|
// calculate packet count based on max packet size
|
||||||
uint16_t mps = gs.ep_IN[ep].max_packet_size;
|
uint16_t mps = gs.ep_IN[ep].max_packet_size;
|
||||||
uint16_t packet_count = 1; // for ZLPs
|
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);
|
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!)
|
// program DIEPTSIZ with transfer length (TODO: currently only a single transfer!)
|
||||||
USBINEP[ep].DIEPTSIZ = (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | writeSize;
|
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
|
// arm OUT endpoint
|
||||||
void usbdrv_arm_OUT_endpoint(uint8_t ep, uint8_t size) {
|
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
|
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
|
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
|
case USB_FSM_SETUP_OPERATE: { // expect SETUP transactions first, then everything else as well
|
||||||
switch (evt_code) {
|
switch (evt_code) {
|
||||||
case USB_EVT_RECEPTION_DONE: { // reception done
|
case USB_EVT_RECEPTION_DONE: { // reception done
|
||||||
|
|
||||||
// for (uint32_t i = 0; i < 100000; i++) {
|
|
||||||
// __NOP();
|
|
||||||
// }
|
|
||||||
|
|
||||||
USBDRV_EventData evt_data = {0};
|
USBDRV_EventData evt_data = {0};
|
||||||
usbdrv_process_rx_fifo_top(&evt_data); // process rx fifo top
|
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) {
|
} else if (evt_data.rx.pckt_status == USB_PCKT_STATUS_OUT_TRANSFER_CPLT) {
|
||||||
stage = UST_DATA;
|
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");
|
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);
|
SET_BIT(USBOUTEP[ep].DOEPINT, USB_OTG_DOEPINT_XFRC);
|
||||||
USBMSG("OUT\n");
|
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);
|
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
|
if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TOC)) { // timeout done
|
||||||
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TOC);
|
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TOC);
|
||||||
USBMSG("TO\n");
|
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
|
if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_XFRC)) { // IN transaction done
|
||||||
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_XFRC);
|
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_XFRC);
|
||||||
|
|
||||||
// reset commenced task state
|
// see if a ZLP transmission was queued
|
||||||
if (gs.ep_IN[ep].task_commenced == USB_EPEVT_ARMED) {
|
if (gs.ep_IN[ep].zlp_next) {
|
||||||
gs.ep_IN[ep].task_commenced = USB_EPEVT_IDLE;
|
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
|
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);
|
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);
|
// USBMSG("IN FIFOEMPTY [%d]\n", ep);
|
||||||
|
|
||||||
cbcpd.code = USB_CBC_IN_FIFOEMPTY;
|
cbcpd.code = USB_CBC_IN_FIFOEMPTY;
|
||||||
|
@ -26,9 +26,7 @@ typedef struct {
|
|||||||
uint8_t is_configured; // the endpoint is in use
|
uint8_t is_configured; // the endpoint is in use
|
||||||
uint16_t fifo_address; // address in the FIFO
|
uint16_t fifo_address; // address in the FIFO
|
||||||
uint16_t fifo_size; // FIFO size
|
uint16_t fifo_size; // FIFO size
|
||||||
|
bool8_t zlp_next; // indicates, that ZLP should be transmitted at the end of the current transfer
|
||||||
// management variables
|
|
||||||
uint8_t task_commenced; // task commenced on endpoint
|
|
||||||
} USBDRV_EpConfig;
|
} USBDRV_EpConfig;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 */
|
|
Loading…
x
Reference in New Issue
Block a user