Skip to main content

C0-microSD Host Interface and Protocol

The C0-microSD communicates with a host over the SD interface, using either the 4-wire SD protocol or SD-over-SPI. When connected to a host, it presents itself as a 20.2 MB (19.3 MiB) unformatted block-storage device in both Bootloader mode and Signaloid SoC mode. See the shared SD interface concept for transport-level details.

All communication is achieved through host-initiated block read and write operations.

note

Communication over the SD interface uses block read and write operations, not the SDIO extension of the SD interface. No additional host drivers are required.

The C0-microSD connects to a host either over the 4-wire SD protocol or over SD-over-SPI:

C0-microSD 4-wire SD block diagramC0-microSD SD-over-SPI block diagram
4-wire SD interfaceSD-over-SPI interface

MMIO memory map and registers

The C0-microSD realizes the shared MMIO interfacing model in the Signaloid SoC. On reset, the SoC copies the first 128 KiB of the flash user-data sector into its internal SPRAM and begins execution from address 0x00.

The Signaloid SoC memory map, from the highest address at the top to the lowest at the bottom:

Communication registers (SoC-Side addresses)

The device application accesses these registers as memory-mapped I/O:

RegisterMemory addressSizeDevice operationReset value
status0x400000004 bytesW0x00000000
SoC Control0x400000044 bytesW0x00000000
command0x400000084 bytesR0x00000000
  • status: set by the device application to declare the application's current status.
  • SoC Control: set by the device application to control SoC peripherals; readable by the host over the SD interface.
  • command: set by the host application, read by the device application, used to send commands to the Signaloid SoC.

The SoC Control register bits:

Register bitUsage
31:2Reserved
1Set CONFIG_DONE pin
0Set on-board red LED

All three registers reset to 0x00000000 when the module powers up, and all three are volatile, so a power cycle returns them to that value. A status of 0 therefore reads the same as the conventional waiting-for-command value, and command reads as 0 until the host writes it, which is why 0 conventionally means no command. See Power Cycles and State.

note

The specific values of the command and status registers are application-dependent.

Data buffers (SoC-Side addresses)

BufferMemory addressSizeDevice operation
MISO_BUFFER_ADDRESS0x400100004 KiBW
MOSI_BUFFER_ADDRESS0x400200004 KiBR
  • MOSI_BUFFER: Manager-Out, Subordinate-In: data sent from the host application to the device application.
  • MISO_BUFFER: Manager-In, Subordinate-Out: data sent from the device application to the host application.

For the bootloader-mode flash address map, see Modes and Custom Bitstream.

Host-side addressing (Signaloid SoC mode)

The host addresses the Signaloid SoC's MMIO registers and buffers through SD-interface block offsets. These differ from the SoC-side memory addresses documented in MMIO memory map and registers. For example, to write the command register from the host you use block offset 0x10000, whereas the SoC application reads it at memory address 0x40000008.

Address spaceOffsetSizeHost operationDescription
STATUS_REGISTER_OFFSET0x000000004 bytesRstatus register
SOC_CONTROL_REGISTER_OFFSET0x000000044 bytesRSoC Control register
COMMAND_REGISTER_OFFSET0x000100004 bytesWcommand register
MOSI_BUFFER_OFFSET0x000500004 KiBWMOSI buffer
MISO_BUFFER_OFFSET0x000600004 KiBRMISO buffer

The following offsets let the host verify the active configuration and switch back to Bootloader mode:

Address spaceOffsetSizeHost operationDescription
CONFIGURATION_ID_OFFSET0x000200004 bytesRActive configuration ID
CONFIGURATION_VERSION_OFFSET0x000200044 bytesRActive configuration version
CONFIGURATION_STATE_OFFSET0x000200084 bytesRActive configuration state (for example, SWITCHING)
BOOTLOADER_SWITCH_CONFIG_OFFSET0x000400004 bytesWSwitch operation mode (write SBLD, ASCII-encoded)

The configuration-ID register identifies the active configuration as a 4-byte ASCII word.

ValueConfiguration
SBLDBootloader
SSOCSignaloid SoC

Any other value means the device is not a C0-microSD. The configuration-version register holds the version of that configuration, with the major version in its first two bytes and the minor version in its last two.

The MOSI and MISO buffers are each 4096 bytes (1024 words).

For the flash address map used in Bootloader mode, see Modes and Custom Bitstream.

Communication model: a polled round trip

The module raises no interrupts toward the host: the host discovers state changes by polling the read-only registers. A typical command round trip:

  1. The host writes operand data to the MOSI buffer (offset 0x050000).
  2. The host writes an application-defined opcode to the command register (offset 0x010000).
  3. The device application reads command, processes the data in MOSI, writes its result to MISO, and updates status.
  4. The host polls the status register (offset 0x000000) until it reads an application-defined completion value.
  5. The host reads the result from the MISO buffer (offset 0x060000).
  6. The host writes the idle command, conventionally 0, to the command register, and the device application returns its status to waiting for the next command.

The values of command and status are application-defined, and the round-trip mechanics are common to every C0-microSD application. Open the block device so that reads bypass the host's page cache, because a poll loop over a buffered descriptor can spin on a stale status value forever. The Python host interface does this for you. See Using the Python Host Interface → Device access model. For a complete working round trip (C and Python host applications plus the matching device application), see the Signaloid-Compute-Module-Demo-Calculator and the Getting Started tutorial.

Host application example (Signaloid SoC mode)

This example, on a macOS host with the device at /dev/disk4, sets the command register to 0x00000001 from a C host application:

#include <stdio.h>
#include <errno.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>

int
main(void)
{
char * devicePath = "/dev/disk4";
uint32_t command = 0x00000001;
uint32_t commandRegisterOffset = 0x00010000;
int fd;
off_t seek_offset;
ssize_t result;

/*
* Open the C0-microSD device.
*/
fd = open(devicePath, O_WRONLY | O_SYNC | O_DSYNC);
if (fd == -1)
{
perror("Error opening device");
return -1;
}

/*
* Seek to the offset for the command register.
*/
seek_offset = lseek(fd, commandRegisterOffset, SEEK_SET);
if (seek_offset == (off_t)-1)
{
perror("Error seeking to target offset");
close(fd);
return -1;
}

/*
* Write the command register data.
*/
result = write(fd, &command, sizeof(uint32_t));
if (result != sizeof(uint32_t))
{
perror("Error writing data to the device");
}

close(fd);

return 0;
}

Header files and helper functions for building C and Python host applications are in the Signaloid-Compute-Module-Utilities repository.

Power cycles and state

The registers and the data buffers of the Signaloid SoC are volatile. The module powers up with all of them cleared to zero, so a power cycle discards whatever state your application held.

StateSurvives a power cycle
Device application in the flashYes
Data in the user data region of the flashYes
Operation mode selectionYes
status, SoC Control, and commandNo
Contents of the MOSI and MISO buffersNo
Contents of the SoC memoryNo

The operation mode survives because the module stores it in the flash. See Modes and Custom Bitstream.

In Signaloid SoC mode the module reloads your device application from the flash and runs it again on its own, with no action from the host. That makes a power cycle easy to miss, because the host keeps receiving responses while your application has restarted from the beginning and lost everything it held in memory.

Hosts that power down an idle module

Some SD host controllers like laptop card readers power down a card that has been idle and then power it back up on the next transaction. Expect this if your host application leaves the module idle for long periods.

Your device application restarts on its own, so the module answers the next command with fresh state rather than with the state that your host application expects. To prevent the power-down, read from the module at least once per second while it is otherwise idle. A read of the status register is enough to keep the host controller from cutting power.

Next steps