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).

Nota: Si no queréis leer nada sino que por el contrario aplicáis aquel principio que dice "Los read.me son para cobardes ¡Ejecuta!" podéis ir directamente a  Recursos, todo lo necesario.

 

 

 
PIC's, Hardware mínimo y Antecedentes varios.

 
  • Ante todo un reconocimiento explícito al amigo Jaime J1M ya que todo esto que aquí os muestro proviene directamente de su Proyecto PicUSB que tenéis publicado tanto en su página personal HobbyPIC como en el Foro Todopic, en el hilo Proyecto PicUSB Lo descargué, lo implementé y lo hice funcionar correctamente. Así que en el fondo todo el mérito es suyo. Yo me he limitado a adaptarlo a Borland Delphi 6.0 y escribir las explicaciones que vienen a continuación. (Bueno, y algún aliño por aquí o por allá)

  • El hardware específico que he utilizado es el de la RRBOARD2 con el adaptador USB y la placa auxiliar RS232 x 2. Sin embargo ésta última no es necesaria ya que solo la uso para ir monitorizando lo que se recibe o envía por el USB. De todas formas abajo os muestro un esquema del hardware mínimo necesario para hacer funcionar este proyecto:


 

  • Todo lo que aquí se explica es aplicable a la familia de PIC's 18Fxx5x que son los que soportan el USB 2.0 (Documento 39632b.pdf de Microchip dedicado a los 18F2455-2550-4455-4550 de.pdfgar 7.912 Kbytes)

 
Descripción del proyecto.

  • Lo que pretendemos en este proyecto es implementar una comunicación bidireccional masiva, bulk transfers, entre el PIC y el Software del PC vía USB 2.0 a full speed.

  • Vamos a realizar completos ambos extremos de esta línea de comunicación, de una parte el firmware para el PIC en CCS C, y de la otra el software del PC en Borland Delphi 6.0. Como intermediarios vamos a utilizar dos recursos que nos provee Microchip: El Driver para Windows y la dll mpusbapi.dll.

  • Para el firmware  vamos a utilizar como base los ejemplos y descriptores USB que trae como ejemplos el CCS C, adaptándolo a nuestras necesidades, fundamentalmente darles los VID&PID que espera encontrar el driver para Windows y el tamaño máximo del buffer de emisión-recepción del canal USB, mas alguna que otra descripción. Después de esto solo nos quedará definir los comandos que vamos a procesar en él e implementar las funciones que lo realizan efectivamente.

  • De la parte del PC vamos a instalar el Driver para Windows XP que nos ofrece Microchip, que nos va a servir de puente entre nuestro software con el canal USB del PC. Es quien define los VID&PID que vamos a utilizar.

  • Y vamos a construir un programa en Borland Delphi 6.0 que sea capaz de utilizar las funciones de la librería de enlace dinámica, DLL, que distribuye gratuitamente Microchip, la mpusbapi.dll que a su vez es capaz de hablar con el driver anterior.

  • En nuestro software en Delphi vamos a repetir los VID&PID definidos en el Driver y en el Firmware e implementar de forma complementaria los mismos comandos USB que van a ser procesados por el Firmware.

  • Para el software en Delphi disponemos también del unit que nos sirve de puente entre nuestra aplicación y la mpusbapi.dll : usbAPI.pas
  • Con todo ello pretendemos conseguir que enviemos comandos e información al PIC y éste nos conteste oportunamente devolviéndonos lo que corresponda. En nuestro ejemplo vamos a implementar los siguientes comandos y/o funciones:
     
    • Una petición sobre la Versión del Firmware, a la que el PIC nos contestará con una cadena de caracteres con la versión actual que calza.
       
    • Un comando de conmutación del estado de un LED en nuestro Hardware.
       
    • La transferencia hacia el PIC de una cadena de caracteres para que éste los reenvíe por su canal RS232.
       
  • O sea emisión y recepción de comandos simples y con parámetros. Para implementar transferencias masivas de información no hay mas que realizar funciones que iteren el envío y/o recepción de paquetes de 32 bytes cada uno.
 
Firmware, Driver, Software y procedimientos de instalación.

 
  • <> Firmware para el PIC 18Fxx5x realizado en CCS C
  • Este firmware está compilado con el compilador PCH CCS C versión 3.242.
  • Las palabras clave y los puntos de interés de este firmware estan marcados en negrita.
  • El descriptor USB está incluido en el fichero rr2_USB_Monitor.h que aparece marcado en rojo. (Se incluye mas abajo)

#fuses HSPLL y PLL5

