先週の続き...の前に、先々週の話を忘れていたのでまずはこちらから。usbd_conf.hが2種類あるという話であるが、実はこれはSTM32F407VGのサンプルコードに含まれている(STM32F4-Discoveryのサンプルコードではない)。こちらのページのDesign supportタブの下のほうにFirmwareが並んでいるが、ここにある"STM32F105/7, STM32F2 and STM32F4 USB on-the-go Host and device library"を展開して出てくるSTM32_USB-Host-Device_Lib_V2.1.0\Project\USB_Device_Examples\VCP\inc の下にあるusbd_conf.hが元ネタである。もっともこちらのファイルは、原稿執筆時点でのバージョンはVersion 1.1.0(2012年3月19日版)であるが、これ以前にSTMicroがリリースしていたVersion 1.0.0版(2011年7月19日版)というのがあちこちのWeb上(たとえばここ)で散見されており、とりあえずはこちらの記述を拝借したという次第。usbd_conf.hに関してVersion 1.0.0とVersion 1.1.0の違いを見ると、USB_MAX_STR_DESC_SIZの値が50か255かの違いだけなので、後でVersion 1.1.0に差し替えるとしても当面は問題なさそうである。

さて、先週の続き。USBD_Init()の最後のUSR_cbだが、こちらはusbd_usr.cの中で定義されており、

USBD_Usr_cb_TypeDef USR_cb =
{
  USBD_USR_Init,
  USBD_USR_DeviceReset,
  USBD_USR_DeviceConfigured,
  USBD_USR_DeviceSuspended,
  USBD_USR_DeviceResumed,
};

とされている。これらの関数はやはりusbd_usr.cの中で定義されており、たとえばUSBD_USR_Init()であれば、

void USBD_USR_Init(void)
{  
  /* Initialize LEDs */
  STM_EVAL_LEDInit(LED1);
  STM_EVAL_LEDInit(LED2);
  STM_EVAL_LEDInit(LED3);
  STM_EVAL_LEDInit(LED4);   

  /* Initialize the LCD */
#ifdef USE_STM3210C_EVAL
  STM3210C_LCD_Init();  
#else
  STM322xG_LCD_Init();
#endif
  LCD_LOG_Init();

#ifdef USE_USB_OTG_HS 
  LCD_LOG_SetHeader(" USB OTG HS VCP Device");
#else
  LCD_LOG_SetHeader(" USB OTG FS VCP Device");
#endif
  LCD_UsrLog("> USB device library started.\n"); 
  LCD_LOG_SetFooter ("     USB Device Library v1.0.0" );
}

てな具合になっている。ボードのLCDの初期かはこちらでまとめて行われているようだ。ちょっとUSB Driverの中身を確認ということでusbd_core.cの中に含まれているUSBD_IInit()の中を見てみると、

/**
* @brief  USBD_Init
*         Initailizes the device stack and load the class driver
* @param  pdev: device instance
* @param  core_address: USB OTG core ID
* @param  class_cb: Class callback structure address
* @param  usr_cb: User callback structure address
* @retval None
*/
void USBD_Init(USB_OTG_CORE_HANDLE *pdev,
               USB_OTG_CORE_ID_TypeDef coreID,
               USBD_DEVICE *pDevice,                  
               USBD_Class_cb_TypeDef *class_cb, 
               USBD_Usr_cb_TypeDef *usr_cb)
{
  /* Hardware Init */
  USB_OTG_BSP_Init(pdev);  

  USBD_DeInit(pdev);

  /*Register class and user callbacks */
  pdev->dev.class_cb = class_cb;
  pdev->dev.usr_cb = usr_cb;  
  pdev->dev.usr_device = pDevice;    

  /* set USB OTG core params */
  DCD_Init(pdev , coreID);

  /* Upon Init call usr callback */
  pdev->dev.usr_cb->Init();

  /* Enable Interrupts */
  USB_OTG_BSP_EnableInterrupt(pdev);
}

といった具合になっている。USR_cbで積んだ中身は、USBD_Initの最後の引数で渡されてくる形であるが、まずUSB_OTG_BSP_Init()でボードの初期化、USBD_DeInit()でドライバの初期化の後、pdev->dev.usr_cb = usr_cbという形でデバイスドライバを管理する構造体にUSR_cbを登録し、ついでpdev->dev.usr_cb->Init();としてUSBD_USR_Init()を呼び出している。これは他の関数も同じで、Init/DeviceReset/DeviceConfigured/DeviceSuspended/DeviceResumedの5つの状態については、usbd_usr.cの中の記述を書き換えれば良いことが判った。

ただこれだと、肝心の送受信の際のCallbackが皆無である。こちらはusbd_cdc_vcp.cの中に含まれている。

(続く)