Atmel AVR Mikrocontroller mit OpenSuse: USB Nutzung

Serielle Schnittstellen sind an heutigen PCs immer seltener vorhanden. Der logische Ersatz des alten RS232 Standards ist die USB-Schnittstelle.

Neuere AVR Controller unterstützen den USB-Standard direkt, indem auf dem Chip USB-Controller-Funktionen integriert wurden. Die „älteren“ AVR-Modelle besitzen selbst keine USB-Unterstützung. Dies ist jedoch kein Hindernis, da externe USB-Controller am Markt verfügbar sind.

Bei der Nutzung von RS232 (ohne USB) wird die UART-Funktionalität des AVR Controllers genutzt (UART=Universal Asynchronous Receiver and Transmitter). Diese erzeugt aus eingehenden Bytes einen Bit-Strom. Der Bit-Strom besteht aus den Nutz-Bits (also den 8 Bits des Datenbytes) sowie Steuerbits, die die UART selbsttätig in den Datenstrom einfügt und die das RS232 Leitungsprotokoll umsetzen. Wesentlich ist dabei das immer eingefügte Start-Bit, welches den Start eine Bytes markiert und optionale weitere Start-Bits und optionale Stop-Bits sowie ein Paritätsprüfungsbit. Die Anzahl der Start/Stop-Bits, Parität und vor allem die Baudrate wird über Kontrollregister der UART geregelt. Da der AVR Controller üblicherweise mit +5V betrieben wird, die RS232 Physik aber mit höheren Spannungen (+-12V) funktioniert, wird nur noch ein externer Chip zur Umsetzung der Spannungspegel benötigt. Dies ist typischerweise ein Baustein der Art MAX232.


Der MAX232 für die „alte“ RS232 Schnittstelle, hier in SMD-Bauform, es sind aber auch DIL-Gehäuse verfügbar

Bei der Nutzung von USB mit dem AVR gibt es unterschiedliche Konzepte:

  • V-USB, einer reinen Software-Implementierung der USB-Anbindung. Dabei werden einfach Port-Pins eines AVRs als USB-Leitungen verwendet und die gesamte USB-Logik im AVR implementiert. Diese Lösung ist simpel, aber leider nicht allzu schnell.
  • Nutzung eines externen USB-Controller-Chips. Dieser Ansatz ist im folgenden ausführlich beschrieben.

AVR mit externem USB-Controller

Am Markt verfügbar sind diverse USB Controller Chips. Ein beliebter Kandidat ist der FT232. FTDI hat diesen Chip sicher bewusst ähnlich benannt wie den „alten“ MAX232. Ganz grob formuliert: Während der MAX232 die Signale eines Mikrocontrollers auf RS232-Physik umsetzt, kann man beim FT232 sagen, dass dieser die Signale des Controllers auf die USB-Physik umsetzt.

Damit ist auch schon in etwa beschrieben, wie der AVR mit den F232 verbunden wird. Wie schon beim reinen RS232 wird die UART genutzt, um aus einem Datenbyte einen Bitstrom zu erzeugen. Dieser Bitstrom wird in den FT232 eingespeist. Den „Rest“, also die Umsetzung in USB-Pakete, erledigt der FT232. Die umgekehrte Richtung funktioniert genauso, der FT232 extrahiert aus dem USB-Datenstrom die für ihn bestimmten Bits und legt diese an den Eingang der AVR UART. Diese macht daraus in gewohnter Weise Datenbytes.
Man könnte also auch sagen, dass der serielle Datenstrom im USB-Datenstrom getunnelt wird.


Der FT232RL für USB, nur in SMD Gehäusen verfügbar

PC-seitige Voraussetzung

