Wednesday, April 8, 2020

How to implement SAR ADC with a minimum analog content - a simple 3-bit ADC example

To implement SAR ADC mixed signal circuit, let's use a microarchitecture of SAR ADC function divided in analog and digital blocks.


To simplify the design process, it is advisable to migrate as many functions of SAR ADC as possible into the digital block. This is because the digital block can be implemented using synchronous logic, making it possible to synthesize using the digital block RTL source code. On the other hand, analog design is inherently complex and should be kept to a minimum in any mixed signal design.


For this example, I have chosen a 3-bit ADC SAR switched capacitor architecture:


In this architecture we really need only capacitors ( and their  three position switches ), one comparator and one two position switch to be implemented in the analog block so all other functions could be implemented in the digital block.

§  Piloting all five analog switches could be done from the digital block as well


Here is an example of a possible microarchitecture split between analog and digital block to implement a 3-bit ADC SAR switched capacitor architecture in our example:



Under assumption that Vref = 1V, here is an explanation what is our ADC supposed to do:

§  translate Vin voltage ranges to their 3-bit equivalents:



Vref = 1V, Vin voltage ranges

ADC expected results per range

> 0 and =< 0.125

000

> 0.125 and =< 0.25

001

> 0.25 and =< 0.375

010

> 0.375 and =< 0.5

011

> 0.5 and =< 0.625

100

> 0.635 and =< 0.75

101

> 0.75 and =< 0.875

110

> 0.875 and =< 1

111




Interface description:

·        Top level signals:

o   clk

§  digital block main ( and only ) clock

o   reset

§  digital block power-on reset ( active low )

o   adc_conversion_en

§  when adc_conversion_en is 1 => ADC function enabled

o   Vin

§  analog signal sampled in ADC


·        Analog-Digital interface

o   adc_compout

§  analog block output of the comparator


o   sw0_closed

§  digital output that determines if analog block switch Sw0 is connecting minus input of comparator to GND ( sw0_closed = 1 ) or not ( sw0_closed = 0)


o   sw<x>_vin,  sw<x>_vref , sw<x>_gnd

§  <x> is representing 1, 2, 3 or 4.   


§   Each signal described as sw<x>* represents a control signal for piloting a three position  analog switch:  Sw4,  Sw3, Sw2 or Sw1 connecting  a respective capacitor  to either  Vin or Vref  or GND.

·        E.g. possible values of analog switch Sw4 in one clock cycle:

Sw4 connecting 4C capacitor to:

sw4_vin

sw4_vref

sw4_gnd

Vin

1

0

0

Vref

0

1

0

GND

0

0

1



As a proof of concept here is an example RTL code of the digital block, and for its quick verification ( sorry the verification  is not self-checking) a crude Verilog analog block model  and a top module where analog and digital block are connected.


To simplify the proof of the concept the assumption is made that analog switches and an analog comparator can finish a job in one digital clock cycle. If this is not true with a real life analog design, we would need a relatively simple change of state-machine timing of changing states to adjust for  specified delays in the analog block.   


Functional verification is done using Vref = 1V, and I used around 26 different Vi samples, keeping one sample for a period of two ADC cycles.

Here are 26 different Vi samples used and for each sample there is a 3-bit expected ADC result:



Vin[V], Vref = 1V

3-bit ADC expected results

0

000

0.01  

000

0.124

000

0.125

000

0.126

001

0.24   

001

0.25

001

0.26

010

0.374

010

0.375 

010

0.376 

011

0.49

011

0.50

011

0.51

100

0.624  

100

0.625

100

0.626

101

0.749

101

0.750

101

0.751

110

0.874

110

0.875

110

0.876

111

0.99

111

1

111


Here are some snapshots of waveforms od ADC data and it's ready signal as a function of Vin:




Finally here is a Verilog code of the digital design and it's simple verification infrastructure:


