Skip to content

Commit a6310c9

Browse files
author
Alrik Vidstrom
committed
Fix channel disabling and endpoint recovery
The HAL_HCD_HC_Halt() function doesn't actually halt a channel correctly, so this fix replaces those calls with code that does. This is necessary both when freeing the bulk endpoints when a USB thumb drive is disconnected, but also when performing error recovery on a channel that is blocked in a NAK state. The HAL_HCD_HC_Init() function doesn't return the channel to an active state itself, so there's also code added to do that. Finally, the endpoint object must be returned to USB_TYPE_IDLE at the end of such an error recovery.
1 parent dce6bdc commit a6310c9

File tree

1 file changed

+30
-4
lines changed

1 file changed

+30
-4
lines changed

src/targets/TARGET_STM/USBEndpoint_STM.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,13 @@ extern uint32_t HAL_HCD_HC_GetType(HCD_HandleTypeDef *hhcd, uint8_t chn_num);
2727
extern void HAL_HCD_DisableInt(HCD_HandleTypeDef *hhcd, uint8_t chn_num);
2828
extern void HAL_HCD_EnableInt(HCD_HandleTypeDef *hhcd, uint8_t chn_num);
2929

30-
31-
30+
#if defined(TARGET_PORTENTA_H7)
31+
#define USBx_BASE USB2_OTG_FS_PERIPH_BASE
32+
#elif defined(TARGET_GIGA)
33+
#define USBx_BASE USB1_OTG_HS_PERIPH_BASE
34+
#else
35+
#define USBx_BASE USB1_OTG_HS_PERIPH_BASE
36+
#endif
3237

3338
void USBEndpoint::init(HCED *hced_, ENDPOINT_TYPE type_, ENDPOINT_DIRECTION dir_, uint32_t size, uint8_t ep_number, HCTD *td_list_[2])
3439
{
@@ -109,13 +114,29 @@ void USBEndpoint::setState(USB_TYPE st)
109114
if ((*addr) && (type != INTERRUPT_ENDPOINT)) {
110115
this->ep_queue.put((uint8_t *)1);
111116
}
112-
HAL_HCD_HC_Halt((HCD_HandleTypeDef *)hced->hhcd, hced->ch_num);
117+
// Flush posted requests
118+
USBx_HC(hced->ch_num)->HCCHAR |= USB_OTG_HCCHAR_CHDIS;
119+
// Disable the channel
120+
USBx_HC(hced->ch_num)->HCCHAR |= USB_OTG_HCCHAR_CHDIS | USB_OTG_HCCHAR_CHENA;
121+
// <-- Notice the lack of error handling here - after testing a lot of
122+
// combinations, it seems that the USB host controller doesn't work fully
123+
// according to the reference manual in this aspect, which might also
124+
// be the reason for lacking error handling in the ST USB LL
125+
113126
HAL_HCD_DisableInt((HCD_HandleTypeDef *)hced->hhcd, hced->ch_num);
114127
*addr = 0;
115128

116129
}
117130
if (st == USB_TYPE_ERROR) {
118-
HAL_HCD_HC_Halt((HCD_HandleTypeDef *)hced->hhcd, hced->ch_num);
131+
// Flush posted requests
132+
USBx_HC(hced->ch_num)->HCCHAR |= USB_OTG_HCCHAR_CHDIS;
133+
// Disable the channel
134+
USBx_HC(hced->ch_num)->HCCHAR |= USB_OTG_HCCHAR_CHDIS | USB_OTG_HCCHAR_CHENA;
135+
// <-- Notice the lack of error handling here - after testing a lot of
136+
// combinations, it seems that the USB host controller doesn't work fully
137+
// according to the reference manual in this aspect, which might also
138+
// be the reason for lacking error handling in the ST USB LL
139+
119140
HAL_HCD_DisableInt((HCD_HandleTypeDef *)hced->hhcd, hced->ch_num);
120141
uint8_t hcd_speed = HCD_SPEED_FULL;
121142
/* small speed device with hub not supported
@@ -124,6 +145,11 @@ void USBEndpoint::setState(USB_TYPE st)
124145
// Notice that dev->getAddress() must be used instead of device_address, because the latter will contain
125146
// incorrect values in certain cases
126147
HAL_HCD_HC_Init((HCD_HandleTypeDef *)hced->hhcd, hced->ch_num, address, dev->getAddress(), hcd_speed, type, size);
148+
// HAL_HCD_HC_Init() doesn't fully enable the channel after disable above, so we do it here -->
149+
USBx_HC(hced->ch_num)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS;
150+
USBx_HC(hced->ch_num)->HCCHAR |= USB_OTG_HCCHAR_CHENA;
151+
// <--
152+
state = USB_TYPE_IDLE;
127153
}
128154
}
129155

0 commit comments

Comments
 (0)