Forum: Mikrocontroller und Digitale Elektronik AT90USB1287 BulkTransfer unter Linux mit libusb ?!


von Ela1983 (Gast)


Angehängte Dateien:

Lesenswert?

Hallo;

Ich habe folgendes Problem...
Ich will Daten via Bulk transfer vom PC zum µC schicken, dann auf ein E² 
schreiben und lesen mit SPI, und die Daten zurück an den PC mit USB Bulk 
transfer...


Bei Windows XP klappt es perfekt, aber nicht unter Linux Suse10.1 mit 
libusb 0.1.12.

Es scheint ein Problem mit dem dataToggle bit unter linux  zu sein???
Das erste mal nach der enumeration klappt es, danach nie wieder...


Was kann ich machen ? bitte schaut euch meine sourcen an ...speziell 
usb_device_task.c

Bitte helft mir, ich versteh es nicht, warum es unter Linux nicht klappt

Vielen Dank an alle die helfen wollen...

von Stefan Salewski (Gast)


Lesenswert?

Du mußt wahrscheinlich das Data-Toggle-Bit zurücksetzen.

Wenn Du das Linux-Programm neu startest, beginnt der Datentransfer 
jeweils mit Data0-Paketen. wenn Du zuvor eine ungerade Anzahl von 
Paketen übertragen hast, sendet die Firmware aber nun ein Data1-Paket -- 
und das verträgt sich nicht.

von Manuel S. (ela1983)


Lesenswert?

Aber ich weiß nicht wo och das DataToggle Bit zurücksetzen muss, bzw. 
wann im Code...

Immer darf ich es nicht zurücksetzen, da ja auch Data1 Pakete kommen 
können...also wo und wie mach in ein Reset am besten...


Vielen vielen Dank

von Stefan Salewski (Gast)


Angehängte Dateien:

Lesenswert?

>Immer darf ich es nicht zurücksetzen, da ja auch Data1 Pakete kommen
>können...also wo und wie mach in ein Reset am besten...

Ja, das ist eine gute Frage!

Ich gehe mal davon aus, dass Du nicht meinen Code, sondern den von Atmel 
für Deine Experimente verwendest. Dann musst Du da mal etwas suchen,
grep -r oggle *
im Quelltextverzeichis beipielsweise.

Ich mache den Reset der Toggle-Bits in der Funktion
UsbDevSetInterface() die Teil der Enumeration ist und beim Start des 
Linux-Programms aufgerufen wird. Ich werde mal versuchen die Funktion 
hier als Anhang anzuhängen, aber das nützt Dir nicht viel, denn beim 
Atmel-Code kann das alles anders sein. Das Makro zum Rücksetzen der 
Toggle-Bits ist
#define UsbDevResetDataToggleBit() SetBit(UECONX, RSTDT) // next packet 
is data0

das sollte im Atmel-Code ähnlich sein, zumindest Register UECONX und Bit 
RSTDT.

Du kannst dieses Problem aber auch vorläufig umgehen, wenn Du immer eine 
gerade Anzahl von Datenpaketen überträgst -- dann sollte das Toggle-Bit 
stimmen.

von Manuel S. (ela1983)


Lesenswert?

Also das resetten der dataToggle bits bekomme ich hin, habe die Funktion 
gefunden...nun ist nur die Frage wann ich resette...

Rufen Sie vor jedem usb_bulk_read(...) und vor jedem usb_bulk_write(...) 
dieses set_interface auf ?

Auf der PC seite sieht mein Programm so aus:

der Hauptteil...:




iError = usb_claim_interface(dev_hnd,0);
      printf(" iError bei claim = %d\n",iError);

iError = usb_bulk_write(dev_hnd,0x03/*int ep*/,(char*)Prot/*char* 
bytes*/, 5/*int size*/,1000 /*int timeout*/);


iError = usb_bulk_read(dev_hnd,0x82/*int ep*/,(char*)RecProt/*char* 
bytes*/, 4096/*int size*/,1000 /*int timeout*/);



usb_release_interface(dev_hnd,0)
/**********************************************************************/

