enhance dcd_ep_ctr_rx_handler()

This commit is contained in:
hathach
2024-07-31 11:35:09 +07:00
parent 0c8d41e25e
commit 126778298e

View File

@@ -178,7 +178,7 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t
static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes); static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes);
static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes); static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes);
TU_ATTR_UNUSED static void edpt0_open(uint8_t rhport); static void edpt0_open(uint8_t rhport);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Inline helper // Inline helper
@@ -285,10 +285,8 @@ static void handle_bus_reset(uint8_t rhport) {
} }
// Handle CTR interrupt for the TX/IN direction // Handle CTR interrupt for the TX/IN direction
// Upon call, (wIstr & USB_ISTR_DIR) == 0U static void dcd_ep_ctr_tx_handler(uint32_t ep_id) {
static void dcd_ep_ctr_tx_handler(uint32_t wIstr) { uint32_t wEPRegVal = pcd_get_endpoint(USB, ep_id);
uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
uint8_t ep_addr = (wEPRegVal & USB_EPADDR_FIELD) | TUSB_DIR_IN_MASK; uint8_t ep_addr = (wEPRegVal & USB_EPADDR_FIELD) | TUSB_DIR_IN_MASK;
// Verify the CTR_TX bit is set. This was in the ST Micro code, // Verify the CTR_TX bit is set. This was in the ST Micro code,
@@ -298,7 +296,7 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr) {
} }
/* clear int flag */ /* clear int flag */
pcd_clear_tx_ep_ctr(USB, EPindex); pcd_clear_tx_ep_ctr(USB, ep_id);
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
@@ -311,20 +309,18 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr) {
} }
xfer->iso_in_sending = false; xfer->iso_in_sending = false;
uint8_t buf_id = (wEPRegVal & USB_EP_DTOG_TX) ? 0 : 1; uint8_t buf_id = (wEPRegVal & USB_EP_DTOG_TX) ? 0 : 1;
btable_set_count(EPindex, buf_id, 0); btable_set_count(ep_id, buf_id, 0);
} }
if ((xfer->total_len != xfer->queued_len)) { if ((xfer->total_len != xfer->queued_len)) {
dcd_transmit_packet(xfer, EPindex); dcd_transmit_packet(xfer, ep_id);
} else { } else {
dcd_event_xfer_complete(0, ep_addr, xfer->total_len, XFER_RESULT_SUCCESS, true); dcd_event_xfer_complete(0, ep_addr, xfer->total_len, XFER_RESULT_SUCCESS, true);
} }
} }
// Handle CTR interrupt for the RX/OUT direction // Handle CTR interrupt for the RX/OUT direction
// Upon call, (wIstr & USB_ISTR_DIR) == 0U static void dcd_ep_ctr_rx_handler(uint32_t ep_id) {
static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
{
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT
/* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf
* From STM32H503 errata 2.15.1: Buffer description table update completes after CTR interrupt triggers * From STM32H503 errata 2.15.1: Buffer description table update completes after CTR interrupt triggers
@@ -346,103 +342,92 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
} }
#endif #endif
uint32_t EPindex = wIstr & USB_ISTR_EP_ID; uint32_t ep_reg = pcd_get_endpoint(USB, ep_id);
uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); uint8_t ep_addr = ep_reg & USB_EPADDR_FIELD;
uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD;
// Verify the CTR_RX bit is set. This was in the ST Micro code, // Verify the CTR_RX bit is set. This was in the ST Micro code,
// but I'm not sure it's actually necessary? // but I'm not sure it's actually necessary?
if ((wEPRegVal & USB_EP_CTR_RX) == 0U) { if ((ep_reg & USB_EP_CTR_RX) == 0U) {
return; return;
} }
if (wEPRegVal & USB_EP_SETUP) { // Clear RX CTR and reserved TX CTR
uint32_t count = btable_get_count(EPindex, BTABLE_BUF_RX); ep_reg = (ep_reg & ~USB_EP_CTR_RX) | USB_EP_CTR_TX;
if (ep_reg & USB_EP_SETUP) {
uint32_t count = btable_get_count(ep_id, BTABLE_BUF_RX);
// Setup packet should always be 8 bytes. If not, ignore it, and try again. // Setup packet should always be 8 bytes. If not, ignore it, and try again.
if (count == 8) { if (count == 8) {
uint16_t rx_addr = btable_get_addr(EPindex, BTABLE_BUF_RX); uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX);
#ifdef FSDEV_BUS_32BIT uint32_t setup_packet[2];
dcd_event_setup_received(0, (uint8_t *)(USB_PMAADDR + rx_addr), true); dcd_read_packet_memory(setup_packet, rx_addr, 8);
#else dcd_event_setup_received(0, (uint8_t*) setup_packet, true);
// The setup_received function uses memcpy, so this must first copy the setup data into
// user memory, to allow for the 32-bit access that memcpy performs.
uint32_t userMemBuf[2];
dcd_read_packet_memory(userMemBuf, rx_addr, 8);
dcd_event_setup_received(0, (uint8_t*) userMemBuf, true);
#endif
// Reset EP to NAK (in case it had been stalling) // Reset EP to NAK (in case it had been stalling)
wEPRegVal = ep_add_tx_status(wEPRegVal, USB_EP_TX_NAK); ep_reg = ep_add_tx_status(ep_reg, USB_EP_TX_NAK);
wEPRegVal = ep_add_rx_status(wEPRegVal, USB_EP_RX_NAK); ep_reg = ep_add_rx_status(ep_reg, USB_EP_RX_NAK);
wEPRegVal = ep_add_tx_dtog(wEPRegVal, 1); ep_reg = ep_add_tx_dtog(ep_reg, 1);
wEPRegVal = ep_add_rx_dtog(wEPRegVal, 1); ep_reg = ep_add_rx_dtog(ep_reg, 1);
pcd_set_endpoint(USB, 0, wEPRegVal | USB_EP_CTR_RX | USB_EP_CTR_TX); } else {
ep_reg &= USB_EPREG_MASK; // reversed all toggle
} }
} else { } else {
// Clear RX CTR interrupt flag ep_reg &= USB_EPRX_STAT | USB_EPREG_MASK; // reversed all toggle except RX Status
if (ep_addr != 0u) {
pcd_clear_rx_ep_ctr(USB, EPindex);
}
bool const is_iso = (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS;
xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
uint8_t buf_id; uint8_t buf_id;
if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { if (is_iso) {
// ISO endpoints are double buffered buf_id = (ep_reg & USB_EP_DTOG_RX) ? 0 : 1; // ISO are double buffered
buf_id = (wEPRegVal & USB_EP_DTOG_RX) ? 0 : 1;
} else { } else {
buf_id = 1; buf_id = BTABLE_BUF_RX;
} }
uint32_t count = btable_get_count(EPindex, buf_id); uint32_t rx_count = btable_get_count(ep_id, buf_id);
uint16_t addr = (uint16_t) btable_get_addr(EPindex, buf_id); uint16_t pma_addr = (uint16_t) btable_get_addr(ep_id, buf_id);
if (count != 0U) { if (rx_count != 0) {
if (xfer->ff) { if (xfer->ff) {
dcd_read_packet_memory_ff(xfer->ff, addr, count); dcd_read_packet_memory_ff(xfer->ff, pma_addr, rx_count);
} else { } else {
dcd_read_packet_memory(xfer->buffer + xfer->queued_len, addr, count); dcd_read_packet_memory(xfer->buffer + xfer->queued_len, pma_addr, rx_count);
} }
xfer->queued_len = (uint16_t)(xfer->queued_len + count); xfer->queued_len = (uint16_t)(xfer->queued_len + rx_count);
} }
if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) { if ((rx_count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) {
// all bytes received or short packet // all bytes received or short packet
dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true); dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true);
} else {
/* Set endpoint active again for receiving more data. if (ep_addr == 0u) {
* Note that isochronous endpoints stay active always */ // prepared for status packet
if ((wEPRegVal & USB_EP_TYPE_MASK) != USB_EP_ISOCHRONOUS) { btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, CFG_TUD_ENDPOINT0_SIZE);
uint16_t remaining = xfer->total_len - xfer->queued_len;
uint16_t cnt = tu_min16(remaining, xfer->max_packet_size);
btable_set_rx_bufsize(EPindex, BTABLE_BUF_RX, cnt);
} }
pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID);
ep_reg = ep_add_rx_status(ep_reg, USB_EP_RX_NAK);
} else {
// Set endpoint active again for receiving more data. Note that isochronous endpoints stay active always
if (!is_iso) {
uint16_t const cnt = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, cnt);
}
ep_reg = ep_add_rx_status(ep_reg, USB_EP_RX_VALID);
} }
} }
// For EP0, prepare to receive another SETUP packet. pcd_set_endpoint(USB, ep_id, ep_reg);
// Clear CTR last so that a new packet does not overwrite the packing being read.
// (Based on the docs, it seems SETUP will always be accepted after CTR is cleared)
if (ep_addr == 0u) {
// Always be prepared for a status packet...
btable_set_rx_bufsize(EPindex, BTABLE_BUF_RX, CFG_TUD_ENDPOINT0_SIZE);
pcd_clear_rx_ep_ctr(USB, EPindex);
}
} }
static void dcd_ep_ctr_handler(void) static void dcd_ep_ctr_handler(void) {
{
uint32_t wIstr; uint32_t wIstr;
/* stay in loop while pending interrupts */ /* stay in loop while pending interrupts */
while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) { while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) {
uint32_t ep_id = wIstr & USB_ISTR_EP_ID;
if ((wIstr & USB_ISTR_DIR) == 0U) { if ((wIstr & USB_ISTR_DIR) == 0U) {
/* TX/IN */ dcd_ep_ctr_tx_handler(ep_id); // TX/IN
dcd_ep_ctr_tx_handler(wIstr);
} else { } else {
/* RX/OUT*/ dcd_ep_ctr_rx_handler(ep_id); // RX/OUT
dcd_ep_ctr_rx_handler(wIstr);
} }
} }
} }
@@ -609,11 +594,14 @@ void edpt0_open(uint8_t rhport) {
btable_set_addr(0, BTABLE_BUF_TX, pma_addr1); btable_set_addr(0, BTABLE_BUF_TX, pma_addr1);
uint32_t ep_reg = FSDEV_REG->ep[0].reg & ~USB_EPREG_MASK; uint32_t ep_reg = FSDEV_REG->ep[0].reg & ~USB_EPREG_MASK;
ep_reg |= USB_EP_CONTROL | USB_EP_CTR_RX | USB_EP_CTR_TX; ep_reg |= USB_EP_CONTROL; // | USB_EP_CTR_RX | USB_EP_CTR_TX;
ep_reg = ep_add_tx_status(ep_reg, USB_EP_TX_NAK); ep_reg = ep_add_tx_status(ep_reg, USB_EP_TX_NAK);
ep_reg = ep_add_rx_status(ep_reg, USB_EP_RX_NAK); ep_reg = ep_add_rx_status(ep_reg, USB_EP_RX_NAK);
// no need to explicitly set DTOG bits since we aren't masked DTOG bit // no need to explicitly set DTOG bits since we aren't masked DTOG bit
// prepare for setup packet
btable_set_rx_bufsize(0, BTABLE_BUF_RX, CFG_TUD_ENDPOINT0_SIZE);
pcd_set_endpoint(USB, 0, ep_reg); pcd_set_endpoint(USB, 0, ep_reg);
} }