/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
// top_test_adc_8bit.v
module top_test_adc_8bit ();
  reg POR_sync_i ;
  reg clk ;

  reg adc_conversion_en ;
  wire adc_comp_out ;

  wire sw4_vin ;
  wire sw4_vref;
  wire sw4_gnd ;

  wire sw3_vin ;
  wire sw3_vref;
  wire sw3_gnd ;

  wire sw2_vin ;
  wire sw2_vref;
  wire sw2_gnd ;

  wire sw1_vin ;
  wire sw1_vref;
  wire sw1_gnd ;

  wire sw0_closed;

  adc_8bit_dig_top adc_8bit_dig_top (
    .POR_sync_i          ( POR_sync_i        ) ,
    .clk                 ( clk               ) ,

    .adc_conversion_en_i ( adc_conversion_en ) ,

    .adc_comp_out_i      ( adc_comp_out      ) ,

    .sw4_vin_o           ( sw4_vin           ) ,
    .sw4_vref_o          ( sw4_vref          ) ,
    .sw4_gnd_o           ( sw4_gnd           ) ,

    .sw3_vin_o           ( sw3_vin           ) ,
    .sw3_vref_o          ( sw3_vref          ) ,
    .sw3_gnd_o           ( sw3_gnd           ) ,

    .sw2_vin_o           ( sw2_vin           ) ,
    .sw2_vref_o          ( sw2_vref          ) ,
    .sw2_gnd_o           ( sw2_gnd           ) ,

    .sw1_vin_o           ( sw1_vin           ) ,
    .sw1_vref_o          ( sw1_vref          ) ,
    .sw1_gnd_o           ( sw1_gnd           ) ,

    .sw0_closed_o        ( sw0_closed        ));

  adc_8bit_analog_model adc_8bit_analog_model (

    .POR_sync_i          ( POR_sync_i        ) ,
    .clk                 ( clk               ) ,

    .adc_conversion_en_i ( adc_conversion_en ) ,

    .adc_comp_out_o      ( adc_comp_out      ) ,

    .sw4_vin_i           ( sw4_vin           ) ,
    .sw4_vref_i          ( sw4_vref          ) ,
    .sw4_gnd_i           ( sw4_gnd           ) ,

    .sw3_vin_i           ( sw3_vin           ) ,
    .sw3_vref_i          ( sw3_vref          ) ,
    .sw3_gnd_i           ( sw3_gnd           ) ,

    .sw2_vin_i           ( sw2_vin           ) ,
    .sw2_vref_i          ( sw2_vref          ) ,
    .sw2_gnd_i           ( sw2_gnd           ) ,

    .sw1_vin_i           ( sw1_vin           ) ,
    .sw1_vref_i          ( sw1_vref          ) ,
    .sw1_gnd_i           ( sw1_gnd           ) ,

    .sw0_closed_i        ( sw0_closed        ));

initial begin
  clk                = 1'b0 ;
  adc_conversion_en  = 1'b0 ;

  POR_sync_i = 1'b1 ;
  #100
  POR_sync_i = 1'b0 ;
  @ ( posedge clk ) ;
  @ ( posedge clk )  ;
  adc_conversion_en  = 1'b1 ;
end


always begin
  #10
  clk = !clk ;
end


endmodule



////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// adc_8bit_analog_model.v

module  adc_8bit_analog_model (
  POR_sync_i          ,
  clk                 ,

  adc_conversion_en_i ,

  adc_comp_out_o      ,

  sw4_vin_i           ,
  sw4_vref_i          ,
  sw4_gnd_i           ,

  sw3_vin_i           ,
  sw3_vref_i          ,
  sw3_gnd_i           ,

  sw2_vin_i           ,
  sw2_vref_i          ,
  sw2_gnd_i           ,

  sw1_vin_i           ,
  sw1_vref_i          ,
  sw1_gnd_i           ,

  sw0_closed_i);

input  POR_sync_i          ;
input  clk                 ;

input  adc_conversion_en_i ;

output adc_comp_out_o      ;

input  sw4_vin_i           ;
input  sw4_vref_i          ;
input  sw4_gnd_i           ;

input  sw3_vin_i           ;
input  sw3_vref_i          ;
input  sw3_gnd_i           ;

input  sw2_vin_i           ;
input  sw2_vref_i          ;
input  sw2_gnd_i           ;

input  sw1_vin_i           ;
input  sw1_vref_i          ;
input  sw1_gnd_i           ;

input  sw0_closed_i        ;




parameter START_ST = 3'b000 ;
parameter MSB_ST   = 3'b001 ;
parameter BIT_1_ST = 3'b010 ;
parameter LSB_ST   = 3'b011 ;


reg[2:0] state, next_state ;


