Imperix offers the possibility to customize the FPGA firmware of the B-Board PRO (equivalently of the B-Box RCP) by instantiating the imperix firmware IP in Xilinx Vivado and editing programmable logic around it. To that end, the provided template provides access to a pre-written framework, designated as sandbox.

The sandbox enable the user to:

  • Exchange data between the application control code running in the CPU (PS) and the logic in the FPGA (PL);

  • Drive the PWM output chain, comprised of a dead-time generation system and the hardware protection mechanisms;

  • Retrieve ADC conversion results as soon as they are available, directly from within the FPGA;

  • Have direct access to physical I/Os pins such as USR, GPI and GPO pins.

C++ drivers and graphical interface blocks (Simulink and PLECS blocksets) are provided in order to exchange data with the FPGA and configure the PWM outputs.

Related examples

  • A custom SPI communication interface for an A/D converter is presented in TN130.

  • FPGA-based hysteresis current control is presented in TN120. The same application is also addressed in TN121, which relies on automated HDL code generation using Matlab HDL Coder.

  • Automated code generation using Xilinx Vivado HLS is addressed in TN133. This note uses the Direct Torque Control (DTC) of a synchronous motor as the application example.


Information on how to set up the toolchain for the FPGA programming is available in PN120.

Firmware IP

The B-Board is based on a Xilinx Zynq XC7Z030 System-on-Chip which consists of a Processing System area (PS) with two CPU cores and a Programmable Logic (PL) area.

  • CPU0: Running on Linux, the first core is responsible for loading the application code, supervising the system execution and managing the data logging.

  • CPU1: Running on BBOS (lightweight secured proprietary operating system), the second core executes the application-level control code developed by the user.

  • FPGA: The PL contains all the application-specific peripherals.

The fixed part of the FPGA firmware containing the pre-implemented peripherals is packaged in the imperix firmware IP.

The step-by-step guidance to instantiate this IP in a Vivado project, generate and load the bitstream into the B-Board is available in PN120.

Schematic overview

The imperix firmware IP is designed such that it provides interfaces for implementing special user HDL logic in the so-called sandbox. All interfaces of the firmware IP are accessible and may read or substituted with respect to physical (chip) I/Os

The content of the imperix firmware IP is obfuscated and cannot be either read or edited.

IP port descriptions

This section describes the ports of the imperix firmware IP.

Digital I/Os drivers

These ports drive the physical digital I/Os of the B-Board. The description of the peripherals driving these ports and the physical location of their I/Os are available in the B-Board datasheet.



Clock domain





Fault inputs




General-purpose inputs




General-purpose outputs




Pulse-width modulated outputs

Private ports




These ports are necessary to communicate with the various components on the B-Board. Modifying these connections could alter the proper behavior of the device.




User interfaces

The user interfaces include data ports and timing signals to exchange data with the CPU, drive PWM outputs and access ADC value.



Clock domain


ADC_reg_00[15:00] to




ADC 16-bit result in 2’s complement format. If in a B-Box, registers 00 to 15 hold the results the B-Box (external) ADCs. Otherwise, registers 00 to 07 hold the results of the B-Board on-board ADCs and registers 08 to 15 return zero.

SBO_reg_00[15:00] to




Output to the Sandbox, registers used by the CPU to send data towards the FPGA. The user can write to these registers from C++ drivers or graphical blocksets.

SBI_reg_00[15:00] to




Input from the Sandbox, registers used by the FPGA to send data to the CPU. The user can read to these registers from C++ drivers or graphical blocksets.

CLOCK_0_period[15:00] to CLOCK_3_period[15:00]



Indicates the timer period of the CLOCK.

CLOCK_0_prescaler[15:00] to CLOCK_3_prescaler[15:00]



Indicates the prescaler division value of the CLOCK.

CLOCK_0_clk_en to CLOCK_3_clk_en



Clock enable generated by the prescaler, provides the counting rate of CLOCK_N_timer. CLOCK_N_clk_en is asserted one period out of CLOCK_N_prescaler.

CLOCK_0_timer[15:00] to CLOCK_3_timer[15:00]



Timer counting from 0 to CLOCK_N_period at CLOCK_N_clk_en rate.




Asserted for the duration of the READ phase, signaling that SBI registers are being read and transferred towards the CPU.




Asserted for one clock period at each ADC sampling instant.




Asserted for one clock period at the end of the configuration phase (end of system startup sequence). It may be used as a synchronous reset. In the case where multiple B-Boards (B-Boxes) are connected, this pulse occurs simultaneously in all devices and can be used to synchronize counters.




User firmware identification number. When a customized firmware is loaded, this number is sent to BB Control and is available from the Configuration tab. It can be used to ensure that the correct firmware has been loaded.




Asserted when the B-Board is in a B-Box, cleared otherwise.

Understanding the real-time behavior of the firmware

To correctly develop and integrate custom logic in the B-Board FPGA, a proper understanding of the system behavior during real-time execution is necessary.

The four phases of a control cycle

The next figure is a simplified representation of the elements involved in the real-time execution of the control code and shows the four phases constituting a cycle, which are:

  • ACQ: Analog-to-digital conversion (physical chips) and results acquisition (transfer to FPGA);

  • READ: Real-time DMA read, FPGA data flagged as real-time are sent to the CPU read buffer;

  • PROCESSING: Execution by the CPU of the main control interrupt, processing the user control code. At the beginning of this phase, the CPU read buffer is read. At the end, the CPU write buffer is updated.

  • WRITE: Real-time DMA write, data flagged as real-time are transferred from the CPU write buffer to the FPGA peripherals (across the network of multiple B-Boards if needed).

