Skip to content

Commit 133d9c1

Browse files
authored
Merge pull request #23 from alrvid/master
Fixes connect() bug, crash bug, I/O error bug, and more.
2 parents f1d0a22 + 3a90c05 commit 133d9c1

File tree

7 files changed

+94
-23
lines changed

7 files changed

+94
-23
lines changed

.codespellrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# See: https://github.com/codespell-project/codespell#using-a-config-file
33
[codespell]
44
# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here:
5-
ignore-words-list = freeed,
5+
ignore-words-list = freeed,unstall,
66
skip = ./.git,./.licenses,__pycache__,node_modules,./go.mod,./go.sum,./package-lock.json,./poetry.lock,./yarn.lock
77
builtin = clear,informal,en-GB_to_en-US
88
check-filenames =

src/USBHost/USBHost.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,8 @@ USB_TYPE USBHost::generalTransfer(USBDeviceConnected * dev, USBEndpoint * ep, ui
11451145
USB_DBG_TRANSFER("%s TRANSFER res: %s on ep: %p\r\n", type_str, ep->getStateString(), ep);
11461146

11471147
if (res != USB_TYPE_IDLE) {
1148+
// Set state to USB_TYPE_IDLE to allow recovery from the error, but return the error
1149+
ep->setState(USB_TYPE_IDLE);
11481150
return res;
11491151
}
11501152

src/USBHostMSD/USBHostMSD.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,14 @@ int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code)
187187

