stmhal: Make USB CDC driver use SOF instead of TIM3 for outgoing data.

Previous to this patch the USB CDC driver used TIM3 to trigger the
sending of outgoing data over USB serial.  This patch changes the
behaviour so that the USB SOF interrupt is used to trigger the processing
of the sending.  This reduces latency and increases bandwidth of outgoing
data.

Thanks to Martin Fischer, aka @hoihu, for the idea and initial prototype.

See PR #1713.
This commit is contained in:
Damien George 2016-01-09 21:59:15 +00:00
parent 7417ccfb0d
commit d363133917
5 changed files with 11 additions and 16 deletions

View File

@ -480,8 +480,6 @@ void EXTI15_10_IRQHandler(void) {
void PVD_IRQHandler(void) { void PVD_IRQHandler(void) {
IRQ_ENTER(PVD_IRQn); IRQ_ENTER(PVD_IRQn);
#if defined(MICROPY_HW_USE_ALT_IRQ_FOR_CDC) #if defined(MICROPY_HW_USE_ALT_IRQ_FOR_CDC)
extern void USBD_CDC_HAL_TIM_PeriodElapsedCallback(void);
USBD_CDC_HAL_TIM_PeriodElapsedCallback();
#endif #endif
Handle_EXTI_Irq(EXTI_PVD_OUTPUT); Handle_EXTI_Irq(EXTI_PVD_OUTPUT);
IRQ_EXIT(PVD_IRQn); IRQ_EXIT(PVD_IRQn);

View File

@ -252,7 +252,6 @@ TIM_HandleTypeDef *timer_tim6_init(uint freq) {
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
#if !defined(MICROPY_HW_USE_ALT_IRQ_FOR_CDC) #if !defined(MICROPY_HW_USE_ALT_IRQ_FOR_CDC)
if (htim == &TIM3_Handle) { if (htim == &TIM3_Handle) {
USBD_CDC_HAL_TIM_PeriodElapsedCallback();
} else } else
#endif #endif
if (htim == &TIM5_Handle) { if (htim == &TIM5_Handle) {

View File

@ -257,12 +257,10 @@ static int8_t CDC_Itf_Control(uint8_t cmd, uint8_t* pbuf, uint16_t length) {
return USBD_OK; return USBD_OK;
} }
/** // This function is called to process outgoing data. We hook directly into the
* @brief TIM period elapsed callback // SOF (start of frame) callback so that it is called exactly at the time it is
* @param htim: TIM handle // needed (reducing latency), and often enough (increasing bandwidth).
* @retval None void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
*/
void USBD_CDC_HAL_TIM_PeriodElapsedCallback(void) {
if (!dev_is_connected) { if (!dev_is_connected) {
// CDC device is not connected to a host, so we are unable to send any data // CDC device is not connected to a host, so we are unable to send any data
return; return;
@ -276,9 +274,8 @@ void USBD_CDC_HAL_TIM_PeriodElapsedCallback(void) {
if (UserTxBufPtrOut != UserTxBufPtrOutShadow) { if (UserTxBufPtrOut != UserTxBufPtrOutShadow) {
// We have sent data and are waiting for the low-level USB driver to // We have sent data and are waiting for the low-level USB driver to
// finish sending it over the USB in-endpoint. // finish sending it over the USB in-endpoint.
// We have a 15 * 10ms = 150ms timeout // SOF occurs every 1ms, so we have a 150 * 1ms = 150ms timeout
if (UserTxBufPtrWaitCount < 15) { if (UserTxBufPtrWaitCount < 150) {
PCD_HandleTypeDef *hpcd = hUSBDDevice.pData;
USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
if (USBx_INEP(CDC_IN_EP & 0x7f)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) { if (USBx_INEP(CDC_IN_EP & 0x7f)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) {
// USB in-endpoint is still reading the data // USB in-endpoint is still reading the data
@ -457,7 +454,7 @@ void USBD_CDC_TxAlways(const uint8_t *buf, uint32_t len) {
} }
// Some unused code that makes sure the low-level USB buffer is drained. // Some unused code that makes sure the low-level USB buffer is drained.
// Waiting for low-level is handled in USBD_CDC_HAL_TIM_PeriodElapsedCallback. // Waiting for low-level is handled in HAL_PCD_SOFCallback.
/* /*
start = HAL_GetTick(); start = HAL_GetTick();
PCD_HandleTypeDef *hpcd = hUSBDDevice.pData; PCD_HandleTypeDef *hpcd = hUSBDDevice.pData;

View File

@ -31,8 +31,6 @@
extern const USBD_CDC_ItfTypeDef USBD_CDC_fops; extern const USBD_CDC_ItfTypeDef USBD_CDC_fops;
void USBD_CDC_HAL_TIM_PeriodElapsedCallback(void);
int USBD_CDC_IsConnected(void); int USBD_CDC_IsConnected(void);
void USBD_CDC_SetInterrupt(int chr, void *data); void USBD_CDC_SetInterrupt(int chr, void *data);

View File

@ -276,10 +276,13 @@ void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
* @param hpcd: PCD handle * @param hpcd: PCD handle
* @retval None * @retval None
*/ */
/*
This is now handled by the USB CDC interface.
void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
{ {
USBD_LL_SOF(hpcd->pData); USBD_LL_SOF(hpcd->pData);
} }
*/
/** /**
* @brief Reset callback. * @brief Reset callback.
@ -394,7 +397,7 @@ if (pdev->id == USB_PHY_FS_ID)
pcd_fs_handle.Init.dma_enable = 0; pcd_fs_handle.Init.dma_enable = 0;
pcd_fs_handle.Init.low_power_enable = 0; pcd_fs_handle.Init.low_power_enable = 0;
pcd_fs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; pcd_fs_handle.Init.phy_itface = PCD_PHY_EMBEDDED;
pcd_fs_handle.Init.Sof_enable = 0; pcd_fs_handle.Init.Sof_enable = 1;
pcd_fs_handle.Init.speed = PCD_SPEED_FULL; pcd_fs_handle.Init.speed = PCD_SPEED_FULL;
#if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN) #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN)
pcd_fs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0 pcd_fs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0