During the READ and WRITE phases, data transfer is handled by the RealSync DMA engines and is independent from the CPU execution.

Four ports of the imperix firmware IP provide timing information, as shown in the next figure.

The ACQ phase start with the assertion of sampling_pulse and ends with the assertion of adc_done_pulse, indicating that new ADC values are available in the ADC registers. A pulse on read_pulse signals the start of the READ phase when SBI registers flagged as real-time are sent toward the CPU. At the end of the WRITE phase data_valid_pulse is asserted notifying that new data is available in the real-time SBO registers.

Configuring the control cycle timings

The sampling and interrupt frequency are configured using the following C++ functions. In Simulink, the same parameters can be entered in the Configuration bloc.

Clock_SetFrequency(CLOCK_0, FREQ);
ConfigureMainInterrupt(UserInterrupt, CLOCK_0, PHASE, POSTSCALER);

In this example, a clock generator (CLOCK_0) is configured to run at a frequency FREQ and the interrupt to be mapped on this clock generator. The interrupt and sampling are by design linked to the same clock generator, but a POSTSCALER can be specified on the interrupt frequency allowing the sampling to run faster and always in a synchronized fashion.

The interrupt frequency is equal to CLOCK_FREQ / (POSTSCALER*2)

Cycle timings with postscaler = 2 (oversampling scenario)

Exchanging data between the CPU and the FPGA

The Output towards the SandBox (SBI) and Input from the SandBox (SBO) registers allow data exchange between the user control code in the CPU and the user logic in the FPGA. The C++ the drivers are available in includes/sbi.h and includes/sbo.h.


uint16_t Sbi_ReadDirectly(unsigned int address, unsigned int device=0);
void Sbi_ConfigureAsRealTime(unsigned int address, unsigned int device=0);
uint16_t Sbi_Read(unsigned int address, unsigned int device=0);


void Sbo_WriteDirectly(unsigned int address, uint16_t data, unsigned int device=0);
void Sbo_ConfigureAsRealTime(unsigned int address, unsigned int device=0);
void Sbo_Write(unsigned int address, uint16_t data, unsigned int device=0);

Their Simulink counterparts are named SBI and SBO.

SBI block
SBO block

Configuration phase

The configuration phase occurs only once at the system startup and aims to initiate FPGA-based peripherals and configure the real-time data traffic, possibly across the control network. During this phase, interrupts and PWM operation are not yet active.

The SBI/SBO registers can be read/written during the configuration phase by using Sbi_ReadDirectly or Sbo_WriteDirectly in the UserInit() function.

As their names indicates, these functions infer immediate data transfers, which are performance-wise rather time consuming and therefore cannot be used during real-time execution.

In Simulink, SBO registers that are only written once are called configuration registers, opposing to real-time registers. The user selects which registers are set as configuration registers from the "Registers" tab of the SBO block and then set up their values from the "Configuration reg. values" tab.

Real-time execution

Configuring a SBI or SBO register as a real-time register indicates that the value of this register is to be transferred at each control interrupt. Configuring a register as real-time is done by using the C++ function Sbi_ConfigureAsRealTime or Sbo_ConfigureAsRealTime.

In Simulink, real-time registers are clearly distinguished from configuration registers. They take their run-time values from the block inputs.

Before entering the control interrupt, the data that have previously been configured as real-time are retrieved from the FPGA peripherals and placed into the CPU read buffer (READ phase). As such, they can readily be used from inside the control interrupt using Sbi_Read.

Reciprocally, using the Sbo_Write function inside the control interrupt stores data into the write buffer, waiting to be sent back to the FPGA once the interrupt is completed (WRITE phase).

In Simulink real-time data can be easily manipulated using signal wires.

Retrieving ADC conversion results

Inside the FPGA, ADC results are available from the ADC interface of the firmware IP. The port sampling_pulse signals the start of an ADC conversion and adc_done_pulse indicate that the results are available in the ADC interface. The conversion 16-bit results are in 2’s complement format.

Driving PWM outputs

On the firmware IP, the sb_pwm[31:0] port provides access to the same PWM output chain as that used by other modulators (CB-PWM, PP-PWM, DO-PWM and SS-PWM). This allows the user to generate complementary signals with dead-time, use the standard activate and deactivate functions and rely on the protection mechanism that blocks PWM outputs when a fault is detected.

The PWM chain can be configured using the C++ function from includes/pwmSandbox.h.

void SbPwm_ConfigureOutputMode(tPwmOutput output, tPwmOutMode outMode, unsigned int device=0);
void SbPwm_ConfigureDeadTime(tPwmOutput output, float deadTime, unsigned int device=0);
void SbPwm_Activate(tPwmOutput output, unsigned int device=0);
void SbPwm_Deactivate(tPwmOutput output, unsigned int device=0);

or using the corresponding Simulink SB-PWM block.

Each bit of the sb_pwm[31:0] IP port corresponds to a PWM lane.

  • sb_pwm[0] : lane #0

  • sb_pwm[1] : lane #1

  • sb_pwm[2] : lane #2

  • etc.

In a channel configuration (pseudo-complimentary signals with dead time), the user only needs to generate the HIGH signal, which must be connected to the appropriate sb_pwm input (sb_pwm[0]sb_pwm[2]sb_pwm[4], etc.). An exemple of such a configuration is available in TN120.

Imperix strongly discourages the user to directly drive the top-level pwm port as this would bypass the enable/disable mechanism! Instead, the SB-PWM port is meant to provide proper access to PWM outputs, which should be used in all cases.

On B-Box RCP, this is only relatively sensitive as hardware protections exist. However, on B-Board PRO, this is critical since this mechanism also handles the fault management !