Wenn AVR und USB-Controller an ihre Betriebsspannung angelegt werden und der USB-Controller per USB-Kabel mit einem PC verbunden wird, meldet sich der USB-Controller mit einer Art eindeutiger Kennung beim USB-System des PCs an (VendorId + ProductId). Beim FT232 ist dies z.B. idVendor=0403 und idProduct=6001. Anhand dieser Parameter kann das Subsystem den dazu passenden USB-Treiber laden und verwenden. Beim FT232 und unter OpenSuse gilt:

  • Der Treiber von FTDI ist bereits im Standardkernel verfügbar und wird automatisch geladen, wenn der FT232 sich am USB-System anmeldet
  • Die Geräteklasse des FT232 ist eine serielle Schnittstelle. Linux bindet das Gerät daher über eine /dev/ttyUSBxx Gerätedatei ins System ein.

Unter Windows muss vermutlich der Treiber von FTDI nachinstalliert werden.
Web-Adresse zu den Treibern: http://www.ftdichip.com/FTDrivers.htm

(unter Windows noch zu machen)

Die dmesg-Ausgabe unter Linux bringt folgendes:

[ 4251.658015] usb 6-2: new full speed USB device using uhci_hcd and address 2
[ 4251.847030] usb 6-2: New USB device found, idVendor=0403, idProduct=6001 
[ 4251.847034] usb 6-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 4251.847037] usb 6-2: Product: FT232R USB UART
[ 4251.847040] usb 6-2: Manufacturer: FTDI
[ 4251.847042] usb 6-2: SerialNumber: A9009NnL
[ 4251.886707] usbcore: registered new interface driver usbserial
[ 4251.886722] USB Serial support registered for generic
[ 4251.886758] usbcore: registered new interface driver usbserial_generic
[ 4251.886761] usbserial: USB Serial Driver core
[ 4251.894285] USB Serial support registered for FTDI USB Serial Device
[ 4251.894362] ftdi_sio 6-2:1.0: FTDI USB Serial Device converter detected
[ 4251.894424] usb 6-2: Detected FT232RL 
[ 4251.894428] usb 6-2: Number of endpoints 2
[ 4251.894431] usb 6-2: Endpoint 1 MaxPacketSize 64
[ 4251.894433] usb 6-2: Endpoint 2 MaxPacketSize 64
[ 4251.894435] usb 6-2: Setting MaxPacketSize 64
[ 4251.896108] usb 6-2: FTDI USB Serial Device converter now attached to ttyUSB0 
[ 4251.896125] usbcore: registered new interface driver ftdi_sio
[ 4251.896127] ftdi_sio: v1.5.0:USB FTDI Serial Converters Driver

Aus der dmesg-Ausgabe erkennt man auch die maximale Paketgröße von 64 Bytes.

Wenn man nun AVR-seitig ein kleines Programm schreibt, dass über eine UART Daten ausgibt und man das bisher durch einen an die UART angeschlossenen MAAX232 als RS232-Datenstrom über die serielle Schnittstelle eingelesen hatte, kann man nun dieselben Daten via USB einlesen, wenn man einfach die UART mit den FT232 verbindet. Da der FT232 z.B. als /dev/ttyUSB0 eingebunden wurde, kann man PC-seitig einfach ein Terminalprogramm starten und statt /dev/tty… nun /dev/ttyUSB… als zu verwendende Gerätedatei angeben. Im Terminal werden die Daten dann wie gewohnt dargestellt. Ich verwende für solche Sachen das Programm kermit, und dort legt man die zu verwendende Schnittstelle fest mit:
    set line /dev/ttyUSB0

Hier der Start von kermit und die Ausgaben des AVRs:

dennis@socraggio:~> kermit 
 C-Kermit 8.0.211, 10 Apr 2004, for Linux 
  Copyright (C) 1985, 2004, 
   Trustees of Columbia University in the City of New York. 
 Type ? or HELP for help. 
 (/home/dennis/) C-Kermit>set line /dev/ttyUSB1 
 (/home/dennis/) C-Kermit>c 
 Connecting to /dev/ttyUSB1, speed 19200 
  Escape character: Ctrl- (ASCII 28, FS): enabled 
 Type the escape character followed by C to get back, 
 or followed by ? to see other options. 
 ---------------------------------------------------- 
 21178 (mo=0;fa=0;ma=0;be=0),steps (r/d): 0000/0000, (mark=X,A=-60,B=60,act=0), last cmd: (nop)

