Autor Tema: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi  (Leído 28824 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *****
  • Mensajes: 5388
    • Picmania by Redraven
La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« en: 12 de Agosto de 2006, 21:48:19 »
Microchip tiene 6 micros de la familia 18F con implementación del USB 2.0. Estos son los 18F2450, 18F2455, 18F2550, 18F4450, 18F4455 y 18F4550.

Para comunicarnos con ellos desde nuestro PC haciendo uso de dicho USB 2.0 sobre una plataforma Windows los amables señores de Microchip ponen a nuestra disposición un DLL específica llamada mpusbapi.dll.

Esta DLL puede ser llamada desde Visual Basic, Visual C++, C Builder o como es nuestro caso desde Delphi. Este hilo está destinado a dar una idea básica de como hacerlo (sin meternos en jardines de los que no sepamos salir después)

Primero. Antes que nada necesitamos la dichosa DLL. La podéis descargar desde la Web de Microchip o al final de este post incluida en el proyecto Delphi de pruebas que vamos a construir.

Segundo. Necesitamos una API que podamos incluir en nuestro proyecto y que sepa cómo llamar a la funciones de mpusbapi.dll para inicializar el puerto USB, enviar y recibir los datos entre nuestro programa y el PIC.

Esta API la vamos a llamar  usbAPI.pas y su contenido es:

Código: Delphi
  1. Unit UsbAPI;
  2. Interface
  3. Uses Windows, SysUtils;
  4.  
  5. Const MPUSB_FAIL                 = 0;
  6.       MPUSB_SUCCESS              = 1;
  7.       MP_WRITE                   = 0;
  8.       MP_READ                    = 1;
  9.       MAX_NUM_MPUSB_DEV          = 127;
  10.  
  11. // MAX_NUM_MPUSB_DEV is an abstract limitation.
  12. // It is very unlikely that a computer system will have more
  13. // then 127 USB devices attached to it. (single or multiple USB hosts)
  14.  
  15. Function MPUSBGetDeviceCount(pVID_PID: PCHAR) : DWORD; cdecl;
  16.  
  17. Function MPUSBOpen(instance : DWORD ; pVID_PID :PCHAR; pEP : PCHAR;
  18.                    dwDir : DWORD; dwReserved : DWORD): THANDLE;cdecl;
  19.  
  20. Function MPUSBGetDLLVersion():DWORD;cdecl;
  21.  
  22. // Reads a data package to the USB device
  23. // HANDLE: Handle to the device
  24. // pData: Pointer to the input buffer
  25. // dwDataLen: expected count of bytes to read
  26. // dwDataLenRead: actually count read data
  27. // waiting time
  28. Function MPUSBRead(HANDLE: THANDLE; pData :Pointer; dwDataLen :DWORD;
  29.                    pDataLenRead :PDWORD;  dwMilliseconds :DWORD):DWORD; cdecl;
  30.  
  31. // Writes a data package to the USB device
  32. // HANDLE: Handle to the device
  33. // pData: Pointer to the output buffer
  34. // dwDataLen: expected count of bytes to send
  35. // dwDataLenSent: actually count of sent data
  36. // waiting time
  37. Function MPUSBWrite(HANDLE :THANDLE; pData :Pointer; dwDataLen : DWORD;
  38.                     pLengthSent :PDWORD; dwMilliseconds :DWORD):DWORD; cdecl;
  39.  
  40. // see microchip documentation
  41. Function MPUSBReadInt(HANDLE :THANDLE; pData :Pointer; dwDataLen : DWORD;
  42.                       pLengthReceive :PDWORD; dwMilliseconds :DWORD):DWORD; cdecl;
  43.  
  44. Function MPUSBClose(HANDLE : THANDLE ): Boolean;cdecl;
  45.  
  46. Implementation
  47.  
  48. Function MPUSBGetDLLVersion;     cdecl; external  'MPUSBAPI.Dll' index 1;
  49. Function MPUSBGetDeviceCount;    cdecl; external  'MPUSBAPI.Dll' index 2;
  50. Function MPUSBOpen;              cdecl; external  'MPUSBAPI.Dll' index 3;
  51. Function MPUSBRead;              cdecl; external  'MPUSBAPI.Dll' index 4;
  52. Function MPUSBWrite;             cdecl; external  'MPUSBAPI.Dll' index 5;
  53. Function MPUSBReadInt;           cdecl; external  'MPUSBAPI.Dll' index 6;
  54. Function MPUSBClose;             cdecl; external  'MPUSBAPI.Dll' index 7;
  55.  
  56. end.
  57.  

y Tercero. Unos ejemplos concretos de como comunicar nuestro programa con la usbAPI.pas que a su vez realice las llamadas a la mpusbapi.dll.

Para que nos responda el PIC hemos debido previamente programarlo con el Firmware desarrollado en el Proyecto PicUSB del maestro J1M.
 
En la sección interface de nuestro programa debemos incluir unas cuantas definiciones:

Código: Delphi
  1. Const
  2.      vid_pid  : PCHAR  = 'vid_04d8&pid_0011'+#0;
  3.      out_pipe : PCHAR = '\MCHP_EP1' + #0;
  4.      in_pipe  : PCHAR = '\MCHP_EP1' + #0;
  5.  
  6.      DO_SUMMA = $00;
  7.      SET_LED  = $01;
  8.  
  9.      UsbBufSize = 64;
  10.  

El vid_pid es el que Jaime ha incluido tanto en dicho firmware como en el driver necesario para su conexión.
Las constantes DO_SUMMA y SET_LED son los comandos a los que va a responder dicho firmware y cuya paternidad también es achacable al amigo Jaime.

También dedemos definir unos cuantos Types necesarios para utilizarlos como parámetros en las llamadas a la DLL:

Código: Delphi
  1. Type
  2.      PByteBuffer = ^TByteBuffer;
  3.      TByteBuffer = Array[0..63] of Byte;
  4.      PUsbData = ^TUsbData;
  5.      TUSBData = Record
  6.         Cmd: Byte;
  7.         Data : Array[0..UsbBufSize-1] of Byte;
  8.      End;
  9.  

Y en el public vamos a declarar las variables y funciones que vamos a manejar en nuestros ejemplos:

Código: Delphi
  1.   public
  2.     myOutPipe: THANDLE;
  3.     myInPipe: THANDLE;
  4.     Function GetSummary():Integer;
  5.     Function SendReceivePacket(SendData: PByteBuffer;
  6.                                SendLength: DWORD;
  7.                                ReceiveData: PByteBuffer;
  8.                                var ReceiveLength: DWORD;
  9.                                SendDelay: Word;
  10.                                ReceiveDelay:Word):DWORD;
  11.     Procedure CheckInvalidHandle();
  12.  

Las tres funciones aquí declaradas tienen el siguiente aspecto:

Código: Delphi
  1. // Funciones de comuniaciones USB /////////////////////////////////////////////////////////////////
  2.  
  3. function TfrmUsbTest.GetSummary():Integer;
  4. Var
  5.    tempPipe:THandle;
  6.    count:DWORD;
  7.    max_Count:DWORD;
  8.    i:Byte;
  9. Begin
  10.      tempPipe := INVALID_HANDLE_VALUE;
  11.      count:=0;
  12.      max_count := MPUSBGetDeviceCount(vid_pid);
  13.      if(max_count=0) then
  14.      Begin
  15.           result:= max_count;
  16.           Memo1.Lines.add('No device found');
  17.           exit;
  18.      End
  19.      Else
  20.          memo1.lines.add(IntToStr(max_Count) + ' device(s) with ' + vid_pid  +  ' currently attached');
  21.      count := 0;
  22.      For i:=0 to MAX_NUM_MPUSB_DEV-1 Do
  23.      Begin
  24.           tempPipe := MPUSBOpen(i,vid_pid,NIL,MP_READ,0);
  25.           if(tempPipe <> INVALID_HANDLE_VALUE) then
  26.           Begin
  27.                memo1.lines.add('Instance Index ' + IntToStr(i));
  28.                MPUSBClose(tempPipe);
  29.                Inc(count);
  30.           end;
  31.           if(count = max_count) Then break;
  32.      end;
  33.      result:= max_count;
  34. End;
  35.  
  36. Function TfrmUsbTest.SendReceivePacket(SendData: PByteBuffer;
  37.                                        SendLength: DWORD;
  38.                                        ReceiveData: PByteBuffer;
  39.                                        var ReceiveLength: DWORD;
  40.                                        SendDelay: Word;
  41.                                        ReceiveDelay:Word):DWORD;
  42. var
  43.    SentDataLength:  DWORD ;
  44.    ExpectedReceiveLength: DWORD;
  45. Begin
  46.      ExpectedReceiveLength := ReceiveLength;
  47.      if(myOutPipe <> INVALID_HANDLE_VALUE) and ( myInPipe <> INVALID_HANDLE_VALUE) then
  48.      Begin
  49.           if MPUSBWrite(myOutPipe,SendData,SendLength,@SentDataLength,SendDelay) <> 0 then
  50.           Begin
  51.                if(MPUSBRead(myInPipe,ReceiveData, ExpectedReceiveLength,@ReceiveLength,ReceiveDelay)) <> 0 then
  52.                Begin
  53.                     if (ReceiveLength = ExpectedReceiveLength) Then
  54.                     Begin
  55.                          result:=1;
  56.                          Exit;
  57.                     End
  58.                     else
  59.                     Begin
  60.                          if (ReceiveLength < ExpectedReceiveLength) then
  61.                          begin
  62.                               result:=2;
  63.                          End;
  64.                     End
  65.                End
  66.                else
  67.                CheckInvalidHandle();
  68.           End
  69.           else
  70.               CheckInvalidHandle();
  71.      End;
  72.      result:=0;
  73. End;
  74.  
  75. Procedure TfrmUsbTest.CheckInvalidHandle();
  76. Begin
  77.   if (GetLastError() = ERROR_INVALID_HANDLE) then
  78.   Begin
  79.     MPUSBClose(myOutPipe);
  80.     MPUSBClose(myInPipe);
  81.     myOutPipe := INVALID_HANDLE_VALUE;
  82.     myInPipe  := INVALID_HANDLE_VALUE;
  83.   End
  84.   else
  85.     Memo1.lines.Add('Error Code ' + IntToStr(GetLastError()));
  86. End;
  87.  

Primer ejemplo: Preguntarle a mpusbapi.dll su propia versión :

Código: Delphi
  1. procedure TfrmUsbTest.btnGetUSBDriverVersionClick(Sender: TObject);
  2. var
  3.    temp:DWORD;
  4.    versionInfo : Array[0..3] of Byte;
  5. begin
  6.   temp := MPUSBGetDLLVersion();
  7.   move(temp,VersionInfo,sizeof(VersionInfo));
  8.   memo1.text:='USB Driver Version ' + intTOStr(VersionInfo[0]) +  '.' +
  9.                                                    intTOStr(VersionInfo[1]) +  '.' +
  10.                                                    intTOStr(VersionInfo[2]) +  '.' +
  11.                                                    intTOStr(VersionInfo[3]);
  12. end;
  13.  

Segundo Ejemplo : Enviar dos bytes siendo el primero el comando "Led" y el segundo el led que queremos que encienda o apague.

Código: Delphi
  1. procedure TfrmUsbTest.chkSwitchLedClick(Sender: TObject);
  2. var
  3.    selection: DWORD;
  4.    send_buf: TUsbData;
  5.    SentDataLength: DWORD;
  6. Begin
  7.   Selection:=0;
  8.   myOutPipe := MPUSBOpen(selection, vid_pid, out_pipe, MP_WRITE, 0);
  9.   if (myOutPipe = INVALID_HANDLE_VALUE) then
  10.   Begin
  11.     if (myOutPipe = INVALID_HANDLE_VALUE) then memo1.lines.add('Failed to open out data pipe');
  12.     Exit; //USB Operation Failed
  13.   End;
  14.   send_buf.Cmd := SET_LED;
  15.   if RadioButton1.Checked then send_buf.Data[0]:=0;
  16.   if RadioButton2.Checked then send_buf.Data[0]:=1;
  17.   if RadioButton3.Checked then send_buf.Data[0]:=2;
  18.   if MPUSBWrite(myOutPipe,@Send_buf,2,@SentDataLength,1000) <> 0 then
  19.   Begin
  20.     if (SentDataLength <> 2) Then
  21.       memo1.lines.Add('Failure on sending command LED')
  22.     else
  23.       memo1.lines.Add('Command LED sended Ok')
  24.   End
  25.   else
  26.     CheckInvalidHandle();
  27.   MPUSBClose(myOutPipe);
  28.   myOutPipe := INVALID_HANDLE_VALUE;
  29. end;
  30.  

Tercer Ejemplo: Enviar tres bytes siendo el primero el comando "Suma" y los dos dos siguientes los numeros a sumar, tras ello esperamos a recibir un byte con el resultado de la suma:

Código: Delphi
  1. procedure TfrmUsbTest.BtnSumaClick(Sender: TObject);
  2. Var
  3.    Selection: DWORD;
  4.    RecvLength: DWORD;
  5.    send_buf: TByteBuffer;
  6.    receive_buf:TByteBuffer;
  7. Begin
  8.     Selection:=0;
  9.     myOutPipe := MPUSBOpen(selection,vid_pid, out_pipe, MP_WRITE, 0);
  10.     myInPipe  := MPUSBOpen(selection,vid_pid, in_pipe,  MP_READ,  0);
  11.     If (myOutPipe = INVALID_HANDLE_VALUE) or (myInPipe = INVALID_HANDLE_VALUE) then
  12.     Begin
  13.       memo1.lines.add('Failed to open data pipes.');
  14.       Exit;
  15.     End;
  16.     send_buf[0] := DO_SUMMA;
  17.     send_buf[1]:=StrToInt(Edit1.Text);
  18.     send_buf[2]:=StrToInt(Edit2.Text);
  19.     RecvLength := 1;
  20.     if (SendReceivePacket(@send_buf,3,@receive_buf,RecvLength,1000,1000) = 1) Then
  21.     Begin
  22.          edit3.Text := IntToStr(receive_buf[0]);
  23.          Memo1.lines.add('Suma '+Edit1.Text+' + '+Edit2.Text+' = '+Edit3.Text);
  24.     End
  25.     Else
  26.       Memo1.lines.add('USB Operation Failed');
  27.     MPUSBClose(myOutPipe);
  28.     MPUSBClose(myInPipe);
  29.     myOutPipe := INVALID_HANDLE_VALUE;
  30.     myInPipe := INVALID_HANDLE_VALUE;
  31. end;
  32.  

Compilado y ejecutado este código nos muestra el siguiente resultado :



Aqui teneis el proyecto PicUSBDelphi completo para Descargar

« Última modificación: 13 de Agosto de 2006, 08:04:22 por RedPic »
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado Rulo

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 164
Re: La mpusbapi.dll desencadenada, PC <-> PIC vía USB en Delphi
« Respuesta #1 en: 13 de Agosto de 2006, 00:57:58 »
Exelente Master, ya esperaba algo asi.

                Saludos

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 17482
    • MicroPIC
Re: La mpusbapi.dll desencadenada, PC <-> PIC vía USB en Delphi
« Respuesta #2 en: 13 de Agosto de 2006, 03:11:31 »
¡¡¡ ATENCIÓN, PELIGRO !!!, DIEGO HA DESCUBIERTO EL USB.

Que tiemblen los bits, los bytes y los words porque empezarán a viajar como nunca por ese cable de 4 hilos conformando la base de magníficos tutoriales.
Un saludo desde Sevilla, España.
Visita MicroPIC                                                                                        ɔ!doɹɔ!ɯ ɐʇ!s!ʌ

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *****
  • Mensajes: 5388
    • Picmania by Redraven
Re: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« Respuesta #3 en: 13 de Agosto de 2006, 06:25:11 »
Ja, ja ja  :D  :D  :D hace tiempo, Manolo, que le tenía ganas al USB pero entre pitos y flautas no le había metido mano .... y ahora ya estoy to'l día dándole vueltas a la perola para sacarle jugo ...

el cognazo es que cualquier aplicación que pueda darle pasa por tener abiertos los dos IDE's, el de CCS y el de Delphi, para avanzar en paralelo between both.

Y despues de la paliza del Analizador lógico me cuesta trabajo empezar con cosas a dos bandas:

Con diez procedures por banda
y un Pentium IV a toda vela
no programa APIS sino vuela
un delphi programil
entorno pirata que llaman
por sus VCL el Intrepído
en todo IDE conocido
del uno al otro confin.


ja ja ja  :D  :D  :D

Adaptación libre de la primera estrofa
de la Canción del pirata
de don José de Espronceda.


« Última modificación: 13 de Agosto de 2006, 09:10:43 por RedPic »
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *****
  • Mensajes: 5388
    • Picmania by Redraven
Re: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« Respuesta #4 en: 13 de Agosto de 2006, 16:17:34 »
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado JulianA

  • PIC10
  • *
  • Mensajes: 6
Re: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« Respuesta #5 en: 13 de Agosto de 2006, 21:59:12 »
Gracias, redundantes también por quí, RedPIC.   :-/ :-/

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *****
  • Mensajes: 5388
    • Picmania by Redraven
Re: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« Respuesta #6 en: 17 de Agosto de 2006, 18:03:48 »
¡¡¡ Esto del USB es la leche !!!

Hardware :



Software :



Monitor debug :



Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado xocas

  • Administrador
  • PIC24H
  • *******
  • Mensajes: 2094
Re: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« Respuesta #7 en: 18 de Agosto de 2006, 09:05:01 »
Amigo RedPic, ya necesitas una mesa mas grande...

Desconectado elmasvital

  • Administrador
  • PIC24H
  • *******
  • Mensajes: 1713
Re: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« Respuesta #8 en: 20 de Agosto de 2006, 19:07:45 »
eres incombustible redpic... cuanto han cambiado las cosas desde que nos vimos en la kedada de sevilla. En la proxima serás tu el que lleve más cacharros a la kedada.

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *****
  • Mensajes: 5388
    • Picmania by Redraven
Re: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« Respuesta #9 en: 21 de Agosto de 2006, 01:27:31 »
Ja, ja, ja  :D :D :D

Jose antonio, el domingo 13 de Noviembre de 2005 tosté mi primer PIC, un 16F628A programado en PicBasic Pro intentando usar la RS232 ... no lo logré y buscando en Internet encontré este Foro. Gio LorLafebre fue mi primer mentor y con su ayuda hice que el 628 y mi PC se hablasen .... así  hasta hoy, 8 meses y 8 días mas tarde.

En la proxima quedada llevaré algunos modulos más, en la primera solo pude llevar uno que calzaba un Atmel, pero voy a llevar sobre todo a todos ustedes conmigo, sin ustedes no hubiese sido nada.

Gracias.
   
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *****
  • Mensajes: 5388
    • Picmania by Redraven
Re: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« Respuesta #10 en: 10 de Septiembre de 2006, 14:46:17 »
¡Dios santo! Me ha salido una verdadera novela ... pero creo que merece la pena.  :mrgreen:

El USB desencadenado : El Bulk USB

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado samshiel_pic

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 773
    • Electrónica·Ingenia
Re: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« Respuesta #11 en: 10 de Septiembre de 2006, 17:24:17 »
Bueno pues que le vamos ha hacer a leer la novela jejeje  :D :D

Aunque su autor no es muy dado a las novelas de intriga, le van mas las historicas romanticonas  jejejeje :D :D :D

Desconectado maunix

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4751
    • Mi Sitio Web Personal
Re: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« Respuesta #12 en: 11 de Septiembre de 2006, 11:14:21 »
¡Dios santo! Me ha salido una verdadera novela ... pero creo que merece la pena.  :mrgreen:

El USB desencadenado : El Bulk USB



Diego, te felicito!  Menudo tutorial!!!!

Espero algún día tener tiempito para echarle un ojo como se debe al tema este :) y de seguro que será visitando tu página.