188188
int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep)
189189
{
190-
// if ep stalled: send clear feature
190+
// Guard against host not being initialized
191+
if (nullptr == host)
192+
{
193+
return -1;
194+
}
195+
196+
// Notice that USB_TYPE_STALL_ERROR is never actually set anywhere in the library for the ST target, because
197+
// URB_STALL is never handled directly. Otherwise, this would be the code to unstall the EP.
191198
if (res == USB_TYPE_STALL_ERROR) {
192199
res = host->controlWrite( dev,
193200
USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
@@ -211,6 +218,12 @@ int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t
211218

212219
int res = 0;
213220

221+
// Guard against host not being initialized
222+
if (nullptr == host)
223+
{
224+
return -1;
225+
}
226+
214227
cbw.Signature = CBW_SIGNATURE;
215228
cbw.Tag = 0;
216229
cbw.DataLength = transfer_len;
@@ -273,7 +286,9 @@ int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t
273286
BO_MASS_STORAGE_RESET,
274287
0, msd_intf, NULL, 0);
275288

276-
// uninstall both endpoints
289+
// Unstall [sic!] both endpoints.
290+
// Notice that this is the unstall that is required by the specification as part of clearing a Phase Error,
291+
// _not_ the unstall for an ordinarily stalled EP!
277292
res = host->controlWrite( dev,
278293
USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
279294
CLEAR_FEATURE,
@@ -310,6 +325,13 @@ int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int
310325
int USBHostMSD::getMaxLun()
311326
{
312327
uint8_t buf[1], res;
328+
329+
// Guard against host not being initialized
330+
if (nullptr == host)
331+
{
332+
return -1;
333+
}
334+
313335
res = host->controlRead( dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
314336
0xfe, 0, msd_intf, buf, 1);
315337
USB_DBG("max lun: %d", buf[0]);

src/USBHostMSD/USBHostMSD.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class USBHostMSD : public IUSBEnumerator, public mbed::BlockDevice
7575

7676

7777
private:
78-
USBHost * host;
78+
USBHost * host = nullptr;
7979
USBDeviceConnected * dev;
8080
bool dev_connected;
8181
USBEndpoint * bulk_in;

src/targets/TARGET_STM/USBEndpoint_STM.cpp

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,20 @@
2020

2121
#include "USBHost/dbg.h"
2222
#include "USBHost/USBEndpoint.h"
23+
#include "USBHost/USBDeviceConnected.h"
24+
2325
extern uint32_t HAL_HCD_HC_GetMaxPacket(HCD_HandleTypeDef *hhcd, uint8_t chn_num);
2426
extern uint32_t HAL_HCD_HC_GetType(HCD_HandleTypeDef *hhcd, uint8_t chn_num);
2527
extern void HAL_HCD_DisableInt(HCD_HandleTypeDef *hhcd, uint8_t chn_num);
2628
extern void HAL_HCD_EnableInt(HCD_HandleTypeDef *hhcd, uint8_t chn_num);
2729

28-
29-
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
3037

3138
void USBEndpoint::init(HCED *hced_, ENDPOINT_TYPE type_, ENDPOINT_DIRECTION dir_, uint32_t size, uint8_t ep_number, HCTD *td_list_[2])
3239
{
@@ -107,21 +114,45 @@ void USBEndpoint::setState(USB_TYPE st)
107114
if ((*addr) && (type != INTERRUPT_ENDPOINT)) {
108115
this->ep_queue.put((uint8_t *)1);
109116
}
110-
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 - instead,
125+
// we use a 50 us delay to wait for the channel to disable
126+
wait_us(50);
127+
111128
HAL_HCD_DisableInt((HCD_HandleTypeDef *)hced->hhcd, hced->ch_num);
112129
*addr = 0;
113130

114131
}
115132
if (st == USB_TYPE_ERROR) {
116-
HAL_HCD_HC_Halt((HCD_HandleTypeDef *)hced->hhcd, hced->ch_num);
117-
HAL_HCD_DisableInt((HCD_HandleTypeDef *)hced->hhcd, hced->ch_num);
133+
// Flush posted requests
134+
USBx_HC(hced->ch_num)->HCCHAR |= USB_OTG_HCCHAR_CHDIS;
135+
// Disable the channel
136+
USBx_HC(hced->ch_num)->HCCHAR |= USB_OTG_HCCHAR_CHDIS | USB_OTG_HCCHAR_CHENA;
137+
// Notice the lack of error handling here - after testing a lot of
138+
// combinations, it seems that the USB host controller doesn't work fully
139+
// according to the reference manual in this aspect, which might also
140+
// be the reason for lacking error handling in the ST USB LL - instead,
141+
// we use a 50 us delay to wait for the channel to disable
142+
wait_us(50);
118143

119-
}
120-
if (st == USB_TYPE_ERROR) {
144+
HAL_HCD_DisableInt((HCD_HandleTypeDef *)hced->hhcd, hced->ch_num);
121145
uint8_t hcd_speed = HCD_SPEED_FULL;
122146
/* small speed device with hub not supported
123147
if (this->speed) hcd_speed = HCD_SPEED_LOW;*/
124-
HAL_HCD_HC_Init((HCD_HandleTypeDef *)hced->hhcd, hced->ch_num, address, 0, hcd_speed, type, size);
148+
149+
// Notice that dev->getAddress() must be used instead of device_address, because the latter will contain
150+
// incorrect values in certain cases
151+
HAL_HCD_HC_Init((HCD_HandleTypeDef *)hced->hhcd, hced->ch_num, address, dev->getAddress(), hcd_speed, type, size);
152+
// HAL_HCD_HC_Init() doesn't fully enable the channel after disable above, so we do it here -->
153+
USBx_HC(hced->ch_num)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS;
154+
USBx_HC(hced->ch_num)->HCCHAR |= USB_OTG_HCCHAR_CHENA;
155+
// <--
125156
}
126157
}
127158

@@ -150,7 +181,7 @@ USB_TYPE USBEndpoint::queueTransfer()
150181
state = USB_TYPE_PROCESSING;
151182
/* one request */
152183
td_current->nextTD = (hcTd *)0;
153-
#if defined(MAX_NYET_RETRY)
184+
#if defined(MAX_NOTREADY_RETRY)
154185
td_current->retry = 0;
155186
#endif
156187
td_current->setup = setup;

src/targets/TARGET_STM/USBHALHost_STM.cpp

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,21 @@ uint32_t HAL_HCD_HC_GetType(HCD_HandleTypeDef *hhcd, uint8_t chnum)
7676
return hhcd->hc[chnum].ep_type;
7777
}
7878

79+
// The urb_state parameter can be one of the following according to the ST documentation, but the explanations
80+
// that follow are the result of an analysis of the ST HAL / LL source code, the Reference Manual for the
81+
// STM32H747 microcontroller, and the source code of this library:
82+
//
83+
// - URB_ERROR = various serious errors that may be hard or impossible to recover from without pulling
84+
// the thumb drive out and putting it back in again, but we will try
85+
// - URB_IDLE = set by a call to HAL_HCD_HC_SubmitRequest(), but never used by this library
86+
// - URB_NYET = never actually used by the ST HAL / LL at the time of writing, nor by this library
87+
// - URB_STALL = a stall response from the device - but it is never handled by the library and will end up
88+
// as a timeout at a higher layer, because of an ep_queue.get() timeout, which will activate
89+
// error recovery indirectly
90+
// - URB_DONE = the transfer completed normally without errors
91+
// - URB_NOTREADY = a NAK, NYET, or not more than a couple of repeats of some of the errors that will
92+
// become URB_ERROR if they repeat several times in a row
93+
//
7994
void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum, HCD_URBStateTypeDef urb_state)
8095
{
8196
USBHALHost_Private_t *priv = (USBHALHost_Private_t *)(hhcd->pData);
@@ -93,7 +108,7 @@ void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum,
93108
if ((type == EP_TYPE_BULK) || (type == EP_TYPE_CTRL)) {
94109
switch (urb_state) {
95110
case URB_DONE:
96-
#if defined(MAX_NYET_RETRY)
111+
#if defined(MAX_NOTREADY_RETRY)
97112
td->retry = 0;
98113
#endif
99114
if (td->size > max_size) {
@@ -107,21 +122,18 @@ void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum,
107122
}
108123
break;
109124
case URB_NOTREADY:
110-
/* try again */
111-
/* abritary limit , to avoid dead lock if other error than
112-
* slow response is */
113-
#if defined(MAX_NYET_RETRY)
114-
if (td->retry < MAX_NYET_RETRY) {
115-
/* increment retry counter */
125+
#if defined(MAX_NOTREADY_RETRY)
126+
if (td->retry < MAX_NOTREADY_RETRY) {
116127
td->retry++;
117128
#endif
129+
// Submit the same request again, because the device wasn't ready to accept the last one
118130
length = td->size <= max_size ? td->size : max_size;
119131
HAL_HCD_HC_SubmitRequest(hhcd, chnum, dir, type, !td->setup, (uint8_t *) td->currBufPtr, length, 0);
120132
HAL_HCD_EnableInt(hhcd, chnum);
121133
return;
122-
#if defined(MAX_NYET_RETRY)
134+
#if defined(MAX_NOTREADY_RETRY)
123135
} else {
124-
//USB_ERR("urb_state != URB_NOTREADY");
136+
// MAX_NOTREADY_RETRY reached, so stop trying to resend and instead wait for a timeout at a higher layer
125137
}
126138
#endif
127139
break;
@@ -138,6 +150,9 @@ void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum,
138150
td->state = USB_TYPE_IDLE;
139151
}
140152
else if (urb_state == URB_ERROR) {
153+
// While USB_TYPE_ERROR in the endpoint state is used to activate error recovery, this value is actually never used.
154+
// Going here will lead to a timeout at a higher layer, because of ep_queue.get() timeout, which will activate error
155+
// recovery indirectly.
141156
td->state = USB_TYPE_ERROR;
142157
} else {
143158
td->state = USB_TYPE_PROCESSING;

src/targets/TARGET_STM/USBHALHost_STM.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838

3939
#define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT * ED_SIZE) + (MAX_TD * TD_SIZE))
4040

41-
#define MAX_NYET_RETRY 5
41+
// This must be a large number to account for the relatively high write latency of USB thumb drives
42+
#define MAX_NOTREADY_RETRY 50000
4243

4344
/* STM device FS have 11 channels (definition is for 60 channels) */
4445
static volatile uint8_t usb_buf[TOTAL_SIZE];

0 commit comments

Comments
 (0)