cancel
Showing results for 
Search instead for 
Did you mean: 

Certain chars lost during USB_FS transmission

OIp.1
Associate III

Hi. I am using a STM32F756-EVAL board for USB_FS transmission.

messageprocesser.c

#include "messageprocesser.h"
#include "main.h"
#include "usbd_cdc_if.h"
#include <string.h>
#include "string.h"
 
//Sample cmd: TOARM_FIRMV_00000000_4C\r\n
#define MESSAGE_LENGTH 25
#define DESTINATION_LENGTH 5
#define COMMAND_CHAR 6	//See SW Protocol or sample cmd
#define COMMAND_LENGTH 5
#define DATA_CHAR 12
#define DATA_LENGTH 8
#define CHECKSUM_CHAR 21
#define CHECKSUM_LENGTH 2
 
enum cmd {FIRMV, VALCN, RQSPC, INVAL};
 
enum cmd cmd_Converter(unsigned char* inputCmd){//Converts the input cmd from uint8_t to an enum.
	switch (inputCmd[0]){	//Currently we are using a switch-case. If we get too many commands (+100), switch to something else.
	case 'F':
		if (memcmp(inputCmd, "FIRMV", COMMAND_LENGTH) == 0) return FIRMV;
		else return INVAL;
		break;
	case 'R':
		if (memcmp(inputCmd, "RQSPC", COMMAND_LENGTH) == 0) return RQSPC;
		else return INVAL;
		break;
	case 'V':
		if (memcmp(inputCmd, "VALCN", COMMAND_LENGTH) == 0) return VALCN;
		else return INVAL;
		break;
	default:
		return INVAL;
	}
}
 
void process_Message(uint8_t* message, uint16_t Len){
	//HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10);
	unsigned char inputCmd[COMMAND_LENGTH];		//These are not null-terminated strings.
	unsigned char inputData[DATA_LENGTH];	//These are just an array of chars.
 
	memcpy((char*) inputCmd, (const char*)message + COMMAND_CHAR, COMMAND_LENGTH);
	memcpy((char*) inputData, (const char*)message + DATA_CHAR, DATA_LENGTH);
	enum cmd enumCmd = cmd_Converter(inputCmd);
	void (*cmd_Function_Pointer[])(unsigned char* inputData) = {FIRMV_F, VALCN_F, RQSPC_F, INVAL_F};	//Is this even needed?
	(*cmd_Function_Pointer[enumCmd])(inputData);	//What is going on here?
 
}
 
//void seperate_Cmd_Data(uint8_t* message, uint16_t Len, **extCmd, **extData){   	//Delete by 16/02/23.
//
//}
 
void FIRMV_F(unsigned char *inputData){
	//HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10);
	unsigned char outputCmd[COMMAND_LENGTH];
	unsigned char outputData[DATA_LENGTH];
	memcpy(outputCmd, "FIRMV", COMMAND_LENGTH);
	memcpy(outputData, "01050A00", DATA_LENGTH);
	unsigned char *outputMessage;
	build_Outgoing_Message(outputCmd, outputData, &outputMessage);
	CDC_Transmit_FS(outputMessage, MESSAGE_LENGTH);
	free(outputMessage);
}
 
void VALCN_F(unsigned char *inputData){
	//HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10);
	unsigned char outputCmd[COMMAND_LENGTH];
	unsigned char outputData[DATA_LENGTH];
	memcpy(outputCmd, "VALCN", COMMAND_LENGTH);
	memcpy(outputData, "00000000", DATA_LENGTH);
	unsigned char *outputMessage;
	build_Outgoing_Message(outputCmd, outputData, &outputMessage);
	CDC_Transmit_FS(outputMessage, MESSAGE_LENGTH);
	free(outputMessage);
}
 
void RQSPC_F(unsigned char *inputData){
	int messageCount = 2;
	unsigned char outputMessage[MESSAGE_LENGTH * messageCount];
 
	//Load all elements into 2D array
	unsigned char outputCmd [messageCount][COMMAND_LENGTH];
	unsigned char outputData [messageCount][DATA_LENGTH];
 
	memcpy(outputCmd[0], "GVP01", COMMAND_LENGTH);
	memcpy(outputData[0], "00000000", DATA_LENGTH); //Data is serial number
 
	memcpy(outputCmd[1], "GVP02", COMMAND_LENGTH);
	memcpy(outputData[1], "30082022", DATA_LENGTH); //Data is date of lid calibration
 
	unsigned char *outputMessageBuf;
	build_Outgoing_Message(outputCmd[0], outputData[0], &outputMessageBuf);
	//Function that combines all strings
	memcpy(outputMessage, outputMessageBuf, MESSAGE_LENGTH);
	memset(outputMessageBuf, '\0', MESSAGE_LENGTH);
	build_Outgoing_Message(outputCmd[1], outputData[1], &outputMessageBuf);
 
	//Function that combines all strings
	memcpy(outputMessage + MESSAGE_LENGTH * 1, outputMessageBuf, MESSAGE_LENGTH);
 
	CDC_Transmit_FS(outputMessage, MESSAGE_LENGTH * messageCount);
	free(outputMessage);
}
 
void INVAL_F(unsigned char *inputData){
	HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10);
	unsigned char outputCmd[COMMAND_LENGTH];
	unsigned char outputData[DATA_LENGTH];
	memcpy(outputCmd, "REEEE", COMMAND_LENGTH);
	memcpy(outputData, "99999999", DATA_LENGTH);
	unsigned char *outputMessage;
	build_Outgoing_Message(outputCmd, outputData, &outputMessage);
	CDC_Transmit_FS(outputMessage, MESSAGE_LENGTH);
	free(outputMessage);
}
 
