Skip to main content

Troubleshooting and FAQ

This page collects the problems that come up most often when you bring up a C0-microSD+, together with the questions that usually follow them. Work top to bottom, because most bring-up problems are one of the first three items.

The device does not show up

  1. Confirm that you are looking for the right thing. The C0-microSD+ enumerates as an unformatted block-storage device with no partition table and no filesystem, so it never mounts as a volume and it never appears in a file browser. See Identify your module.
  2. Reseat the module, then try a different card reader or a different slot. Not every reader drives every card reliably. Tested readers and hosts are recorded in Compatibility.
  3. Confirm that the slot does not drive UHS-II signaling. The module does not support a host that drives UHS-II signaling on the second pad row, because the UHS-II differential lines interfere with the configuration flash. Move the module to a standard microSD slot, or into a full-size SD slot through a passive microSD-to-SD adapter, which wires only the eight SD pads of the first row.
  4. If you are working on an SD-Dev carrier board, check that you power the board through the port that matches your configuration. See SD-Dev Carrier Board.
  5. Once you have a candidate device path, confirm the module identity with the info subcommand of the C0_SD_toolkit.py script from the Signaloid-Compute-Module-Utilities repository.
sudo python3 C0_SD_toolkit.py /dev/disk4 info

A C0-microSD+ reports C0-microSD+ as its compute module type, decoded from the metadata prefix embedded in the on-device bitstream.

The OS asks me to format the device

Dismiss the prompt. The module is intentionally unformatted, and formatting writes a filesystem over the on-device data layout.

Some desktop environments repeat the prompt on every insertion. That is expected behavior for an unformatted block device and it does not indicate a fault.

I formatted the device by accident

The FPGA bitstream region of the SPI flash is write protected unless it has been explicitly unlocked, so a format cannot overwrite the bitstream and does not remove the core function of the module. The whole region stays readable at all times, and only writes are gated. Re-flash your device application, along with any user data your application expects, and start the core again. See Flash an application.

If the module still does not respond to the toolkit afterwards, contact Signaloid at developer-support@signaloid.com and describe what the module does and does not do. Signaloid will advise you on the recovery options for your module.

Permission denied on the device path

Raw block-device access requires root privileges. Run the toolkit and your host applications under sudo, or with administrator privileges on Windows. The toolkit reports a permission error and exits when it cannot open the device path.

Two further causes produce the same class of failure.

  • Your operating system has mounted a volume on the device, usually after an accidental format, and holds it open. Unmount the volume before you write to the raw device.
  • A microSD-to-SD adapter has its write-protect switch in the locked position, so the adapter refuses every write. See Flashing fails.

The toolkit will not start

A toolkit that exits immediately with a SyntaxError, a TypeError about unsupported operand types, or a message naming an unexpected argument is almost always running on a Python that is too old. The tools need Python 3.10 or later.

Check which interpreter your shell actually runs.

python3 -c 'import sys; print(sys.version_info >= (3, 10), sys.executable)'

If that prints False, install a newer Python. See Python Environment.

The version check passes but the tool still fails under sudo

On Linux, sudo replaces your PATH, so sudo python3 can run a different interpreter from the one your shell uses. A newer Python that you installed for yourself is invisible to sudo unless you name it by its full path. Compare the two.

python3 -c 'import sys; print(sys.version_info >= (3, 10), sys.executable)'
sudo python3 -c 'import sys; print(sys.version_info >= (3, 10), sys.executable)'

When the second command reports an older interpreter, give sudo the full path to the one you installed, for example sudo /usr/bin/python3.12 C0_SD_toolkit.py /dev/sdb info. See Python Environment.

Flashing fails

  • Run the toolkit under sudo. Every flash operation writes to the raw block device.
  • Pass the whole device to the toolkit, for example /dev/sdb or /dev/disk4, and never a partition path such as /dev/sdb1.
  • The device path is a positional argument that comes before the subcommand. There is no flag for it.

A correct invocation therefore looks like the following.

sudo python3 C0_SD_toolkit.py /dev/disk4 flash-application program.bin

The remaining checks cover the causes that are easiest to miss.

  • The toolkit stops the core for you: flash-application stops the core before it writes, and flash-bitstream stops the core, unlocks the bitstream region, flashes, and locks it again. If you flash from your own host code, stop the core yourself, so that the running device application does not access the SPI flash while you write to it. See Start and stop the core.
  • MicroSD-to-SD adapters usually carry a write-protect switch on the side. In the locked position the adapter blocks every write, and flashing then fails either with a permission error or with a verification mismatch. Slide the switch to the unlocked position and try again.
  • The toolkit reads back what it wrote and compares the two. When it prints Error: The data do not match. on every attempt, the writes are not reaching the flash. The usual causes are a locked adapter, a reader that silently drops writes, a device path that points at something other than the module, or a write into the bitstream region while that region is locked, which the module discards without reporting an error. See Unlocking the bitstream region fails.

Unlocking the bitstream region fails

The bitstream region accepts writes only while the BITSTREAM_UNLOCK register holds the ASCII key UNLK, and the hardware forces that key to 0x00000000 whenever the Signaloid SoC core is running. A key write issued against a running core is discarded, and the register reads back as 0x00000000.

