STM32FSDEV: Rewrite transfer ISR

This commit is contained in:
Nathan Conrad 2020-03-22 14:19:31 -04:00
parent 00eabbac35
commit eaf767b0db
3 changed files with 121 additions and 150 deletions

View File

@ -185,10 +185,7 @@ void HardFault_Handler (void)
*/ */
void assert_failed(char *file, uint32_t line) void assert_failed(char *file, uint32_t line)
{ {
/* USER CODE BEGIN 6 */ TU_LOG1("Assertion failed (%s:%ld)\r\n", file, line);
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
} }
#endif /* USE_FULL_ASSERT */ #endif /* USE_FULL_ASSERT */

View File

@ -184,7 +184,7 @@ static void dcd_handle_bus_reset(void);
static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes); static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes);
static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes); static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes);
static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix); static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix);
static uint16_t dcd_ep_ctr_handler(void); static void dcd_ep_ctr_handler(void);
// Using a function due to better type checks // Using a function due to better type checks
@ -363,66 +363,59 @@ static void dcd_handle_bus_reset(void)
USB->DADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero. USB->DADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero.
} }
// FIXME: Defined to return uint16 so that ASSERT can be used, even though a return value is not needed. // Handle CTR interrupt for the TX/IN direction
static uint16_t dcd_ep_ctr_handler(void) //
// Upon call, (wIstr & USB_ISTR_DIR) == 0U
static void dcd_ep_ctr_tx_handler(uint32_t wIstr)
{ {
uint32_t count=0U; uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
uint8_t EPindex; uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
__IO uint16_t wIstr;
__IO uint16_t wEPVal = 0U;
// stack variables to pass to USBD // Verify the CTR_TX bit is set. This was in the ST Micro code,
// but I'm not sure it's actually necessary?
/* stay in loop while pending interrupts */ if((wEPRegVal & USB_EP_CTR_TX) == 0U)
while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U)
{ {
/* extract highest priority endpoint index */ return;
EPindex = (uint8_t)(wIstr & USB_ISTR_EP_ID); }
if (EPindex == 0U) /* clear int flag */
{ pcd_clear_tx_ep_ctr(USB, EPindex);
/* Decode and service control endpoint interrupt */
/* DIR bit = origin of the interrupt */
if ((wIstr & USB_ISTR_DIR) == 0U)
{
/* DIR = 0 => IN int */
/* DIR = 0 implies that (EP_CTR_TX = 1) always */
pcd_clear_tx_ep_ctr(USB, 0);
xfer_ctl_t * xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_IN); xfer_ctl_t * xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_IN);
if((xfer->total_len != xfer->queued_len)) /* TX not complete */
{
dcd_transmit_packet(xfer, EPindex);
}
else /* TX Complete */
{
dcd_event_xfer_complete(0, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true);
}
}
if((xfer->total_len == xfer->queued_len)) // Handle CTR interrupt for the RX/OUT direction
{ //
dcd_event_xfer_complete(0u, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true); // Upon call, (wIstr & USB_ISTR_DIR) == 0U
static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
if(xfer->total_len == 0) // Probably a status message? {
{ uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
pcd_clear_rx_dtog(USB,EPindex); uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
} uint32_t count = pcd_get_ep_rx_cnt(USB,EPindex);
}
else
{
dcd_transmit_packet(xfer,EPindex);
}
}
else
{
/* DIR = 1 & CTR_RX => SETUP or OUT int */
/* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */
xfer_ctl_t *xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_OUT); xfer_ctl_t *xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_OUT);
//ep = &hpcd->OUT_ep[0]; // Verify the CTR_RX bit is set. This was in the ST Micro code,
wEPVal = pcd_get_endpoint(USB, EPindex); // but I'm not sure it's actually necessary?
if((wEPRegVal & USB_EP_CTR_RX) == 0U)
{
return;
}
if ((wEPVal & USB_EP_SETUP) != 0U) // SETUP if((EPindex == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) /* Setup packet */
{ {
// The setup_received function uses memcpy, so this must first copy the setup data into // 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. // user memory, to allow for the 32-bit access that memcpy performs.
uint8_t userMemBuf[8]; uint8_t userMemBuf[8];
/* Get SETUP Packet*/ /* Get SETUP Packet*/
count = pcd_get_ep_rx_cnt(USB, EPindex);
if(count == 8) // Setup packet should always be 8 bytes. If not, ignore it, and try again. if(count == 8) // Setup packet should always be 8 bytes. If not, ignore it, and try again.
{ {
// Must reset EP to NAK (in case it had been stalling) (though, maybe too late here) // Must reset EP to NAK (in case it had been stalling) (though, maybe too late here)
@ -431,56 +424,21 @@ static uint16_t dcd_ep_ctr_handler(void)
dcd_read_packet_memory(userMemBuf, *pcd_ep_rx_address_ptr(USB,EPindex), 8); dcd_read_packet_memory(userMemBuf, *pcd_ep_rx_address_ptr(USB,EPindex), 8);
dcd_event_setup_received(0, (uint8_t*)userMemBuf, true); dcd_event_setup_received(0, (uint8_t*)userMemBuf, true);
} }
/* SETUP bit kept frozen while CTR_RX = 1*/ }
else
{
// Clear RX CTR interrupt flag
if(EPindex != 0u)
{
pcd_clear_rx_ep_ctr(USB, EPindex); pcd_clear_rx_ep_ctr(USB, EPindex);
} }
else if ((wEPVal & USB_EP_CTR_RX) != 0U) // OUT
{
pcd_clear_rx_ep_ctr(USB, EPindex);
/* Get Control Data OUT Packet */
count = pcd_get_ep_rx_cnt(USB,EPindex);
if (count != 0U)
{
dcd_read_packet_memory(xfer->buffer, *pcd_ep_rx_address_ptr(USB,EPindex), count);
xfer->queued_len = (uint16_t)(xfer->queued_len + count);
}
/* Process Control Data OUT status Packet*/
dcd_event_xfer_complete(0, EPindex, xfer->total_len, XFER_RESULT_SUCCESS, true);
pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE);
if(EPindex == 0u && xfer->total_len == 0u)
{
pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID);// Await next SETUP
}
}
}
}
else /* Decode and service non control endpoints interrupt */
{
/* process related endpoint register */
wEPVal = pcd_get_endpoint(USB, EPindex);
if ((wEPVal & USB_EP_CTR_RX) != 0U) // OUT
{
/* clear int flag */
pcd_clear_rx_ep_ctr(USB, EPindex);
xfer_ctl_t * xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_OUT);
//ep = &hpcd->OUT_ep[EPindex];
count = pcd_get_ep_rx_cnt(USB, EPindex);
if (count != 0U) if (count != 0U)
{ {
dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]),
*pcd_ep_rx_address_ptr(USB,EPindex), count); *pcd_ep_rx_address_ptr(USB,EPindex), count);
}
/*multi-packet on the NON control OUT endpoint */
xfer->queued_len = (uint16_t)(xfer->queued_len + count); xfer->queued_len = (uint16_t)(xfer->queued_len + count);
}
if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len))
{ {
@ -497,29 +455,38 @@ static uint16_t dcd_ep_ctr_handler(void)
} else { } else {
pcd_set_ep_rx_cnt(USB, EPindex,remaining); pcd_set_ep_rx_cnt(USB, EPindex,remaining);
} }
pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID);
} }
}
} /* if((wEPVal & EP_CTR_RX) */ // For EP0, prepare to receive another SETUP packet.
// Clear CTR last so that a new packet does not overwrite the packing being read.
if ((wEPVal & USB_EP_CTR_TX) != 0U) // IN // (Based on the docs, it seems SETUP will always be accepted after CTR is cleared)
if(EPindex == 0u)
{ {
/* clear int flag */ // Always be prepared for a status packet...
pcd_clear_tx_ep_ctr(USB, EPindex); pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE);
pcd_clear_rx_ep_ctr(USB, EPindex);
}
}
xfer_ctl_t * xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_IN); static void dcd_ep_ctr_handler(void)
{
uint32_t wIstr;
if (xfer->queued_len != xfer->total_len) // data remaining in transfer? /* stay in loop while pending interrupts */
while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U)
{ {
dcd_transmit_packet(xfer, EPindex);
} else { if ((wIstr & USB_ISTR_DIR) == 0U) /* TX/IN */
dcd_event_xfer_complete(0, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true); {
dcd_ep_ctr_tx_handler(wIstr);
}
else /* RX/OUT*/
{
dcd_ep_ctr_rx_handler(wIstr);
} }
} }
}
}
return 0;
} }
static void dcd_fs_irqHandler(void) { static void dcd_fs_irqHandler(void) {

View File

@ -310,6 +310,13 @@ static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum, ui
pcd_set_endpoint(USBx, bEpNum, regVal); pcd_set_endpoint(USBx, bEpNum, regVal);
} /* pcd_set_ep_rx_status */ } /* pcd_set_ep_rx_status */
static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum)
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
return (regVal & USB_EPRX_STAT) >> (12u);
} /* pcd_get_ep_rx_status */
/** /**
* @brief Toggles DTOG_RX / DTOG_TX bit in the endpoint register. * @brief Toggles DTOG_RX / DTOG_TX bit in the endpoint register.
* @param USBx USB peripheral instance register address. * @param USBx USB peripheral instance register address.