bitte Sie sind meine letzte Hoffnung...vielen Dank für Ihre Hilfe

von Stefan Salewski (Gast)


Lesenswert?

In meinem Testprogramm sieht das so aus:

  dev = UsbFindDevice();
  if (dev == NULL)
  {
    puts("USB device not found!");
    exit(EXIT_FAILURE);
  }
  handle = usb_open(dev);
  if (handle == NULL)
  {
    puts("USB device handle not found!");
    exit(EXIT_FAILURE);
  }
  if (usb_claim_interface(handle, 0) < 0)
  {
    puts("Can not claim interface!");
    usb_close(handle);
    exit(EXIT_FAILURE);
  }

Dann kommt eine Anzahl Bulk-Transfers, und am Programmende

  usb_release_interface(handle, 0);
  usb_close(handle);
  exit(EXIT_SUCCESS);

Hast Du probiert, jeweils eine gerade Anzahl von Transfers zu machen,
also statt einem Bulk-Read gleich zwei, ebenso für Bulk-Write.

Wenn dann alles ok ist, wissen wir, dass es sicher am Toggle-Bit liegt.
Wo jetzt im Atmel-Code die Toggle-Bits (jeder Enpoint hat ein eigenes!) 
zurückgesetzt werden, weiss ich nicht. Ich bin mir auch nicht sicher, 
welche Funktion der LibUSB meine Funktion UsbDevSetInterface() meiner 
Firmware aufruft -- aber wenn ich LibUSB nach deren (spärlicher) 
Dokumentation verwende, wird bei mir die Funktion UsbDevSetInterface() 
meiner Firmware aufgerufen, und damit werden die Toggle-Bits bei jeden 
Neustart meines Linux-Programms zurückgesetzt und es funktioniert.

von Stefan Salewski (Gast)


Lesenswert?

Ok, ich hatte noch den Atmel-Code des mouse-examples auf der Festplatte:

grep -r oggle *

liefert

at90usb128/modules/usb/usb_standard_request.c: 
Usb_reset_data_toggle();

Und in usb_standard_request.c

findet man, dass

 Usb_reset_data_toggle();

in Funktion

void usb_clear_feature(void)

aufgerufen wird.

Wie ich das sehe, wird der StandardDeviceRequest ClearFeature
von LibUSB nicht aufgerufen! Sieh mal in der Dokumentation von LibUSB 
nach, ob es eine Funktion ResetEndpoint oder ähnliches gibt. Die 
Funktion müsstest Du dann an geeigneter Stelle in dein Linux-Programm 
einbauen -- vor den Bulk-Read.

Alternativ: In der Atmel-Datei usb_standard_request.c sehe ich eine 
Funktion void usb_set_configuration( void ) und darin enthalten ist
usb_user_endpoint_init(usb_configuration_nb);
Da könntest Du die Toggle Bits zurücksetzen.

Gruß

Stefan Salewski

von Manuel S. (ela1983)


Lesenswert?

Erst einmal vielen vielen Dank für Ihre Hilfe...

In der libUSB Dokumentation habe ich folgendes gefunden:

/*********************************************************************** 
***/
usb_resetep
Name
usb_resetep -- Resets state for an endpoint
Description

int usb_resetep(usb_dev_handle *dev, unsigned int ep);

usb_resetep resets all state (like toggles) for the specified endpoint. 
The ep parameter is the value specified in the descriptor field 
bEndpointAddress. Returns 0 on success or < 0 on error.

    Deprecated: usb_resetep is deprecated. You probably want to use 
usb_clear_halt.

/*********************************************************************** 
****/

Wenn ich Sie richtig verstanden habe, müsste diese Funktion beim starten 
meines Programmes aufgerufen werden...richtig ???

also prinzipiell so: ??

/*ProgrammStart*/
openDevice
claim_interface
resetEndpoint(EP2)
resetEndpoint(EP3)
usb_bulk_write()
usb_bulk_read()
release_interface
/*ProgrammEnde*/

Nochmals vielen vielen Dank

von Stefan Salewski (Gast)


Lesenswert?

