Hochschule Kempten      
Fakultät Elektrotechnik      
Publications       Fachgebiet Elektronik, Prof. Vollrath      

NodeEEBench with Digilent BASYS3 FPGA board

Lookup table Implementation

Jörg Vollrath, University of Applied Science Kempten, Germany, Joerg.vollrath@hs-kempten.de
March, 2024



Overview


Introduction

Implementation as VHDL Program

Testing




Introduction



Figure: Error correction with look up tables

The picture shows a typical DAC and ADC system. Digital codes for waveforms can be mapped with lookup tables to codes for a DAC to compensate for errors.
For testing vector memory can be used to contain the vectors necessary for a test.
A lookup table can act as a vector memory if the input address is a simple counter. A lookup table can also map bad codes to good codes for error compensation.
Therefore 2 lookup tables for DAC and ADC operation are implemented.

Since 4k x 16 memory with 12 address bits is used a maximum of 12 bits can be realized.
There is no counting or adding of lower 4 bits of AWG implemented. This could lead to higher resolutions.

Implementation


Usage of Block RAM


A one port memory template is used.
-- Memory
COMPONENT One_port_ram
  generic(
    ADDR_WIDTH: integer := 16;   -- 64k 
    DATA_WIDTH: integer := 16
   );
  port (
      clk: in std_logic;
      we: in std_logic;
      addr: in std_logic_vector(ADDR_WIDTH-1 downto 0);
      din: in std_logic_vector(DATA_WIDTH-1 downto 0);
      dout: out std_logic_vector(DATA_WIDTH-1 downto 0)
    );
end COMPONENT;
2 lookup tables 4k (ADDR_WIDTH => 12) x 16 each are implemented.
So far only the myLUT1 AWG part is functional connected.
myLut1: One_port_ram
   generic map ( ADDR_WIDTH => 12 )
   port map (
      clk => CLK,
      we => we01,
      addr => addr01,
      din => din01,
      dout => dout01
    );

-- address multiplexer write read
addr01b <= mywave(15 downto 4);         -- from AWG

with rMem(13) select
    addr01 <= addr01a  when '0',        -- uart writing
              addr01b  when '1',        -- lut reading
              addrGen when others;      -- switches

myLut2: One_port_ram
   generic map ( ADDR_WIDTH => 12 )
   port map (
      clk => CLK,
      we => we02,
      addr => addr02,
      din => din02,
      dout => dout02
    );

Multiplexing data from AWG1 via Block RAM to JB, JC


Only bits 15 downto 4 of mywave are used for addr01b for the LUT.

rMem(13) control normal operation or activation of lookup table by feeding the AWG code mywave to the address and connecting mywave or dout01 to the Pmod JB, JC via mywaveX.
with rMem(13) select -- lookup table data or not
    mywaveX <= mywave when '0',
               dout01 when '1',
               "0000000000000000" when others;

JB <= mywaveX(7 downto 0);  			 			 
JC <= mywaveX(15 downto 8);		

Transfer Data serially into Block RAM


The process getCmd in the file uart_mem.vhd manages the receiving of commands in VHDL.

numD = 32k hex values giving 8k (2 * 12 bit address) 16 bit numbers
rmAddress, 16 bit, counting from 0 up.

Testing


Downloading fixed data and activating LUT


To check activation of LUT and correct Hex value transfer of the lookup values a routine 'defaultLookup(md)' to write a fixed number to the LUT was created.

md0123
lookupnormal
i*16
reverse
8 *1024 - 1 - i * 16
fixedsteps
Math.trunc(i / 128) * 128 * 16

The command line shows the correct R command with hex values.
Digital values were used to set all LUT values and measurement done with an Electronic Explorer board.

Value1248 163264128 25651210242048 409681921638432768
Voltage 0.0450.0600.090.145 0.250.4650.871.655

Output voltages for the values are ok. The sequence of storing hex values in LUT memory seems to be ok.

The steps mapping was then done to a triangle waveform and gave a stair function with visible limited levels.

Implementation, testing and documentation took 3 days 24 h.