Änderung USBSMart auf großen USB Treiber

  • 1
  • 2
  • Page 1 of 2
pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Änderung USBSMart auf großen USB Treiber

 · 
Posted: 07.09.2022 - 18:05  ·  #1
Hallo,

bei dem USBSMart musste man mit einem Task sicherstelle, das USB_ControlJob schnell und regelmäßig ausgeführt wird.

Code

Task ControlJob(iData, resumed);
begin
// USB
  USB_ControlJob;
end;


Muss ich bei dem Großen USB-Treiber auch sowas beachten?

Thorsten
miparo
Administrator
Avatar
Gender:
Location: Germany
Age: 59
Posts: 956
Registered: 09 / 2007
Subject:

Re: Änderung USBSMart auf großen USB Treiber

 · 
Posted: 07.09.2022 - 19:18  ·  #2
Hi Thorsten,
nein , der große USB braucht das nicht.

Am besten mal das Sample unter Demos anschauen.

miparo
pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Re: Änderung USBSMart auf großen USB Treiber

 · 
Posted: 07.09.2022 - 19:32  ·  #3
Quote by miparo

Hi Thorsten,
nein , der große USB braucht das nicht.

Am besten mal das Sample unter Demos anschauen.

miparo


Hallo Miparo,

ich habe irgendwie ein Timing-Problem innerhalb einer Process/Task Umgebung.
Wenn ich die anderen Funktionen (Prozesse / Tasks) rausnehme und die USB-Funktion in den Main lege geht es, deswegen diese Frage.

Gruß
Thorsten
miparo
Administrator
Avatar
Gender:
Location: Germany
Age: 59
Posts: 956
Registered: 09 / 2007
Subject:

Re: Änderung USBSMart auf großen USB Treiber

 · 
Posted: 07.09.2022 - 19:56  ·  #4
Du kannst den ja in die Main Proc legen aber USB_ControlJob; muss < 50ms zum Zuge kommen
ansonsten stürzt die USB Verbindung ab.
USB_ControlJob macht aber im Leerlauf kaum was, was bei deinen Geräten ja normal der Fall ist ?
pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Re: Änderung USBSMart auf großen USB Treiber

 · 
Posted: 08.09.2022 - 20:53  ·  #5
Quote by miparo

Du kannst den ja in die Main Proc legen aber USB_ControlJob; muss < 50ms zum Zuge kommen
ansonsten stürzt die USB Verbindung ab.
USB_ControlJob macht aber im Leerlauf kaum was, was bei deinen Geräten ja normal der Fall ist ?


Hallo miparo,

ich dachte der Große USB-Treiber braucht das nicht mit dem "USB_ControlJob" ?
Erzeugt der Treiber einen eigenen Task/Process für die Aufrechterhaltung der Verbindung?
Oder ist die Funktion "xUSB_Attach" dies? DIes wird ja in Deinem Demo regelmäßig im Loop aufgerufen. Im Handbuch finde ich dazu leider nichts.

Code
    xUSB_RXsetBuffer(1, @USB_Rx_Receive, @RXbuf, 512);   // Link RX Event 

Hier lege ich ja die CallBack Funktion für den Empfang der Daten an. Muss ich die bei jedem neuen UsbDriverConnect erneut aufrufen?
Ich denke eigentlich nicht.

Vom Ablauf her würde ich das so verstehen:
1. xUSB_UserVendorRequest(@xUSB_VendorRequest); // Callback für die Request's

2. xUSB_Enable; // Einschalten der USB Funktionen

3. xUSB_Attach // wie oft muss der aufgerufen werden? auch 50ms? Bei einem USB DriverConnect wird er ja erstmal nicht mehr aufgerufen. Wahrscheinlich ist dies einfach nur ein Check ob ein PC angeschlossen wurde.

4. xUSB_RXsetBuffer(1, @USB_Rx_Receive, @RXbuf, 512); // CallBack für den Empfangsbuffer

5. Bei Datenempfang Im Callback den Empfangsbuffer umkopieren. Die Verarbeitung der kopierten Daten könnte ja dann in einen anderen Process verarbeitet werden.