La frecuencia de oscilación necesaria para el USB 2.0 es de 48 Mhz. Como estamos utilizando en nuestro hardware un cristal de cuarzo de 20 Mhz necesitamos hacer uso del módulo PLL interno del PIC. Para ello utilizamos el fuse HSPLL. Como el módulo PLL requiere una oscilación de entrada de 4 Mhz debemos utilizar el divisor 1:5 indicado con el fuse PLL5 para obtener los 20:5 = 4 Mhz requeridos. (Para mas detalles consultar Consiguiendo 4 Mhz para los 48 Mhz necesarios en los PIC's con USB 2.0 en esta misma página)

USB_ENABLE_BULK y SIZE 32

Para activar el método de transferencia masiva mediante el USB debemos configurar los EndPoint de transmisión y recepción, USB_EP1_TX_ENABLE y USB_EP1_RX_ENABLE, indicándolo con la constante USB_ENABLE_BULK. Es imprescindible deshabilitar el método HID (Human Interface Device). El tamaño del buffer de transferencia lo podemos ajustar desde 1 a 32 bytes como máximo. Nosotros vamos a establecer el máximo de 32 bytes por envío o recepción de paquetes USB. (Recordad que si se utiliza un dispositivo USB 1.0 Low Speed el máximo tamaño del buffer es de 8 bytes)

#include rr2_USB_Monitor.h

En el fichero rr2_usb_monitor.h, cargado con el correspondiente include, se definen las estructuras y parámetros necesarios para la conexión USB. Se discutirá su contenido un poco mas abajo donde además se muestra su contenido completo.

#define COMMAND_Xxxxx 9

Este programa va a recibir distintos comandos que han de ser ejecutados posteriormente. La convención que vamos a utilizar es la de definir cada comando con un único byte, que enviaremos al principio, seguido de aquellos parámetros que sean necesarios, en caso de utilizarlos. Para este ejemplo en concreto hemos definido tres comandos numerados del 1 al 3:

COMMAND_LED 1 Que ejecutará la función de conmutar el LED_AMARILLO.
COMMAND_FIRMWARE 2 Que ejecutará la función de devolver el contenido de la variable Version[], y
COMMAND_STRING_RS232 3 Que ejecutará la función de devolver por el canal RS232 la cadena de caracteres que reciba por el canal USB.

La implementación efectiva de cada una de estas funciones puede verse en el código dentro del bucle infinito While(true) si y solo si el USB está correctamente "enumerado", resultado true de usb_enumerated() (conectado y activado el canal correspondiente en el master USB del PC) y como respuesta a la recepción de un paquete USB, detectado en el firmware con la función usb_kbhit()

char Version[]="v.1.0";

El contenido de la variable Versión es lo que vamos a enviar como respuesta a la recepción del COMMAND_FIRMWARE.

main()

Las funciones usb_init(), usb_task(), usb_wait_for_enumeration(), usb_enumerated(), usb_kbhit(), usb_get_packet() y usb_put_packet() están desarrolladas en el driver que nos proporciona CCS C para el manejo del USB 2.0 y vienen definidas e implementadas en los includes pic18_usb.h, usb.c y usb.h que podeis encontrar en el directorio ..\Drivers de vuestra inslación de CCS C.

usb_init(), usb_task() y usb_wait_for_enumeration() se utilizan solo para establecer la comunicación y se ejecutan únicamente tras un reset del micro.

Si todo ha sido satisfactorio, y ya dentro del bucle infinito while(true), solo actuaremos si la función usb_enumerated() nos devuelve true, o sea que estamos correctamente conectados y reconocidos por el Windows del PC.

A partir de este punto solo nos queda esperar a recibir un comando proveniente del PC. Esto lo detectamos con usb_kbhit() que al devolvernos true nos indicará que tenemos algo pendiente de recibir. Y los vamos a recoger mediante usb_get_packet() quedando disponible en recbuf.

Para contestar utilizaremos la función usb_put_packet() tal como hacemos al responder al comando COMMAND_FIRMWARE en el que respondemos con usb_put_packet(1, Version, 6, USB_DTS_TOGGLE); enviando el contenido de Version[].

 
 
 
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);
    }
  }
}
 
 

 

 
 
  • El el fichero rr2_USB_Monitor.h vamos a incluir las estructuras y parámetros necesarios para una correcta conexión con el driver del PC.
  • Es un tema absolutamente complejo e inacabable, muy propio de la gente de Microsoft, que debe adaptarse a la estructura que espera recibir el driver del Windows XP. Nosotros vamos a centrarnos únicamente en un par de puntos que generan la mayoría de las consultas que recibo: El concepto del VID&PID y la modificación de la tabla USB_STRING_DESC[].

VID&PID

El VID es un número de 16 bits que significa Vendor Identification o código que identifica al fabricante del hardware a conectar. En nuestro caso utilizamos el número 04D8h que identifica a Microchip.

El PID es un número de 16 bits que significa Product Identification o código que identifica al dispositivo en concreto hardware a conectar. En nuestro caso utilizamos el número 000Bh que identifica a la familia de los PIC18 de este fabricante.