int checkSum_Generator(uint8_t* message){
	  int checkSum = 0;
	  for (int i = 0; i < CHECKSUM_CHAR; i++){  //Gives the cs of TOARM_COMND_DATA0000_.
		  checkSum ^= message[i];
	  }
	  return checkSum;
}
 
void checkSum_Hex_Converter(int checkSum_Dec){
	//char outputCheckSumHex[2] = {'0', '0'};
}
 
void build_Outgoing_Message(uint8_t* cmd, uint8_t* data, uint8_t **message){
	unsigned char *outputMessage = malloc(MESSAGE_LENGTH);
	//uint8_t outputMessage[MESSAGE_LENGTH] = "TOWST_";
	unsigned char outputDestination[5] = {'T', 'O', 'W', 'S', 'T'};
	memcpy((char*) outputMessage, (const char*) outputDestination, DESTINATION_LENGTH);	//Need to split the macros.
	outputMessage[COMMAND_CHAR - 1] = '_';
	memcpy((char*) outputMessage + COMMAND_CHAR, (const char*) cmd, COMMAND_LENGTH);
	outputMessage[COMMAND_CHAR + COMMAND_LENGTH] = '_';
	memcpy((char*) outputMessage + DATA_CHAR, (const char*) data, DATA_LENGTH);
	outputMessage[DATA_CHAR + DATA_LENGTH] = '_';
 
	//Deal with checksum
	int outputCheckSum = checkSum_Generator(outputMessage);
	char outputCheckSumHex[2] = {'0', '0'};
	itoa (outputCheckSum, outputCheckSumHex, 16);
	if (outputCheckSum < 16) { //Adds a 0 if CS has fewer than 2 numbers
	    outputCheckSumHex[1] = outputCheckSumHex[0];
	    outputCheckSumHex[0] = '0';
	}
	outputCheckSumHex[0] = toupper (outputCheckSumHex[0]);
	outputCheckSumHex[1] = toupper (outputCheckSumHex[1]);
 
	memcpy((char*) outputMessage + CHECKSUM_CHAR, (const char*) outputCheckSumHex, CHECKSUM_LENGTH);
	outputMessage[23] = '\r';
	outputMessage[24] = '\n';
 
	//Return char array outside
	*message = outputMessage;
}

usbd_cdc_if.c

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
 
  memset (buffer, '\0', 64);  // clear the buffer
  uint8_t len = (uint8_t)*Len;	//Converts Len as uint32_t to len as uint8_t
  memcpy(buffer, Buf, len);  // copy the data to the buffer
  memset(Buf, '\0', len);   // clear the Buf also
 
  process_Message(buffer, len);
  return (USBD_OK);
  /* USER CODE END 6 */
}
 
/**
  * @brief  CDC_Transmit_FS
  *         Data to send over USB IN endpoint are sent over CDC interface
  *         through this function.
  *         @note
  *
  *
  * @param  Buf: Buffer of data to be sent
  * @param  Len: Number of data to be sent (in bytes)
  * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
  */
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 7 */
  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;	//hcdc is given the data of pClassData. What is pClassData?
  if (hcdc->TxState != 0){	//If TxState in hcdc is not 0, return USBD_BUSY.
    return USBD_BUSY;
  }
  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);	//SetTxBuffer sets the size of the buffer, as well as the buffer itself.
  result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);	//USBD_CDC_TransmitPacket(&hUsbDeviceFS) transmits
  /* USER CODE END 7 */
  return result;
}

On my output I am facing a partially truncated results. I am expecting an output like:

TOWST_REEEE_99999999_27

But I am getting:

T_REEEE_99999999_27

I have used the debugger to determine that the message is "TOWST_REEEE_99999999_27\r\n" at the outputMessage at line 115, as well as line 36, usbd_cdc_if.c

However, it is "T_REEEE_99999999_27\r\n" at stm32f7xx_ll_usb.c, USB_WritePacket(USB_OTG_GlobalTypeDef *USBx, uint8_t *src,

                 uint8_t ch_ep_num, uint16_t len, uint8_t dma)

HAL_StatusTypeDef USB_WritePacket(USB_OTG_GlobalTypeDef *USBx, uint8_t *src,
                                  uint8_t ch_ep_num, uint16_t len, uint8_t dma)
{
  uint32_t USBx_BASE = (uint32_t)USBx;
  uint8_t *pSrc = src;
  uint32_t count32b;
  uint32_t i;
 
  if (dma == 0U)
  {
    count32b = ((uint32_t)len + 3U) / 4U;
    for (i = 0U; i < count32b; i++)
    {
      USBx_DFIFO((uint32_t)ch_ep_num) = __UNALIGNED_UINT32_READ(pSrc);	//What is USBx_DFIFO((uint32_t)ch_ep_num)?
      pSrc++;
      pSrc++;
      pSrc++;
      pSrc++;
    }
  }
 
  return HAL_OK;
}

This issue only started showing up after I implemented line 134/135 in messageprocesser.c

unsigned char outputDestination[5] = {'T', 'O', 'W', 'S', 'T'};
	memcpy((char*) outputMessage, (const char*) outputDestination, DESTINATION_LENGTH);	//Need to split the macros.

Please let me know if more information is required to solve this issue.

1 REPLY 1

I don't use Cube, but the buffer, from which you are transmitting, should probably be persistent. Transmission does not happen at the moment when you call CDC_Transmit_FS, but later, when host sends IN token, when data are actually copied into the FIFO, so those data must be unchanged until that moment.

Citing from CDC chapter of UM1734:

6.5.2 Data IN transfer management (from device to host)

The data transfer is managed periodically depending on host request (the device specifies

the interval between packet requests). For this reason, a circular static buffer is used for

storing data sent by the device terminal (i.e. USART in the case of Virtual COM Port

terminal).

JW