Question
CubeMX gen. project, CDC_Transmit_FS not working reliable
Posted on August 26, 2016 at 23:46
In a CubeMX (lastest version now) generated project CDC_Transmit_FS resp.
USBD_CDC_TransmitPacket do not work reliable. On every few request there are no data readable on host from the device (/dev/ttyACM0) despite the function returns a complete write. Target is a STM32F103CBT6 The trigger and reading on the host is at the command line It shall be replaced by a config tool later: Terminal line is set raw (stty -F /dev/ttyACM0 raw) and works at 115200 8N1. Commandline:printf 'push_settings\0' > /dev/ttyACM0; cat flashpage.0x0801Fbin > /dev/ttyACM0
and the other direction which is malfunctioning some times:
printf 'pull_settings\0' > /dev/ttyACM0; ./read-settings.pl > flashpage.0x0801F400-down.bin
read-settings.pl is the perl script below. It just don't return if malfunctioning happens.
#!/usr/bin/perl
open $device, ''< /dev/ttyACM0'' or die;
my $buffer;
my $bufsize=1024;
my $total=0;
my $read=0;
while ( $total < 1024 and $read = sysread($device , $buffer , $bufsize, $total ) )
{
$total += $read;
}
close $device;
syswrite ( STDOUT, $buffer);
The debugging implementation on the MCU is as the follows.
usbd_cdc_if.c:
...
#define APP_TX_DATA_SIZE 32
#define APP_RX_DATA_SIZE 64
...
static int8_t CDC_Init_FS(void)
{
/* USER CODE BEGIN 3 */
// Set Application Buffers
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
return (USBD_OK);
/* USER CODE END 3 */
}
...
// This is functioning very well and fills reliable my 1k
// received_data buffer in 16 steps. Rearming in main.
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
if ( cdc_received_tot + *Len > 1024 )
{
cdc_received_tot = 0;
}
// store bytes from UserRxBufferFS at next received_data index
memcpy(&received_data[cdc_received_tot], Buf, *Len);
cdc_received_tot += *Len;
cdc_received = 1;
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
return (USBD_OK);
/* USER CODE END 6 */
}
...
uint16_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
uint8_t result = USBD_OK;
/* USER CODE BEGIN 7 */
uint16_t bytes_written = 0;
uint16_t bytes_to_write;
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) hUsbDeviceFS.pClassData;
if (hcdc->TxState != 0)
{
return USBD_BUSY;
}
// Check if USB interface is connected
if ( hUsbDeviceFS.dev_state != USBD_STATE_CONFIGURED )
{
return = USBD_FAIL;
}
else
{
// Busy wait if USB is busy or exit on success or disconnection happens
while (bytes_written <
Len
)
{
HAL_Delay(10);
bytes_to_write = (Len - bytes_written) > APP_TX_DATA_SIZE ? APP_TX_DATA_SIZE : ( Len - bytes_written );
memcpy(UserTxBufferFS, &Buf[bytes_written], bytes_to_write );
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, bytes_to_write);
//Check if USB disconnected while retrying
if ( hUsbDeviceFS.dev_state != USBD_STATE_CONFIGURED )
{
return USBD_FAIL;
}
// Try send
result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
if (result == USBD_OK)
{
bytes_written += bytes_to_write;
}
else if (result != USBD_BUSY) // other error
{
return result;
}
}
}
/* USER CODE END 7 */
return bytes_written;
}
main.c:
while (1)
{
...
// 200 Hz, flag from timer callback which don't have to be paced in this part/mode of the program
if (PeriodElapsed == 1)
{
...
if ( cdc_received == 1)
{
if (rcv_settings == 1)
{
if (cdc_received_tot < 1024)
{
cdc_received = 0;
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
}
else
{
sprintf(buf, ''%d'', cdc_received_tot);
BSP_LCD_SetTextColor(LCD_COLOR_BLACK);
BSP_LCD_SetBackColor(LCD_COLOR_BLACK);
BSP_LCD_FillRect(0, 1 * 12, BSP_LCD_GetXSize(), 12);
BSP_LCD_SetTextColor(LCD_COLOR_YELLOW);
BSP_LCD_DisplayStringAtLine(1, (uint8_t *) buf);
cdc_received = 0;
cdc_received_tot = 0;
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
rcv_settings = 0;
if (erase_flash_page() != HAL_OK)
{
Error_Handler();
}
else
{
if (write_flash_vars((uint32_t*) received_data, 256, 0) != HAL_OK)
{
Error_Handler();
}
}
}
}
else if (strcmp((const char *) received_data, (const char *) ''bootloader'') == 0)
{
//setting flag in flash
//so reborn as bootloader we can know that we should not start this live immediately again
// write string ''DFU'' (4 bytes incl. trailing \0) to last 32 bit wide space of flash page
write_flash_vars((uint32_t*) ''DFU'', 1, 1020);
// is this really needed? I think it is not
HAL_NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
HAL_NVIC_DisableIRQ(USART1_IRQn);
HAL_NVIC_DisableIRQ(TIM2_IRQn);
// set stackpointer pointing to bootloader startup and reset system
__set_MSP(*(__IO uint32_t*) BOOTLOADER_ADDRESS);
HAL_NVIC_SystemReset();
}
else if (strcmp((const char *) received_data, (const char *) ''push_settings'') == 0)
{
cdc_received_tot = 0;
cdc_received = 0;
rcv_settings = 1;
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
}
else if (strcmp((const char *) received_data, (const char *) ''pull_settings'') == 0)
{
cdc_received_tot = 0;
cdc_received = 0;
snd_settings = 1;
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
read_flash_vars((uint32_t *) flash_buf, 256, 0);
BSP_LCD_SetTextColor(LCD_COLOR_BLACK);
BSP_LCD_SetBackColor(LCD_COLOR_BLACK);
BSP_LCD_FillRect(0, 0 * 12, BSP_LCD_GetXSize(), 12);
BSP_LCD_SetTextColor(LCD_COLOR_YELLOW);
BSP_LCD_DisplayStringAtLine(0, (uint8_t *) ''XXXX'');
}
}
if (snd_settings == 1 )
{
usb_res = CDC_Transmit_FS((uint8_t*) flash_buf, 1024);
sprintf(buf, ''%d'', usb_res);
BSP_LCD_SetTextColor(LCD_COLOR_BLACK);
BSP_LCD_SetBackColor(LCD_COLOR_BLACK);
BSP_LCD_FillRect(0, 0 * 12, BSP_LCD_GetXSize(), 12);
BSP_LCD_SetTextColor(LCD_COLOR_YELLOW);
BSP_LCD_DisplayStringAtLine(0, (uint8_t *) buf);
if ( usb_res != USBD_BUSY)
{
snd_settings = 0;
}
}
}
...
}
}
...
On the display one can read always the completed 1024 bytes even if there is nothing to read
from /dev/ttyACM0. Of course variables like cdc_received_tot and so on are declared volatile.
How to debug this thing?
Bug in CDC Lib?
Kind regards