2024年10月30日水曜日

STM32H723 USB BULK転送したい(1)open

STM32CubeMXが生成してくれるUSB MiddleWareには、単純なBULK transferのexampleが無いんです.HID,Audio,CDC,DFUなどのClass exampleの中にBULK transferしている場所が見当たらないというのが正しい.別の手段か別の名前で実装しているには違いないのだろうけど.

というわけでUSB BULK transferをするまでの試行錯誤を書いてゆきます.

環境:
 Nulceo H723Z USB device FS (12Mbps)
 STM32CubeIDE 1.15 (windows)
 HOSTマシン Linux
 LinuxのUSB library usblib-1.0.27

usblibについて注意:
Linuxマシンにはusblib-1.0.25がインストされていましたが、最新はusblib-1.0.27のようですので1.0.27をインストしました.
こちらのページによると、apt installでやると1.0.25がインストされちゃうと警告しています.ただし、こちらのページ通りですとインストまでは通りませんでした.configureが無かった.

ーーーー
まずは、STM32CubeMXで生成したDFU Classを使ってみる.

DFUを選んだ理由は、HIDだと定期的アクセスが生じてめんどくさい気がした、Audioは複雑すぎるだろう、といった理由.DFUはfirmware updateするためのclassらしいのでシンプルにdata転送に特化してるんじゃないのかなと思ったりして.

生成されたDFU classほぼそのままをNucleoに焼いて、Linuxマシンに接続し、どんな素性のUSB deviceが接続されたんだろうねぇとlsusbで表示させてみる.少し略すがこんな感じ.
Device Descriptor:
  bcdUSB               2.00
  bDeviceClass            0
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x0483 STMicroelectronics
  idProduct          0xdf11 STM Device in DFU Mode
  bcdDevice            2.00
  bNumConfigurations      1
  Configuration Descriptor:
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          2 HIRASAKA
    bmAttributes         0xc0
      Self Powered
    MaxPower              100mA
    Interface Descriptor:
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass       254 Application Specific Interface
      bInterfaceSubClass      1 Device Firmware Update
      bInterfaceProtocol      2
      iInterface              6 @Internal Flash
      Device Firmware Upgrade Interface Descriptor:
        bDescriptorType                    33
        bmAttributes                       11
          Will Detach
          Manifestation Intolerant
          Upload Supported
          Download Supported
        wDetachTimeout                    255 milliseconds
        wTransferSize                    1024 bytes
        bcdDFUVersion                   1.1a
感想としては、
・シンプルだなぁ (Audio classはもっと複雑)
・EPの記述無し
・control EPで64BYTE packetでトロトロ流す感じなのだろう
・細かいところはDFU Classにぶん投げ

ーーーー
次に、Linux HOSTからSTM32をopenしてみるなり.
コンパイルの呪文はこれにて.
 gcc eprw.c -I/usr/include/libusb-1.0 -lusb-1.0 -o eprw

↓Linux HOSTは概略このcodeでopenできてる.
#include <libusb.h>    // usblib1.0

struct libusb_device_descriptor desc;
libusb_device_handle *h_dev;
unsigned char text[512];

int main(int argc, char *argv[]){
  libusb_device **list;
  libusb_device *found = NULL;
  
  // search & open
  libusb_init( NULL );
  int dcnt = libusb_get_device_list(NULL,&list); 
  if(dcnt<0) exit(1);
  printf("There are %d USB device.\n",dcnt);

  for(int i=0;i<dcnt;i++) {
    libusb_device *device = list[i];
    libusb_get_device_descriptor(device, &desc); 
    int ret = libusb_open(device, &h_dev); 
    if(ret==0) {
      libusb_get_string_descriptor_ascii(h_dev, desc.iManufacturer, text, sizeof(text)); 
      int vid = desc.idVendor; 
      int pid = desc.idProduct; 
      printf("%d %04x/%04x %s\n",i,vid,pid,text);
      if(strcmp("HIRASAKA",text)==0) { 
        found = device;
        printf("-->found my device.\n");
      }
      libusb_close(h_dev);
    }
  }
  libusb_free_device_list(list,1);
  libusb_open(found, &h_dev);  
}

まずはopenだけしかやってません.

libusbの作法通りにやってます~
 ①list[]にUSB deviceをリストする
 ②各リストのdevice descriptorを取得
 ③各々をお試しopen
 ④Manufacturer名称、VID、PIDを抽出
 ⑤Manufacturer名称=HIRASAKAだったら目的のdeviceだ
 ⑥改めて目的のdeviceをopen

こうゆう探すやりかたじゃなくて、VID,PIDで狙い撃ちopenする方法もありますが割愛します.


ーーーー
上記⑥でopenしたのに続き、、、kernel driverを起動したりするおまじない.
  libusb_set_auto_detach_kernel_driver( h_dev , 1 );
  libusb_set_configuration( h_dev , 1 ); 
  libusb_claim_interface( h_dev , 0 ); // select interface

さらに、EndPointのmax packet sizeを読んでみる.正しくconfig出来れば64などが表示されるはず.
  int psize0 = libusb_get_max_packet_size( found, 0 );
  int psize1 = libusb_get_max_packet_size( found, 1 );
  int psize2 = libusb_get_max_packet_size( found, 2 );
  int psize3 = libusb_get_max_packet_size( found, 3 );
  int psize4 = libusb_get_max_packet_size( found, 4 );
  int psize5 = libusb_get_max_packet_size( found, 5 );
  printf("%d %d %d %d %d %d\n", psize0, psize1, psize2, psize3,\ 
          psize4, psize5);
ところが、printf結果は、「-5 -5 -5 -5 -5 -5」になってしまった.-5はNOT FOUNDのerr codeなので、EP0~EP5が定義されてないことを意味する.descriptorにEPが書かれてないので無理も無かろうと思う.

DFU Classを雛形にするのは諦めます.

以後はCDC Classに切り替えます.
CDC Classですと、「-5 64 -5 -5 -5 -5」の表示になり、EP1がmax packet size 64に設定されていることがわかる.

CDC ClassのdescriptorをチェックするとEP2IN,EP1OUT,EP1INの3つのEP descriptorが存在する.これらのうちEP1の64bytesが表示されたが、EP2の8bytesが表示されなかったのは理由不明.
Endpoint Descriptor:
  bEndpointAddress     0x82  EP 2 IN
  bmAttributes            3
    Transfer Type            Interrupt
    Synch Type               None
    Usage Type               Data
  wMaxPacketSize     0x0008  1x 8 bytes
  bInterval              16

Endpoint Descriptor:
  bEndpointAddress     0x01  EP 1 OUT
  bmAttributes            2
    Transfer Type            Bulk
    Synch Type               None
    Usage Type               Data
  wMaxPacketSize     0x0040  1x 64 bytes

Endpoint Descriptor:
  bEndpointAddress     0x81  EP 1 IN
  bmAttributes            2
    Transfer Type            Bulk
    Synch Type               None
    Usage Type               Data
 wMaxPacketSize     0x0040  1x 64 bytes

第一回はこれまでにしとうございます.


かしこ

0 件のコメント:

コメントを投稿