Ja, würde ich so in der Art probieren.
Oder eben usb_clear_halt(). Ich erwarte, dass usb_clear_halt() von 
LibUSB
void usb_clear_feature(void) der Atmel-Firmware aufruft -- genau was Du 
brauchst. Probier also am besten zuerst usb_clear_halt().

Gruß

Stefan Salewski

von Manuel S. (ela1983)


Lesenswert?

SUPER!!!

Vielen vielen Dank

der Clear Feature Befehl wird duch die libusb Funktion usb_clear_halt() 
ausgeführt und führ ein Reset der ToggleBits durch...

Vielen Dank für Ihre Hilfe...

Nun bin ich am Interrupt dran...wenn ich einen Interrupt einem Endpoint 
zuweisen will, muss ich dann diesen zuerst selektieren ?

Beispiel:

usb_select_endpoint(ENDPOINTNUMMER);
usb_receive_out_interrupt_enable();

so dass ich einen Interrupt bekomme sobald ich auf der jeweiligen Nummer 
ein OUT empfange, oder gilt das interrupt enable allgemein für alle 
endpoints ?

Vielen Dank

Mit freundlcihen Grüßen

Manuel Sahm

von Stefan Salewski (Gast)


Lesenswert?

>Nun bin ich am Interrupt dran...wenn ich einen Interrupt einem Endpoint
>zuweisen will, muss ich dann diesen zuerst selektieren ?

>Beispiel:

>usb_select_endpoint(ENDPOINTNUMMER);
>usb_receive_out_interrupt_enable();

>so dass ich einen Interrupt bekomme sobald ich auf der jeweiligen Nummer
>ein OUT empfange, oder gilt das interrupt enable allgemein für alle
>endpoints ?

Nach Figure 22-5, Seite 280 im Datenblatt sind die verschiedenen 
Interruptquellen jeweils auf einen speziellen Endpoint bezogen.
Deine Vermutung ist daher richtig, Du musst den Endpoint zunächst 
selektieren um danach die Interruptquelle für diesen Endpoint 
freizugeben.

Du musst, wenn ein Interrupt eingetreten ist, in der Regel auch 
überprüfen, auf welchen Endpoint er sich bezieht. Das geschieht über das 
Register UEINT, ein gesetztes Bit bedeutet, dass der zugehörige Endpoint 
den Interrupt ausgelöst hat. Eventuell ist diese Auswertung aber bereits 
im Atmel-Code enthalten, so dass man eventuell nur noch festlegen muss, 
welche Funktion für einen bestimmten Endpoint aufgerufen werden soll.

Gruß

Stefan Salewski

von Manuel S. (ela1983)


Lesenswert?

Ah OK, alles klar, habe ich auch so verstanden...

Ich habe bis jetzt das USBKEY128 DevBoard, da ist ja leider nur ein 8 
MHz Quartz drauf; ich würde aber gerne mal einen 16MHz Quartz benutzen, 
dafür müsste ich mir aber dann wahrscheinlich das STK500 + STK525 
zulegen oder ?

Und weiterhin wollte ich die TimerInterrupts mal testen...wie könnte ich 
denn jede Sekunde die LED namchen bzw. wieder ausmachen...

Braucht man da nicht ne Formel, falls man das über COMPARE Mode machen 
will ?

Vielen Dank

Mfg

M. Sahm

von Stefan Salewski (Gast)


Lesenswert?

>Und weiterhin wollte ich die TimerInterrupts mal testen...wie könnte ich
>denn jede Sekunde die LED namchen bzw. wieder ausmachen...

>Braucht man da nicht ne Formel, falls man das über COMPARE Mode machen
>will ?

Die Timer sind bei allen AVRs ähnlich -- falls Du die Beschreibung im 
Datenblatt nicht sofort verstehst, musst Du mal nach Beispielen oder 
Tutorials im Internet suchen.

>Ich habe bis jetzt das USBKEY128 DevBoard, da ist ja leider nur ein 8
>MHz Quartz drauf; ich würde aber gerne mal einen 16MHz Quartz benutzen,
>dafür müsste ich mir aber dann wahrscheinlich das STK500 + STK525
>zulegen oder ?