- La soberbia de un Einstein es entendible.. la de un salame es intolerable (A.Dolina)
- En teoría no hay diferencia entre la teoría y la práctica. En la práctica... si la hay.
- Lee, Lee, Lee y luego pregunta.(maunix)
- Las que conducen y arrastran al mundo no son las máquinas, sino las ideas (V. Hugo)
- Todos los hombres se parecen por sus palabras; solamente las obras evidencian que no son iguales.(Moliere)
- Todo debería ser hecho tan simple como sea posible pero no mas simple que eso.(A.Einstein)

Desconectado PalitroqueZ

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5425
    • Electrónica Didacta
Re: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« Respuesta #13 en: 19 de Febrero de 2007, 12:49:58 »
Hola Diego.

sabes que estoy viendo las apis disponibles para mpusbapi.dll y practicando con la fácil, que es la de preguntar la versión, MPUSBGetDLLVersion debe dar el resultado en hexa.

hice un ensayo en VB y me dice 10000, creo que se refiere a que es la versión 1.0000 si clico en propiedades de la .dll me dice: "Versión del producto = Versión del archivo = 1.0.0.0

pero viendo el ejemplo tuyo PicUSBDelphi.exe arroja la versión: USB Driver Version 0.0.1.0

entonces estoy confundido allí ¿porqué hay 2 ceros delante del 1?

viendo el código fuente de la libreria _mpusbapi.cpp y la constante es:

#define MPUSBAPI_VERSION            0x00010000L

entonces ¿como es el formato para decir la versión de la .dll?

Salu2
Pedro
La propiedad privada es la mayor garantía de libertad.
Friedrich August von Hayek

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *****
  • Mensajes: 5388
    • Picmania by Redraven
Re: La mpusbapi.dll desencadenada: PC <-> PIC vía USB en Delphi
« Respuesta #14 en: 19 de Febrero de 2007, 15:33:59 »
Me encanta que me haga esa pregunta  :mrgreen:

No me había dado cuenta de eso. Investigaré a ver si veo quien es el gira-números. Podria ser la diferencia que hay entre los punteros a parámetros en las DLL que hay entre C++ estandar y Delphi ... pero no lo tengo claro.

Veré.  :o
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania


 

anything