OBD-II and ELM327 (7), MITM Timing Analysis

I tried to replay everything on my desktop on the car, but HUD doesn't work. Fortunately, the car is still working, so I'm trying to figure out what happened

My intuition told me, maybe the MITM latency caused the problem, which caused HUD behavior unexpected (in later article, I would prove this was wrong)


Check minimum latency first
  • CAN@500kbps, 8 bytes packets needs roughly 200us
    • 1 bit requires 2us, 8 byte packets requires ~100bits (considering bit-stuffing)
    • t_pkg = 2us * 100bit = 200us
  • Mitm latency (t_delay) includes two parts
    • t_delay = t_mitm + t_pkg
      • t_mitm is internal processing delay within Linux operating system
      • t_pkg is the time to re-transmit packet, so this value would be 200us
        • Unless using FPGA to re-design CAN controller, which sending as receiving. Otherwise, the time can't be avoided in normal method
  • HUD undertakes two shot of t_delay as query & wait-for-response
    • Before
      • t_roundtrip1 = t_pkg + t_pkg = t_pkg*2
    • After
      • t_roundtrip2 = (t_pkg + t_delay) + (t_pkg + t_delay) = t_pkg*4 + t_mitm*2
    • Delay due to MITM
      • t_roundtrip2 - t_roundtrip1 = t_pkg*2 + t_mitm*2

  • In Raspberry Pi, minimum t_mitm = 20us
    • CAN controller MCP2515 uses 10Mhz SPI interface
      • 10Mhz, 1bit = 0.1us
      • Minimum time to read/write 100bits from MCP2515 is 10us, read + write takes 20us
  • Assume HUD had a query timeout within 1000us (NOTICE this is wrong !!)
    • 1000 = t_pkg*4 + t_mitm*2 = 800us + t_mitm*2
      • This means that HUD is satisfied if t_mitm < 100us
    • I don't know the true requirement of HUD, so just casual guess here
  • Estimate current platform's t_mitm, and minimize it as much as possible

The 1st software: Python-CAN, t_mitm is 1920us !!!!

I love Python, it's easy to write. With Python-CAN, I can use Python without torturing Socket Programming. I used Python3 and learned asyncio module as well this time. Besides, I solved following questions as well:
  • If receiving error frame, I shall filtered the error frame
  • Before HUD connects to CANBUS, the opposite CAN interface can't transmit data successfully and the CAN TX-buffer would overflow
    • So the transmit code shall add sort of try..except
Using new technology is fun, and the code is elegant. Building Pi-WIRE & Pi-CAR with Python-CAN is easy. However, it's a bit slow. In the picture below, yellow signal is CAN packet arrival and blue signal is transmission. The distance between them was t_mitm, whose value was in upper left corner, BY-AX=1.92ms=1920us. This is sort of the *evidence* that Python is not suitable to handle the micro-second processing condition




The 2nd software: use candump to inter-connect can0/can1, but t_mitm is still 570us

The most wonderful part of Raspberry Pi was Linux, which had ready-to-use, Free tool, CAN-UTILS. The tool was easy to use, and can connect with other utilities. The drawback was users shall understand more details, with steeper learning curve
  • cansend (Send packet)
  • candump (Record CAN traffic)
  • cangen (Generate random CAN packet)
  • cansniffer (online analyze CAN packet)
  • ISO-TP tools
Actually, we can use candump to forward packets between can0/can1 without writing any code. And it's convenient to sniffer packets:
  • Two commands to inter-connect CAN0/CAN1
    • candump -s2 -B can0 can1 &
    • candump -s2 -B can1 can0 &
      • -s2, silent mode, no output to terminal
      • -B, bridging mode, no loopback
  • Sniffer CAN0/CAN1
    • candump -t d -l can0 can1 > can_traffic.txt &
      • -t d, show timestamp in delta way
      • -l can0, can1, logging traffic of can0/can1
The result showed t_mitm reduced to ~25%, but the experiment still failed



Other Attempt
  • Adjust Linux task priority (use nice)
    • No effect, since the system is not busy at all. Higher priority doesn't help
  • Modify Linux scheduling (SCHED_FIFO)
    • I had 4x core, so use two core to run dedicated candump
    • No effect as well
  • Write my own C program with socketcan
    • Slightly improved, but no much effect

Latency coming from MCP2515 Linux Device Driver

In the picture below, yellow is CAN bus signal, and purple line CAN packet out, so the difference between yellow to purple was roughly t_mitm. The deep-blue was IRQ signal sent by MCP2515, where low-level means IRQ asserted. In the picture, t_mitm is almost processing MCP2515 IRQ. This proved MCP2515 Linux Device Driver efficiency is quite poor



Searching "Linux MCP2515 Latency" in the Internet, many people also encountered the problem. The key was SPI itself is slow, using SPI to handshake with MCP2515 is quite slow. Besides, Linux context switch also takes time

I tried to add printk in MCP2515 driver to profile execution time, and the most of t_mitm was in kernel space. I could only say SPI driver on Raspberry Pi is not very fast. Shall I spend more time on MCP2515? Or try different program?
  • https://github.com/msperl/mcp2515a
  • https://github.com/raspberrypi/linux/pull/147/files
  • https://linux-rpi-kernel.infradead.narkive.com/AcfW6GTP/arm-bcm2835-dma-driver-spi-optimize-message-some-questions-info
  • https://github.com/msperl/spi-bcm2835/wiki
  • https://elinux.org/images/2/20/Whats_going_on_with_SPI--mark_brown.pdf

Other methods
  • Buy some CAN-USB devices that Linux kernel supports 
    • 8device Korlan USB2CAN looks good at 65 USD
      • However, USB itself seems having problem
        • USB 2.0 Full speed, frame period is 1ms (USB generates 1000us latency)
        • USB 2.0 High speed, frame period is 125us, still not good
  • Do it by myself, ESP32 had CAN and WiFi. With CAN transceiver, I can do CAN2WiFi
    • It's fun to do a remote CAN logger
    • WiFi latency is even harder to do MITM, that's probably ms level
  • Do it by myself again, I bought Nucleo-F767ZI, which had 3x CAN, 1x Ethernet, 1x USB
    • It can't be faster to relay CAN packets within MCU
    • MCU@216Mhz, fast enough, I can do anything within
    • The sniffer result can be written by Ethernet or USB-OTG

This article is nothing to do with ELM327...

Comments

Popular posts from this blog

OBD-II and ELM327 (1)

OBD-II and ELM327 (3), try to decode CAN package recorded by ELM327

OBD-II and ELM327 (2), the underlying interface of ELM327