General

SEN0628 8×8 mode limited to ~5 Hz over I²C on Raspberry Pi, despite advertised 15 Hz update rate

userHead Nate2331 2026-08-02 21:41:31 279 Views4 Replies

Hello,

 

I’m integrating the DFRobot SEN0628 8×8 Matrix ToF 3D Distance Sensor into a Raspberry Pi 5 robot running Ubuntu 24.04 and ROS 2 Jazzy.

 

Hardware and firmware

 Sensor: DFRobot SEN0628Sensor IC: VL53L7CXOnboard MCU: RP2040Firmware: SEN0628-V1.3-20250904.uf2Host: Raspberry PiInterface: I²C bus 1Selected address: 0x33Matrix mode: 8×8I²C bus speed: normally 100 kHz Only the SEN0628 is present on this I²C bus

The sensor works and produces believable 64-zone depth matrices. However, I am having difficulty achieving the documented update rate reliably over I²C.

 

Current I²C performance

 

Our ROS driver is configured to request five frames per second.

Measured results:

Requested rateActual complete ROS matrices
5 Hzapproximately 4.63 Hz
8 Hzapproximately 4.38 Hz
10 Hzapproximately 5.03 Hz
15 Hzsensor initialization/response timeout during the test

This indicates a practical ceiling of approximately five complete 8×8 matrices per second over the current I²C protocol.

 

The DFRobot product information lists a ranging update rate of 15–60 Hz. We assume 15 Hz applies to 8×8 mode and the higher rate may apply to 4×4 mode. Is that correct?

 

Protocol implementation

 

We are using the command protocol found in DFRobot’s reference library:

Request: 0x55, argument_length_high, argument_length_low, command, arguments... Response: status, command, payload_length_low, payload_length_high, payload...

 

Commands used:

 

1 = set matrix mode 2 = get all matrix data

A valid 8×8 response contains 128 payload bytes representing 64 little-endian uint16 distances.

 

We validate the response command, length, full payload, and every distance before publishing a matrix.

 

Earlier reliability problems

 

At the original 100 kHz I²C speed, a longer test produced:

561 attempts 528 accepted frames 33 final errors 5.9% error rate

 

Representative errors included:

 

sensor response timed out implausible response length 32896 response command 130 does not match command 2 response command 129 does not match command 2 8x8 frame must contain 128 bytes, received 192

 

Recurring corrupted values included:

 

32896 = 0x8080 129   = 0x81 130   = 0x82

 

These looked like distance payload bytes being interpreted as response-header bytes, possibly because the RP2040 response stream or FIFO had become misaligned.

 

Reducing the bus speed produced:

I²C speedResult
100 kHz5.9% final frame errors
50 kHz2.45% final frame errors
25 kHzthroughput became unusably slow

We subsequently added bounded retries and stream resynchronization. Reliability is now much better. A recent 20-second test accepted 91 of 91 matrices with no final errors, although five transactions required internal retries.

 

The remaining problem is throughput: requesting more than 5 Hz does not produce more than approximately 5 Hz.

 

Official Python example

 

DFRobot’s Raspberry Pi Python example can continuously display matrices, proving that the sensor and basic electrical connection work. However, we observed occasional values greater than the documented 4000 mm maximum, including values such as 34720 and 36768.

Our production driver therefore validates and normalizes every cell.

 

Questions

What is the expected maximum full-matrix rate for 8×8 mode over I²C? Is 15 Hz achievable through the documented get all data command, or does 15 Hz require UART/USB continuous streaming? What I²C bus speed does DFRobot recommend for obtaining 15 Hz? Does the RP2040 support clock stretching or require any delay between: Sending command 2Reading the response headerReading the 128-byte payload? Should one I²C transaction retrieve the complete response, or must it be read one byte/block at a time? Is there an official description of the RP2040 response FIFO and how the host should resynchronize after a partial or timed-out response? Is command 2 queued if the previous response has not been completely consumed? Is there a data-ready register, interrupt, frame counter, or status command that should be used instead of repeatedly polling command 2? Does firmware V1.3 contain any known I²C timing or response-stream issues? Does the 15 Hz specification refer to the VL53L7CX’s internal ranging rate, the RP2040 output rate, or the rate available to an external host? For USB output, is 115200 baud with DTR enabled required for the SEN0628 V1.3 firmware? Is the exact USB/UART framing format documented, including line terminators, matrix order, checksums, and any frame counter?

 

Additional observations

 

The depth data itself is useful. We have successfully produced:

 An 8×8 depth displayA ROS PointCloud2Forward obstacle detectionExperimental floor and cliff detection

 

The bottom matrix rows correctly observe the floor. At the edge of a staircase, those rows show a substantial increase in distance or loss of the expected floor return. This agrees with DFRobot’s Maqueen Plus V3 cliff-detection example.

 

