CH552でUSBのserial number


ch552を使ってUSB機器を作れるようになったが, ch55xduinoとch554_sdcc_usb_blinkyを組み合わせた方法では,serial numberを記述することが出来なかった. 同じ機器を同時にいくつも接続した場合に,それらを区別するのにはserial numberが便利である. そこで,前回使ったプログラムを改造して,serial numberを使えるようにした.

まずは,serial numberのデータを他の文字列を参考にして定義する.

#ifndef USB_CUST_PRODUCT_SERIAL
#define USB_CUST_PRODUCT_SERIAL_LEN 10
#define USB_CUST_PRODUCT_SERIAL {'0','1','2','3','4','5','6','7','8','9'}
#endif

このデータから,その文字列を表すdescriptorを作る.

__code struct {uint8_t bLength; uint8_t bDscType; uint16_t string[USB_CUST_PRODUCT_SERIAL_LEN];} sd003 = {
  sizeof(sd003), USB_DESCR_TYP_STRING,
  USB_CUST_PRODUCT_SERIAL
};

そして,他の文字列を処理している部分と同様に,以下のプログラムを追加する.

else if(UsbSetupBuf->wValueL == 3)
     {
     UsbIntrDescr = (uint8_t*) sd003;
     len = sizeof(sd003);
     }

これで,serial numberが扱えるようになる. 実際,USBに挿してdmesgで確認すると,SerialNumber:の後に文字列が表示されている.

しかし,それぞれのマイコンにプログラムを書き込む時に,異なったserial numberを与えたり,それを管理するのは面倒である. そこで,ch552のunique IDをserial numberにすることにした. 上では変更することが無いので,flash上にデータがあり,__codeと定義したが,それを変更できるようにvolatile __xdataと変更する. そして,USBの初期化の部分で,sd003の文字列の部分をunique IDを16進数に直した文字列に書き換える.

  uint16_t ser;
  uint8_t num,i;
  ser=*(__code uint16_t*)ROM_CHIP_ID_HX;
  for(i=0;2>i;ser>>=4){num='0'+(ser&0x0f); sd003.string[1-i++]=num>'9'?num+7:num;}
  ser=*(__code uint16_t*)ROM_CHIP_ID_HI;
  for(i=0;4>i;ser>>=4){num='0'+(ser&0x0f); sd003.string[5-i++]=num>'9'?num+7:num;}
  ser=*(__code uint16_t*)ROM_CHIP_ID_LO;
  for(i=0;4>i;ser>>=4){num='0'+(ser&0x0f); sd003.string[9-i++]=num>'9'?num+7:num;}

unique IDのデータはflashの上にあり,これをどうやって読み出すかに少し苦労したが,アドレスをポインタとしてキャストして,それを数値に変換することによって読み出せた. flash上にあることを示すために__codeをつけるというのも独特である.

少しずつUSBのデータ処理の仕方の理解が進んできているが,それを生かして今後もいろいろなUSB機器を作ることになるだろう.