Bug in CAN lib

Hello,

we want to use your toradexcelibaries in version 2.2 under c#. We’ve determined that they’re changed the internal type of the data field in the tCanMsg object from byte array to char array. In this context we were able to detect a conversion error in your CAN lib.

If we’re putting { 1,1,0,0,0,0,0,0 } in the char array, we’re expecting “01 01” on the CAN bus, however “31 00” was sent.
Next we put { 0,€,0,0,0,0,0,0 } in the char array and “AC 20” was sent. This indicates a wrong processing in your lib.

Hello @zualri,

Would you mind sharing some working source code with us in order to fully understand and reproduce the issue?

Thanks,

Samuel

Our setup contains a external CAN controller and the latest TdxAllLib 2.2 .

Line 138 contains the function which creates the CAN message.

Line 310 contains the function which calls the CAN_Write method.

The problem is, that a value of a Char object in C# is a 16-bit numeric (ordinal) value and in C it is an 8-bit value. Moreover, you are writing the hex-unicode on the bus instead of the original value.

SPI Signal: 31 00 31 00 was send to the controller, instead of 01 01

Dear @zualri,

Our v2.2 Toradex CE libraries don’t have DotNet demo application. v2.2b4501 library release is having the DotNet demo application. Could you please test the same on the DotNet(…\libDemos\dotNet\CanDemo\Demo.cs) application?

I tested that DotNet demo application, it works. Moreover, the CanMsg structure contains BYTE data[8] member. It will not convert char to int or TCHAR to int. The raw 8 byte memory contents will be passed to the library that will be sent to the controller. The libray will not do any conversion on that. We are happy to know if you any suggestion to improve our demo application.

the implementation is not well chosen, because the sense is not immediately apparent.

The tCanMsg.data field is a char array, but internally you are working with a byte array. In your linked demo application, you are using the Buffer.BlockCopy method to move the data from the specified byte array to the tCanMsg.data field (which is a char array). Which is an unnecessary overhead on an embedded device. In older versions of your lib, the tCanMsg.data field was a byte array. This makes it easier to understand.

    public struct tCanMsg
    {
        public UInt32 id;             ///< ID for CAN Bus Message Buffer (11 or 29bits used)
        public UInt32 canMsgFlags;    ///< message specific flags.Currently only 2 bits are used:\n * @ref IDE "CanMsgFlags_IDE"\n * @ref RTR "CanMsgFlags_RTR" (read only)
        public UInt32 dataLen;        ///< Message Data Length (0...8). This matches the DLC field of a CAN message.
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public Char[] data;        ///< Message Data (0...8 bytes used). This matches the data field of a CAN message.
    };

Moreover, I can not receive any data from CAN bus. Writing messages to bus works, but the receive method doesn’t receive data.

The receive and send methods are running in separate threads (as you can see in the gist).

The serial debug interface doesn’t show any error message.

Dear @zualri,

We are happy to receive your feedback and thank you. Soon we will try to improve the demo application.

Could you please quickly do a Can_Demo native application test, whether write and read APIs works on the native application? If the native application works well then we can narrow down the problem.

Thank you

It’s nice to hear, that you want to improve your demo application, but you have to improve the wrapper for C# too.

I have tested your native demo application and see exactly the same behavior as in the C# app. There is no error message on the serial debug interface.

For better research, I created an overview of the used pins.

1228-tegra-can-spi-pins-1.png

I have noticed a strange behavior on the SPI bus, after transmitting a message.

As you can see, the first byte indicates the write request ( 02 ) and the next byte must be the address of the register. But I didn’t find the address ( 06 ) in the MCP2515 datasheet. Can you explain, what sort of data I’m looking at?

Moreover, I didn’t saw any data on the SPI bus after calling the receive function.

Dear @zualri
register 0x06 of the MCP2515 is the register RXF1EID8. Please refer to Table 11-1: CAN CONTROLLER REGISTER MAP in the MCP2515 datasheet.
Regards, Andy

Thanks for the hint. Nevertheless, I didn’t see any data on SPI bus after calling the receive method in your native demo application.

Dear @zualri

To exclude the additional layer of .NET, let’s first focus on making the native demo working properly on your side.
I successfully tested the following modified version of the CanDemo:

The system I used for testing:

  • Colibri Evaluation Board V3.2A
    • Colibri T20
      • WEC7 V2.1
      • Toradex CE Libraries V2.3
  • CanDo ISO Can analyzer (sending 1 CAN message per second)

Make sure that you use the latest Toradex CE Libraries. You can copy the contents of the ZIP file over the existing Toradex CE Libraries, replacing the original CanDemo.
Enable Debug messages and monitor the serial port to see the output of the demo application.

  1. Run the executable, which is part of the .zip file.
  2. Select ‘b’ to start parallel Rx / Tx threads.
    Make sure you have another device on the CAN bus which sends messages.
    Do you see the messages for transmitted and received CAN messages on the serial port?
    ...
    CAN Transmit: Frame ID = 0x4ad Remote/Data Frame = DATA
    Data: 80 1 2 3 4 5 6 7
    CAN Rcv DATA [0x100 (STD)]:Data: 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08
    ...

If it does not work, here are a few hints for tracking down the problem:

  1. Check (and modify) the demo source code: are all parameters matching your system, for example baud rate?
  2. Check your cabling. Is there a proper termination on the CAN bus?
  3. Is there another sending device on the CAN bus?
  4. Do you use the same hardware pins as we do on the Evaluation board?
  5. Make sure your MCP2515 reset signal never gets active

Regards
Andy

Hi Andy,

thank you for your reply!

We managed to get your example to work finally. What prevented it from working correctly was the configuration of the interrupt-pin. In our setup, this is 127. So what we did was adding the lines

uIo = COLIBRI_PIN(127);
Can_SetConfigInt(hCan, L"ioInterrupt", uIo.GenericDefinition, StoreVolatile);

to the initialization routine (using lines 132ff from the original example as a reference). This did not compile, so after a digging around for a while, we simply changed the parameter of the SetConfigInt method to 127 - After all, the method is named SetConfigInt and we expected it to work with an actual integer value. This did compile and we could send data. Receiving was still impossible though.

Because this was compiling just fine and receiving just fine we suspected the problem is elsewhere and started digging around and monitored the CAN signal and the SPI signal using an oscilloscope. This yielded no relevant results, so we had a look at whether the interrupt pin actually was set and evaluated correctly. We found out that the pin got set correctly on incoming data but was never reset.

This time we suspected that we configured the pin incorrectly and started searching for a solution for the initial compile problem. Some googling brought the answer: https://stackoverflow.com/a/9903698/1521227: The compiler could not handle this correctly, we needed to rename the code file to *.cpp to trick Visual Studio into using the correct compiler settings. Once we changed this, the example did indeed compile and the interrupt-pin got evaluated and handled correctly - we could send and receive data.

Next steps will be to make this work with the .NET-layer on top of this.

Greetings