reg adc_comp_out_o ;

wire  sw4_vin_i  ;
wire  sw4_vref_i ;
wire  sw4_gnd_i  ;

wire  sw3_vin_i  ;
wire  sw3_vref_i ;
wire  sw3_gnd_i  ;

wire  sw2_vin_i  ;
wire  sw2_vref_i ;
wire  sw2_gnd_i  ;

wire  sw1_vin_i  ;
wire  sw1_vref_i ;
wire  sw1_gnd_i  ;

wire  sw0_closed_i ;

real neg_inp_comp ;

real vin ;

reg[5:0] count, next_count ;


initial begin
  vin = 0   ;
  adc_comp_out_o = 0 ;
end

always@(
        count
      ) begin

  case ( count )
    6'd0,6'd1, 6'd2:
      vin = 0  ;
    6'd3, 6'd4 :
      vin = 0.01  ;
    6'd5, 6'd6 :
      vin = 0.124  ;
    6'd7, 6'd8 :
      vin = 0.125  ;
    6'd9, 6'd10 :
      vin = 0.126  ;
    6'd11,6'd12 :
      vin = 0.24  ;
    6'd13, 6'd14 :
      vin = 0.25  ;
    6'd15, 6'd16 :
      vin = 0.26  ;
    6'd17, 6'd18 :
      vin = 0.374  ;
    6'd19, 6'd20 :
      vin = 0.375  ;
    6'd21, 6'd22 :
      vin = 0.376  ;
    6'd23, 6'd24 :
      vin = 0.49  ;
    6'd25, 6'd26 :
      vin = 0.50  ;
    6'd27, 6'd28 :
      vin = 0.51  ;
    6'd29,6'd30 :
      vin = 0.624  ;
    6'd31, 6'd32 :
      vin = 0.625  ;
    6'd33, 6'd34:
      vin = 0.626  ;
    6'd35, 6'd36:
      vin = 0.749  ;
    6'd37, 6'd38:
      vin = 0.750  ;
    6'd39, 6'd40:
      vin = 0.751  ;
    6'd41, 6'd42:
      vin = 0.874  ;
    6'd43, 6'd44:
      vin = 0.875  ;
    6'd45, 6'd46:
      vin = 0.876  ;
    6'd47, 6'd48:
      vin = 0.99  ;
    6'd49, 6'd50:
      vin = 1  ;
    6'd51, 6'd52:
      vin = 1.1  ;
  endcase
end

/// SEQ
always@ ( posedge clk or negedge POR_sync_i  ) begin
  if( !POR_sync_i ) begin
      state <= START_ST ;
      count <= 6'd0     ;
    end
  else begin
      state <= next_state ;
      count <= next_count ;
  end

end

// COMB
always@(*) begin
  next_state = state ;
  next_count = count ;
  case( state )
//////////////////////////////////////////////
    START_ST: begin
      if( adc_conversion_en_i ) begin
        if(
            sw4_vin_i    &&
            sw3_vin_i    &&
            sw2_vin_i    &&
            sw1_vin_i    &&
            sw0_closed_i
          )begin
              neg_inp_comp = vin ;
              next_state  = MSB_ST ;
            end
      end
    end
///////////////////////////////////////////////
    MSB_ST: begin
      if( adc_conversion_en_i ) begin
        if( sw4_vref_i    &&
            sw3_vin_i    &&
            sw2_vin_i    &&
            sw1_vin_i    &&
            !sw0_closed_i
          )begin
            neg_inp_comp = 0.5 - vin ;

            if( ( 0.5 - vin ) >= 0 ) begin
              adc_comp_out_o = 1'b0 ;
            end else begin
              adc_comp_out_o = 1'b1 ;
            end
            next_state  = BIT_1_ST ;
          end else begin
            neg_inp_comp   = 1'b0     ;
            adc_comp_out_o = 1'bx     ;
            next_state     = START_ST ;
          end
      end
    end
