am Beispiel des PIC18F2550
Einleitung
USB-Hardware der
PIX18Fxx5x
Ein einfaches USB-Beispiel-Übungsprojekt
Im Windows-PC vermitteld der Device-Treiber zwischen dem Anwendungsprogramm und dem USB-Interface. Die Programmierschnittstelle stellt in der Regel eine DLL bereit. Im Fall des Microchip Custom Driver (verfügbar auf der Microchip Homepage) ist das die mpusbapi.dll (C:\MCHPFSUSB\Pc\Mpusbapi\Dll) .
Die DLL wurde in C geschrieben. Sie
verwendet
einige Daten-Typen, deren Aufbau in der C-Header-Datei mpusbapi.h
(C:\MCHPFSUSB\Pc\Mpusbapi\Dll\Borland_C)
beschrieben sind. Wer seine
Anwendungssoftware
auch in C schreiben will, fügt diese Header-Datei einfach seinem
Projekt
zu, und hat damit alle Daten-Typen und Konstanten
definiert. Ich arbeite mit Delphi, und
habe eine Unit (usbdll.pas) zusammengestellt, die die
Daten-Typen,
die Konstanten und die Funktionsaufrufe der DLL enthält. Diese Unit
basiert auf Informationen von
http://www.sixca.com/delphi/article/microchip_usb.html.
unit usbdll;
interface uses //based on http://www.sixca.com/delphi/article/microchip_usb.html Const type var // Version der mpusbapi.dll auslesen
// Anzahl der zu vid&pid
passenden USB-Devices function
_MPUSBOpen(instance:DWORD;pVID_PID:PCHAR8; function
_MPUSBClose(handle:THANDLE):DWORD; function
_MPUSBRead(handle:THANDLE;var pData:PBYTE; function
_MPUSBReadInt(handle:THANDLE; function
_MPUSBWrite(handle:THANDLE;pData:PBYTE; function
SendReceivePacket(SendData:PBYTE;SendLength:DWORD;var
ReceiveData:PBYTE; implementation procedure CheckInvalidHandle();
myInPipe:=INVALID_HANDLE_VALUE; function
SendReceivePacket(SendData:PBYTE;SendLength:DWORD;var
ReceiveData:PBYTE; initialization end. |
Diese DLL stellt für Delphi die folgenden Funktionen der mpusbapi.dll zur Verfügung:
_MPUSBGetDLLVersion
function _MPUSBGetDLLVersion():DWORD;
Mit dem Aufruf dieser Funktion kann man
prüfen, ob die mpusbapi.dll geladen ist, und welche
Version
der DLL bereitsteht. Die Funktion benötigt keine
Übergabeparameter,
und liefert eine vorzeichenlose 32-Bit-Zahl als DLL-Versionsnummer
zurück.
Bei der Version 1 der DLL erhält man 0x00010000.
Ein typischer Aufruf könnte z.B.
so aussehen:
. memo1.Lines.add('_MPUSBGetDLLVersion : '+inttohex(_MPUSBGetDLLVersion,8)); . |
Mit dem Aufruf dieser Funktion kann man prüfen, ob das eigene USB-Device von Windows richtig erkannt wurde. Dazu muss man der Funktion einen Pointer auf einen nullterminierten String übergeben. Der String enthält die VID (vendor ID) und die PID (product ID) des USB-Device. Die Funktion liefert die Zahl der gefundenen Devices zurück, auf die VID und PID passen. Normalerweise ist das 0x00000001.
Der nötige Pointer auf den String
ist in dieser Unit schon definiert. Er heißt vid_pid und
trägt
die Microchip-VID 0x04D8 und die PID 0x000C. Wer eine andere PID
einsetzen
will, muss den Eintrag anpassen. In der Grundeinstellung ist die mpusbapi.dll
nur für die PIDs 0x000B und 0x000C verantwortlich. Beim Einsatz
anderer
PIDs ist der entsprechende Eintrag in der mchpusb.inf
anzupassen.
. memo1.Lines.add('_MPUSBGetDeviceCount : '+inttohex(_MPUSBGetDeviceCount(vid_pid),8)); . |
Das ist eine universelle
Schreib-und-Lese-Funktion,
die ich aus http://www.sixca.com/delphi/article/microchip_usb.html
übernommen
habe. Sie schreibt in den out-Endpunkt und liest aus dem in-Endpunkt.
Dabei
kümmert sie sich auch gleich um allen Kleinkram. Die Funktion
benötigt
6 Übergabeparameter:
Parameter | Bedeutung |
SendData:PBYTE; | SendData ist ein 64 Byte langes Array. In ihm legt man for dem Funktionsaufruf beginnend mit dem Index 0 die Daten ab, die man zum out-Endpunkt übertragen möchte. |
SendLength:DWORD; | Das ist die Anzahl der Bytes in SendData, die zum out-Endpunkt geschrieben werden sollen. Sollen gar keine Daten zum Device geschrieben werden, so ist hier 0 einzutragen. |
var ReceiveData:PBYTE; | ReceiveData ist ein 64 Byte langes Array. In ihm befinden sich nach dem Funktionsaufruf die aus dem in-Endpunkt gelesenen Daten. |
var ReceiveLength:DWORD; | Vor dem Funktionsaufruf wird
hier eingetragen,
wieviele Bytes aus dem in-Endpunkt gelesen werden sollen. Nach dem Funktionsaufruf steht hier die Zahl der wirklich gelesenen Bytes. |
SendDelay:UINT; | Das ist die Time-out-Zeit in Millisekunden. Nach dieser Zeit wird das Übertragen von Daten zum out-Endpunkt abgebrochen, auch wenn noch nicht alle Daten übertragen wurden. |
ReceiveDelay:UINT | Das ist die Time-out-Zeit in Millisekunden. Nach dieser Zeit wird das Lesen von Daten aus dem in-Endpunkt abgebrochen, auch wenn noch nicht alle Daten gelesen wurden. |
Darüberhinaus liefert sie als Ergebnis einen 32-Bit-Zahlenwert, der Informationen darüber enthält, ob der Aufruf erfolgreich war:
Vor der Nutzung dieser Funktion ist
aber etwas Vorarbeit und hinterher etwas Aufräumen nötig.
Insbesondere
sind die USB-Ports zu öffnen und zu schließen. Im Folgenden
Beispiel soll ein einzelnes Byte mit dem Wert "1" in das USB-Device
geschrieben
werden:
. procedure TForm1.USB_Sende_Test; var selection : DWORD; send_buf : PBYTE; receive_buf : PBYTE; RecvLength : DWORD; CurrentCMD : BYTE; begin //instance ist warscheinlich 0, kann aber auch einen anderen Wert haben selection:=0; //pipes anfordern
//Daten in den Puffer
_MPUSBClose(myOutPipe);
|
Das Beispiel geht davon aus, dass dieses Device das einzige mit seiner VID&PID ist, und deshalb beim Durchzählen den selection-Wert "0" bekommen hat. Rein Theoretisch könnte es auch einen anderen selection-Wert bekommen, das ist mir aber noch nie passiert.
Eine Alternative zu meiner DLL ist ist die USB-API von Gerhard Burger. Er hat sie auf seiner Homepage veröffentlicht. Dort findet sich auch eine passende Testplatine mit einem PIC18F4550, bei der es sich um eine vereinfachte Eigenbauversion des USB-Demo-Boards von Microchip handelt.
Autor: sprut
erstellt: 02.03.2006
letzte Änderung 24.02.20010