Welcome to the Board Support Package (BSP) for the Efinix Sapphire SoC. This BSP allows software running on the RISC-V processor to interact with on-chip peripherals such as SPI, I2C, GPIO, and Timers.
The drivers are designed to be bare-metal compliant, lightweight, and capable of running with or without an operating system (RTOS).
Driver Implementation Model
The BSP follows an Instance-Based driver model. Each peripheral driver consists of two main data structures:
- Hardware Register Map (*_hwreg_t): A structure that maps directly to the physical memory address of the peripheral. This is typically used internally by the driver to read/write hardware registers.
- Software Instance (*_instance_t): A high-level structure that holds the Configuration State (Shadow Registers) and a pointer to the hardware base address. @ Unlike traditional drivers that write to hardware immediately, this BSP uses a "Configure-then-Apply" pattern to ensure atomic updates:
- Modify: Update the settings in the instance structure (e.g., spi.cpol = HIGH).
- Apply: Call the *_applyConfig() function to flush these settings to the hardware.
Initialization Sequence
To use a specific driver, user must follow this initialization flow:
| Step | Action | Description |
| 1 | Instantiate: | Declare the driver instance structure. |
| 2 | Link: | Assign the hardware base address (defined in soc.h). |
| 3 | Configure: | Set the desired parameters (Prescalers, Modes, Interrupts). |
| 4 | Apply: | Call *_applyConfig() to initialize the hardware. |
| 5 | Enable: | (Optional) Register the interrupt handler via the PLIC. |
Usage Example
This example shows how to instantiate I2C using i2c_instance_t and i2c_hwreg_t.
Step 1–3: Instantiate, Link, Configure
#define I2C_FREQ 100000
#define I2C_ADDR 0x67<<1
#define I2C_CTRL_HZ SYSTEM_CLINT_HZ
#define I2C_CTRL (i2c_hwreg_t *)SYSTEM_I2C_1_IO_CTRL
.hwreg = I2C_CTRL,
.slaveAddress = I2C_ADDR,
.samplingClockDivider = 3,
.timeout = I2C_CTRL_HZ/1000,
.tsuDat = I2C_CTRL_HZ/(I2C_FREQ*5),
.tLow = I2C_CTRL_HZ/(I2C_FREQ*2),
.tHigh = I2C_CTRL_HZ/(I2C_FREQ*2),
.tBuf = I2C_CTRL_HZ/(I2C_FREQ),
};
I2C driver API definitions.
I2C instance. Holds the software registers and hardware pointer.
Step 4: Apply Config
void main() {
void bsp_init()
Initialize Board Support Package Peripherals.
void i2c_applyConfig(i2c_instance_t *inst)
Apply the software configuration to the hardware.
Step 5a: Enable Machine Mode Trap (External Interrupt)
}
void trap_entry(void)
The Main Trap Entry Point (Naked).
void irq_enable(void)
Enable Global Interrupts (MIE bit).
void irq_setType(cpu_irq_t enable)
Enable specific CPU interrupt sources.
void irq_setTrapVector(void(*trap_vector)(void))
Set the Machine Trap Vector (mtvec).
Step 5b: Register I2C Interrupt Handler
Ensure the IRQ handler function name exactly matches an entry in the IRQ dispatch table to use the custom IRQ.
Using an incorrect handler name will cause the interrupt to fall back to irq_handleDefault.
printf("Interrupt triggered by I2C.\n");
}
int irq_m_i2c0_handler(void)
- See also
- Example Software Demos for all available demos.
-
mtrap.c for the full details of available IRQ Handler.
Revision History
| Version | Date | Author | Description of Changes |
| 1.0.0 | 2026-06-01 | Efinix | Initial BSP release. |
View License and Legal Information