Skip to content

Commit 2e44a4d

Browse files
committed
USBD: Added critical sections to EP OUT handler
1 parent a912722 commit 2e44a4d

File tree

1 file changed

+79
-32
lines changed

1 file changed

+79
-32
lines changed

cores/arduino/USB/SAMD21_USBDevice.h

Lines changed: 79 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,32 @@ void USBDevice_SAMD21G18x::calibrate() {
195195
usb.PADCAL.bit.TRIM = pad_trim;
196196
}
197197

198+
/*
199+
* Synchronization primitives.
200+
* TODO: Move into a separate header file and make an API out of it
201+
*/
202+
203+
class __Guard {
204+
public:
205+
__Guard() : primask(__get_PRIMASK()), loops(1) {
206+
__disable_irq();
207+
}
208+
~__Guard() {
209+
if (primask == 0) {
210+
__enable_irq();
211+
// http://infocenter.arm.com/help/topic/com.arm.doc.dai0321a/BIHBFEIB.html
212+
__ISB();
213+
}
214+
}
215+
uint32_t enter() { return loops--; }
216+
private:
217+
uint32_t primask;
218+
uint32_t loops;
219+
};
220+
221+
#define synchronized for (__Guard __guard; __guard.enter(); )
222+
223+
198224
/*
199225
* USB EP generic handlers.
200226
*/
@@ -222,39 +248,51 @@ class DoubleBufferedEPOutHandler : public EPHandler {
222248
usbd.epBank0SetSize(ep, 64);
223249
usbd.epBank0SetType(ep, 3); // BULK OUT
224250

225-
usbd.epBank0SetAddress(ep, data0);
251+
usbd.epBank0SetAddress(ep, const_cast<uint8_t *>(data0));
226252

227253
release();
228254
}
229255

230256
// Read one byte from the buffer, if the buffer is empty -1 is returned
231257
int read() {
258+
// R/W: current, first0/1, ready0/1, notify
259+
// R : last0/1, data0/1
232260
if (current == 0) {
233-
if (!ready0) {
234-
return -1;
261+
synchronized {
262+
if (!ready0) {
263+
return -1;
264+
}
235265
}
266+
// when ready0==true the buffer is not being filled and last0 is constant
236267
if (first0 == last0) {
237268
first0 = 0;
238269
current = 1;
239-
ready0 = false;
240-
if (notify) {
241-
notify = false;
242-
release();
270+
synchronized {
271+
ready0 = false;
272+
if (notify) {
273+
notify = false;
274+
release();
275+
}
243276
}
244277
return -1;
245278
}
246279
return data0[first0++];
247280
} else {
248-
if (!ready1) {
249-
return -1;
281+
synchronized {
282+
if (!ready1) {
283+
return -1;
284+
}
250285
}
286+
// when ready1==true the buffer is not being filled and last1 is constant
251287
if (first1 == last1) {
252288
first1 = 0;
253289
current = 0;
254-
ready1 = false;
255-
if (notify) {
256-
notify = false;
257-
release();
290+
synchronized {
291+
ready1 = false;
292+
if (notify) {
293+
notify = false;
294+
release();
295+
}
258296
}
259297
return -1;
260298
}
@@ -264,40 +302,47 @@ class DoubleBufferedEPOutHandler : public EPHandler {
264302

265303
virtual void handleEndpoint()
266304
{
305+
// R/W : incoming, ready0/1
306+
// W : last0/1, notify
267307
if (usbd.epBank0IsTransferComplete(ep))
268308
{
269309
// Ack Transfer complete
270310
usbd.epBank0AckTransferComplete(ep);
271-
//usbd.epBank0AckTransferFailed(ep);
311+
//usbd.epBank0AckTransferFailed(ep); // XXX
272312

273313
// Update counters and swap banks
274314
if (incoming == 0) {
275315
last0 = usbd.epBank0ByteCount(ep);
276316
incoming = 1;
277-
usbd.epBank0SetAddress(ep, data1);
317+
usbd.epBank0SetAddress(ep, const_cast<uint8_t *>(data1));
278318
ready0 = true;
279-
if (ready1) {
280-
notify = true;
281-
return;
319+
synchronized {
320+
if (ready1) {
321+
notify = true;
322+
return;
323+
}
324+
notify = false;
282325
}
283-
notify = false;
284326
} else {
285327
last1 = usbd.epBank0ByteCount(ep);
286328
incoming = 0;
287-
usbd.epBank0SetAddress(ep, data0);
288-
ready1 = true;
289-
if (ready0) {
290-
notify = true;
291-
return;
329+
usbd.epBank0SetAddress(ep, const_cast<uint8_t *>(data0));
330+
synchronized {
331+
ready1 = true;
332+
if (ready0) {
333+
notify = true;
334+
return;
335+
}
336+
notify = false;
292337
}
293-
notify = false;
294338
}
295339
release();
296340
}
297341
}
298342

299343
virtual uint32_t recv(void *_data, uint32_t len)
300344
{
345+
// TODO Write an optimized version of this one
301346
uint8_t *data = reinterpret_cast<uint8_t *>(_data);
302347
uint32_t i;
303348
for (i=0; i<len; i++) {
@@ -328,14 +373,16 @@ class DoubleBufferedEPOutHandler : public EPHandler {
328373
const uint32_t size;
329374
uint32_t current, incoming;
330375

331-
uint8_t *data0;
332-
uint32_t first0, last0;
333-
bool ready0;
376+
volatile uint8_t *data0;
377+
uint32_t first0;
378+
volatile uint32_t last0;
379+
volatile bool ready0;
334380

335-
uint8_t *data1;
336-
uint32_t first1, last1;
337-
bool ready1;
381+
volatile uint8_t *data1;
382+
uint32_t first1;
383+
volatile uint32_t last1;
384+
volatile bool ready1;
338385

339-
bool notify;
386+
volatile bool notify;
340387
};
341388

0 commit comments

Comments
 (0)