Die letzte Zeile, beginnend mit 21178… ist die vom AVR erzeugte Ausgabezeile.

Daten via USB lesen und schreiben

Als nächstes soll betrachtet werden, wie man von einem eigenen Programm aus via USB kommuniziert.

Linux

Da der FT232 linux-seitig wie ein normaler serieller Port aussieht, kann man auch die normalen Kommandos zu Nutzung des Ports verwenden. Alles was man zur Programmierung eines seriellen Ports wissen muß findet man in der „Serial Programming HowTo„.
Die zu nutzenden Funktionen sind:

  • open(), read(), write(), close() für den Datentransfer
  • Für die Konfiguration des Ports die Funktionen tcgetattr(),  tcsetattr() und tcflush()

Im erwähnten HowTo ist auch Beispielcode zu finden.

Nutzbare Geschwindigkeit

Da der FT232 genauso angesprochen wird wie ein altes Terminal, sind auch die Definitionen für die Baud-Raten gültig. Ich habe einige Tests gemacht, hier die Ergebnisse. Die Daten wurden immer in 64 Byte großen Blöcken aus dem Hauptprogramm im AVR an die UART übergeben.

19200 und 38400 Baud (oder noch weniger) sind kein Problem. Da ich auch eine Zeitmessung durchführe und die tatsächliche Transferrate (Nettorate) berechne, stelle ich fest, dass diese ziemlich genau 80% der Baudrate beträgt (durch Start- und Stopbit verursacht, die allgemein bekannten Baudraten-Werte sind also Brutto-Zahlen: 8 Nutzbits+2 Protokollbits ergeben  den Faktor von 8/10).

Bei 57600 Baud gibt es unreproduzierbare Lesefehler.
Nachlesen bringt die Erkenntnis, dass die Baudraten unterschiedlich gut unterstützt werden, je nach Quarzfrequenz des Controllers. Durch Teilung und Rundungen entsteht eine leichte Abweichung in der tatsächlich gefahrenen Baudrate, die dann im PC eventuell nicht sauber erkannt wird. Ein Rechner, der zu einer Taktfrequenz die unterschiedlichen Rundungsfehler zu den Baudraten berechnet findet sich hier: http://www.gjlay.de/helferlein/avr-uart-rechner.html

Ich probiere auch 115.200 und 230.400 Baud, die bei 16Mhz eine ziemlich große Abweichung von den Sollwerten haben. Und tatsächlich erkennt mein PC nichts im Datenstrom.

500.000 Baud haben bei 16Mhz einen Fehler von 0. Ich stelle es mutig ein und tatsächlich, diese Rate wird wieder sauber erkannt. Auch 250.000 Baud hätten einen Fehler von 0, aber das kann mein PC nicht. Unter Linux/GNU-gcc findet man die möglichen Baud-Raten übrigens unter /usr/include/bits/termios.h. Diese Datei wird via „#include <termios.h>“ indirekt eingebunden. Die Baudraten sind Defines der Art „B57600“ und gehen bis 4Mega-Baud.

Schließlich probiere ich noch 1, 2 und 4 MBaud. Mehr als 4MBaud kann der PC nicht und auch beim FT232 ist laut Foren irgendwo bei 3MBaud Schluss.
1 MBaud funktioniert ebenfalls sehr gut. Dabei kann ich Netto-Datenraten von 55KByte/s (etwa 445KBit/s) messen. Das ist ein sehr hoher Wert, den ich eigentlich nicht erwartet hätte.
2 und 4 MBaud bringen keine brauchbaren Ergebnisse, im Dump des Datenstrom kann ich keine korrekt übertragenen Daten erkennen.

Vertiefende Infos, Links

Schreibe einen Kommentar