Skip to content

Commit 93c95e4

Browse files
committed
dap thread: multiple bugfixes
- Fix obvious bug with multi-packet pending response lengths The length needs to go along with the data buf, not a random global - Move to async notifications instead of polling or hacky suspend/resume For a tick interval ~= the time taken to transmit one full bulk packet, you could get a NAK and flow-controlled if usb_thread went to sleep - Remove redundant memcpys and unused variables - Hack the reported DAP packet count to avoid bulk-OUT/NAK conditions as much as possible
1 parent 6c8b1e1 commit 93c95e4

5 files changed

Lines changed: 57 additions & 44 deletions

File tree

CMSIS_DAP/CMSIS/DAP/Firmware/Source/DAP.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ static uint8_t DAP_Info(uint8_t id, uint8_t *info) {
132132
length = 2U;
133133
break;
134134
case DAP_ID_PACKET_COUNT:
135-
info[0] = DAP_PACKET_COUNT;
135+
info[0] = DAP_PACKET_COUNT - 2; // HACK to avoid ring buffer fullness
136136
length = 1U;
137137
break;
138138
default:

include/DAP_config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ This information includes:
9696
/// This configuration settings is used to optimize the communication performance with the
9797
/// debugger and depends on the USB peripheral. For devices with limited RAM or USB buffer the
9898
/// setting can be reduced (valid range is 1 .. 255).
99-
#define DAP_PACKET_COUNT 2U ///< Specifies number of packets buffered.
99+
#define DAP_PACKET_COUNT 8U ///< Specifies number of packets buffered.
100100

101101
/// Indicate that UART Serial Wire Output (SWO) trace is available.
102102
/// This information is returned by the command \ref DAP_Info as part of <b>Capabilities</b>.

src/main.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,21 @@ void dev_mon(void *ptr)
9494
} while (1);
9595
}
9696

97+
void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr)
98+
{
99+
(void) rhport;
100+
(void) eventid;
101+
BaseType_t blah;
102+
if (in_isr) {
103+
xTaskNotifyFromISR(tud_taskhandle, 0, 0, &blah);
104+
} else {
105+
xTaskNotify(tud_taskhandle, 0, 0);
106+
}
107+
}
108+
97109
void usb_thread(void *ptr)
98110
{
111+
uint32_t cmd;
99112
#ifdef PROBE_USB_CONNECTED_LED
100113
gpio_init(PROBE_USB_CONNECTED_LED);
101114
gpio_set_dir(PROBE_USB_CONNECTED_LED, GPIO_OUT);
@@ -113,9 +126,10 @@ void usb_thread(void *ptr)
113126
// If suspended or disconnected, delay for 1ms (20 ticks)
114127
if (tud_suspended() || !tud_connected())
115128
xTaskDelayUntil(&wake, 20);
116-
// Go to sleep for up to a tick if nothing to do
129+
// Go to sleep if nothing to do
117130
else if (!tud_task_event_ready())
118-
xTaskDelayUntil(&wake, 1);
131+
xTaskNotifyWait(0, 0xFFFFFFFFu, &cmd, 1);
132+
119133
} while (1);
120134
}
121135

@@ -282,7 +296,7 @@ void tud_mount_cb(void)
282296
xTaskCreate(autobaud_thread, "ABR", configMINIMAL_STACK_SIZE, NULL, AUTOBAUD_TASK_PRIO, &autobaud_taskhandle);
283297
#if(configNUMBER_OF_CORES > 1)
284298
vTaskCoreAffinitySet(autobaud_taskhandle, (1 << 1));
285-
vTaskCoreAffinitySet(dap_taskhandle, (1 << 0));
299+
vTaskCoreAffinitySet(dap_taskhandle, (1 << 1));
286300
vTaskCoreAffinitySet(uart_taskhandle, (1 << 0));
287301
#endif
288302
was_configured = 1;

src/tusb_edpt_handler.c

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@
66

77
#include "tusb_edpt_handler.h"
88
#include "DAP.h"
9+
#include "semphr.h"
10+
911

1012
static uint8_t itf_num;
1113
static uint8_t _rhport;
1214

13-
volatile uint32_t _resp_len;
1415

1516
static uint8_t _out_ep_addr;
1617
static uint8_t _in_ep_addr;
1718

1819
static buffer_t USBRequestBuffer;
1920
static buffer_t USBResponseBuffer;
2021

21-
static uint8_t DAPRequestBuffer[DAP_PACKET_SIZE];
22-
static uint8_t DAPResponseBuffer[DAP_PACKET_SIZE];
22+
static SemaphoreHandle_t edpt_spoon;
2323