Du hast den USB-KEY -- dieses winzige Ding? Das liegt bei mir seit 
letztem Sommer unbenutzt in der Schublade, weil ich nicht so recht weiss 
was man damit sinnvolles machen soll. Debugging ist damit kaum möglich, 
da man kein UART hat. Quarz könnte man ja eventuell wechseln, aber 16 
MHz sind nicht mehr ganz so problemlos wie 8 MHz.

STK525: Wenn man nur Software entwickeln will und einem der Preis nicht 
abschreckt wohl ganz ok. Wenn man aber später eh eigene Platinen 
aufbauen will, kann man sich auch gleich eine Platine selber machen, wie 
etwa meine von http://www.ssalewski.de/AVR_USB_gEDA.html.de

Natürlich sollte man elekrische Grundkenntnisse haben und etwas löten 
können. Die Bauteile kosten ca. 25 Euro, und die Platine pro Stück rund 
15 Euro, wenn man sich mindestens 4 machen lässt (Bilex).

Gruß

Stefan Salewski

von Manuel S. (ela1983)


Lesenswert?

Ich benutze zum Debuggen den JTAGICE mkII;

habe mir das SPI (PORTB) und zwei Pins von PORTA geholt un ein E² 
anzuschließen.

Hatte eigentlich bisher keine schlechten Erfahrungen mit dem USB-KEY...

Jetzt will ich halt versuchen Geschwindigkeit rauszukriegen, indem ich 
die frequenz verdopple...haben Sie vergleiche von 8 MHz zu 16 MHz...?

Erreicht man bei manchen Funktionen den Faktor 2 in der Geschwindigkeit 
(z. B. kopieren von Daten in den USB Fifo)?

Mein Projekt ist ein LOW COST RFID reader:

PC -----via USB BULK Transfer --> µC ----via SPI----> ReaderIC ----via 
SPI---> µC -------via USB BULK Transfer -> PC

Dieser Bulk transfer ist schon verdammt schnell,...aber beim kopieren 
der Daten kann man noch was rausholen denke ich...

Viele Grüße

M. Sahm

von Stefan Salewski (Gast)


Lesenswert?

Fast alle Operationen des Controllers skalieren selbstverständlich mit 
der Taktfrequenz -- bei 16MHz hat man entsprechend die doppelte 
Geschwindigkeit wie bei 8 MHz. Die Datenübertragung zwischen Host und 
Device ist aber nicht von der Taktfrequenz des uC abhängig, da der 
USB-Teil eine feste Taktfrequenz hat (intern bis zu 48 MHz). Mit 
Fullspeed sollte eine Übertragung vom bis zu ca. 1MByte/s möglich sein 
-- aber soweit ich weiss ist der Atmel-USB-Code doch für die HID Klasse 
ausgelegt und dann hat man nur Low-Speed.

Mit Fullspeed sollte man ohne Probleme bis zu 1MByte/s übertragen 
können, wenn man den FIFO kontinuierlich auslesen bzw. beschreiben kann, 
etwa wenn man die Daten aus einem großen Puffer liest oder 
hineinschreibt. Wenn die Daten aber in sehr kleinen Portionen 
eintrudeln, etwas immer ein oder zwei Byte vom ADC, ist die Situation 
ungünstiger. In meiner Beispielanwendung, wo ich per Timerinterrupt 
Daten vom internen ADC auslese (jeweils 2 Byte), erreiche ich mit C bei 
16MHz und Fullspeed bis zu 100kByte/s. Aber das ist nur eine 
Beispielanwendung -- Timergesteuert einzelne Bytes in den FIFO zu 
schreiben macht viel Overhead, insbesondere da ich die Daten noch durch 
einen separaten Ringpuffer schiebe, um USB-Latenzzeiten zu überbrücken 
und Datenaufzeichnung in Echtzeit zu garantieren (alle 20us).

Gruß

Stefan Salewski

von Manuel S. (ela1983)


Lesenswert?

Super; danke für die Info;

habe heute alles hibekommen mit Timer usw...

Jetzt habe ich eventuell ein Hardwareproblem.