6. Wenn der "NOT UsbDriverConnect" ist, dann wird ein "xUSB_Detach" ausgeführt.

7. erneut im loop regelmäßig "xUSB_Attach" aufrufen, also wieder an Punkt 3

Habe ich das so richtig verstanden?

Wenn ja, muss ja der xUSB_Attach nur aufgerufen werden, wenn UsbDriverConnect=FALSE ist. Dies könnte man ohne Probleme im Main-Zyklus reinlegen.

In Deinen Demo ist der CallBack:
Code
{ functions } 
procedure USB_Rx_Receive(Status: tUSBep_Status; nb_transfered: word); 
var
  ch                     : char; 
begin
  //Writeln(SerOutC0, 'recv:' + IntToStr(nb_transfered)); 
  if Status = USBEP_TRANSFER_OK then 
    usbRXCount:= nb_transfered; 
    USBdataAvail:= true; 
  else 
    usbRXCount:= 0; 
    USBdataAvail:= true; 
  endif; 
end; 


Hier wird ja nur deer Bool gesetzt das Daten vorhanden sind.

Code
procedure MainLoop; 
var
  ch   : char; 
  bb   : byte; 
  bool : boolean; 
begin
  repeat
    if USBdataAvail then 
      HostCmd:= RxCmd; 
      ch:= HostCmd.cmd; 
      case HostCmd.typ of 
        CTRLcmd: 
                 // here your comands from PC are received 
                 case ch of 
                   'C': // check sd card present 
                        bb:= byte(CheckMMC); 
                        if bb = 0 then 
                          TxByte($FF); // ok 
                        else 
                          TxByte($00); // fail 
                        endif; 
                      |
                   'L':  // upload file list to pc 
                        UploadFilesDirs(); 
                      |
                 endcase; 
               |
      else 
        Writeln(SerOutC0, 'Unknown cmd'); 
        TXchar('?'); 
      endcase; 
    endif; 
  until (not UsbDriverConnect) {or (not USBvBUS.USBvBUSpin)} ; 
end; 


Im Mainloop bleibst Du ja so lange drinnen bis der USBDriverConnect FALSE ist. Dort verarbeitest Du dann die Daten wenn der "USBdataAvail:= true" ist.

Thorsten
miparo
Administrator
Avatar
Gender:
Location: Germany
Age: 59
Posts: 956
Registered: 09 / 2007
Subject:

Re: Änderung USBSMart auf großen USB Treiber

 · 
Posted: 09.09.2022 - 02:59  ·  #6
Hi Thorsten,

Quote
ich dachte der Große USB-Treiber braucht das nicht mit dem "USB_ControlJob" ?
Erzeugt der Treiber einen eigenen Task/Process für die Aufrechterhaltung der Verbindung?


das habe ich ja nicht anders behauptet. :)
Nur der kleine und der USBboot Treiber


Der große USB läuft im Interrupt und erledigt alles automatisch im Hintergrund.


Mal ein Beispiel.

Code


type
   tCmdTyp                = (CTRLcmd, ISP3cmd, UPPcmd, DEBcmd);
  tCMDrec                = record
                             typ                    : tCmdTyp;
                             cmd                    : char;
                           end;

var
  RXbuf                  : tbuf512, Align4;  // USB incomming Buffer
  TXbuf                   : tbuf512, Align4;  // USB outgoing Buffer
  cnt[@TXbuf]           : word;
  CMDrec1[@RXbuf]  : tCMDrec;
  CMDrec                 : tCMDrec;
  HostCmd                : tCMDrec;


  USBdataAvail           : boolean; 
  HostFailed             : boolean; 
  usbRXCount             : word; 
  _Rx                    : word; 
  _usbRxTimeOut          : boolean;

procedure USB_Rx_Receive(Status : tUSBep_Status; nb_transfered : word);
var
  ch  : char; 
begin
  if Status = USBEP_TRANSFER_OK then 
    usbRXCount:= nb_transfered; 
    USBdataAvail:= true; 
  else 
    usbRXCount:= 0; 
    USBdataAvail:= true; 
  endif; 
end; 

 {--------------------------------------------------------------} 