2424
#define WR_IDX(x) (x.wptr % DAP_PACKET_COUNT)
2525
#define RD_IDX(x) (x.rptr % DAP_PACKET_COUNT)
@@ -38,15 +38,15 @@ bool buffer_empty(buffer_t *buffer)
3838
}
3939

4040
void dap_edpt_init(void) {
41-
41+
edpt_spoon = xSemaphoreCreateMutex();
42+
xSemaphoreGive(edpt_spoon);
4243
}
4344

4445
bool dap_edpt_deinit(void)
4546
{
46-
memset(DAPRequestBuffer, 0, sizeof(DAPRequestBuffer));
47-
memset(DAPResponseBuffer, 0, sizeof(DAPResponseBuffer));
48-
USBRequestBuffer.wptr = USBRequestBuffer.rptr = 0;
49-
USBResponseBuffer.wptr = USBResponseBuffer.rptr = 0;
47+
memset(&USBRequestBuffer, 0, sizeof(USBRequestBuffer));
48+
memset(&USBResponseBuffer, 0, sizeof(USBResponseBuffer));
49+
vSemaphoreDelete(edpt_spoon);
5050
return true;
5151
}
5252

@@ -131,6 +131,8 @@ uint16_t dap_edpt_open(uint8_t __unused rhport, tusb_desc_interface_t const *itf
131131
// The IN endpoint doesn't need a transfer to initialise it, as this will be done by the main loop of dap_thread
132132
usbd_edpt_open(rhport, edpt_desc);
133133

134+
// Spawn DAP thread?
135+
134136
return drv_len;
135137

136138
}
@@ -149,29 +151,29 @@ bool dap_edpt_xfer_cb(uint8_t __unused rhport, uint8_t ep_addr, xfer_result_t re
149151
{
150152
if(xferred_bytes >= 0u && xferred_bytes <= DAP_PACKET_SIZE)
151153
{
154+
xSemaphoreTake(edpt_spoon, portMAX_DELAY);
152155
USBResponseBuffer.rptr++;
153-
154156
// This checks that the buffer was not empty in DAP thread, which means the next buffer was not queued up for the in endpoint callback
155157
// So, queue up the buffer at the new read index, since we expect read to catch up to write at this point.
156158
// It is possible for the read index to be multiple spaces behind the write index (if the USB callbacks are lagging behind dap thread),
157159
// so we account for this by only setting wasEmpty to true if the next callback will empty the buffer
158160
if(!USBResponseBuffer.wasEmpty)
159161
{
160-
usbd_edpt_xfer(rhport, ep_addr, RD_SLOT_PTR(USBResponseBuffer), (uint16_t) _resp_len);
162+
usbd_edpt_xfer(rhport, ep_addr, RD_SLOT_PTR(USBResponseBuffer), USBResponseBuffer.data_len[RD_IDX(USBResponseBuffer)]);
161163
USBResponseBuffer.wasEmpty = (USBResponseBuffer.rptr + 1) == USBResponseBuffer.wptr;
162164
}
163-
165+
xSemaphoreGive(edpt_spoon);
164166
// Wake up DAP thread after processing the callback
165-
vTaskResume(dap_taskhandle);
167+
xTaskNotify(dap_taskhandle, 0, eSetValueWithOverwrite);
166168
return true;
167169
}
168-
169170
return false;
170171

171-
} else if(ep_dir == TUSB_DIR_OUT) {
172+
} else if(ep_dir == TUSB_DIR_OUT) {
172173

173174
if(xferred_bytes >= 0u && xferred_bytes <= DAP_PACKET_SIZE)
174175
{
176+
xSemaphoreTake(edpt_spoon, portMAX_DELAY);
175177
// Only queue the next buffer in the out callback if the buffer is not full
176178
// If full, we set the wasFull flag, which will be checked by dap thread
177179
if(!buffer_full(&USBRequestBuffer))
@@ -183,22 +185,26 @@ bool dap_edpt_xfer_cb(uint8_t __unused rhport, uint8_t ep_addr, xfer_result_t re
183185
else {
184186
USBRequestBuffer.wasFull = true;
185187
}
186-
188+
xSemaphoreGive(edpt_spoon);
187189
// Wake up DAP thread after processing the callback
188-
vTaskResume(dap_taskhandle);
190+
xTaskNotify(dap_taskhandle, 0, eSetValueWithOverwrite);
189191
return true;
190192
}
191-
192193
return false;
193194
}
194-
else return false;
195+
return false;
195196
}
196197

197198
void dap_thread(void *ptr)
198199
{
199200
uint32_t n;
201+
uint32_t cmd;
202+
uint16_t resp_len;
200203
do
201204
{
205+
// Wait for usb CB wake
206+
xTaskNotifyWait(0, 0xFFFFFFFFu, &cmd, 1);
207+
202208
while(USBRequestBuffer.rptr != USBRequestBuffer.wptr)
203209
{
204210
/*
@@ -219,53 +225,45 @@ void dap_thread(void *ptr)
219225
}
220226
}
221227
// Read a single packet from the USB buffer into the DAP Request buffer
222-
memcpy(DAPRequestBuffer, RD_SLOT_PTR(USBRequestBuffer), DAP_PACKET_SIZE);
223228
probe_info("%lu %lu DAP cmd %s len %02x\n",
224-
USBRequestBuffer.wptr, USBRequestBuffer.rptr,
225-
dap_cmd_string[DAPRequestBuffer[0]], DAPRequestBuffer[1]);
226-
USBRequestBuffer.rptr++;
229+
USBRequestBuffer.wptr, USBRequestBuffer.rptr,
230+
dap_cmd_string[RD_SLOT_PTR(USBRequestBuffer)[0], RD_SLOT_PTR(USBRequestBuffer)[1]]);
227231

228232
// If the buffer was full in the out callback, we need to queue up another buffer for the endpoint to consume, now that we know there is space in the buffer.
233+
xSemaphoreTake(edpt_spoon, portMAX_DELAY); // Suspend the scheduler to safely update the write index
229234
if(USBRequestBuffer.wasFull)
230235
{
231-
vTaskSuspendAll(); // Suspend the scheduler to safely update the write index
232236
USBRequestBuffer.wptr++;
233237
usbd_edpt_xfer(_rhport, _out_ep_addr, WR_SLOT_PTR(USBRequestBuffer), DAP_PACKET_SIZE);
234238
USBRequestBuffer.wasFull = false;
235-
xTaskResumeAll();
236239
}
240+
xSemaphoreGive(edpt_spoon);
237241

238-
_resp_len = DAP_ExecuteCommand(DAPRequestBuffer, DAPResponseBuffer);
239-
probe_info("%lu %lu DAP resp %s\n",
240-
USBResponseBuffer.wptr, USBResponseBuffer.rptr,
241-
dap_cmd_string[DAPResponseBuffer[0]]);
242-
242+
resp_len = DAP_ExecuteCommand(RD_SLOT_PTR(USBRequestBuffer), WR_SLOT_PTR(USBResponseBuffer)) & 0xffff;
243+
USBRequestBuffer.rptr++;
244+
probe_info("%lu %lu DAP resp %s len %u\n",
245+
USBResponseBuffer.wptr, USBResponseBuffer.rptr,
246+
dap_cmd_string[WR_SLOT_PTR(USBResponseBuffer)[0], resp_len);
243247

248+
USBResponseBuffer.data_len[WR_IDX(USBResponseBuffer)] = resp_len;
244249
// Suspend the scheduler to avoid stale values/race conditions between threads
245-
vTaskSuspendAll();
250+
xSemaphoreTake(edpt_spoon, portMAX_DELAY);
246251

247252
if(buffer_empty(&USBResponseBuffer))
248253
{
249-
memcpy(WR_SLOT_PTR(USBResponseBuffer), DAPResponseBuffer, (uint16_t) _resp_len);
250254
USBResponseBuffer.wptr++;
251255

252-
usbd_edpt_xfer(_rhport, _in_ep_addr, RD_SLOT_PTR(USBResponseBuffer), (uint16_t) _resp_len);
256+
usbd_edpt_xfer(_rhport, _in_ep_addr, RD_SLOT_PTR(USBResponseBuffer), USBResponseBuffer.data_len[RD_IDX(USBResponseBuffer)]);
253257
} else {
254258

255-
memcpy(WR_SLOT_PTR(USBResponseBuffer), DAPResponseBuffer, (uint16_t) _resp_len);
256259
USBResponseBuffer.wptr++;
257260

258261
// The In callback needs to check this flag to know when to queue up the next buffer.
259262
USBResponseBuffer.wasEmpty = false;
260263
}
261-
xTaskResumeAll();
264+
xSemaphoreGive(edpt_spoon);
262265
}
263-
264-
// Suspend DAP thread until it is awoken by a USB thread callback
265-
vTaskSuspend(dap_taskhandle);
266-
267266
} while (1);
268-
269267
}
270268

271269
usbd_class_driver_t const _dap_edpt_driver =

src/tusb_edpt_handler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
typedef struct {
1919
uint8_t data[DAP_PACKET_COUNT][DAP_PACKET_SIZE];
20+
uint16_t data_len[DAP_PACKET_COUNT];
2021
volatile uint32_t wptr;
2122
volatile uint32_t rptr;
2223
volatile bool wasEmpty;

0 commit comments

Comments
 (0)