These exercises assume you have read 07 — Can Bus Encoder and 08 — Uart Gps Nmea.
Answer in your own words. If you can explain it simply, you understand it.
A1. You wire up a CAN node using a TJA1050 transceiver and a 3.3V STM32. Describe the exact failure mode that will occur. Why does the TJA1050 not work here? What chip should you use instead, and why?
A2. A technician measures 112Ω between CANH and CANL on a running 2-node CAN bus. Is this correct, too high, or too low? Where should the two 120Ω termination resistors be placed on the bus, and why does placement matter (not just total resistance)?
(Hint: think about signal reflection.)
A3. You connect a USB-CAN adapter to the bus and run candump can0. The terminal is completely
silent — no frames appear, no errors. Meanwhile your STM32 firmware calls can_send() every
100ms and returns 0 (success). List the three most likely causes in order of probability. How
do you confirm which one is the culprit?
A4. Explain “bus-off” in your own words: - What sequence of events puts a CAN node into bus-off state? - What is the error counter threshold at which bus-off is entered? - What happens to a node in bus-off state (can it send? receive? does it affect other nodes)? - How do you recover from bus-off in Zephyr? - Why might a bitrate mismatch produce intermittent bus-off rather than immediate hard failure?
A5. Your CAN encoder sends this frame:
ID: 0x201
DLC: 8
Data: F4 01 0C FE 39 30 00 00
Using the encoder frame struct definition:
struct encoder_frame {
int16_t left_vel_mms; // bytes 0-1, little-endian
int16_t right_vel_mms; // bytes 2-3, little-endian
uint32_t timestamp_ms; // bytes 4-7, little-endian
};
Calculate: what are left_vel_mms, right_vel_mms, and timestamp_ms?
Convert left_vel_mms and right_vel_mms to m/s.
A6. In Zephyr, can_add_rx_filter_msgq() takes a can_filter struct. You want to receive:
- All frames with IDs 0x200–0x20F (encoder frames from any of 16 wheels)
Write the can_filter struct initialization to match exactly this range using a mask filter.
Explain what the mask field means (which bits does 1 match against?).
A7. Explain why you must call can_set_state_change_callback() in a production CAN receiver,
not just can_add_rx_filter_msgq(). What will happen without it if CANH is shorted to ground
mid-operation?
B1. Explain why you cannot process a UART receive callback as if it contains a complete NMEA sentence. What causes NMEA sentences to arrive fragmented? How does the baud rate and sentence length interact to determine the number of callbacks needed for one sentence?
(Show the calculation for $GNGGA at 9600 baud: how many bytes per sentence, how many
milliseconds to transmit, how many 1ms timer ticks could theoretically fire during one sentence?)
B2. The Zephyr ring buffer API uses ring_buf_put() and ring_buf_get(). Explain what
happens when ring_buf_put() is called from UART IRQ context and the buffer is full. Is data
dropped or does it block? How should you handle this case in a GPS parser?
B3. Validate this NMEA sentence checksum:
$GNGGA,120000.00,3540.123456,N,13940.654321,E,1,08,0.9,45.2,M,36.7,M,,*XX
The checksum is the XOR of all characters between $ and * (exclusive). What is XX in hex?
(You need to calculate this by hand — step through the XOR character by character or write a
5-line Python script to verify.)
B4. Convert these two raw NMEA coordinate values to decimal degrees:
3540.123456,N13940.654321,EShow the formula and intermediate steps. Why does NMEA use DDMM.MMMMMM format instead of
decimal degrees, and what is the classic off-by-one mistake beginners make when parsing it?
B5. Your GPS loopback injection test works perfectly (inject_nmea produces lat=35.67),
but when you connect the real u-blox M8N module, you see lat=0.0 and fix=0. List four
plausible causes in order of likelihood. Which one is most common indoors? What is the minimum
satellite count for a valid GGA fix?
B6. Write pseudocode for a parse_nmea_line() function that:
1. Validates the checksum
2. Identifies the sentence type ($GNGGA, $GNRMC, etc.)
3. Returns false for unrecognized types without crashing
Then explain: your buffer contains "$GNGGA,12000\r\n$GNRM" — two partial sentences in one
string. Describe exactly how your ring-buffer accumulation logic handles this without state
corruption.
These are “write the exact command” questions — muscle memory for hardware debugging.
C1. Before writing any Zephyr CAN code, you should verify the physical bus with a USB-CAN
adapter. Write the exact Linux commands to:
1. Bring up can0 at 500kbps
2. Start capturing all frames to terminal
3. Send a test frame with ID 0x123, DLC 8, data DE AD BE EF 00 01 02 03
4. Verify the bitrate setting was applied correctly
C2. You have a u-blox M8N connected to a Linux laptop via USB-UART adapter at /dev/ttyUSB0.
Write the exact command to see raw NMEA output at 9600 baud without any installation.
C3. You need to simulate a UART GPS input for testing without real hardware. Your Zephyr shell
has an inject_nmea command. Write the full $GNGGA sentence you would inject for:
- Time: 10:30:00 UTC
- Position: 35°40.123456’N, 139°40.654321’E
- Fix type: 1 (GPS fix)
- Satellites: 8
- Altitude: 45.2m
(Include a correct checksum.)
D1. In your ZBus+nanopb bridge (session 09), the packer thread reads from three ZBus channels: IMU, CAN odometry, and GPS. The GPS updates at 1Hz, IMU at 100Hz. In a typical 10ms frame: - Which channels will have new data? - What does your packer thread do for the GPS channel when there’s no new message? - Specifically, what ZBus function should it use to get the last-known value without blocking?
D2. After receiving a CAN encoder frame, you compute a forward velocity and angular velocity and
publish them on ZBus. Then the packer thread reads them. If the CAN bus goes silent for 500ms
(cable disconnected), what does the Jetson see in the odom.vel field of decoded frames? Is this
safe default behavior? What should you add?