さて、コンパイルも通ったことなので、もう少し真面目にコードをチェックしてみる。まずはSTM32F207VGのVCPのコードを見てみよう。app.cの中にmain()があるわけだが、その中身はこれだけである(List 1)。最初にUSBD_Init()を呼び出しただけで、後はLEDをぐるぐる点滅させるだけ、という代物だ。では通信はどうやっているか? というと、RS232Cの通信割り込みにあわせて割り込みルーチンが動き、そこで各々の処理を行う形になる。で、USBD_Init()は? というと、こちらはusbd_usr.cの中にある。余談だが、IAR Embedded Workbenchはこれを一発で探せる(Photo01)のが非常に便利である。
そのUSBD_Init()はList 2の様になっている。ざっくり言えば、
(1) USB_OTG_BSP_Init()で、オンチップのUSB OTGドライバの初期化
(2) USBD_DeInit()でデバイスライブラリの再初期化
(3) 構造体に必要なパラメータを積む
(4) DCD_Init()でデバイスにパラメータを設定
(5) ユーザーCallbackの初期化ルーチンを起動
(6) USB_OTG_BSP_EnableInterrupt()を呼び出し、割り込みを許可=通信開始
といった流れになっている。このうち(2)に関しては、USBD_Init()の直後にコードがあるのだが、List 3の通り「何もしていない」ので無視していいのだろう。おそらくこれはソフトウェア的に何か初期化&再初期化の際に処理が必要な場合に定義を追加せよ、というためのStubと思われる。
さて、まず(1)。USB_OTG_BSP_Init()はusb_bsp.cに含まれている。これはSTM32のUSB Driverに属する部分で、デバイス別の設定になっている。今回の場合、STM32F207VG用とSTM32F4-Discovery用は殆ど同じながら若干異なる部分が散見される。このあたりはいじる必要はなさそうだ。(2)はそういうわけで無視するとして、ちょっと飛んで(6)。こちらもusb_bsp.cの中に含まれており、中身はSTM32F207VG用とSTM32F4-Discovery用で完全に一緒だった。このusb_bsp.cの中身はそういうわけで一切手をいれなくてもよさそう、という感じだ(最終的には動くまで判らないけど)。
ではいじらないといけないあたりはどこか? というと(3)~(5)の部分である。まずmain()からのUSBD_Initの呼び出しを見ると、
USBD_Init(&USB_OTG_dev,
#ifdef USE_USB_OTG_HS
USB_OTG_HS_CORE_ID,
#else
USB_OTG_FS_CORE_ID,
#endif
&USR_desc,
&USBD_CDC_cb,
&USR_cb);
となっている。最初のUSB_OTG_devはデバイスハンドルで。main()の手前でグローバル変数定義されている。次の引数はFS(Full-Speed:12Mbps)かHS(High-Speed:480Mbps)かの選択なので置いておくとして、続くUSB_desc/USB_CDC_cb/USR_cbの定義を見てみる。
USR_descはusbd_desc.cの中で定義されており、
USBD_DEVICE USR_desc =
{
USBD_USR_DeviceDescriptor,
USBD_USR_LangIDStrDescriptor,
USBD_USR_ManufacturerStrDescriptor,
USBD_USR_ProductStrDescriptor,
USBD_USR_SerialStrDescriptor,
USBD_USR_ConfigStrDescriptor,
USBD_USR_InterfaceStrDescriptor,
};
てな感じになっている。これはSTM32F207VG用もSTM32F4-Discovery用も同じで、名前から見るとUSB DeviceのDevice Descriptionと思われる。次のUSBD_CDC_cbは、usbd_cdc_core.cの中で定義されており、
USBD_Class_cb_TypeDef USBD_CDC_cb =
{
usbd_cdc_Init,
usbd_cdc_DeInit,
usbd_cdc_Setup,
NULL, /* EP0_TxSent, */
usbd_cdc_EP0_RxReady,
usbd_cdc_DataIn,
usbd_cdc_DataOut,
usbd_cdc_SOF,
NULL,
NULL,
USBD_cdc_GetCfgDesc,
#ifdef USE_USB_OTG_HS
USBD_cdc_GetOtherCfgDesc, /* use same cobfig as per FS */
#endif /* USE_USB_OTG_HS */
};
といった具合だ。このUSBD_Class_cb_TypeDefの定義はusb_core.hの中にあり、
typedef struct _Device_cb
{
uint8_t (*Init) (void *pdev , uint8_t cfgidx);
uint8_t (*DeInit) (void *pdev , uint8_t cfgidx);
/* Control Endpoints*/
uint8_t (*Setup) (void *pdev , USB_SETUP_REQ *req);
uint8_t (*EP0_TxSent) (void *pdev );
uint8_t (*EP0_RxReady) (void *pdev );
/* Class Specific Endpoints*/
uint8_t (*DataIn) (void *pdev , uint8_t epnum);
uint8_t (*DataOut) (void *pdev , uint8_t epnum);
uint8_t (*SOF) (void *pdev);
uint8_t (*IsoINIncomplete) (void *pdev);
uint8_t (*IsoOUTIncomplete) (void *pdev);
uint8_t *(*GetConfigDescriptor)( uint8_t speed , uint16_t *length);
#ifdef USB_OTG_HS_CORE
uint8_t *(*GetOtherConfigDescriptor)( uint8_t speed , uint16_t *length);
#endif
#ifdef USB_SUPPORT_USER_STRING_DESC
uint8_t *(*GetUsrStrDescriptor)( uint8_t speed ,uint8_t index, uint16_t *length);
#endif
} USBD_Class_cb_TypeDef;
となっている。どうもこのなかに、コールバックルーチンを定義している様だ。
(続く)
List 1:
int main(void)
{
__IO uint32_t i = 0;
/*!< At this stage the microcontroller clock setting is already configured,
this is done through SystemInit() function which is called from startup
file (startup_stm32fxxx_xx.s) before to branch to application main.
To reconfigure the default setting of SystemInit() function, refer to
system_stm32fxxx.c file
*/
USBD_Init(&USB_OTG_dev,
#ifdef USE_USB_OTG_HS
USB_OTG_HS_CORE_ID,
#else
USB_OTG_FS_CORE_ID,
#endif
&USR_desc,
&USBD_CDC_cb,
&USR_cb);
/* Main loop */
while (1)
{
if (i++ == 0x100000)
{
STM_EVAL_LEDToggle(LED1);
STM_EVAL_LEDToggle(LED2);
STM_EVAL_LEDToggle(LED3);
STM_EVAL_LEDToggle(LED4);
i = 0;
}
}
}
List 2:
/**
* @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);
}
List 3:
USBD_Status USBD_DeInit(USB_OTG_CORE_HANDLE *pdev)
{
/* Software Init */
return USBD_OK;
}