Wrong ID of CAN frame on Colibri iMX6 Wince

I am testing flexcan on colibri imx6 WinCE1.3b4 with Toradex CE Libraries v2.1 as customer also reports the same issue to us. The test code is based on Can_Demo application. Before entering ‘2’ to receive CAN frame, USB2CAN adapter on PC has sent 400 frames to imx6. Then input ‘2’, and the first read can frame’s ID is wrong as well as the data payload.

766-11.png

It can also happen if the gap of each frame is 1ms from USB2CAN adapter on PC meanwhile printing every frame received on iMX6(it is not easy to reproduce if only printing 500th frame instead of each one). Is it possible that the buffer in flexcan driver is overflow if Can_Read is not called
timely when the frame gap is very small e.g. 1ms. CAN bus is critical task in this customer’s project, wrong frame ID is not accepted as this wrong id could be in valid range 29bit/11bit.
Here is the main code.

DWORD CanRxProcess(HANDLE hCan)
{
    INT i;
    tCanMsg canBuf = {0};
    BYTE data[8] = {0};   // Rx buffer
	DWORD busStatus;
	INT j =0;

    // Configure timeout to 5 sec, by default it is set to 1 sec
    Can_SetConfigInt(hCan, L"Timeout", 5000, StoreVolatile);    // optional

    // 4. Use CAN
	while(1)
	{
		canBuf.dataLen = 8;
		if (Can_Read(hCan, &canBuf))
		{
			j++;
		
			printf("\nCAN Receive: Frame ID = 0x%x, len %d, COUNT: %d\n", canBuf.id, canBuf.dataLen, j);
		
			if(canBuf.id == 0x11)
			{

			}
			else
			{
				//return 0;
				printf("\nCAN Receive error, other ID found.\r\n");
				printf("\nCAN Receive: Frame ID = 0x%x, len %d\n", canBuf.id, canBuf.dataLen);
				for (i = 0; i<canBuf.dataLen; i++)
				{
					printf(" %d", canBuf.data[i]);
				}
				return 0;

			}
			
		}
		else
		{
			printf("\nCAN Receive error\r\n");
			Can_GetConfigInt(hCan, L"BusStatus", &busStatus);
			printf("BusStatus %x\n",busStatus);
		}

	}

    return 0;
}



int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdLine, int cmdShow)
{
    HANDLE hCan = NULL;
    BOOL isSelectionDone = FALSE;
    INT selectedOption;
    BOOL returnValue = FALSE;
    DWORD busStatus;

	UNREFERENCED_PARAMETER(instance);
	UNREFERENCED_PARAMETER(prevInstance);
	UNREFERENCED_PARAMETER(cmdLine);
	UNREFERENCED_PARAMETER(cmdShow);

    printf("Toradex CAN demo\r\n");

	hCan = Can_Init(L"CAN1"); // Internal CAN
	
    if (hCan == NULL)
    {
        printf("Error in CAN initialization\r\n");
        return FALSE;
    }

	{
        uIo ioRx =  COLIBRI_PIN(63);
        uIo ioTx =  COLIBRI_PIN(55);
        Can_SetConfigInt(hCan, L"ioRx", ioRx.GenericDefinition, StoreToRegistry);
        Can_SetConfigInt(hCan, L"ioTx", ioTx.GenericDefinition, StoreToRegistry);
    }

    returnValue = Can_SetConfigString(hCan, L"FilterFrameFormat",    L"None",     StoreVolatile);
	returnValue = Can_SetConfigString(hCan, L"FilterRemote",   L"None",     StoreVolatile);
    returnValue = Can_SetConfigInt(hCan, L"FilterID",   0x00,       StoreVolatile);     //
    returnValue = Can_SetConfigInt(hCan, L"FilterMask", 0x00,       StoreVolatile);     //

    {
        DWORD bitRate;
		bitRate = 250000;
        returnValue = Can_SetConfigInt(hCan, L"BitRateHz", bitRate, StoreVolatile);
    }

    if (!Can_Open(hCan))
    {
        printf("CAN Open failed\r\n");
        Can_Deinit(hCan);
        return 0;
    }

    returnValue = Can_GetConfigInt(hCan, L"BusStatus", &busStatus);
    printf("BusStatus %x\n",busStatus);

    do
    {
        printf("\nOptions:\n");
        printf("1. CAN Transmit   2. CAN Receive   3. Quit\n\n");
        printf("Choose the option and press Enter key: ");
        scanf_s("%d", &selectedOption);
        printf("\n");

        switch (selectedOption)
        {
            case 1:
                /// CAN Transmit
                CanTxProcess(hCan);
                break;

            case 2:
                /// CAN Receive
                CanRxProcess(hCan);
                break;

            case 3:
                /// Quits the demo
                isSelectionDone = TRUE;
                break;

            default:
                printf("Invalid entry, try again!\n\n");
                isSelectionDone = FALSE;
        }
    } while (!isSelectionDone);
    Can_Close(hCan);
    Can_Deinit(hCan);

    return(TRUE);
}

CAN_Read should return (DWORD)-1 if it fails. If you send 400 packets and then call read this will overflow the CAN internal queues (HW fifo and SW fifo) that are limited to 256 message before you call CAN_Read, so the first call to it will fail (return -1) to report this issue, in this case packet data are not valid.

However, the first call to CanRxProcess dosen’t return -1. As the code shows, there is a if condition for CanRead(), but it still prints the wrong ID and the frame payload only if Can_Read() returns 1.

while(1)
{
	canBuf.dataLen = 8;
	if (Can_Read(hCan, &canBuf))
	{
		j++;
		printf("\nCAN Receive: Frame ID = 0x%x, len %d, COUNT: %d\n", canBuf.id, canBuf.dataLen, j);
		if(canBuf.id == 0x11)
		{
		}
		else
		{
			printf("\nCAN Receive error, other ID found.\r\n");
			printf("\nCAN Receive: Frame ID = 0x%x, len %d\n", canBuf.id, canBuf.dataLen);
			for (i = 0; i<canBuf.dataLen; i++)
			{
				printf(" %d", canBuf.data[i]);
			}
			return 0;
		}
		
	}
	else
	{
		printf("\nCAN Receive error\r\n");
		Can_GetConfigInt(hCan, L"BusStatus", &busStatus);
		printf("BusStatus %x\n",busStatus);
	}

}

We found an issue on the implementation used on imx6,imx7 and vybrid.
This is going to be fixed in next release of the libraries.