Posted on September 13, 2016 at 06:36
> However, when I play a note on the keyboard, I notice no data is being received.
1) The Major state machine in USBH_MIDI_Process()
Unless your firmware calls USBH_BulkReceiveData(), no bulk IN transaction occurs on the bus. Your MIDI class implementation calls it in MIDI_ProcessReception():case MIDI_RECEIVE_DATA (usbh_MIHI.c). But it doesn't reach to this case while the major state machine (USBH_MIDI_Process()) stays in MIDI_IDLE_STATE.
Do you really need MIDI_IDLE_STATE at this state machine ?
The host bulk IN pipe should poll the EP repeatedly, to get ''asynchronous'' input from the device - so called polling bulk IN. While no data to send on the device, it returns NAK. And then, your firmware should call USBH_BulkReceiveData(), periodically. There is no ''idle'' state on this endpoint.
For the host bulk OUT pipe, Of course, would stay in idle, while the host app doesn't have any data to send. This idle state should be processed in the independent state machine for the bulk OUT pipe, apart from the bulk IN state machine.
2) Problem of the host engine on bulk IN-NAK
Ideally for USB host engine, it should process bulk IN-NAK without any firmware intervention - it should automatically re-send bulk IN transaction, until the firmware explicitly stops it. Unfortunately, the USB host engines on STM32, both of OTG_FS and OTG_HS, require firmware intervention to re-send IN transaction after NAK (**1). On the ST's Cube/HAL USB host library, this re-prime process is coded in USB NAK interrupt. Immediately after the re-activate of the host channel, another bulk IN-NAK occurs. And then, the host firmware suffers USB interrupt flood, while target device is NAKing. 50% or more of MCU time is eaten up by this interrupt process. This problem had discussed in
/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/STM32Cube%20USB%20Host%20Driver%20Interrupt%20Flood
.
Here is the host process of the bulk IN-NAK on Cube/HAL.
When the NAK interrupt occurs, the channel is deactivated by the host engine (OTG_HCCHARx.CHENA = 0). This code re-activates the channel at (**2) lines.
stm32f7xx_hal_hcd.c
static void HCD_HC_IN_IRQHandler (HCD_HandleTypeDef *hhcd, uint8_t chnum)
{
...
line:916
else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_NAK)
{
if(hhcd->hc[chnum].ep_type == EP_TYPE_INTR)
{
__HAL_HCD_UNMASK_HALT_HC_INT(chnum);
USB_HC_Halt(hhcd->Instance, chnum);
}
else if ((hhcd->hc[chnum].ep_type == EP_TYPE_CTRL)||
(hhcd->hc[chnum].ep_type == EP_TYPE_BULK))
{
/* re-activate the channel */ <----- (**2)
tmpreg = USBx_HC(chnum)->HCCHAR;
tmpreg &= ~USB_OTG_HCCHAR_CHDIS;
tmpreg |= USB_OTG_HCCHAR_CHENA;
USBx_HC(chnum)->HCCHAR = tmpreg;
}
hhcd->hc[chnum].state = HC_NAK;
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
}
}
Your options are,
A) Complete the transaction at NAK
Separate EP_TYPE_BULK from EP_TYPE_CTRL in above ''if'' clause.
Don't re-activate the channel for EP_TYPE_BULK. Instead, force the channel to halt, as if the transaction would successfully complete (XFRC) with Zero-Length packet.
__HAL_HCD_UNMASK_HALT_HC_INT(chnum);
USB_HC_Halt(hhcd->Instance, chnum);
hhcd->hc[chnum].state = HC_XFRC;
hhcd->hc[chnum].ErrCnt = 0;
__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
Your class code should repeat USBH_BulkReceiveData() calls periodically.
B) Assign the bulk IN EP as interrupt IN EP
As of the handle of periodical interrupt IN call, refer to host HID example.
(**1) I'm not sure this is feature or bug of the engine. The latter revision of USB IP by Synopsys (ex. on EFM32) works ''ideally'' without any firmware intervention.
Tsuneo