Simulating serial communication in ngspice

Most systems today involve both analog and digital components, and digital components in a lot of cases would be communicating with each other via some form of serial communication interface (I2C, UART, SPI or any other). In such a scenario it might be useful to have a way to simulate these communications.

In this post I will be explaining an example of an ADC over SPI interface. For reference I will be taking the example of ADC081S021 which is an 8-bit analog to digital converter by Texas instruments. For simulation I will be using ngspice as a circuit simulator. Ngspice is an open source circuit simulation which allows you to build custom models of a device using the XSPICE extension. (for more details on ngspice and xspice checkout the ngspice page and user manual).

Functional details of the ADC.

In this section I will be describing the details of the ADC and its communication protocol. For reference look at the figure below, it describes the timing of adc communications. (source : The device works in a slave SPI mode.

Screenshot from 2021-05-15 11-19-00.png

The ADC starts conversion and transmission after the CS (chip select) pin on the ADC is taken from high to low. After the CS pin is taken from high to low the ADC (on its SDATA pin) transmits a zero for three clock cycles. the next 8 cycles are for the data in the ADC register and the 4 trailing cycles again transmit a zero. Thus the full conversion and transmission requires 16 cycles (one cycle gap will be present before the next transmission can happen). The next conversion and transmission will start when the CS pin is taken high and then back low.


The output format for the ADC is a straight binary. LSB having a width of VA / 256. (where VA is the supply voltage to to the ADC)

Screenshot from 2021-05-15 11-36-22.png

Building the simulation model

I will be simulating the ADC in ngspice by building an Xspice code model of the device. The code model has two main components : the interface specification file (ifspc.ifs) and the main code model ( cfunc.mod). The ifspec.ifs file will look like this :-

Screenshot from 2021-05-15 11-42-46.png

each of the ports defines a pin of the ADC. SDATA , clock and CS are the pins used in SPI communication. clock is the clock pin used for synchronizing data transfer, and CS port is the chip select the pin.

the function model in the cfunc.mod file is given by-

code model (cfunc.mod):
#include <stdint.h>

#include <stdio.h>

#include <stdlib.h>

double l_to_volt(_Bool logic){

    return logic * 10;


void c_adc(ARGS){ //the name of the c_function is defined in the ifspec.ifs file

    static double clock_v, clock_cache_v,t_pre, edge, cs,va,vin,cs_pre, sdata;

    static _Bool transmit = 0;

    clock_v = INPUT(clock); //this is the general format of reading input

                            //in a code model INPUT(<port_name>)

    cs = INPUT(CS);

    va = INPUT(VA);

    vin = INPUT(analog_in);

    static uint8_t data_reg, output_buff, clk_count;


        if(TIME - t_pre > 0.000001){//if the sampling is done in each iteration

                                    //it might cause convergence issues

                                    //thus better to have a time gap

                                    //here it is 1us

            edge = (clock_v - clock_cache_v) / (TIME - t_pre);

            t_pre = TIME;

            clock_cache_v = clock_v;

            if(edge > 100){//when the clock goes from low to high

                           //(rising edge clock)

                data_reg = (int) (vin * 0xFF / va);

                if(cs_pre > 5 && cs < 0.5){

                    clk_count = 0;//start transmiting

                    transmit = 1;



                    if(clk_count < 3){

                        sdata = 0;


                    else if(clk_count > 10 && clk_count < 16){

                        sdata = 0;


                    else if(clk_count > 15){

                        transmit = 0; //at clk_count is complete

                                      //stop the tranmission



                        sdata = l_to_volt((data_reg >> clk_count - 3) & 0x01);


                    clk_count++;//increase clock count


               cs_pre = cs;




    OUTPUT(SDATA) = sdata;//this is the general format of giving output

                          //to a port OUTPUT(<port_name>) = value


Now that we have completed the code we can compile it along with ngspice. To do that simply go the the ngspice folder and type "make" then "sudo make install". Now we can type simulate this like a normal component of a circuit. (refer to ngspice manual for more details)

The example netlist file is :

circuit netlist:
*adc test example

.model adc_device adc()

v1 clock 0 PULSE(0 5 0 1ns 1ns 1 2 0) ; the clock pulse

v2 analog_in 0 dc 8 ;analog input

v3 a 0 dc 10 ; dc supply voltage

v4 cs 0 dc 10;cs pin is high initially

A1 clock analog_in sdata  cs a adc_device ;node 4 is the SDATA output port


stop when time = 3

tran 0.001 33

alter @v4 = 0



Simulation and results :

the result of the simulation are shown in the figure below:

Screenshot from 2021-05-15 12-39-14.png

At t=3 the chip select line goes low. In the next rising edge (t=4) the transmission starts. The first 3 bits are leading bits which are zero. The next 8 bits are the data (the voltage converted to digital). Th voltage we have applied is 8V dc voltage. The digital converted value will be

data = Vin x 255 / Va

= 8 x 255 / 10

= 204 = (converting to hex) 0xCC

The transmission is LSB first. 0xCC in binary is (0x11001100), so the transmitted bits would be (0 0 1 1 0 0 1 1) which can be seen in the figure. The last 4 bits are trailing bits which are zero.

This is a basic example of how devices with serial communication can be simulated in ngspice (this model should be compatible with LTSpice too). I will be trying to build models or more such devices and maybe a general SPI debugger model which can be used anywhere.

Note : I have kept the clock input as 5 and other digital inputs as 10 to maintain clarity in the plots. The plot is not of very good quality as I am using the built in plotter of ngspice which is very basic. Next time on, I can try to export the data to file and plot using python. I will also be trying to complete this code model by including all the electrical characteristics f the device (max dc power, pin impedance, minimum timing requirements etc.).

Blog entry information

Harsh Chittora 1
Last update

More entries in General

Share this entry