function usbRxBuf(p : pointer; c : word) : boolean; 
var
  i   : word; 
begin
  
  if HostFailed or (not UsbDriverConnect) then 
    c:= 0; 
    return(false); 
  endif; 
  
  SetSysTimer(TimerU, 2000 div SysTick); 
  repeat
  until isSysTimerZero(TimerU) or USBdataAvail; 

  if c > usbRXCount then 
    c:= usbRXCount; 
  endif; 
  
  _usbRxTimeOut:= isSysTimerZero(TimerU); 
  
  _Rx:= usbRXCount; 
  CopyBlock(@RXbuf[2], p, c); // die ersten beiden sind die Länge 
  USBdataAvail:= false;       // oder nach RXCallback ?? 
  usbRXCount:= 0; 
  xUSB_RXsetBuffer(1, @USB_Rx_Receive, @RXbuf, 512); 
  //RestoreInts; 
  return(_Rx > 0); 
end; 

function RxStat : boolean; 
begin
  if HostFailed then 
    return(false); 
  endif; 
  return(USBdataAvail); 
end; 


function RxByte : byte; 
var
  b                      : byte; 
begin
  if HostFailed then 
    return(0); 
  endif; 
  w:= 1;                  // 1bytes data 
  if usbRxBuf(@b, w) then 
    return(b); 
  else 
    return(0); 
  endif; 
end; 

procedure TxByte(bb : byte); 
begin
  if not UsbDriverConnect then 
    return; 
  endif; 
  usbTxBuf(@bb, 1); 
end; 

procedure TxChar(ch : char); 
begin
  TxByte(byte(ch)); 
end; 

procedure TxBlock(p : pointer; cnt : word); 
begin
  if HostFailed then 
    return; 
  endif; 
  usbTxBuf(p, cnt); 
end; 

function RxCmd : tCMDrec; 
var
  w                      : word; 
  CMD[@w]                : tCMDrec; 
begin
  w:= RxWord; 
  return(CMD); 
end; 

 // receive a block of bytes
function RxBlock(p : pointer; w : word) : word; 
begin
  if HostFailed then 
    return(0); 
  endif; 
  usbRxBuf(p, w); 
  return(w); 
end; 

 //-------------------------------------------------------------- 
function usbTxBuf(p : pointer; Count : word) : boolean; 
begin
  if HostFailed or (not UsbDriverConnect) then 
    return(false); 
  endif; 
  
  TxJob:= USB_Ep_GetJob($81); 
  SetSysTimer(TimerU, 2000 div SysTick); 
  repeat
    if not TxJob^.busy then 
      cnt:= Count; 
      CopyBlock(p, @TXbuf[2], Count); 
      if USB_EpRun($81, true, @TXbuf, Count + 2, nil) then     // Job noch belegt  ? 
        return(true); 
      else 
        return(false); 
      endif; 
    endif; 
  until isSysTimerZero(TimerU); 
  return(false); 
end; 
// usw ...

Procedure MainLoop;
  var ch : char;
  begin
    repeat
      xUSB_GetUSBbusState;
      if USBdataAvail then
        HostCmd:= RxCmd;
        ch:= HostCmd.cmd;
        case HostCMD.typ of          
          ISP3cmd : ISP3mode(ch);
                  |
          UPPcmd  : UPPmode(ch);
                  |
        else
          TXchar('?');
        endcase;
      endif;

  
    until (not UsbDriverConnect) or (not USBvBUS.USBvBUSpin);
  end;

// Main --------------------
   xUSB_UserVendorRequest(@USB_VendorRequest);
   xUSB_Enable;                   // USB aktivieren
   while (not UsbDriverConnect) or (not USBvBUS.USBvBUSpin) do
     BeepClick();
   endwhile;
   

   xUSB_RXsetBuffer(1, @USB_Rx_Receive, @RXbuf, 512);   // Link RX Event

   // wait for Windows Setconfiguration
  repeat
    mDelay(700);         
    BeepClick;
  until USBDEV_State = UsbDev_STATE_Configured;
  USB_RxSetBuf(@RxBuf);
   
  while UsbDriverConnect and USBvBUS.USBvBUSpin do
        MainLoop;
   endwhile;
   xUSB_Detach;  // am Win abmelden
