Skip to main content
JRoyn.1
Associate
March 1, 2022
Question

USB MTP object transfer only transfers 16 bytes of data

  • March 1, 2022
  • 4 replies
  • 1054 views

Hello,

I’m struggling using STM32_USB_Device_Library V2.10.

I’m developing a device with storage, and I want to transfer files via USB to a Windows PC using MTP.

I currently have a simple setup using STM32H7B3 eval board. I have made a test project with STM32_USB_Device_Library using the USB HS.

I have come so far that the device is showing up on the PC, and I can read contents (files) from the dummy file system on the device (currently I just fake the file system). Files are showing up correctly in File Explorer. I have 5 files, from 1K to 5K size, on the device.

But when I try to transfer the files to PC, I only get 16 bytes of data. Size of file is showing correct in Windows Explorer for the device, but for the transferred file, it is only 16 bytes. It also does not contain correct data, only a chunk of the first data in the file.

I have used usbd_mtp_if_template.c as start, and implemented the functions for reading file system data.

The USBD_MTP_Itf_ReadData() looks like this:

static uint32_t USBD_MTP_Itf_ReadData(uint32_t Param1, uint8_t *buff, MTP_DataLengthTypeDef *data_length)
{
 uint8_t *pBuf = buff; 
 
 data_length->totallen = Param1 * 1000; //Just fake length
 
 uint16_t i;
 for(i = 0; i < data_length->rx_length; i++)
 {
 *pBuf = i; //Just use fake data
 pBuf++;
 }
 
 data_length->readbytes = i;
 data_length->temp_length += i;
 
 return MTP_RESPONSE_OK;
}

Could someone please point me in the right direction, so this will work?

Regards,

Jan

4 replies

Associate II
September 20, 2024

Were you able to come up with a solution to this problem?  I am trying to work through the same thing and am having the same issues.

Grzegorz Kania
Associate II
June 24, 2026

 

uint8_t USBD_MTP_STORAGE_ReadData(USBD_HandleTypeDef  *pdev)
{
USBD_MTP_HandleTypeDef *hmtp = (USBD_MTP_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
uint32_t *data_buff;
uint32_t buffer_size;

/* Get the data buffer pointer from the low layer interface */
data_buff = ((USBD_MTP_ItfTypeDef *)pdev->pUserData[pdev->classId])->ScratchBuff;

/* Get Data Buffer Size */
buffer_size = ((USBD_MTP_ItfTypeDef *)pdev->pUserData[pdev->classId])->ScratchBuffSze;

if ((data_buff == NULL) || (buffer_size < MTP_CONT_HEADER_SIZE))
{
return (uint8_t)USBD_FAIL;
}

switch (ReadDataStatus)
{
case READ_FIRST_DATA:
/* Reset the data length */
MTP_DataLength.temp_length = 0U;
MTP_DataLength.totallen = hmtp->GenericContainer.length; //😁😁😁
MTP_DataLength.rx_length = buffer_size-MTP_CONT_HEADER_SIZE; //😁😁😁

/* Add the container header to the data buffer */
(void)USBD_memcpy((uint8_t *)data_buff, (uint8_t *)&hmtp->GenericContainer, MTP_CONT_HEADER_SIZE);

/* Perform the low layer read operation on the scratch buffer
* first packet expected data length: MPS - MTP_CONT_HEADER_SIZE
*/
(void)((USBD_MTP_ItfTypeDef *)pdev->pUserData[pdev->classId])->ReadData(hmtp->OperationsContainer.Param1,
(uint8_t *)data_buff +
MTP_CONT_HEADER_SIZE, &MTP_DataLength);

/* Start USB data transmission to the host */
(void)USBD_MTP_STORAGE_SendData(pdev, (uint8_t *)data_buff,
MIN((MTP_DataLength.readbytes + MTP_CONT_HEADER_SIZE), buffer_size));

/* Check if this will be the last packet to send ? */
//if (MTP_DataLength.readbytes < ((uint32_t)hmtp->MaxPcktLen - MTP_CONT_HEADER_SIZE))
if (MTP_DataLength.temp_length == MTP_DataLength.totallen) //😁😁😁
{
/* Move to response phase */
hmtp->MTP_ResponsePhase = MTP_RESPONSE_PHASE;
}
else
{
/* Continue to the next packets sending */
ReadDataStatus = READ_REST_OF_DATA;
}
break;

case READ_REST_OF_DATA:
MTP_DataLength.rx_length = buffer_size; //😁😁😁
/* Perform the low layer read operation on the scratch buffer */
(void)((USBD_MTP_ItfTypeDef *)pdev->pUserData[pdev->classId])->ReadData(hmtp->OperationsContainer.Param1,
(uint8_t *)data_buff, &MTP_DataLength);

/* Check if more data need to be sent */
if (MTP_DataLength.temp_length == MTP_DataLength.totallen)
{
/* Start USB data transmission to the host */
(void)USBD_MTP_STORAGE_SendData(pdev, (uint8_t *)data_buff, MIN(MTP_DataLength.readbytes, buffer_size));

/* Move to response phase */
hmtp->MTP_ResponsePhase = MTP_RESPONSE_PHASE;

/* Reset the state machine */
ReadDataStatus = READ_FIRST_DATA;
}
else
{
/* Start USB data transmission to the host */
(void)USBD_MTP_STORAGE_SendData(pdev, (uint8_t *)data_buff, MIN(MTP_DataLength.readbytes, buffer_size));

/* Keep the state machine into sending next packet of data */
ReadDataStatus = READ_REST_OF_DATA;
}
break;

default:
break;
}

return (uint8_t)USBD_OK;
}

There seem to be some errors in usbd_mtp_storega.c. I fixed four lines of errors and it started working.

However, I'm getting a strange error: I can't read a 12-byte file. Only 12-byte files.

ST Technical Moderator
June 24, 2026

Hi ​@JRoyn.1 ​@patrickwright 

If still having the same issue, would you share minimum firmware that reproduces it? For a new design, I would recommend proposing this MTP example using USBX rather than the classic USB Device Core MTP middleware since no equivalent example is planned as I mentioned here earlier.

​@Grzegorz Kania I suspect that manually changing totallen and rx_length can break the MTP transfer state machine in end of transfer handling or ZLP handling.

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
Grzegorz Kania
Associate II
June 25, 2026

Thanks for your links.

For now, I'm still trying to figure it out myself. The solution must be close. If I find it, I'll share it.

 

Fields totallen and rx_length should be prepared before call to USBD_MTP_ItfTypeDef.ReadData. I haven’t found where it is done. So this is reason of my fix.