Forum: Mikrocontroller und Digitale Elektronik STM32F407 Weitere IN Token am EP1


von Tycho B. (asellus)


Lesenswert?

Ich habe einen Virtual ComPort von STM realisiert, Anmelden am System 
funktioniert, jetzt gehe ich über, Daten hin und her zu schicken. Die 
erste Testidee war, nach einem Erhalt von 5 Zeichen im uC eine Antwort 
mit z.B. 36 Zeichen an den PC zu schicken.

Ich erhalte auch die Zeichen, dann initialisiere ich die Senderoutine 
mit:
1
dieptsiz1.d32 = USB.INEP_REGS[1]->DIEPTSIZ;
2
dieptsiz1.b.xfrsiz = 36;
3
dieptsiz1.b.pktcnt = 1;
4
USB.INEP_REGS[1]->DIEPTSIZ = dieptsiz1.d32;
5
USB.INEP_REGS[1]->DIEPCTL |= DIEPCTLx_EPENA|DIEPCTLx_CNAK;
6
for (uint32_t i = 0; i < 9; i++){
7
  *(USB).DFIFO[1]=USB_buffer[i];
8
}
Daten werden auch am PC empfangen und ein XFRC (transfer complete) am 
EP1 IN wird ausgelöst. Danach kommt aber ein weiterer IN token und ich 
bekomme ein ITTXFE (IN token received while Tx empty) interrupt.

Eigentlich ist doch dem Host durch vorherige Anweisung bekannt, dass ich 
nur 36 Bytes senden möchte, warum kommt da ein weiteres IN Token?

: Bearbeitet durch User
von Tycho B. (asellus)


Lesenswert?

Bump?
Wirklich keiner?

von Johnny B. (johnnyb)


Lesenswert?

Das macht doch alles die HAL für Dich und Du brauchst nur diese eine 
Funktion um was zu senden:
CDC_Transmit_FS(USB_buffer, USB_buffer_len);

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Tycho B. schrieb:
> Eigentlich ist doch dem Host durch vorherige Anweisung bekannt, dass ich
> nur 36 Bytes senden möchte, warum kommt da ein weiteres IN Token?

Der Host sendet doch immer wieder "IN", bis Daten im Puffer sind. 
Solange keine Daten da sind, antwortet die Peripherie automatisch mit 
"NAK". Diese ankommenden "IN" sollten die Software aber normalerweise 
nicht interessieren. Den ITTXFE Interrupt kannst du daher komplett 
weglassen und abgeschaltet lassen.

Im Transfer Complete Interrupt kannst du zur Sicherheit wieder NAK 
aktivieren, aber das sollte eigentlich nicht nötig sein:
1
USB.INEP_REGS[1]->DIEPCTL |= USB_OTG_DIEPCTL_SNAK_Msk;

von Tycho B. (asellus)


Lesenswert?

Ich bin mir nicht sicher ob es so stimmt. Ich sende ja bei der 
Enumeration Deskriptoren an das System. Danach taucht dieses ITTXFE 
nicht auf. Ich dachte, wenn ich SNAK setze, dann sendet der uc nacks an 
den PC transparent ohne mich zu belästigen. Erst wenn ich mit
1
USB.INEP_REGS[1]->DIEPCTL |= DIEPCTLx_EPENA|DIEPCTLx_CNAK;
starte und etwas falsch konfiguriere oder sende, dann kommt ITTXFE und 
sagt mir, dass der Host noch Daten erwartet.

von Tycho B. (asellus)


Lesenswert?

Johnny B. schrieb:
> Das macht doch alles die HAL für Dich und Du brauchst nur diese eine
> Funktion um was zu senden:
> CDC_Transmit_FS(USB_buffer, USB_buffer_len);

Ich programmiere bare metal.

von Tycho B. (asellus)


Lesenswert?

Ok...
Also: wenn der XFRC-Interrupt ausgelöst wird, dann muss
1
USB.INEP_REGS[1]->DIEPCTL |= DIEPCTLx_SNAK;
gesetzt werden.
Ich dachte das geschieht automatisch.

von Niklas Gürtler (Gast)


Lesenswert?

Tycho B. schrieb:
> Ich dachte das geschieht automatisch.

Das muss automatisch passieren, sonst würde die Kommunikation abreißen 
wenn der Interrupt nicht extrem schnell kommt...

Tycho B. schrieb:
> Danach taucht dieses ITTXFE nicht auf.

Ja, weil der Host auf dem EP0 nicht kontinuierlich IN sendet.

Tycho B. schrieb:
> Ich dachte, wenn ich SNAK setze, dann sendet der uc nacks an den PC
> transparent ohne mich zu belästigen

Jo.

Vermutlich sendet der uC bei leerem FIFO automatisch immer NAK, aber 
wenn du das NAK Bit nicht gesetzt hast ("SNAK") kommt der ITTXFE 
Interrupt, den du aber eigentlich ignorieren kannst.

von Tycho B. (asellus)


Lesenswert?

Tja, zu früh gefreut,
irgendwie funktioniert es 2-3-5 mal, dann kommt wieder ein ITTXFE.

von Tycho B. (asellus)


Angehängte Dateien:

Lesenswert?

Um die Funktionalität zu testen habe ich ein kleines Beispielprogramm 
geschrieben: wenn der uC 5 Zeichen erhält, dann sendet er 60 zurück an 
den PC.
1
    dieptsiz1.d32 = USB.INEP_REGS[1]->DIEPTSIZ;
2
    dieptsiz1.b.xfrsiz = 60;
3
    dieptsiz1.b.pktcnt = 1;
4
    USB.INEP_REGS[1]->DIEPTSIZ = dieptsiz1.d32;
5
    USB.INEP_REGS[1]->DIEPCTL |= DIEPCTLx_EPENA|DIEPCTLx_CNAK;
6
    for (uint32_t i = 0; i < 15; i++){
7
      *(USB).DFIFO[1]=USB_buffer[i];
8
    }

Wenn diese IN Übertragung durch ist, also 60 Zeichen an den PC gesendet 
wurden, dann wird das DIEPINT_XFRC (IN Transfer completed interrupt) 
ausgelöst und in dieser ISR SNAK gesetzt, damit ITTXFE(IN token received 
when TxFIFO is empty) beim nächsten IN Token nicht aktiv wird.
1
USB.INEP_REGS[1]->DIEPCTL |= DIEPCTLx_SNAK;
Das funktioniert auch mehrere Male, nur irgendwann mal antwortet uC 
nicht mit 60 Zeichen, sondern  mit Status 0xC0000004 - STALL_PID.

Und das ist für mich nicht verständlich - warum plötzlich STALL wenn der 
Transfer davor 10 mal funktioniert hat (siehe PNG)?

PS.: Wenn ich kontinuierlich Daten sende und nicht nur 60 Zeichen, dann 
funktioniert es(

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.