end ISP3_X.


Das wäre ein Beispiel:

Der AVrco sendet immer [Typ,cmd, data] oder Daten [CountW, Daten....]


Der AVRProg sendet hier ein Overlay CMD auf den RXBuf, welcher im usbRxBuf zerlegt wird.

So könnte man ein Protokoll aufbauen, da der USB ja auch nur eine Serielle ist.

Das ist simple gelöst hat aber auch einen Nachteil.
CMDs schön easy aber wenn du später Daten pur senden willst, musst du ja z.B. 2+ 512 Bytes senden. Länge+Daten.
Aber das ist halt kein Vielfaches von 64 Bytes und muss in zwei Blöcken gesendet werden.
Diese Einzelbytes kosten Zeit, da der USB ja nur bei Langeweile vom WIn dran kommt. Da kann ein Paket schon mal ne Sekunde im Buffer warten.

Deshalb für sowas dann:
Komando Anzahl z.B 512 Blöcke und Feuer frei.
Nach jeden Paket läßt du deinen Xmega ein ACK senden, das er empfangen hat und fertig ist.
Ist zwar langsam aber sicher.

Je nach Anwendung kann man auch darauf verzichten und alle Blöcke so durchschieben. Das hängt ja immer von der Menge ab. Ich schiebe immer 4MB Blöcke rüber, da machen solche Kleinigkeiten viel aus.
Ich habe mein Board 3x aufgebaut. Einmal mit Xmega und mit jeweils SAMD21 und SAM51.Beim Xmega muss ich ein ACK senden, weil er sonst überannt wird aber bei den ARMs kann ich die Blöcke in eins so durchschiebeen. Ohne das langesame Einzelbyte.

Es kommt immer darauf, was du machen willst.
Sind es nur ein paar kB dann ist das ober Frage/Antwort Protokoll genau richtig, so wird es auch in den Programmern gemacht.

Quote


Im Delphi Senden....


function usbTxBlock(p: pointer; count: word): boolean;
var
Buf: TBuf;
begin
if count = 0 then begin
Result := true;
Exit;
end
else
Result := false;
try
if usbHandle <> Invalid_Handle_Value then begin
Buf[0] := count;
Buf[1] := count shr 8; // [Anzahl bytes die kommen]
move(p^, Buf[2], count);
inc(count, 2);
repeat
repeat
Result := usbWriteFile(Buf, count, nWritten);
if Result and (nWritten = count) then
Exit;
if not Result then begin
Result:= false;
Exit;
end;
until Result;
Dec(count, nWritten);
until count = 0;
end;
except
Result := false;
end;
end;


Dies ist eigentlich nur nötig , wenn man Devices hat die nur 64 bytes Buffer haben.
Der große Treiber kann aber Multipaket und packt dir die automatisch zu einen RX Buf zusammnen.
D.h du bekommst auch 512 bytes in einen Block.
So könnte man sich das Word vor dem Buffe sparen.

Das geht bei den kleinen Treibern nicht , da muss man es über den obrigen Umweg machen.



so ...

miparo
pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Re: Änderung USBSMart auf großen USB Treiber

 · 
Posted: 09.09.2022 - 12:01  ·  #7
Hallo miparo,

danke für die Infos :-)

Thorsten
miparo
Administrator
Avatar
Gender:
Location: Germany
Age: 59
Posts: 956
Registered: 09 / 2007
Subject:

Re: Änderung USBSMart auf großen USB Treiber

 · 
Posted: 09.09.2022 - 17:31  ·  #8
Hi Thorsten,
ich hoffe, das es die meisten Fragen geklärt hat.

miparo
  • 1
  • 2
  • Page 1 of 2
Selected quotes for multi-quoting:   0

Registered users in this topic

Currently no registered users in this section

The statistic shows who was online during the last 5 minutes. Updated every 90 seconds.
MySQL Queries: 15 · Cache Hits: 14   137   151 · Page-Gen-Time: 0.03046s · Memory Usage: 2 MB · GZIP: on · Viewport: SMXL-HiDPI