///////////////////////////////////////////////
    BIT_1_ST: begin
      if( adc_conversion_en_i ) begin
        if(
            ( ( sw4_vref_i || sw4_gnd_i ) && !sw4_vin_i )  &&
            sw3_vref_i                                     &&
            sw2_vin_i                                      &&
            sw1_vin_i                                      &&
            !sw0_closed_i
          )begin
            if( sw4_vref_i )
              neg_inp_comp = ( 0.5 + 0.25 ) - vin ;
              if( sw4_gnd_i )
                neg_inp_comp = 0.25 - vin ;
                if( neg_inp_comp >= 0 )
                  adc_comp_out_o = 1'b0 ;
                else
                  adc_comp_out_o = 1'b1 ;

            next_state  = LSB_ST ;
          end
      end else begin
        neg_inp_comp = 1'b0  ;
        adc_comp_out_o = 1'bx  ;

        next_state      = START_ST ;
      end
    end
///////////////////////////////////////////////
    LSB_ST: begin
      if( adc_conversion_en_i ) begin
        if(
            ( ( sw4_vref_i || sw4_gnd_i ) && !sw4_vin_i )  &&
            ( ( sw3_vref_i || sw3_gnd_i ) && !sw3_vin_i )  &&
            sw2_vref_i                                     &&
            sw1_vref_i                                     &&
            !sw0_closed_i
          )begin
            case( { sw4_vref_i, sw3_vref_i } )
              2'b00:
                  neg_inp_comp = 0.5/4               - vin ;

              2'b01:
                  neg_inp_comp = 0.5/2 + 0.5/4       - vin ;

              2'b10:
                  neg_inp_comp = 0.5   + 0.5/4      - vin ;

              2'b11:
                  neg_inp_comp = 0.5 +  0.5/2 + 0.5/4 - vin ;
            endcase

            if( neg_inp_comp >= 0 )
              adc_comp_out_o = 1'b0 ;
            else
              adc_comp_out_o = 1'b1 ;

            if( count <= 6'd51 )
              next_count = count  + 5'd1 ;

            next_state = START_ST ;

          end
      end else begin
        neg_inp_comp = 1'b0  ;
        adc_comp_out_o = 1'bx;

        next_state = START_ST ;
      end
    end
  endcase

end

endmodule



/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
// adc_8bit_dig_top.v
module  adc_8bit_dig_top (
  POR_sync_i          ,  
  clk                 ,
 
  adc_conversion_en_i ,
 
  adc_comp_out_i      ,
 
  sw4_vin_o           ,
  sw4_vref_o          ,
  sw4_gnd_o           ,
         
  sw3_vin_o           ,
  sw3_vref_o          ,
  sw3_gnd_o           ,
         
  sw2_vin_o           ,
  sw2_vref_o          ,
  sw2_gnd_o           ,
         
  sw1_vin_o           ,
  sw1_vref_o          ,
  sw1_gnd_o           ,
         
  sw0_closed_o);

  input  POR_sync_i          ;
  input  clk                 ;
 
  output adc_comp_out_i      ;
 
  input  adc_conversion_en_i ;
       
  output sw4_vin_o    ;
  output sw4_vref_o   ;
  output sw4_gnd_o    ;
       
  output sw3_vin_o    ;
  output sw3_vref_o   ;
  output sw3_gnd_o    ;
                 
  output sw2_vin_o    ;
  output sw2_vref_o   ;
  output sw2_gnd_o    ;
                 
  output sw1_vin_o    ;
  output sw1_vref_o   ;
  output sw1_gnd_o    ;
       
  output sw0_closed_o ;
 
 
 
 
  parameter START_ST = 3'b000 ;
  parameter MSB_ST   = 3'b001 ;
  parameter BIT_1_ST = 3'b010 ;
  parameter LSB_ST   = 3'b011 ;
  parameter END_ST   = 3'b100 ;
 
 
  reg[2:0] state, next_state         ;                        
 
  reg  sw4_vin_o  ,   next_sw4_vin   ;
  reg  sw4_vref_o  ,   next_sw4_vref ;
  reg  sw4_gnd_o   ,   next_sw4_gnd  ;
           
  reg  sw3_vin_o   ,   next_sw3_vin  ;
  reg  sw3_vref_o  ,   next_sw3_vref ;
  reg  sw3_gnd_o   ,   next_sw3_gnd  ;
           
  reg  sw2_vin_o   ,   next_sw2_vin  ;
  reg  sw2_vref_o  ,   next_sw2_vref ;
  reg  sw2_gnd_o   ,   next_sw2_gnd  ;
           
  reg  sw1_vin_o   ,   next_sw1_vin  ;
  reg  sw1_vref_o  ,   next_sw1_vref ;
  reg  sw1_gnd_o   ,   next_sw1_gnd  ;
 
  reg  sw0_closed_o,   next_sw0_closed ;
 
  reg[2:0] adc_data,   next_adc_data   ;
 
  reg      adc_data_rdy,  next_adc_data_rdy ;
           
/// SEQ      
always@ ( posedge clk or negedge POR_sync_i  ) begin

  if( !POR_sync_i ) begin
    state        <= START_ST ;
   
    sw4_vin_o    <= 1'b0 ;
    sw4_vref_o   <= 1'b0 ;
    sw4_gnd_o    <= 1'b0 ;

    sw3_vin_o    <= 1'b0 ;
    sw3_vref_o   <= 1'b0 ;
    sw3_gnd_o    <= 1'b0 ;

    sw2_vin_o    <= 1'b0 ;
    sw2_vref_o   <= 1'b0 ;
    sw2_gnd_o    <= 1'b0 ;

    sw1_vin_o    <= 1'b0 ;
    sw1_vref_o   <= 1'b0 ;
    sw1_gnd_o    <= 1'b0 ;
   
    sw0_closed_o <= 1'b0 ;

    adc_data     <= 3'd0 ;

    adc_data_rdy <= 1'd0 ;                                        
  end else begin                                  
    state        <= next_state      ;

    sw4_vin_o    <= next_sw4_vin    ;
    sw4_vref_o   <= next_sw4_vref   ;
    sw4_gnd_o    <= next_sw4_gnd    ;
               
    sw3_vin_o    <= next_sw3_vin    ;
    sw3_vref_o   <= next_sw3_vref   ;
    sw3_gnd_o    <= next_sw3_gnd    ;
               
    sw2_vin_o    <= next_sw2_vin    ;
    sw2_vref_o   <= next_sw2_vref   ;
    sw2_gnd_o    <= next_sw2_gnd    ;
               
    sw1_vin_o    <= next_sw1_vin    ;
    sw1_vref_o   <= next_sw1_vref   ;
    sw1_gnd_o    <= next_sw1_gnd    ;
               
    sw0_closed_o <= next_sw0_closed ;
   
    adc_data     <= next_adc_data   ;
   
    adc_data_rdy <= next_adc_data_rdy ;
  end
end

// COMB
always@(*) begin
  next_state      = state         ;
 
  next_sw4_vin    =  sw4_vin_o    ;
  next_sw4_vref   =  sw4_vref_o   ;
  next_sw4_gnd    =  sw4_gnd_o    ;
                               
  next_sw3_vin    =  sw3_vin_o    ;
  next_sw3_vref   =  sw3_vref_o   ;
  next_sw3_gnd    =  sw3_gnd_o    ;
                               
  next_sw2_vin    =  sw2_vin_o    ;
  next_sw2_vref   =  sw2_vref_o   ;
  next_sw2_gnd    =  sw2_gnd_o    ;
                               
  next_sw1_vin    =  sw1_vin_o    ;
  next_sw1_vref   =  sw1_vref_o   ;
  next_sw1_gnd    =  sw1_gnd_o    ;
                               
  next_sw0_closed =  sw0_closed_o ;
 
  next_adc_data   =  adc_data     ;
 
  next_adc_data_rdy =  adc_data_rdy ;
  case( state )
//////////////////////////////////////////////  
    START_ST: begin
      next_sw4_vin    = 1'b1 ;
      next_sw4_vref   = 1'b0 ;
      next_sw4_gnd    = 1'b0 ;

      next_sw3_vin    = 1'b1 ;
      next_sw3_vref   = 1'b0 ;
      next_sw3_gnd    = 1'b0 ;

      next_sw2_vin    = 1'b1 ;
      next_sw2_vref   = 1'b0 ;
      next_sw2_gnd    = 1'b0 ;

      next_sw1_vin    = 1'b1 ;
      next_sw1_vref   = 1'b0 ;
      next_sw1_gnd    = 1'b0 ;

      next_sw0_closed = 1'b1 ;
   
      if( adc_conversion_en_i ) begin
       
      next_sw4_vin    = 1'b0 ;
      next_sw4_vref   = 1'b1 ;
 
      next_sw0_closed = 1'b0 ;
   
      next_state      = MSB_ST ;
      end
    end
///////////////////////////////////////////////
    MSB_ST: begin
      if( adc_conversion_en_i ) begin
        if( adc_comp_out_i ==  1'b1 )begin
          next_adc_data[2] = 1'b1 ;
          next_sw4_vref    = 1'b1 ;
          next_sw4_gnd     = 1'b0 ;
        end else begin           
          next_adc_data[2] = 1'b0 ;
          next_sw4_vref    = 1'b0 ;
          next_sw4_gnd     = 1'b1 ;
        end
        next_state    = BIT_1_ST ;

        next_sw3_vin  = 1'b0 ;
        next_sw3_vref = 1'b1 ;
      end else begin
        next_sw0_closed = 1'b1   ;
        next_sw4_vin    = 1'b1   ;
        next_sw4_vref   = 1'b0   ;
        next_sw4_gnd    = 1'b0   ;
   
        next_state      = START_ST ;
      end
    end
///////////////////////////////////////////////
    BIT_1_ST: begin
      if( adc_conversion_en_i ) begin
        if( adc_comp_out_i ==  1'b1 )begin
          next_adc_data[1] = 1'b1   ;
          next_sw3_vref    = 1'b1   ;
          next_sw3_gnd     = 1'b0   ;
        end else begin
          next_adc_data[1] = 1'b0   ;
          next_sw3_vref    = 1'b0   ;
          next_sw3_gnd     = 1'b1   ;
        end
   
        next_state    = LSB_ST ;
   
        next_sw2_vin  = 1'b0   ;
        next_sw2_vref = 1'b1   ;
   
        next_sw1_vin  = 1'b0   ;
        next_sw1_vref = 1'b1   ;                 
      end else begin
        next_sw0_closed = 1'b1 ;
        next_sw3_vin    = 1'b1 ;
        next_sw3_vref   = 1'b0 ;
        next_sw3_gnd    = 1'b0 ;
   
        next_state = START_ST  ;
      end
    end
///////////////////////////////////////////////
    LSB_ST: begin
      if( adc_conversion_en_i ) begin
        next_sw3_vin = 1'b0 ;
        if( adc_comp_out_i == 1'b1 )begin
          next_adc_data[0] = 1'b1 ;
          next_sw2_vref    = 1'b1 ;
          next_sw2_gnd     = 1'b0 ;
 
          next_sw1_vref    = 1'b1 ;
          next_sw1_gnd     = 1'b0 ;
     
        end else begin
          next_adc_data[0] = 1'b0 ;
   
          next_sw2_vref   = 1'b0 ;
          next_sw2_gnd    = 1'b1 ;

          next_sw1_vref   = 1'b0 ;
          next_sw1_gnd    = 1'b1 ;
        end
        next_adc_data_rdy   = 1'b1 ;
        next_state      = END_ST ;    
                     
      end else begin
        next_sw0_closed = 1'b1   ;
         
        next_sw2_vin    = 1'b1   ;
        next_sw2_vref   = 1'b0   ;
        next_sw2_gnd    = 1'b0   ;
   
      next_sw1_vin    = 1'b1   ;
      next_sw1_vref   = 1'b0   ;
      next_sw1_gnd    = 1'b0   ;
      next_state      = START_ST ;
    end
  end
///////////////////////////////////////////////
  END_ST: begin
    next_sw0_closed = 1'b1   ;
   
next_sw4_vin    = 1'b1   ;
    next_sw4_vref   = 1'b0   ;
    next_sw4_gnd    = 1'b0   ;
   
    next_sw3_vin    = 1'b1   ;
    next_sw3_vref   = 1'b0   ;
    next_sw3_gnd    = 1'b0   ;
       
    next_sw2_vin    = 1'b1   ;
    next_sw2_vref   = 1'b0   ;
    next_sw2_gnd    = 1'b0   ;
   
    next_sw1_vin    = 1'b1   ;
    next_sw1_vref   = 1'b0   ;
    next_sw1_gnd    = 1'b0   ;
   
    next_adc_data_rdy   = 1'b0   ;
    next_adc_data       = 3'd0   ;
   
    next_state      = START_ST ;
  end
endcase
end

endmodule




© 2011-2023 ASIC Stoic. All rights reserved

Sunday, April 5, 2020

SAR ADC implemented with a switched capacitor array architecture: a step by step calculation of a maximum value of the external driving source resistance to achieve a desired accuracy - an example



Many of SAR ADC’s are implemented using a switched capacitor array architecture and for an ADC like that one, here is an equivalent circuit:


Let’s approximate a driving of this type of SAR ADC input done with an equivalent circuit like this one:


Here is an example,  step by step calculation of maximum value of the external driving source resistance ( RS ) to achieve a desired accuracy of our SAR ADC.

·        First here are some basic characteristics of the SAR ADC used in this calculation/example:
·         Our SAR ADC has 8 bits output result
·         Our SAR ADC operates on 2 MHz clock frequency 
·         Our SAR ADC needs 4 clock cycles to sample a single data 
·         Our SAR ADC should have accuracy of 1/16 LSB 
·         Our SAR ADC equivalent circuit has Ri = 1KΩ, Ci=100pF

1.     Step 1 ( calculation of the sample time: Ts )
    • Ts = 4 *1/2Mhz = 2μs 

      • 4 represents number of clock cycles that our ADC SAR uses to sample a data
      • 2MHz represents our ADC SAR operation clock frequency



       2.     Step 2  ( finding a conversion time  of our ADC with the accuracy desired)
·        It can be proven that our ADC conversion time with the accuracy desired is calculated using a following formula:


where:
o   Rt = Rs + RI
o   8 represents how many output bits has our ADC SAR
o   4 is derived from a desired accuracy.  The desired accuracy is 1/16 and 16 = 2^^4
3.         Step 3,  our ADC’s sample time should be always bigger or equal to our ADC’s conversion time with the accuracy desired :
·        


After solving this last equation per Rs, the conclusion is:
·        The analog source resistance can be no larger than 1.40 kΩ for 1/16 LSB accuracy for the SAR ADC in our example.
© 2011-2020 ASIC Stoic. All rights reserved

Saturday, April 4, 2020

SAR ADC error budget measured in the number of bits or error percentage

we used the example where   we needed to digitize an analog input signal in the range of 0-1V and that digital samples are represented as 8-bits values and we found that 0.003922V ( 1V/255 ) is the resolution of our ADC.

Obviously in our example ADC number of bits ( 8 bits ) and the analog input signal range of 0-1V  drives the resolution of our ADC ( 0.003922V ) and all of this represents the most basic error budget of our ADC( or any ADC for that matter ).
  • So the conclusion here is that ADC number of bits ( 8 bits ) and analog input signal range of 0-1V drive how much error in measurement  is introduced by our ADC .
It would be nice to represent this ADC error in measurement with one single number for example a percentage of the analog input signal range of 0-1V of our ADC and to do this we can use a following formula:

ADC error [%] = 100* ( analog input signal range )/2^^(ADC number of bits)

=> for our example: ADC error [%] = 100*( 1V -0V) /( 2^^8 -1 ) =  0.3922%


By looking into this simple formula it is clear that we could make a smaller ADC error [%] if we do one of two things ( or both of them in the same time ):
  • decrease ADC analog input signal range
  • increase ADC number of bits
e.g. If we increase ADC analog input signal range from 0-1V to 0-0.25V the ADC error will decrease from 0.3922% to 0.1%  :
=> ADC error [%] = 100*( 0.25V -0V ) /( 2^^8 -1 ) =  0.1%


As a conclusion:
  •  if you come across that somebody is talking about, for example an ADC error budget of 12 bits or 0.024% what they really mean is the ADC error budget of 12 bits ADC for the input signal range of 0-1V is  0.024% because:


=> ADC error [%] = 100*( 1V -0V) /( 2^^12 -1 ) =  0.024%

© 2011-2020 ASIC Stoic. All rights reserved


Thursday, April 2, 2020

Successive Approximation Register (SAR) ADC algorithm - an example



 The SAR ADC is one of the most intuitive analog-to-digital converter algorithm and it can be implemented as a mix design circuit consisting of analog and digital part.

Let's imagine that we need to digitize an analog input signal in the range of 0-1V and that digital samples of the input signals will be represented as 8-bits values.
  • This means that a digital representation of continues analog signal in the range of 0-1V has to be represented with only 2^^8 (256) different values. Foe example: 
    • 0V is represented with a minimum 8 bit value decimal 0 or in binary 8'b0000_0000 and 
    • 1V is represented with maximum 8'bit value decimal 255 or in binary 8'b1111_1111
Since we have only 256 possible digital 8-bit values to represent continues analog signal in the range of 0-1V obviously we will  represent a sub-range of an input voltage with a single 8-bit value.This subrange/step size of the converter defines the converter's resolution.

e.g. 
  • 8'b0000_0000 digital value represents 0V analog input and first next digital value is 8'b0000_0001 that will represent 1V/255 = 0.003922 V if we assume precision on 6 decimal places ( meaning 0.003922 V is the resolution of our ADC in this example ) 
    • This means that we have to adopt a criteria that any input voltage, in the range bigger or equal to 0V and less than 0.003922, will be digitally coded with a value of 8'b0000_0000.
      • Further,  any input voltage in the range bigger or equal of 0.003922 but less than 0.007843( represents result of  2/255)  it will be digitally coded with a value of 8'b0000_0001 etc. etc. 
=> The final table looks like this:
  • There will be 256 ( for example 0, 1, 2....253, 254, 255 ), 8-bit  digital values  representation of the analog input in the range of 0-1V : 
Decimal digital value
Binary digital value
Input analog voltage [V]
Comment
        0
8'b0000_0000
0           
0 /255     = 0             V
        1
8'b0000_0001
0.003922
1 /255     = 0.003922 V  
        2
8'b0000_0010
0.007843 
2 /255     = 0.007843 V
        3
8'b0000_0011
0.011765 
3 /255     = 0.011765 V
.....
…..
…..
…..
        253
8'b1111_1101
0.988235 
253 /255 = 0.988235 V
        254
8'b1111_1110
0.996078 
254 /255 = 0.996078 V
        255
8'b1111_1111
1             
255 /255    = 1           V

And finaly Successive Approximation Register ADC algorithm to output for example a digital value 8'b0000_0001 when input signal is 0.003922 V looks like this:

1.    if  0.003922 V would be bigger or equal than 0.5 V ( this is maximum analog signal voltage of 1V divided by 2 ) MSB bit ( or bit 7)  of a digitized result would be 1 ( but that is not the case so result is 0 )
=> so far the digital result is: 8'b0xxx_xxxx

2.    if  0.003922 V would be bigger or equal than  0.25 V ( this is maximum analog signal voltage of 1V divided by 4 ) bit 6  of a digitized result would be 1 ( but that is not the case so result is 0 )
=> so far the digital result is: 8'b00xx_xxxx

3.    if  0.003922 V would be bigger or equal than  0.125 V ( this is maximum analog signal voltage of 1V divided by 8 ) bit 5  of a digitized result would be 1 ( but that is not the case so result is 0 )
=> so far the digital result is: 8'b000x_xxxx
4.    if  0.003922 V would be bigger or equal than 0.0625  V ( this is maximum analog signal voltage of 1V divided by 16 ) bit 4  of a digitized result would be 1 ( but that is not the case so result is 0 )
=> so far the digital result is: 8'b0000_xxxx
5.    if  0.003922 V would be bigger or equal than  0.03125 V ( this is maximum analog signal voltage of 1V divided by 32 ) bit 3  of a digitized result would be 1 ( but that is not the case so result is 0 ) 
=> so far the digital result is: 8'b0000_0xxx
6.    if  0.003922 V would be bigger or equal than  0.015625 V ( this is maximum analog signal voltage of 1V divided by 64 ) bit 2  of a digitized result would be 1 ( but that is not the case so result is 0 ) 
=> so far the digital result is: 8'b0000_00xx
7.    if  0.003922 V would be bigger or equal than  0.0078125 V ( this is maximum analog signal voltage of 1V divided by 128 ) bit 1  of a digitized result would be 1 ( but that is not the case so result is 0 )
=> so far the digital result is: 8'b0000_000x
8.    if  0.003922 V would be bigger or equal than  0.00390625 V ( this is maximum analog signal voltage of 1V divided by 256 ) LSB bit or bit 0  of a digitized result would be 1, which is the case.
=> and the final result is: 8'b0000_0001

© 2011-2020 ASIC Stoic. All rights reserved