2017-05-26 01:59 AM
I am developing a UVC Host FULL Speed Driver in Kit STM32F4 Discovery .
I brought up Webcam and it streaming data.
But when I receive data from
Isochronos Endpoint
My source :
USBH_IsocReceiveData(phost,imgBuffer,EpOutSize,pipe_out_uvc);
uint32_t time_count = phost->Timer;while (1){
URB_Status = USBH_LL_GetURBState(phost,pipe_out_uvc);
if (USBH_URB_DONE == URB_Status && phost->Timer-time_count > tbInterval_stream){
time_count = phost->Timer;
uint32_t
Xfer_
len =USBH_LL_GetLastXferSize (phost, pipe_out_uvc);if(
Xfer_len
){USBH_UsrLog('[DEBUG]==========>header size : %d',*imgBuffer);
}
}
}
I received event
USBH_URB_DONE
butXfer_len always
equal 0 and nothing in
imgBuffer
.Please help me fix my problem. Thanks you so much !!!
I using lib usb in STM32Cube FW_F4 V1.16.0
#usb #isochronos-endpoint #isochronos #isocreceivedata #stm32f4-discovery2017-08-15 01:15 AM
show your complete initialisation...
probe get
probe set
commit set
set interface ( with correct alternate setting !! )
why are you using while() loop?
you can use the original example code from ST to usw several states.
switch (pVideo->StreamState){
case VIDEO_STREAM_PROBE_SET: break; case VIDEO_STREAM_PROBE_GET: break;case VIDEO_STREAM_COMMIT_SET:
break;case VIDEO_STREAM_SET_INTERFACE:
break;case VIDEO_STREAM_START:
USBH_IsocReceiveData( phost , DMA_USBH_Buffer , pVideo->EpVideoStream.wMaxPacketSize , pVideo->EpVideoStream.bPipe );pVideo->StreamState = VIDEO_STREAM_PLAY;
osMessagePut ( phost->os_event, USBH_CLASS_EVENT ,pVideo->EpVideoStream.bInterval);
break;case VIDEO_STREAM_PLAY:
if((phost->Timer-pVideo->EpVideoStream.wTimer) >= pVideo->EpVideoStream.bInterval){ pVideo->EpVideoStream.wTimer = phost->Timer;USBH_URBStateTypeDef urb_state = USBH_LL_GetURBState(phost , pVideo->EpVideoStream.bPipe);
switch( urb_state ){ case USBH_URB_DONE: HandleReceivedFrame( phost, pVideo , DMA_USBH_Buffer, USBH_LL_GetLastXferSize(phost, pVideo->EpVideoStream.bPipe ));USBH_IsocReceiveData( phost ,
DMA_USBH_Buffer, pVideo->EpVideoStream.wMaxPacketSize, pVideo->EpVideoStream.bPipe ); break; case USBH_URB_IDLE: case USBH_URB_NOTREADY: case USBH_URB_NYET: case USBH_URB_ERROR: case USBH_URB_STALL: default: break; } }else{osMessagePut ( phost->os_event, USBH_CLASS_EVENT, pVideo->EpVideoStream.bInterval );
}
break;default:
break; }if alternate settings and interface is correct, then you receive data from camera.
2018-07-03 03:18 PM
Hey! I am in a similar situation, I am writing a UVC class driver for a STM32F769 Discovery board. I'm doing the stream negociation in this way : probe set -> probe get -> commit set. I then set an alternate interface for the video streaming interface and up to there everything works just fine. I've checked the values returned in the probe get phase and they are coherent. The LED on the webcam turns on (which seems to be a good indicator that the webcam is recording) but when I perform a
USBH_IsocReceiveData() the value returned by
USBH_LL_GetURBState is always USBH_URB_IDLE. This leads me to think that the webcam is not outputting video data. Do you have any idea on how I could make some progress on this ?
What does the DMA_USBH_Buffer parameter mean in the USBH_IsocReceiveData() function ?
I attached the code of my class driver. The stream negotiation is done in the USBH_CAM_NegociateRequests() function
the USBH_CAM_Process() function is the main state machine of the driver and the USBH_IsocReceiveData is done there.
Also by reverse engineering the webcam with an USB protocol analyser I noticed that the Windows driver managed the stream in a completely different way (using the vendor specific extension units) would it be possible to access the probe and commit controls? Does a webcam have to implement these controls (probe commit) to be compliant to the UVC class?
You seem to know your way around this and I would be really grateful if you could provide me with some info.
Best regards
Colin Cina
Attached code :
=============
USBH_StatusTypeDef USBH_CAM_NegociateRequests(USBH_HandleTypeDef* phost, CAM_HandleTypeDef* CAM_Handle)
{ USBH_StatusTypeDef testStatus = USBH_BUSY; USBH_StatusTypeDef status = USBH_BUSY;switch(CAM_Handle->streamNeg_state)
{ case CAM_REQ_STREAM_INIT: CAM_Handle->streamNeg_state = CAM_REQ_SET_PROBE; break;case CAM_REQ_SET_PROBE:
initProbeSet(&(CAM_Handle->probeSet)); CAM_Handle->streamNeg_state = CAM_REQ_SET_PROBE_WAIT; break;case CAM_REQ_SET_PROBE_WAIT:
//SET_CUR request [probe] with the probe control data structure if(USBH_CSRequest(phost, USB_REQ_SET_CUR, VS_PROBE_CONTROL, VS_INTERFACE) == USBH_OK) { CAM_Handle->streamNeg_state = CAM_REQ_GET_PROBE; } break;case CAM_REQ_GET_PROBE:
//GET_CUR request [probe] -> store the probe control data received if(USBH_CSRequest(phost, USB_REQ_GET_CUR, VS_PROBE_CONTROL, VS_INTERFACE) == USBH_OK) { CAM_Handle->streamNeg_state = CAM_REQ_SET_COMMIT; }break;
case CAM_REQ_SET_COMMIT:
//SET_CUR request [commit] with the data read back from the GET_CUR request //Compare the two videoProbe data structure and set the definitive version to the probe commit terminal memcpy(CAM_Handle->probeSet.data, phost->device.Data, 26); CAM_Handle->streamNeg_state = CAM_REQ_SET_COMMIT_WAIT; break;case CAM_REQ_SET_COMMIT_WAIT:
testStatus = USBH_CSRequest(phost, USB_REQ_SET_CUR, VS_COMMIT_CONTROL, VS_INTERFACE); if(testStatus == USBH_OK) { CAM_Handle->streamNeg_state = CAM_REQ_SET_INTERFACE; } break;case CAM_REQ_SET_INTERFACE:
//select an aternate setting for the interface based on the MaxPayloadTransferSize received in the GET_CUR CAM_Handle->stream_altSetting = setAppropriateInterface(phost, CAM_Handle->probeSet.params.dwMaxPayloadTransferSize); CAM_Handle->stream_interface = USBH_FindInterfaceIndex(phost, 0x01, CAM_Handle->stream_altSetting); //1 stands for the video streaming interface number if(CAM_Handle->stream_interface != 0xFF) { if(USBH_SelectInterface(phost, CAM_Handle->stream_interface) == USBH_OK) { CAM_Handle->streamNeg_state = CAM_REQ_SET_INTERFACE_WAIT; } } break;case CAM_REQ_SET_INTERFACE_WAIT:
if(USBH_SetInterface(phost, 0x01, CAM_Handle->stream_altSetting) == USBH_OK) { //allow the host process state machine to move on the the HOST_CLASS state from where the bgnd function is gonna be called status = USBH_OK; CAM_Handle->ctl_state = CAM_REQ_IDLE; } break;default:
break; } return status;}USBH_StatusTypeDef USBH_CAM_Process(USBH_HandleTypeDef *phost)
{ USBH_StatusTypeDef status = USBH_OK; USBH_URBStateTypeDef urbStatus = USBH_URB_IDLE; CAM_HandleTypeDef *CAM_Handle = (CAM_HandleTypeDef *) phost->pActiveClass->pData; switch (CAM_Handle->state) { case CAM_INIT: CAM_Handle->state = CAM_CONFIG; break;case CAM_IDLE:
break;case CAM_CONFIG:
if(configureDevice(phost, CAM_Handle) == USBH_OK) { CAM_Handle->state = CAM_IDLE; } break;case CAM_POLL:
if(USBH_LL_GetURBState(phost , CAM_Handle->interruptPipe) == USBH_URB_STALL) /* IN Endpoint Stalled */
{/* Issue Clear Feature on interrupt IN endpoint */
if(USBH_ClrFeature(phost, CAM_Handle->interruptEp_addr) == USBH_OK) { /* Change state to issue next IN token */ CAM_Handle->state = CAM_HANDLE_INT; } } break;case CAM_HANDLE_INT:
if(USBH_InterruptReceiveData(phost, CAM_Handle->interruptDataBuffer, CAM_Handle->interruptLength, CAM_Handle->interruptPipe) == USBH_OK){ CAM_Handle->state = CAM_CONFIG; }break;
case CAM_GET_STREAM_START:
if((phost->Timer & 1) == 0) { CAM_Handle->timer = phost->Timer; CAM_Handle->state = CAM_GET_STREAM; USBH_IsocReceiveData(phost, CAM_Handle->pImgData, CAM_Handle->streamLength, CAM_Handle->streamPipe); } break;case CAM_GET_STREAM:
urbStatus = USBH_LL_GetURBState(phost, CAM_Handle->streamPipe); if((urbStatus == USBH_URB_DONE) && (( phost->Timer - CAM_Handle->timer) >= CAM_Handle->streamPoll)) { uint32_t rx_size = USBH_LL_GetLastXferSize(phost, CAM_Handle->streamPipe); CAM_Handle->timer = phost->Timer; CAM_Handle->state = CAM_IDLE; } break;case CAM_ERROR:
break;default:
break; } return status;}2018-07-03 11:52 PM
hi
i had some trouble in the past with isochronous transfer.
the original library doesn't support this mode.
https://community.st.com/0D50X00009XkdyKSAR
did you fix it?
try this first.
uint8_t DMA_USBH_Buffer[ USB_MAX_ENDPOINT_SIZE] ;
//this is the data receive buffer
2018-07-06 10:19 AM
Hi !
Thanks for your response, it was indeed helpful. I am able to retrieve what seems to be the header of an MJEPG video frame now that the HAL_HCD_IN_IRQHandler takes also isochronous endpoints into account. However I am only able to make one transfer, after that the URB status remains to USBH_URB_IDLE because somehow the conditons to get to the
else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_XFRC)
{...
else if((hhcd->hc[chnum].ep_type == EP_TYPE_INTR)||
(hhcd->hc[chnum].ep_type == EP_TYPE_ISOC )) {...
}
}
If I am right about this video frame header being transmitted, it indicates an end of frame. Could that mean that the webcam has no more data to transmit? I forgot to mention that I am currently NOT working with an RTOS
2018-07-06 10:23 AM
I guess that doesn't change the behavior of the program, but I took your example of the process state machine ( where the isocReceiveData() calls are made)
Kind regards
Colin Cina
PS : this comment belongs with the one above but something went wrong and I couln't editi it.
2018-07-08 01:40 AM
Colin,
There is another bug in stm32f7xx_hal_hcd.c shown below diff lines.
--- Src_org/stm32f7xx_hal_hcd.c 2018-03-23 12:48:34.000000000 +0900
+++ Src/stm32f7xx_hal_hcd.c 2018-06-04 13:41:21.000000000 +0900
@@ -423,7 +423,11 @@ HAL_StatusTypeDef HAL_HCD_HC_SubmitReque
break;
case EP_TYPE_ISOC:
+ ♯ if 0
hhcd->hc[ch_num].data_pid = HC_PID_DATA0;
+ ♯ else
+
hhcd->hc[ch_num].data_pid = HC_PID_DATA2;
+ ♯ endif
break;
}
@@ -883,6 +887,15 @@ static void HCD_HC_IN_IRQHandler
(HCD_
hhcd->hc[chnum].urb_state = URB_DONE;
HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);
}
+ ♯ if 0
+ ♯ else
+
else if(hhcd->hc[chnum].ep_type == EP_TYPE_ISOC)
+
{
+
USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_ODDFRM;
+
hhcd->hc[chnum].urb_state = URB_DONE;
+
HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);
+
}
+ ♯ endif
hhcd->hc[chnum].toggle_in ^= 1;
}
HAL_HCD_HC_SubmitRequest() always uses DATA0 as data_pid. It means
it can send only one transaction within a micro frame.
Normally, UVC camera needs to send large
amount
of data and requiresmultiples (two or three) transactions per micro frame.
Check your web camera stream endpoint and use DATA1 or DATA2 data_pid instead.
Toshiharu
2018-07-10 11:16 PM
2018-07-12 06:34 AM
no, SOF is not in use !!
USBH_ClassTypeDef VIDEO_Class = {
'VIDEO', VC_CLASS, USBH_VIDEO_InterfaceInit, USBH_VIDEO_InterfaceDeInit, USBH_VIDEO_ClassRequest, USBH_VIDEO_Process, USBH_VIDEO_SOFProcess};the ISR creates a Event for USBH_VIDEO_Process function.
ISO streams don't use handshake or controlframes btw HALT or STALL
you must react as fast as possible to free the DMA buffer
btw i'm using USB HS peripherials in FULL Speed mode...
USBH_StatusTypeDef USBH_LL_Init (USBH_HandleTypeDef *phost)
{ /* Init USB_IP */ if (phost->id == HOST_HS) { /* Link The driver to the stack */ hhcd_USB_OTG_HS.pData = phost; phost->pData = &hhcd_USB_OTG_HS;hhcd_USB_OTG_HS.Instance = USB_OTG_HS;
hhcd_USB_OTG_HS.Init.Host_channels = 12; hhcd_USB_OTG_HS.Init.speed = HCD_SPEED_FULL; hhcd_USB_OTG_HS.Init.dma_enable = ENABLE; hhcd_USB_OTG_HS.Init.phy_itface = USB_OTG_EMBEDDED_PHY;because you cant use USB FS peripherials with DMA mode!!
2018-07-12 07:41 AM
Hey thanks a lot for the example! I noticed that you don't make use of the SOF process call back in order to schedule the
USBH_IsocReceiveData requests. Isn't that mandatory ? I'm asking this because that's how I intend to do it but I notice that after a while the SOF interrupt do not happen any more and I'm not sure what the cause is.
Edit : Appart from that SOF issue, I am receiving Image data from the webcam with the correct settings.
Kind regards
Colin Cina