Tened en cuenta que la conjunción de estos dos numeros VID&PID es la que nos va a servir para conectar con el Driver de Windows XP Cuando el S.O. conecte con nuestro firmware recibirá el VID&PID y buscará entre sus drivers instalados para encontrar el que corresponde a esta identificación, si no la encuentra nos preguntará sobre donde ha de buscar un driver adecuado y deberemos indicarle su ubicación. Este driver deberá estar configurado para conectar con un hardware cuyo VID&PID sea el mismo.

USB_STRING_DESC[].

La tabla USB_STRING_DESC contiene la descripción del dispositivo detectado por el Driver de Windows XP y que nos va a mostrar en la correspondiente entrada en la lista del Hardware Instalado en el Sistema.

Consta de dos partes o tablas, la propiamente dicha USB_STRING_DESC que contiene las descripciones requeridas y una tabla accesoria llamada USB_STRING_DESC_OFFSET  que contiene los offset, o desplazamientos con respecto al inicio de USB_STRING_DESC en donde se encuentran las correspondientes cadenas. Ambas constan de tres elementos cada una de ellas.

USB_STRING_DESC_OFFSET  tiene tres números que indican cada uno de ellos donde comienza el correspondiente dato en la tabla USB_STRING_DESC. Así un contenido de {0,4,12} nos dice que que el primer string comienza en el byte 0, el segundo en el byte 4 y el tercero se encuentra a partir del byte número 12. Si cambiamos la longitud de cualquiera de los strings  deberemos reordenar esta tabla correspondientemente con solo contar los caracteres y apuntar en esta tabla el número de byte donde comienza cada uno de ellos.

USB_STRING_DESC contiene los tres strings en concreto que deseamos transmitir con el descriptor USB. Cada uno de ellos tiene la misma estructura que consta de un primer byte que indica la longitud total de la correspondiente cadena, un segundo byte que indica el tipo de dato que viene a continuación y por último tantos bytes como sean necesarios como contenido del string.

El primer dato de esta tabla es:

4, USB_DES_STRING_TYPE, 0x09, 0x04
que puede leerse como 4 : Longitud en bytes del dato incluido él mismo. USB_DES_STRING_TYPE que es una constante cuyo valor e 3 y que dice que lo que sigue es un string. Y 0x09, 0x04 que le indica al Windows que los strings que siguen están escritos en  correcto ingles americano (US-English)

Los dos siguientes datos son los dos strings que definen nuestro dispositivo y cuya estructura es idéntica al caso anterior:

8, USB_DES_STRING_TYPE, 'R', 0, 'R', 0, '2', 0
que define el string el nombre "RR2" de mis Hardware. Total 8 bytes ya que "RR2" se codifica añadiendo un 0x00 tras cada uno de los caracteres.

Y
22, USB_DESC_STRING_TYPE,  'R', 0, 'e', 0, 'd', 0, 'P', 0, 'i', 0, 'c', 0, ' ', 0, 'U', 0, 'S', 0, 'B', 0 que define el nombre de mi dispositivo como "RedPic USB"

 
 
 
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
   
 
 

 

 
 
 
  • Con el Hardware correctamente montado, con su firmware debidamente programado en él y con su cable USB conectando ambos, el PIC y el PC es cuando el Sistema Operativo Windows lo detectará recibiendo su VID&PID y buscará entre sus drivers instalados para encontrar el que corresponde a esa identificación, si no la encuentra nos preguntará sobre donde ha de buscar un driver adecuado y entonces deberemos indicarle su ubicación:

 

 

 

 

 

 

 

 

 
 

De la aplicación .exe solo haceros notar que es fundamental que el VID&PID definido en el mismo debe coincidir exactamente con el del driver de Windows y con el del firmware del PIC. Lo demás es hacer uso de las funciones USB desarrolladas en él. Asimismo los comandos enviados como primer byte de cada paquete USB han de ser los esperados en el firmware para su correcto reconocimiento y su posterior ejecución

 
 
 
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


Esta página usa la letra Ñ

Nota pública importante sobre las consultas al Webmaster de PicManía.


Sugerencias a Picmanía... (que serán leídas pero seguramente no podrán ser contestadas)

Esta página pertenece al grupo de páginas de Diego RedRaven

 

 



Nota: Esta página Web esta repleta de imágenes, textos, logotipos y demás material extraídos de los mas variados medios de los que no soy ni autor ni depositario de los correspondientes derechos de autor, uso y/o reproducción. Si Ud. es depositario de dichos derechos y desea que el material correspondiente sea eliminado de esta Web no dude en ponerse en contacto conmigo mediante e-mail y será inmediatamente retirado. Gracias.
 
Visitas
Totales : 67170 Hoy: 2 Activas: 1 Vistas: 67170

Esta página fue modificada el 07-08-2010 15:42:20

           
 DmSoft WAMP Escribir Unreal