Stop the core first, then unlock.

sudo python3 C0_SD_toolkit.py /dev/disk4 config core-stop
sudo python3 C0_SD_toolkit.py /dev/disk4 config unlock-bitstream

My application does not run

Start the core. Flashing a binary does not run it, and the RISC-V core stays in reset until you release it.

sudo python3 C0_SD_toolkit.py /dev/disk4 config core-start

Then read the module registers back with the status subcommand. It prints COMMAND, CONFIG, STATUS, and SD_CONFIG.

sudo python3 C0_SD_toolkit.py /dev/disk4 status

The output takes the following form.

Detected compute module: C0-microSD+
COMMAND: 0x00000000
CONFIG: 0x00000001
STATUS: 0x00000000
SD_CONFIG: 0x00000001

Read the output as follows.

  • Bit 0 of CONFIG is rstn. When it reads 0 the core is held in reset, so nothing runs. Start the core, then read status again and confirm that the bit reads 1.
  • Read the trap registers at 0x08210000. A TRAP_MCAUSE value other than 0xFFFFFFFF means your device application faulted and was halted rather than stalling. Look TRAP_MEPC up in the map file of your build to find the instruction that faulted. See Host Interface and Protocol → Trap registers.
  • A STATUS register that never leaves the waiting for command value, with no trap recorded, points at the host side rather than the device side. See The host application cannot communicate with the module.

Two further checks are worth making when the registers look healthy but the application still does nothing useful.

  • Confirm that you flashed a binary built for this module, with DEVICE_TYPE set to SIGNALOID_C0_MICROSD_PLUS, and that its code and data fit in the 320 KiB of LRAM. A binary built with MODE set to xip executes in place from the SPI flash, so only its writable data has to fit in the LRAM.
  • Rebuild the device application with ENABLE_DEBUG_LOGGING and read the log records back with the C0_debug_logger.py script from the Signaloid-Compute-Module-Utilities repository. The logger claims a 512-byte window at the top of the output half of the MMIO buffer, so keep your result data clear of that window in debug builds.

The host application cannot communicate with the module

  • Open the block device so that reads bypass the host page cache, using O_DIRECT on Linux and the raw /dev/rdiskN node on macOS. Without this, a polling read is served from the page cache of the host and your application never observes the module changing STATUS. The Python host interface handles this for you.
  • Use the same addresses the device application uses. The address map of the C0-microSD+ is unified, so the host and the Signaloid SoC address every register and every buffer identically. There is no separate host-side offset map and nothing to translate. A host application written against the offsets of a different Signaloid compute module reads and writes the wrong locations on this one. See Host Interface and Protocol.
  • Confirm that the two halves of the MMIO buffer are the right way round. The host writes operands into the input half at 0x08308000 and reads results from the output half at 0x08300000.
  • Confirm that the core is running, as described in My application does not run. A stopped core never updates STATUS, which looks from the host like a module that ignores commands.
  • Poll rather than wait for a notification. The module never initiates a transfer and raises no interrupt toward the host, so every state change is discovered by a host-initiated read.

Frequently asked questions

How do I control what the module runs? The C0-microSD+ features the Signaloid SoC. You drive the module by flashing an application into the SPI flash and by starting and stopping the core. See Start and stop the core.

Can I load my own FPGA bitstream onto the module? No. The C0-microSD+ does not support custom user FPGA designs or custom bitstreams, and it is not an open FPGA development board. It runs the Signaloid-supplied bitstream, and you program the module by flashing a device application that runs on the Signaloid SoC.

Can I use the module as regular storage? No. The exposed block device is the address map of the module, not general-purpose storage. Every read and write lands on a register, on the MMIO buffer, or in a flash region.

Do I need drivers? No. Any operating system that supports the standard SD protocol enumerates the module as a block device with no additional drivers. See Host OS support.

Can I hot-swap the module? Yes, in normal operation. Do not remove power while a flash operation is in progress.

Does flashing wear anything out? The module stores applications and user data in the on-board SPI flash, which supports at least 100,000 erase cycles per sector. Ordinary development flashing stays far below that, but an application that rewrites the same sector continuously can reach it. See SPI Flash Write and Erase Semantics.

My application stops responding, or loses its state, after sitting idle. Some SD host controllers power down a card that has been idle and power it back up on the next transaction. The module then comes back with the core in reset and every register at its default, so your device application is stopped and its state is gone. Read from the module at least once per second to keep the host controller from cutting power, or start the core again and restore your configuration after you detect it. See Power Cycles and State.

Why does sudo python3 not find the packages I installed? Under sudo, a plain python3 runs the system interpreter and ignores the virtual environment you activated. Invoke the interpreter of the virtual environment directly, for example with sudo .venv/bin/python3 host_application.py.

Where do I get help? Email developer-support@signaloid.com, or open an issue on the relevant repository under the Signaloid GitHub organization.

Next steps

  • Identify your module, confirming the device path and the module identity before anything else.
  • Using the C0_SD_toolkit, the command reference for flashing, starting, stopping, and inspecting the core.
  • Host OS support, the per-platform notes for device paths, privileges, and validation status.
  • Getting Started, the known-good sequence to compare your setup against.