PicManía by RedRaven |
Búsqueda personalizada
|
EL USB DESENCADENADO : BULK USB |
||
Transferencia bidireccional masiva de información |
Cómo realizar un proyecto
con el USB 2.0 (en formato Bulk transfers) y Delphi 6.0, paso a paso. El Firmware del PIC, el Driver
USB para Windows, la librería
mpusbapi.dll que suministra
Microchip, la API en Delphi que conecta
con ella y el programa en Delphi que conecta con la API, y con su
mediación, con la dll y a través de ella con el PIC. Todo completo y
con fuentes (incluso los de la dll en C++ Builder). |
|
PIC's, Hardware mínimo y Antecedentes varios. |
|
|
|
|
|
|
Descripción del proyecto. |
|
|
|
|
|
|
|
|
|
Firmware, Driver, Software y procedimientos de instalación. |
|
|
|
|
|
|
|
#include rr2_USB_Monitor.h |
|
#define COMMAND_Xxxxx 9 |
|
char Version[]="v.1.0"; |
|
|
|
|
|
|
|
rr_usb_monitor.c |
||
/////////////////////////////////////////////////////////////////////////////////////////////////// //// //// Ejemplo de comunicación USB entre PIC y PC //// /////////////////////////////////////////////////////////////////////////////////////////////////// #include <18F4550.h> #fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN #use delay(clock=48000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) /////////////////////////////////////////////////////////////////////////////////////////////////// // // CCS Library dynamic defines. For dynamic configuration of the CCS Library // for your application several defines need to be made. See the comments // at usb.h for more information // /////////////////////////////////////////////////////////////////////////////////////////////////// #define USB_HID_DEVICE FALSE // deshabilitamos el uso de las directivas HID #define USB_EP1_TX_ENABLE USB_ENABLE_BULK // turn on EP1(EndPoint1) for IN bulk/interrupt transfers #define USB_EP1_RX_ENABLE USB_ENABLE_BULK // turn on EP1(EndPoint1) for OUT bulk/interrupt transfers #define USB_EP1_TX_SIZE 32 // size to allocate for the tx endpoint 1 buffer #define USB_EP1_RX_SIZE 32 // size to allocate for the rx endpoint 1 buffer /////////////////////////////////////////////////////////////////////////////////////////////////// // // Include the CCS USB Libraries. See the comments at the top of these // files for more information // /////////////////////////////////////////////////////////////////////////////////////////////////// #include <pic18_usb.h> // Microchip PIC18Fxx5x Hardware layer for CCS's PIC USB driver #include ".\include\rr2_USB_Monitor.h" // Configuración del USB y los descriptores para este dispositivo #include <usb.c> // handles usb setup tokens and get descriptor reports /////////////////////////////////////////////////////////////////////////////////////////////////// // // Defines y otras zarandajas // /////////////////////////////////////////////////////////////////////////////////////////////////// #define LED_VERDE PIN_E0 #define LED_AMARILLO PIN_E1 #define LED_ROJO PIN_E2 #define Enciende Output_High #define Apaga Output_Low #define Conmuta Output_Toggle #define RecCommand recbuf[0] #define COMMAND_LED 1 #define COMMAND_FIRMWARE 2 #define COMMAND_STRING_RS232 3 const int8 Lenbuf = 32; /////////////////////////////////////////////////////////////////////////////////////////////////// // // RAM, RAM, RAM // /////////////////////////////////////////////////////////////////////////////////////////////////// char Version[] = "v.1.0"; int i; int8 recbuf[Lenbuf]; int8 sndbuf[Lenbuf]; /////////////////////////////////////////////////////////////////////////////////////////////////// // // M A I N // /////////////////////////////////////////////////////////////////////////////////////////////////// void main(void) { delay_ms(500); printf("RRUSB By Redpic %s\r\n",Version); Apaga(LED_VERDE); Apaga(LED_AMARILLO); Enciende(LED_ROJO); delay_ms(100); printf("USB Mon : usb_init()\r\n"); usb_init(); printf("USB Mon : usb_task()\r\n"); usb_task(); printf("USB Mon : usb_wait_for_enumeration()\r\n"); usb_wait_for_enumeration(); enable_interrupts(global); printf("USB Mon : while(TRUE)\r\n"); while (TRUE) { if(usb_enumerated()){ Apaga(LED_ROJO); Enciende(LED_VERDE); if (usb_kbhit(1)){ printf("USB Mon : usb_kbhit()\r\n"); // Recibe Packet usb_get_packet(1, recbuf, Lenbuf); printf("USB Mon : usb_get_packet()\r\n"); // Comando : Conmuta LED if(RecCommand==COMMAND_LED){ printf("USB Mon : Conmuta(LED_AMARILLO)\r\n"); Conmuta(LED_AMARILLO); } // Comando : Transmite Version if(RecCommand==COMMAND_FIRMWARE){ printf("USB Mon : usb_put_packet(%s)\r\n",Version); usb_put_packet(1,Version,6,USB_DTS_TOGGLE); } // Comando : Escribe String en RS232 if(RecCommand==COMMAND_STRING_RS232){ printf("USB Mon : String_2_RS232(%s)\r\n",recbuf); printf("%s\r\n",recbuf); } } } else{ Apaga(LED_VERDE); Enciende(LED_ROJO); } } } |
||
|
|
|
|
|
|
|
|
|
|
|
|
rr2_USB_Monitor.h |
||
///////////////////////////////////////////////////////////////////////// //// rr2_USB_Monitor.h //// //// ///////////////////////////////////////////////////////////////////////// #IFNDEF __USB_DESCRIPTORS__ #DEFINE __USB_DESCRIPTORS__ #include <usb.h> ////////////////////////////////////////////////////////////////// /// /// start config descriptor /// right now we only support one configuration descriptor. /// the config, interface, class, and endpoint goes into this array. /// ////////////////////////////////////////////////////////////////// #DEFINE USB_TOTAL_CONFIG_LEN 32 //config+interface+class+endpoint //configuration descriptor char const USB_CONFIG_DESC[] = { //config_descriptor for config index 1 USB_DESC_CONFIG_LEN, //length of descriptor size USB_DESC_CONFIG_TYPE, //constant CONFIGURATION (0x02) USB_TOTAL_CONFIG_LEN,0, //size of all data returned for this config 1, //number of interfaces this device supports 0x01, //identifier for this configuration. (IF we had more than one configurations) 0x00, //index of string descriptor for this configuration 0xC0, //bit 6=1 if self powered, bit 5=1 if supports remote wakeup (we don't), bits 0-4 reserved and bit7=1 0x32, //maximum bus power required (maximum milliamperes/2) (0x32 = 100mA) //interface descriptor 0 alt 0 USB_DESC_INTERFACE_LEN, //length of descriptor USB_DESC_INTERFACE_TYPE, //constant INTERFACE (0x04) 0x00, //number defining this interface (IF we had more than one interface) 0x00, //alternate setting 2, //number of endpoints, not counting endpoint 0. 0xFF, //class code, FF = vendor defined 0xFF, //subclass code, FF = vendor 0xFF, //protocol code, FF = vendor 0x00, //index of string descriptor for interface //endpoint descriptor USB_DESC_ENDPOINT_LEN, //length of descriptor USB_DESC_ENDPOINT_TYPE, //constant ENDPOINT (0x05) 0x81, //endpoint number and direction (0x81 = EP1 IN) 0x02, //transfer type supported (0 is control, 1 is iso, 2 is bulk, 3 is interrupt) USB_EP1_TX_SIZE,0x00, //maximum packet size supported 0x01, //polling interval in ms. (for interrupt transfers ONLY) //endpoint descriptor USB_DESC_ENDPOINT_LEN, //length of descriptor USB_DESC_ENDPOINT_TYPE, //constant ENDPOINT (0x05) 0x01, //endpoint number and direction (0x01 = EP1 OUT) 0x02, //transfer type supported (0 is control, 1 is iso, 2 is bulk, 3 is interrupt) USB_EP1_RX_SIZE,0x00, //maximum packet size supported 0x01, //polling interval in ms. (for interrupt transfers ONLY) }; //****** BEGIN CONFIG DESCRIPTOR LOOKUP TABLES ******** //since we can't make pointers to constants in certain pic16s, this is an offset table to find // a specific descriptor in the above table. //NOTE: DO TO A LIMITATION OF THE CCS CODE, ALL HID INTERFACES MUST START AT 0 AND BE SEQUENTIAL // FOR EXAMPLE, IF YOU HAVE 2 HID INTERFACES THEY MUST BE INTERFACE 0 AND INTERFACE 1 #define USB_NUM_HID_INTERFACES 0 //the maximum number of interfaces seen on any config //for example, if config 1 has 1 interface and config 2 has 2 interfaces you must define this as 2 #define USB_MAX_NUM_INTERFACES 1 //define how many interfaces there are per config. [0] is the first config, etc. const char USB_NUM_INTERFACES[USB_NUM_CONFIGURATIONS]={1}; #if (sizeof(USB_CONFIG_DESC) != USB_TOTAL_CONFIG_LEN) #error USB_TOTAL_CONFIG_LEN not defined correctly #endif ////////////////////////////////////////////////////////////////// /// /// start device descriptors /// ////////////////////////////////////////////////////////////////// //device descriptor char const USB_DEVICE_DESC[] ={ USB_DESC_DEVICE_LEN, //the length of this report 0x01, //constant DEVICE (0x01) 0x10,0x01, //usb version in bcd 0x00, //class code (if 0, interface defines class. FF is vendor defined) 0x00, //subclass code 0x00, //protocol code USB_MAX_EP0_PACKET_LENGTH, //max packet size for endpoint 0. (SLOW SPEED SPECIFIES 8) 0xD8,0x04, //vendor id (0x04D8 is Microchip) 0x0B,0x00, //product id 0x01,0x00, //device release number 0x01, //index of string description of manufacturer. therefore we point to string_1 array (see below) 0x02, //index of string descriptor of the product 0x00, //index of string descriptor of serial number USB_NUM_CONFIGURATIONS //number of possible configurations }; ////////////////////////////////////////////////////////////////// /// /// start string descriptors /// String 0 is a special language string, and must be defined. People in U.S.A. can leave this alone. /// /// You must define the length else get_next_string_character() will not see the string /// Current code only supports 10 strings (0 thru 9) /// ////////////////////////////////////////////////////////////////// //the offset of the starting location of each string. //offset[0] is the start of string 0, offset[1] is the start of string 1, etc. const char USB_STRING_DESC_OFFSET[]={0,4,12}; #define USB_STRING_DESC_COUNT sizeof(USB_STRING_DESC_OFFSET) char const USB_STRING_DESC[]={ //string 0 4, //length of string index USB_DESC_STRING_TYPE, //descriptor type 0x03 (STRING) 0x09,0x04, //Microsoft Defined for US-English //string 1 --> la compañia del producto ??? 8, //length of string index USB_DESC_STRING_TYPE, //descriptor type 0x03 (STRING) 'R',0, 'R',0, '2',0, //string 2 --> nombre del dispositivo 22, //length of string index USB_DESC_STRING_TYPE, //descriptor type 0x03 (STRING) 'R',0, 'e',0, 'd',0, 'P',0, 'i',0, 'c',0, ' ',0, 'U',0, 'S',0, 'B',0 }; #ENDIF |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
Extracto de PicUSB.pas |
||
/////////////////////////////////////////////////////////////////////////////////////////////////// // // Ejemplo de comunicaciones PIC <-> PC vía USB 2.0 // // by Redraven http://picmania.garcia-cuervo.net // /////////////////////////////////////////////////////////////////////////////////////////////////// unit PICUSB; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, usbAPI, ExtCtrls, shellapi, ComCtrls, jpeg, Buttons; Const vid_pid : PCHAR = 'vid_04d8&pid_000b'+#0; out_pipe : PCHAR = '\MCHP_EP1' + #0; in_pipe : PCHAR = '\MCHP_EP1' + #0; TOGGLE_LED = $01; GET_FIRMWARE = $02; SEND_STRING_RS232 = $03; UsbBufSize = 32; Type PByteBuffer = ^TByteBuffer; TByteBuffer = Array[0..63] of Byte; PUsbData = ^TUsbData; TUSBData = Record Cmd: Byte; Data: Array[0..UsbBufSize-1] of Byte; End; TVersionInfo = Array[0..3] of Byte; /////////////////////////////////////////////////////////////////////////////////////////////////// // // Funciones de comuniaciones USB // /////////////////////////////////////////////////////////////////////////////////////////////////// function TfrmUsbMonitor.USBCheckInvalidHandle():string; var res: string; Begin if (GetLastError() = ERROR_INVALID_HANDLE) then Begin MPUSBClose(myOutPipe); MPUSBClose(myInPipe); myOutPipe := INVALID_HANDLE_VALUE; myInPipe := INVALID_HANDLE_VALUE; res := 'USB INVALID_HANDLE_VALUE'; End else res := 'Error Code ' + IntToStr(GetLastError()); result := res; End; Function TfrmUsbMonitor.USBSendReceivePacket(SendData: PByteBuffer; SendLength: DWORD; ReceiveData: PByteBuffer; var ReceiveLength: DWORD; SendDelay: Word; ReceiveDelay:Word):DWORD; var SentDataLength: DWORD ; ExpectedReceiveLength: DWORD; Begin ExpectedReceiveLength := ReceiveLength; if(myOutPipe <> INVALID_HANDLE_VALUE) and ( myInPipe <> INVALID_HANDLE_VALUE) then Begin if MPUSBWrite(myOutPipe,SendData,SendLength,@SentDataLength,SendDelay) <> 0 then Begin if(MPUSBRead(myInPipe,ReceiveData,ExpectedReceiveLength,@ReceiveLength,ReceiveDelay)) <> 0 then Begin if (ReceiveLength = ExpectedReceiveLength) Then Begin result:=1; Exit; End else Begin if (ReceiveLength < ExpectedReceiveLength) then begin result:=2; Exit; End; End End else Memo1.Lines.Add(USBCheckInvalidHandle()); end else Memo1.Lines.Add(USBCheckInvalidHandle()); End; result:=0; End; function TfrmUsbMonitor.GetUSBSummary():Integer; Var tempPipe:THandle; count:DWORD; max_Count:DWORD; i:Byte; Begin max_count := MPUSBGetDeviceCount(vid_pid); if(max_count=0) then Begin result:= max_count; Memo1.Lines.add('No device found'); exit; End Else memo1.lines.add(IntToStr(max_Count) + ' device(s) with ' + vid_pid + ' currently attached'); count := 0; For i:=0 to MAX_NUM_MPUSB_DEV-1 Do Begin tempPipe := MPUSBOpen(i,vid_pid,NIL,MP_READ,0); if(tempPipe <> INVALID_HANDLE_VALUE) then Begin memo1.lines.add('Instance Index ' + IntToStr(i)); MPUSBClose(tempPipe); Inc(count); end; if(count = max_count) Then break; end; result:= max_count; End; function TfrmUsbMonitor.GetUSBDriverVersion(): TVersionInfo; var temp:DWORD; VersionInfo: TVersionInfo; begin temp := MPUSBGetDLLVersion(); move(temp,VersionInfo,sizeof(VersionInfo)); result := VersionInfo; end; function TfrmUsbMonitor.GetUSBRequest(Command: byte; ReceiveLength: DWORD; Title: string; Prefix: string): string; Var Selection: DWORD; RecvLength: DWORD; send_buf: TByteBuffer; receive_buf: TByteBuffer; p: array[0..UsbBufSize-1] of char; i: integer; s: string; Begin Selection :=0; myOutPipe := MPUSBOpen(selection,vid_pid, out_pipe, MP_WRITE, 0); myInPipe := MPUSBOpen(selection,vid_pid, in_pipe, MP_READ, 0); If (myOutPipe = INVALID_HANDLE_VALUE) or (myInPipe = INVALID_HANDLE_VALUE) then Begin s := 'USB Failed to open data pipes.'; Exit; End; send_buf[0] := Command; RecvLength := ReceiveLength; if (USBSendReceivePacket(@send_buf,1,@receive_buf,RecvLength,1000,1000) = 1) Then Begin for i:=0 to ReceiveLength do p[i] :=Chr(receive_buf[i]); s := Prefix+strpas(p); End Else s := 'USB Operation Failed : '+Title; MPUSBClose(myOutPipe); MPUSBClose(myInPipe); myOutPipe := INVALID_HANDLE_VALUE; myInPipe := INVALID_HANDLE_VALUE; result := s; end; function TfrmUsbMonitor.SendUSBSimpleCommand(Command: byte; Title: string): string; var selection: DWORD; send_buf: TUsbData; SentDataLength: DWORD; s: string; Begin Selection:=0; myOutPipe := MPUSBOpen(selection, vid_pid, out_pipe, MP_WRITE, 0); if (myOutPipe = INVALID_HANDLE_VALUE) then Begin s := 'USB Failed to open out data pipe'; Exit; End; send_buf.cmd := Command; if MPUSBWrite(myOutPipe,@Send_buf,1,@SentDataLength,1000) <> 0 then Begin if (SentDataLength <> 1) Then s := 'USB Failure on sending : '+Title else s := Title+' : sended Ok' End else s := USBCheckInvalidHandle(); MPUSBClose(myOutPipe); myOutPipe := INVALID_HANDLE_VALUE; result := s; end; function TfrmUsbMonitor.SendUSBParamCommand(Command: byte; Param: string; Title: string): string; var selection: DWORD; send_buf: TUsbData; SentDataLength,CompareSentDataLength: DWORD; tmp: array[0..UsbBufSize-1] of char; i: integer; s: string; Begin Selection:=0; myOutPipe := MPUSBOpen(selection, vid_pid, out_pipe, MP_WRITE, 0); if (myOutPipe = INVALID_HANDLE_VALUE) then Begin s := 'USB Failed to open out data pipe'; Exit; End; send_buf.cmd := Command; StrPCopy(tmp,Param); CompareSentDataLength := Length(Param); for i:=0 to CompareSentDataLength do begin send_buf.Data[i] := ord(tmp[i]); end; if MPUSBWrite(myOutPipe,@Send_buf,CompareSentDataLength+1,@SentDataLength,1000) <> 0 then Begin if (SentDataLength <> CompareSentDataLength+1) Then s := 'USB Failure on sending : '+Title else s := Title+' : sended Ok' End else s := USBCheckInvalidHandle(); MPUSBClose(myOutPipe); myOutPipe := INVALID_HANDLE_VALUE; result := s; end;
|
||
|
Esta es la librería para conectar con la mpusbapi.dll |
usbAPI.pas | ||
//-------------------------------------------------------------------------------- // Interface for Usb-API for PIC 18F4550 Demo board // Author: Gerhard Burger // E-Mail: gCoolfire@yahoo.de // Web: http://members.aon.at/geburger/ // Last Update: 2nd of June 2005 // Version 1.0 // Compiler: Borland Delphi, Version 7.0 // This software is free for non commercial use, for commercial use, please contact // the author // // THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES, // WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED // TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A // PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, // IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR // CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. //--------------------------------------------------------------------------------- Unit UsbAPI; Interface Uses Windows, SysUtils; Const MPUSB_FAIL = 0; MPUSB_SUCCESS = 1; MP_WRITE = 0; MP_READ = 1; MAX_NUM_MPUSB_DEV = 127; // MAX_NUM_MPUSB_DEV is an abstract limitation. // It is very unlikely that a computer system will have more // then 127 USB devices attached to it. (single or multiple USB hosts) Function MPUSBGetDeviceCount(pVID_PID: PCHAR) : DWORD; cdecl; Function MPUSBOpen(instance : DWORD ; pVID_PID :PCHAR; pEP : PCHAR; dwDir : DWORD; dwReserved : DWORD): THANDLE;cdecl; Function MPUSBGetDLLVersion():DWORD;cdecl; // Reads a data package to the USB device // HANDLE: Handle to the device // pData: Pointer to the input buffer // dwDataLen: expected count of bytes to read // dwDataLenRead: actually count read data // waiting time Function MPUSBRead(HANDLE: THANDLE; pData :Pointer; dwDataLen :DWORD; pDataLenRead :PDWORD; dwMilliseconds :DWORD):DWORD; cdecl; // Writes a data package to the USB device // HANDLE: Handle to the device // pData: Pointer to the output buffer // dwDataLen: expected count of bytes to send // dwDataLenSent: actually count of sent data // waiting time Function MPUSBWrite(HANDLE :THANDLE; pData :Pointer; dwDataLen : DWORD; pLengthSent :PDWORD; dwMilliseconds :DWORD):DWORD; cdecl; // see microchip documentation Function MPUSBReadInt(HANDLE :THANDLE; pData :Pointer; dwDataLen : DWORD; pLengthReceive :PDWORD; dwMilliseconds :DWORD):DWORD; cdecl; Function MPUSBClose(HANDLE : THANDLE ): Boolean;cdecl; Implementation Function MPUSBGetDLLVersion; cdecl; external 'MPUSBAPI.Dll' index 1; Function MPUSBGetDeviceCount; cdecl; external 'MPUSBAPI.Dll' index 2; Function MPUSBOpen; cdecl; external 'MPUSBAPI.Dll' index 3; Function MPUSBRead; cdecl; external 'MPUSBAPI.Dll' index 4; Function MPUSBWrite; cdecl; external 'MPUSBAPI.Dll' index 5; Function MPUSBReadInt; cdecl; external 'MPUSBAPI.Dll' index 6; Function MPUSBClose; cdecl; external 'MPUSBAPI.Dll' index 7; end. |
||
|
Y ¿como no? todo esto funcionando correctamente: |
|
|
Recursos, todo lo necesario. |
|
Aquí tenéis todo los
necesario para este proyecto: El Firmware
para el 18F4550, el .hex y el .c para el CCS C,
El Driver USB 2.0 de Microchip para instalar en vuestro Windows
XP y el programa Monitor para conectar
con él, tanto el .exe como los fuentes en Delphi 6.0 (incluidas la
mpusbapidll y la usbAPI.pas para conectar con ella). En el fichero
instalable de Microchip que también incluyo en este zip,
MCHPFSUSB_Setup.EXE, vienen los fuentes completos en Borland C++ Builder
de la mpusbapi.dll y los del driver. |
|
Nota: RRUSB_Complete_zip incluye
también los recursos para los demás métodos de conexión USB descritos en
El USB desencadenado |
|
Enlaces imprescindibles. |
|
|
|
|
Esta página se modificó el 27/12/2008
|