Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
Collapse
Brand Logo

ModalAI Forum

  1. ModalAI Support Forum
  2. VOXL Compute & Autopilot
  3. VOXL 2
  4. VOXL2 SPI3: sharing bus 3 between the onboard ICM-42688 and a second SPI device — SPI_NO_CS rejected, requesting cs-gpios guidance

VOXL2 SPI3: sharing bus 3 between the onboard ICM-42688 and a second SPI device — SPI_NO_CS rejected, requesting cs-gpios guidance

Scheduled Pinned Locked Moved VOXL 2
1 Posts 1 Posters 4 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Rowan DempsterR Offline
    Rowan DempsterR Offline
    Rowan Dempster
    Regular
    wrote last edited by
    #1

    Setup

    • Board: VOXL2 (M0054)
    • System image: 1.7.8-M0054-14.1a-perf, kernel 4.19.125
    • libqrb5165-io 0.5.0
    • Bus 3 controller: qcom,spi-geni, bound to the spi_geni platform driver, exposing a single chip select (spi3.0 → /dev/spidev3.0)

    We are adding an ams TMF8829 time-of-flight ranging sensor to an existing VOXL2 design. For layout reasons it is wired to SPI3, the same bus as the onboard ICM-42688 IMU that voxl-imu-server services. The IMU runs at SPI_MODE_3 on the controller's native chip select; the TMF8829 runs at SPI_MODE_0 and is selected through a TLMM GPIO (117), with its enable line on GPIO 118.

    The problem

    SPI3 exposes exactly one native chip select, and it is wired to the IMU. The GENI controller asserts that native CS on every transfer it performs, so any transfer we issue for the TMF8829 also selects the IMU. Since the TMF8829 wire protocol begins each transaction with a write opcode (0x02), the IMU interprets TMF traffic as register writes addressed to itself. That is not merely a corrupted read — it can reconfigure the IMU mid-flight and take down a flight-critical data stream.

    The standard Linux remedy is the SPI_NO_CS mode flag, suppressing the controller's chip select so our GPIO alone selects the target. The kernel rejects it on this platform. Issuing the ioctl directly on the descriptor returned by voxl_spi_get_fd(3):

    spi_bus3: SPI_IOC_WR_MODE32 0x40 failed: Invalid argument
    

    0x40 is SPI_MODE_0 | SPI_NO_CS. Both the legacy 8-bit SPI_IOC_WR_MODE and the 32-bit SPI_IOC_WR_MODE32 return EINVAL, which points to SPI_NO_CS not being advertised in the controller driver's mode_bits. Separately, voxl_spi_init() in libqrb5165-io validates its mode argument strictly against SPI_MODE_0..3 and rejects any extra flag bits, so the flag cannot be requested through the library either — but we bypassed that with direct ioctls on the raw fd and the kernel is the hard stop.

    Our integration treats this as a safety gate: at startup it writes SPI_MODE_0 | SPI_NO_CS, reads it back, and if the readback fails it disables the TMF entirely and leaves IMU publication untouched rather than risk corrupting the IMU. That gate is what fires today, so the second sensor never comes up.

    For completeness, the surrounding work is done and validated on hardware. We have a bus-3 arbiter that serializes access with a mutex, switches mode and clock per transaction, and restores SPI_MODE_3 with native CS on every success and error path. Matched 10-second A/B captures with the TMF path compiled in but gated off show no IMU regression: 1024 Hz in both conditions, 0.977 ms mean sample interval with no interval above 2 ms, and zero FIFO errors, logger drops, or mode-restore failures. The TMF8829 itself is known good and streams reliably at 15–18 MHz when it has a bus to itself. The only missing capability is per-device chip-select control on a shared bus 3.

    Path 1 (preferred): declare bus 3 with cs-gpios and a second spidev child node

    Rather than work around chip select in userspace, we would rather let the kernel own it, which is how Linux is designed to share an SPI bus. Concretely, on the SPI3 node: raise the chip-select count to 2, add cs-gpios with the native CS in slot 0 and &tlmm 117 in slot 1, and add a second spidev child at reg = <1>. The TMF8829 then appears as its own /dev/spidev3.1 with its own spi-max-frequency and mode.

    With that in place the kernel handles chip-select assertion, clock, and mode switching per device. On our side we delete the manual GPIO chip-select toggling and the entire mode-restore arbiter, and the IMU is never exposed to TMF traffic at all — a substantially safer arrangement than anything we can build in userspace.

    Questions on this path:

    1. Does the spi_geni driver in the 1.7.8 kernel cooperate with the SPI core's generic cs-gpios handling, or does its own set_cs implementation bypass GPIO chip selects?
    2. Is there a supported way for us to apply a devicetree overlay or a patched DTB to a VOXL2 system image, or does this have to come from ModalAI as an image change?
    3. Are there known constraints on SPI3 specifically — reserved chip selects, pinmux conflicts on TLMM 117, or other consumers of that controller we should know about?

    Path 2 (fallback): add SPI_NO_CS to the controller driver's supported mode bits

    If the devicetree route isn't viable, the smaller change is to advertise SPI_NO_CS in the GENI SPI controller's mode_bits and honor it in the driver's chip-select path. Our existing arbiter code already works unmodified against that interface, so this would unblock us with no changes on our side, and it would also need voxl_spi_init() in libqrb5165-io to stop rejecting mode values with flag bits set (or we continue issuing raw ioctls on the fd from voxl_spi_get_fd()).

    We consider this less idiomatic than Path 1 — chip select stays a userspace responsibility, with per-transaction GPIO toggling and mode restoration that has to be correct on every error path — and it still requires a custom kernel build. But it is a much narrower diff if that matters for your release process.

    Question: is SPI_NO_CS omitted from mode_bits deliberately, for a hardware reason on the GENI controller, or simply because nothing has needed it yet?

    What we're asking

    Guidance on which of these two you'd support, and whether either can be delivered through an official system image rather than a fork we have to maintain. If neither is practical in the near term, our fallback is a hardware change moving the TMF8829 to its own SPI bus, and we'd appreciate confirmation that a shared bus 3 is simply not supported on this platform so we can commit to that redesign.

    Happy to share the arbiter source, the A/B log captures, or a minimal reproducer that only issues the failing ioctl if that's useful.

    1 Reply Last reply
    0

    Hello! It looks like you're interested in this conversation, but you don't have an account yet.

    Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

    With your input, this post could be even better 💗

    Register Login
    Reply
    • Reply as topic
    Log in to reply
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes


    ModalAI
    Categories Recent Tags ModalAI.com Docs
    © 2026 ModalAI® · Accelerating autonomy for smaller, smarter, safer drones · Powered by NodeBB
    • Login

    • Don't have an account? Register

    • Login or register to search.
    • First post
      Last post
    0
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups