Autor Beitrag
delphimike
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 117



BeitragVerfasst: Di 16.06.09 09:48 
Hallo

ich möchte per USB auf einen PIC 18F4550 Prozessor zugreifen. Über ein Hilfsprogramm in Delphi (Marke Sprut) funktioniert das auch. Sobald ich dieses Programm als Formular in meine Anwendung einbinde passiert merkwürdiges. Die Funktion SendReceivePacket haut mir lokale Variablen in der aufrufenden onclick Prozedur kaputt. Ich kann nur vermuten, daß auf dem Stack irgendetwas schiefläuft und mir die Variablen überschreibt, weil irgendetwas inkompatibel deklariert ist.
Nach 2 intensiven Debuggertagen bis in die Maschinenebene weiß ich nicht mehr weiter. Vielleicht hat jemand eine Idee dazu....

Im vorliegenden Fall hat nach Aufruf die Variable Selection den Wert 34 , das entspricht den gelesenen Datenbytes. Zufall oder Anhaltspunkt? Je nach Variablenkonstellation kann auch die self Variable überschrieben werden.

Nachtrag:
Mir ist aufgefallen, daß die DLL Funktionen ihre Parameter auf den Stack geschrieben bekommen, wie es sein soll, nach der externen Funktion steht der Stackpointer aber noch auf der Position hinter den gepushten Parametern. Es scheint als bereinige die externe Funktion den Stackpointer nicht von den Parametern, was dann zu der Verschiebung der lokalen Variablen führt. Warum das passiert, weiß ich noch nicht.

Hier die aufrufende onclick Prozedur:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
procedure Tusbdlg.Button16Click(Sender: TObject);
  var
   selection   : LONGWORD;
   send_buf    : PBYTE;
   receive_buf : PBYTE;
   RecvLength  : LONGWORD;
   CurrentCMD  : BYTE;
   i,j : integer;
   s: string;