Our main goal is to obtain the highest reliable 8×8 update rate without publishing partial, stale, or misaligned matrices.

 

Any official protocol timing information, known-good Raspberry Pi code capable of 15 Hz, or clarification of the advertised update rate would be greatly appreciated.

 

Thanks

 

Nate

2026-08-03 15:14:27

I ran into very similar timing and throughput limits with this sensor over I²C, and even after improving reliability, I couldn't consistently get close to the advertised update rate. Debugging it felt a bit like improving lap times in https://polytrackgame.org —small protocol tweaks helped, but there still seemed to be a hard limit that needed official clarification.

userHeadPic Poly.Trackk
2026-08-03 10:58:55

The 15 Hz figure is the VL53L7CX's internal ranging rate in 8x8 mode, not what you'll see over I2C — the RP2040 firmware sits in between, so the effective host rate is capped by however fast the firmware can pull a frame and push it out.
At 100 kHz, a full 8x8 transaction eats about 15-20 ms of bus time alone, and the official Arduino examples call getAllData() with a 100 ms delay, so the library isn't chasing 15 Hz either. Your corrupted headers (0x8080, 0x81, 0x82) look like the RP2040 response stream getting misaligned when reads are too slow — no public docs describe the FIFO or a resync procedure.
Try bumping the Pi's I2C bus to 400 kHz (Fast Mode) — both the RP2040 and VL53L7CX support it, and it should cut transfer time to ~4-5 ms. If the firmware itself is the bottleneck, UART at 115200 or USB might be the only way to get closer to 15 Hz — the 15/60 Hz figures map to 8x8/4x4 from the ST datasheet, USB is fixed at 115200 baud, and V1.3 only fixed invalid-value handling, not I2C timing.

userHeadPic Jason.Miao
Nate2331 wrote:

Your read on the misaligned response stream matches what I saw, and I ended up at the same conclusion you land on at the end.

 

Data from my side — factory V1.3 over I2C at 100 kHz on a Pi:

561 attempts, 528 accepted, 33 transport/frame errors (5.9%), sustained ~4.59 Hz Failure modes were exactly what you'd predict: response timeouts, stale response commands, implausible response lengths399 values normalized to 4000 mm

 

So agreed, 15 Hz was never on the table over that path — the host rate isn't sensor-limited.

 

On resync: since nothing public describes the FIFO, I wrote a protocol-aware serialized reader that scans for the exact response header and retries a bounded number of attempts rather than trusting alignment. A ~9.5 minute run gave 2593/2593 accepted logical frames with 135 additional retries and no malformed matrix published; a concurrent RPLIDAR + ToF run held 1671/1674 and recovered after each timeout. That makes I2C survivable, but it's recovery, not throughput — I still wouldn't put it under collision control.

 

I haven't tried 400 kHz yet. Worth running as a control before blaming the firmware, and I'll report back.

 

One note on the USB point: over CDC the baud number is nominal — the host sets it but the RP2040 doesn't gate on it (the Pico SDK even repurposes 1200 baud as a BOOTSEL request). The real ceiling is USB full-speed, so it isn't a 115200 bit budget.

 

The bigger problem for me wasn't rate, though — it was semantics. V1.3's changelog normalizes invalid values to 4000 mm, and the documented range is 20–4000 mm, so factory output collapses "no return" and "valid return at max range" into the same number. You can't build a floor filter on that.

 

So I wrote replacement RP2040 firmware. Pico SDK 2.2.0, vendored ST VL53L7CX ULD 2.0.1, 10 Hz acquisition, framed output over USB CDC: fixed-width little-endian records carrying 64 distances plus all 64 VL53L7CX target-status bytes, monotonic sequence numbers, RP2040 acquisition timestamps, explicit validity/error flags, CRC-32. The ROS driver decides what an invalid zone means instead of the firmware pre-deciding.

 

Caveats, because this isn't solved: it's diagnostic-only and feeds no safety consumer yet. Practical usable limit is about 2.0 m — dark wood returns 4000 near 1.7 m, so absence of a return can't establish free space. Recovery is the factory V1.3 UF2 (SHA-256 recorded, verified against DFRobot's official URL) through BOOT/RPI-RP2, and I proved the restore path before flashing anything experimental.

 

Happy to share the protocol doc if it's useful.

2026-08-05 01:29:57
Jason.Miao wrote:

Good catch on the CDC baud rate — you're right, the Pico SDK treats it as nominal and the real pipe is USB full-speed. The 4000 mm normalization bug is a bigger problem than the I2C throughput, since it collapses two completely different physical states into one value. Your replacement firmware with per-zone target status and CRC framing sounds like exactly what this sensor needs. If you end up publishing the protocol doc, drop a link — it'd save the next person a lot of reverse engineering.
 

2026-08-05 11:52:57
2 Replies