cancel
Showing results for 
Search instead for 
Did you mean: 

CCID USBD transfer block (splitting)

Ayoub-Marghoub
Associate II

Hello,

I'm currently preparing the firmware for a USB NFC reader (CCID). I'm working with the STM32F103 MCU and the ST25R3916 NFC reader.
The STM32F103 MCU is programmed on a CCID USB device using the CCID USBD driver provided by STM32. The MCU acts as the mediator between the computer and the ST25R3916 NFC reader. It takes the APDU command sent by the computer and transfers it to the NFC reader, and takes the NFC reader's response and transfers it to the computer using the SC_Itf_XferBlock() function.

The STM32F103 MCU supports usb full-speed, this means that the maximum amount of data to be transferred to the computer is 64 bytes. If you want to transfer data larger than 64 bytes, you transfer it using chunk-by-chunk methods.

To transfer 253-byte data, the splitting is as follows:
5 chunks: chunk 1 (54 bytes of data with 10 bytes of header), chunk 2 (64 bytes of data), chunk 3 (64 bytes of data), chunk 4 (64 bytes of data), and chunk 5 (7 bytes).

The issue is that when I try to transfer 253 bytes of data using splitting, the computer finishes the transfer directly after chunk 4 and doesn't wait for chunk 5, knowing that chunk 4 is 64 bytes long, and I don't send any 0s after chunk 4.
This problem is related to my firmware (CCID USB driver). Can you help me resolve this issue?
Thanks in advance.

4 REPLIES 4
FBL
ST Employee

Hi @Ayoub-Marghoub 

Did you refer to this example provided on H7?

It seems the sum is more than 253Bytes! 4 chunks already 256Bytes.

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.




Best regards,
FBL
Ayoub-Marghoub
Associate II

The first ten bytes of the first chunk are reserved for the transfer header; 54 bytes remain for the data.
The first chunk contains 54 bytes of data, and the following three chunks contain 64 bytes of data, totaling 246 bytes of data. To send 253 bytes of data to the computer, another chunk is needed to contain the remaining seven bytes.
When I capture the transfers with Wireshark software, I find that the computer only received 246 bytes of data. It didn't wait for the fifth chunk; it completed the transfer directly after receiving the fourth chunk.

FBL
ST Employee

Hi @Ayoub-Marghoub 

 

The issue is more likely linked to your firmware.

FBL_0-1754059525664.png

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.




Best regards,
FBL

My firmware is based on this ccid usbd driver https://github.com/STMicroelectronics/stm32-mw-usb-device/blob/master/Class/CCID/Src/usbd_ccid.c .

The issue that I face, the PC finishes receiving data immediately after receiving 256 bytes (10 bytes of header + 246 bytes of data). when I want to send to pc 253 bytes of data + 10 bytes of header (263 bytes in total) by splitting (64 bytes by 64 bytes) the PC finishes receiving data immediately after receiving the fourth chunk which is 256 bytes (10 bytes of header and 243 bytes of data), It doesn't wait for the fifth chunk, which carries the remaining 7 bytes of my data which arrives in an unknown message despite the fact that I define the size of the data to be sent as 253 bytes. Images 1 and 2 show these details captured by wireshark software.1122

this is my code used to send data by chunks :

uint8_t SC_Itf_XferBlock(uint8_t *ptrBlock, uint32_t blockLen, uint16_t expectedLen,
                         USBD_CCID_BulkIn_DataTypeDef *CCID_BulkIn_Data)
{
  uint8_t ErrorCode = SLOT_NO_ERROR;
  UNUSED(CCID_BulkIn_Data);
  UNUSED(expectedLen);
  UNUSED(blockLen);
  UNUSED(ptrBlock);
 
  if (ProtocolNUM_OUT == 0x00U)
  {
    /* Add your code here */
  }
 
  if (ProtocolNUM_OUT == 0x01U)
  {
    /* Add your code here */
 
 
  data_to_send_size = 253;
  
 
  CCID_BulkIn_Data->dwLength = data_to_send_size;
  memcpy(CCID_BulkIn_Data->abData, data_to_send, data_to_send_size);
 
  if (data_to_send_size > 54U)
  {
      tx_remaining_ptr = &data_to_send[54];
      tx_remaining_len = data_to_send_size - 54;
      tx_in_progress   = 1;
  }
  else
  {
      tx_remaining_ptr = NULL;
      tx_remaining_len = 0;
      tx_in_progress   = 0;
  }
 
  }
 
  if (ErrorCode != SLOT_NO_ERROR)
  {
    return ErrorCode;
  }
 
  return ErrorCode;
}
static uint8_t USBD_CCID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
  USBD_CCID_HandleTypeDef *hccid = (USBD_CCID_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
 
#ifdef USE_USBD_COMPOSITE
  /* Get the Endpoints addresses allocated for this class instance */
  CCIDInEpAdd  = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
  CCIDCmdEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_INTR, (uint8_t)pdev->classId);
#endif /* USE_USBD_COMPOSITE */
 
  if (epnum == (CCIDInEpAdd & 0x7FU))
  {
    /* Filter the epnum by masking with 0x7f (mask of IN Direction)  */
 
    /*************** Handle Bulk Transfer IN data completion  *****************/
 
    switch (hccid->blkt_state)
    {
      case CCID_STATE_SEND_RESP:
 
        /* won't wait ack to avoid missing a command */
    if(tx_in_progress && tx_remaining_len > 0)
    {
    uint8_t chunk = (tx_remaining_len > 64) ? 64 : tx_remaining_len;
 
    USBD_LL_Transmit(pdev, CCIDInEpAdd, (uint8_t *)tx_remaining_ptr, chunk);
 
    tx_remaining_ptr += chunk;
    tx_remaining_len -= chunk;
    }
    else
    {
    tx_in_progress = 0;
 
hccid->blkt_state = CCID_STATE_IDLE;
 
/* Prepare EP to Receive  Cmd */
(void)USBD_LL_PrepareReceive(pdev, CCID_OUT_EP,
hccid->data, hccid->MaxPcktLen);
    }
 
        break;
 
      default:
        break;
    }
  }
  else if (epnum == (CCIDCmdEpAdd & 0x7FU))
  {
    /* Filter the epnum by masking with 0x7f (mask of IN Direction)  */
 
    /*************** Handle Interrupt Transfer IN data completion  *****************/
 
    (void)USBD_CCID_IntMessage(pdev);
  }
  else
  {
    return (uint8_t)USBD_FAIL;
  }
 
  return (uint8_t)USBD_OK;
}