begin
  //instance ist warscheinlich 0, kann aber auch einen anderen Wert haben
  selection:=0;

  //pipes anfordern
  //für die instance=0
  //es kann aber passieren, da´ss instance<>0 !!
  //da ist noch nacharbeit nötig
  For selection:=0 to MAX_NUM_MPUSB_DEV-1 Do
  Begin
    myOutPipe:= _MPUSBOpen(selection,vid_pid,out_pipe,MP_WRITE,0);
    if(myoutpipe <> INVALID_HANDLE_VALUE) then break;
  end;
  myInPipe:=  _MPUSBOpen(selection,vid_pid,out_pipe,MP_READ,0);

  //habe ich pipes bekommen?
  if ((myOutPipe = INVALID_HANDLE_VALUE) or (myInPipe = INVALID_HANDLE_VALUE)) then
  begin
    Memo1.lines.add('USB Error, no pipes');
    exit;
  end;

  //Values

  s:='';
  send_buf[0]:=Read_Block32;    //6
  send_buf[2]:=0; send_buf[3]:=$3C;
  RecvLength:=34;

  if(SendReceivePacket(send_buf,4,receive_buf,RecvLength,100,100) = 1then begin
    if(receive_buf[0] =  READ_Block32) then
      begin
        for i:=0 to 31 do
        begin
          s:=s+intToHex(receive_buf[i+2],2)+' ';
        end;
        Memo1.lines.add(intTostr(selection)+' '+s);
      end;
    end
    else
    begin
      Memo1.lines.add('USB Error');
      exit;
    end;


  _MPUSBClose(myOutPipe);
  _MPUSBClose(myInPipe);
  myInPipe:= INVALID_HANDLE_VALUE;
  myOutPipe:=INVALID_HANDLE_VALUE;

end;


Hier die DLL dazu:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
unit usbdll;

interface

uses
  Windows, Dialogs, Sysutils;

//based on http://www.sixca.com/delphi/article/microchip_usb.html

Const
  MAXSIZE           = 64;
  MPUSB_FAIL        = 0;
  MPUSB_SUCCESS     = 1;
  MP_WRITE:DWORD    = 0;
  MP_READ:DWORD     = 1;
  MAX_NUM_MPUSB_DEV = 127;

  READ_VERSION    = $00;
  // konstanten für bootloader


  READ_FLASH      = $01;
  WRITE_FLASH     = $02;
  ERASE_FLASH     = $03;
  READ_EEDATA     = $04;
  WRITE_EEDATA    = $05;
  READ_CONFIG     = $06;
  WRITE_CONFIG    = $07;

  READ_BLOCK32    = $10;
  READ_16VALUES   = $11;
  WRITE_BLOCK32   = $15;
  ERASE_BLOCK64   = $1F;
  UPDATE_LED      = $32;
  RESET_DEVICE    = $FF;
  //konstanten für 28pin board
  LED_ONOFF       = $31;
  READ_SWITCH     = $32;
  RD_POT          = $37;
  RESET           = $FF;



type
  DWORD  = LongWORD;
  PCHAR8 = array[0..MAXSIZE] of char;
  PBYTE  = array[0..MAXSIZE] of BYTE;
  PDWORD = array[0..MAXSIZE] of DWORD;
  PVOID  = Pointer;
  UINT   = Cardinal;


var
  vid_pid     : PCHAR8 = 'vid_04d8&pid_000c';
  out_pipe    : PCHAR8 = '\MCHP_EP1';
  in_pipe     : PCHAR8 = '\MCHP_EP1';
  myOutPipe   : THANDLE;
  myInPipe    : THANDLE;
  isConnected : boolean;


// Version der mpusbapi.dll auslesen
function _MPUSBGetDLLVersion():DWORD;
             stdcall;external 'mpusbapi.dll';

// Anzahl der zu vid&pid passenden USB-Devices
function _MPUSBGetDeviceCount(pVID_PID:PCHAR8):DWORD;
             stdcall;external 'mpusbapi.dll';

function _MPUSBOpen(instance:DWORD;pVID_PID:PCHAR8;
             pEP:PCHAR8;dwDir:DWORD;dwReserved:DWORD):
             THANDLE;stdcall;external 'mpusbapi.dll';

function _MPUSBClose(handle:THANDLE):DWORD;
             stdcall;external 'mpusbapi.dll';

function _MPUSBRead(handle:THANDLE;var pData:PBYTE;
             dwLen:LONGWORD;var pLength:LONGWORD;
             dwMilliseconds:LONGWORD):LONGWORD;stdcall;
             external 'mpusbapi.dll';

function _MPUSBReadInt(handle:THANDLE;
             var pData:PBYTE;dwLen:DWORD;
             var pLength:PDWORD;
             dwMilliseconds:DWORD):DWORD;
             stdcall;external 'mpusbapi.dll';

function _MPUSBWrite(handle:THANDLE;pData:PBYTE;
             dwLen:LONGWORD;
             var pLength:LONGWORD;
             dwMilliseconds:LONGWORD):LONGWORD;
             stdcall;external 'mpusbapi.dll';

function SendReceivePacket(SendData:PBYTE;SendLength:LONGWORD;var ReceiveData:PBYTE;
         var ReceiveLength:LONGWORD;SendDelay:LONGWORD;ReceiveDelay:LONGWORD):LONGWORD; stdcall;

implementation


procedure CheckInvalidHandle();
begin
  if(GetLastError=ERROR_INVALID_HANDLE) then
  begin
        _MPUSBClose(myOutPipe);
        _MPUSBClose(myInPipe);

        myInPipe:=INVALID_HANDLE_VALUE;
        myOutPipe:=INVALID_HANDLE_VALUE;
  end
  else
    ShowMessage('Error Code :'+inttostr(GetLastError()));
end;



function SendReceivePacket(SendData:PBYTE;SendLength:LONGWORD;var ReceiveData:PBYTE;
         var ReceiveLength:LONGWORD;SendDelay:LONGWORD;ReceiveDelay:LONGWORD):LONGWORD; stdcall;
var
  SentDataLength:LONGWORD ;
  ExpectedReceiveLength:LONGWORD;

begin
  result:=100;
  ExpectedReceiveLength:= ReceiveLength;

  if((myOutPipe <> INVALID_HANDLE_VALUE) and (myInPipe <> INVALID_HANDLE_VALUE)) then begin
    if(_MPUSBWrite(myOutPipe,SendData,SendLength,SentDataLength,SendDelay)<>0then
    if(_MPUSBRead(myInPipe,ReceiveData,ExpectedReceiveLength,Receivelength,ReceiveDelay)<>0)then begin
      if(ReceiveLength = ExpectedReceiveLength) then begin
        Result:=1// Success
        exit;
      end else
      if(ReceiveLength < ExpectedReceiveLength) then begin
        Result:=2// incorrect receive length
        exit;
      end
    end else
    CheckInvalidHandle()
    else
    CheckInvalidHandle()
  end else begin
    Result:=0// Failed
  end;
end;
initialization
end.


Die Deklarationen der DLL in C lauten hierzu

ausblenden C#-Quelltext
1:
2:
3:
DWORD MPUSBWrite (HANDLE handle, PVOID pData, DWORD dwLen, PDWORD pLength, DWORD dwMilliseconds)

DWORD MPUSBRead (HANDLE handle, PVOID pData, DWORD dwLen, PDWORD pLength, DWORD dwMilliseconds)

_________________
kaum macht man was richtig, schon gehts!
delphimike Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 117



BeitragVerfasst: Di 16.06.09 13:27 
Habs selbst gelöst

Hier die Lösung für die Nachwelt:

wie oben im Nachtrag erwähnt korrigiert die DLL Software des PICs nicht den Stack

Ein Prozeduraufruf erfolgt normalerweise so

PUSH PARAMETER1
PUSH PARAMETER2
CALL PROC

und endet dann mit

RET $8

um 8 bytes Stackparameter wegzuräumen

die PIC DLL endet mit einem schlichten RET

Mein Beispielcode korrigiert den Stackpointer:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
function SendReceivePacket(SendData:PBYTE;SendLength:LONGWORD;var ReceiveData:PBYTE;
         var ReceiveLength:LONGWORD;SendDelay:LONGWORD;ReceiveDelay:LONGWORD):LONGWORD; stdcall;
var
  SentDataLength:LONGWORD ;
  ExpectedReceiveLength:LONGWORD;
  r:LongWord;

begin
  result:=100;
  ExpectedReceiveLength:= ReceiveLength;


  if((myOutPipe <> INVALID_HANDLE_VALUE) and (myInPipe <> INVALID_HANDLE_VALUE)) then
  begin
    r:=_MPUSBWrite(myOutPipe,SendData,SendLength,SentDataLength,SendDelay);
    asm
      add esp,20
    end;
    if r<>0 then
    begin
      r:=_MPUSBRead(myInPipe,ReceiveData,ExpectedReceiveLength,Receivelength,ReceiveDelay);
      asm
        add esp,20
      end;
      if r<>0 then
      begin
        if(ReceiveLength = ExpectedReceiveLength) then
        begin
          Result:=1// Success
          exit;
        end
        else
        if(ReceiveLength < ExpectedReceiveLength) then
        begin
          Result:=2// incorrect receive length
          exit;
        end
      end
      else
      CheckInvalidHandle()
    end
    else
    CheckInvalidHandle()
  end else
  begin
    Result:=0// Failed  }
  end;
end;


vielleicht gibts elegantere Lösungen oder Einstellungen die das wiedergutmachen, was auf dem Stack geschieht, aber so funktionierts.

_________________
kaum macht man was richtig, schon gehts!