USART - CAN Dongle (Fixed Size Serializer with Robust Timeout Handling)
Last updated
Last updated
We will build a CAN-USB (UART) Adapter in this section.
We will be using the SerialBus packet format from python-can.
The UART packet will be framed as follows:
Start of frame | Timestamp | DLC | Arbitration ID | Payload | End of frame | |
---|---|---|---|---|---|---|
Length (Byte) | 1 | 4 | 1 | 4 | 0 - 8 | 1 |
Data type | Byte | Unsigned 4 byte integer | Unsigned 1 byte integer | Unsigned 4 byte integer | Byte | Byte |
Byte order | - | Little-Endian | Little-Endian | Little-Endian | - | - |
Description | Must be 0xAA | Usually s, ms or µs since start of the device | Length in byte of the payload | - | - | Must be 0xBB |
Notice that this is actually a variable-length data packet ---- the packet length can range from 11 to 19 depending on the number of bytes in the payload. However, because we can calculate the size of the entire packet from the DLC field, we still regard this as a fixed-size data packet.
Receiving an unknown length of data will be much more challenging, and involves another entirely different set of mechanisms.
Because the TX and RX process of our CAN dongle is independent, and we need to respond to both of them in time, we will use interrupt-based message handling.
First, we enable the NVIC interrupt on UART2.
At the end of code initialization, we start receiving UART using interrupt.
Because we cannot know the length of the data field before we read out the header section, we will receive for 11 bytes here, which handles the following two circumstances:
If DLC is 0, then we have received all data available, and can go ahead and process the packet. The index 10 will contain the End of Frame.
If DLC is greater than 0, we have received the header section as well as the first byte of data section. We will index 10 to index 0 of our data, and proceed to receive another DLC
number of bytes, which will contain the remaining data and the End of Frame.
Because of the two different states mentioned above, we need to define a global variable uart_rx_data_pending
to signal our interrupt routine which part of the packet we are receiving ---- header part, or the payload part.
Then, in the interrupt handler, we process the data and do state changing.