Hallo zusammen,
ich befasse mich gerade näher mit der USB-Implementierung auf einem
Atmel SAM D21 uC. Die Lib aus dem ASF funktioniert problemlos. Mir fehlt
es nur etwas am Verständnis der Funktionsweise. Konkret geht es um einen
isochronen Transfer.
Im Beispiel wird ein simpler Loopback in Verbindung mit einer
Testsoftware auf dem PC implementiert. Hier mal ein Code-Ausschnitt der
hauptsächlich wichtigen Funktionen:
1 | bool udi_vendor_iso_out_run(uint8_t * buf, iram_size_t buf_size,
|
2 | udd_callback_trans_t callback)
|
3 | {
|
4 | return udd_ep_run(UDI_VENDOR_EP_ISO_OUT,
|
5 | false,
|
6 | buf,
|
7 | buf_size,
|
8 | callback);
|
9 | }
|
10 |
|
11 | void main_vendor_iso_out_received(udd_ep_status_t status,
|
12 | iram_size_t nb_transfered, udd_ep_id_t ep)
|
13 | {
|
14 | uint8_t *buf_ptr;
|
15 | UNUSED(ep);
|
16 |
|
17 | if (UDD_EP_TRANSFER_OK != status) {
|
18 | return; // Transfer aborted, then stop loopback
|
19 | }
|
20 |
|
21 | if (nb_transfered) {
|
22 | ui_loop_back_state(true);
|
23 | // Send on IN endpoint the data received on endpoint OUT
|
24 | buf_ptr = &main_buf_loopback[ main_buf_iso_sel
|
25 | *(sizeof(main_buf_loopback)/2) ];
|
26 | udi_vendor_iso_in_run(
|
27 | buf_ptr,
|
28 | nb_transfered,
|
29 | main_vendor_iso_in_received);
|
30 | }
|
31 |
|
32 | // Switch of buffer
|
33 | main_buf_iso_sel = main_buf_iso_sel? 0:1;
|
34 |
|
35 | buf_ptr = &main_buf_loopback[ main_buf_iso_sel
|
36 | *(sizeof(main_buf_loopback)/2) ];
|
37 |
|
38 | // Send on IN endpoint the data received on endpoint OUT
|
39 | udi_vendor_iso_out_run(
|
40 | buf_ptr,
|
41 | udd_is_high_speed()?
|
42 | UDI_VENDOR_EPS_SIZE_ISO_FS,
|
43 | main_vendor_iso_out_received);
|
44 | }
|
Es wird also zunächst die Funktion aufgerufen, um den Endpoint zu
bedienen (Daten empfangen)
--> "udd_ep_run".
Wenn die Daten empfangen wurden, wird eine Callback-Funktion aufgerufen
--> "main_vendor_iso_out_received"
In der Callback-Funktion wird wieder die ursprüngliche Funktion
udd_ep_run aufgerufen.
Da das nun ja beliebig lange so weiterlaufen würde und sich im Grunde
unendlich rekursiv selbst aufruft, müsste doch irgendwann der Stack
überlaufen, wenn nicht irgendwann wieder zurückgesprungen wird?
Ich habe diverse Tests durchgeführt. Das scheint so aber zu laufen.
Rein von der Logik hatte ich eigentlich folgenden Ansatz:
- nach erfolgreicher Beendigung der USB-Enumeration bekomme ich bei
jedem erkannten Start-of-Frame (SOF) einen Interrupt
- theoretisch müsste ich nun einfach hergehen und in jedem SOF-Interrupt
1x udd_ep_run aufrufen, um die Daten im zugehörigen Frame zu
transferieren.
Somit wäre die Funktion sauber terminiert bzw es wird wieder
zurückgesprungen.
Ich habe nun diverse Tests gemacht. Es scheint, dass dabei Daten
verloren gehen.
In der Programmierung rund um die USB-Schnittstelle bin ich noch recht
neu, deshalb die Frage, ob mir da jemand etwas auf die Sprünge helfen
kann.
Beste Grüße,
Markus