Was ich will:

Den AT90USB1287 mit 16 MHz betreiben, dies ist von der Spannung her kein 
Problem, da die USB Schnittstelle ja 5V bereitstellt. An den µC will ich 
ein RFID reader IC anschließen, diese läuft aber mit 3,3V. Von 5V auf 
3,3V ist ja kein Problem, aber:

Ich schließe dieses ReaderIc via SPI an, und da, wenn ich richtig liege 
sind bei 16 MHz die IO Pins mit einem Pegel von 5V am laufen, müsste es 
doch Probleme geben.

Ich kann doch nicht 5V Pegel von der SPI auf eine 3,3V System jagen, 
oder doch ?

Weiterhin habe ich nichts gefunden uber die Detektierung der HIGH und 
LOW Pegel vom AT90USB. Von dem IC komman ja dann auch nur 3,3V Pegel via 
SPI zurück...kann der AT90USB diese im 16MHz Betrieb (also 5V) überhaupt 
als High und Low identifiezieren ?

Ich hoffe es war einigermaßen verständlich...

Danke im vorraus

Mit freundlichen Grüßen

Manuel Sahm

von Peter (Gast)


Lesenswert?

Der AT90USB wird die Pegel schon als Low oder High erkennen, nur musst 
du schauen, ob der RFID-IC mit den 5V-Pegeln klarkommt. Entweder hat der 
IC 5V-tolerante Eingänge oder du musst die Pegel anpassen.

Was für einen RFID-Reader willst du denn einsetzen?

Gruß, Peter

von Manuel S. (ela1983)


Lesenswert?

Ich will das MFRC522 von NXP (Philips) ansteuern...zum Testen, später 
soll da glaube ich das MFRC530 dran...

Tja und das läuft nunmal nur mit 3,3V und die maximalen Spannungen sind 
laut Datenblatt 4V (so wie ich das erkennen kann).

Also müsste man sämtliche Signale die vom AT90USB1287 kommen von 5V auf 
3,3V runterschrauben...????, oder ???

Sind Sie sicher, dass der Atmel die Pegel sicher detektieren kann (bei 
5V) ? ich habe dazu im Datenblatt auch nichts gefunden...

viele grüße

Manuel

von Hansi (Gast)


Lesenswert?

>Also müsste man sämtliche Signale die vom AT90USB1287 kommen von 5V auf
>3,3V runterschrauben...????, oder ???

>Sind Sie sicher, dass der Atmel die Pegel sicher detektieren kann (bei
>5V) ? ich habe dazu im Datenblatt auch nichts gefunden...

Datenblatt AT90USB Seite 400:

Input High Voltage Min: 0.6 VCC

Gute 3 V sollte er noch als High erkennen.

>Von 5V auf 3,3V ist ja kein Problem, aber:

Naja, zumindest auch etwas Aufwand.

Aber frag Dich mal, warum Atmel den USB-KEY mit 8MHz ausliefert.
16 MHz braucht zumindest stabile 4,5 V -- ob das am USB immer garantiert 
ist? Ich will dir keine Angst machen, bei mir geht es auch, aber wenn 
man unter allen Umständen die Funktion garantieren will?

Ich würde mal drüber nachdenken ob nicht doch 8 MHz ausreichen -- dann 
kann eventuell der AT90USB auch mit gut 3V laufen.

Gruß

Stefan Salewski

von Stefan Salewski (Gast)


Lesenswert?

Mist, das war mein Deckname für

Beitrag "wer baut mir 12v zeitsteuerung"

von Ela1983 (Gast)


Lesenswert?

Hallo;

habe jetzt ein anderes Problem...

ich muss Variablen bzw. ganze Tabellen im Flash ablegen...

In der mir vorliegenden Firmware macht man das mit __tiny

Jetzt bringt mir der Compiler immer fehlermeldungen von wegen TINY_Z zu 
klein oder so...? Data:100-100

Irgendwie muss das mit dem XLC - File zu tun haben...?

Könnte mir das mal jemand erklären...?

Vielen Dank

Viele Grüße

Manuel Sahm

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.