Professional Documents
Culture Documents
Pincushion Correction On CRT Using Digital Means
Pincushion Correction On CRT Using Digital Means
Assumptions
The CRT display plane is (assumed square) split into 128 blocks (i.e. 64 blocks in each quadrant) for
the purpose of pincushion correction. This should provide sufficient pincushion correction.
The pincushion correction is centrally symmetrical.
Correction factor is as those mentioned in the literature i.e x(x2 + y2) and y(x2 + y2) for each x and y
respectively.
Implementation Approach
In view of first assumption, the values of correction factors should be based on the 6 MSBs (as we have 12
bit resolution). The values of correction factor would be determined at regular intervals and stored in the
memory. These become our break points. The correction factor for coordinates within those breakpoints is
determined by the linear approximation.
Implementation
Y11
X11 } These bits are used to determine the quadrant
D15 – D8 CorrY
Y10 – Y5
Block RAM
Y11
Y11 – Y0
Adder / 12 bit data Corrected Y*
Subtractor
CorrY (D15 – D8) 12 bit data
k (D3 – D0)
The Deficiencies
The display obtained after applying above correction looks as following on the CRO. Where the orange is the
uncorrected square and blue one is the corrected display. It may be seen that the curves overlap at the axis.
To correct this, second order corrections need to be applied.
Figure 1
Implementaion of Second Order Distortion
The overlap region corresponds to the difference between the correction values along diagonals and the
axis. Therefore, the intension is to pull all the quadrants away by half of the magnitude of overlap.
In this table, the difference of values of correction along diagonal and axis as computed in the previous table
is recorded.
The bit pattern as shown in the last column is stored in the ROM.
Corrected X/Y*
Block
Sec_level_corr Pin Corr X/Y
X/Y (10 – Y6) RAM
(Single
Dimensional
Array having
32 locations k (D3 – D0)
each one of
8 bits )
Code
-------------------------------------------------------------------------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_arith.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
--------------------------------------------------------------------------------------------------------------------------------------------------
entity pin_top is
Port ( x_dac_out : out std_logic_vector (11 downto 0);
y_dac_out : out std_logic_vector (11 downto 0);
clk_in : in std_logic;
z : out std_logic;
clk_dac1 : out std_logic;
clk_dac2 : out std_logic;
wr_dac1 : out std_logic;
wr_dac2 : out std_logic;
sw : in std_logic;
sw11 : out std_logic
-- k : in std_logic_vector(3 downto 0)
);
end pin_top;
component square
port(
clk_in : in std_logic; --- 54 MHZ
sw1 : out std_logic;
z : out std_logic;
x_dac_out : out std_logic_vector(11 downto 0);
y_dac_out : out std_logic_vector(11 downto 0);
clk_in1 : out std_logic
);
end component;
component pin_mem
port (
clka : in std_logic;
addra : in std_logic_VECTOR(11 downto 0);
douta : out std_logic_VECTOR(15 downto 0));
end component;
component corr_2ndodr
port (
clka : in std_logic;
addra : in std_logic_VECTOR(4 downto 0);
douta : out std_logic_VECTOR(7 downto 0));
end component;
----------------------------------Signal Declaration----------------------------------------------------------------------------------------------
process(clk20ms) -- Internally generated value of k for testing. This is incremented after some interval
begin
if(clk20ms'event and clk20ms='1')then
sw_reg1<=sw_reg;
k_reg<=sw_reg1+k_reg;
end if;
end process;
process(clk20ms)
begin
if(clk20ms'event and clk20ms='1')then
if(k_reg>="1000")then
k<="0000";
else
k<=k_reg;
end if;
end if;
end process;
--------------- Generate the Square for Testing: Instantiation (actual code follows later) -------------------------------------
dut_pin: square
port map(
clk_in =>clk_in, --- 54 MHZ
sw1 =>sw1,
z =>z,
x_dac_out =>x_dac_out_sig1,
y_dac_out =>y_dac_out_sig1,
clk_in1 =>clk_in1
);
-------------------------------------------------------------------------- PIN CUSION CORRECTION MODULE: BEGINS ------------------------------------------
process(clk_in1) -- Determine polarity of X for determining quadrant and addr generation for 1 st level corr mem
begin
if(clk_in1'event and clk_in1='1')then
if(x_dac_out_sig1>2047)then
x_dac_out_sig(10 downto 5)<= x_dac_out_sig1(10 downto 5); --determine the addr of block ram for FIRST order corr
if (y_dac_out_sig(10 downto 0)<x_dac_out_sig(10 downto 0))then
addrbx<= x_dac_out_sig1(10 downto 6); --determine the addr of block ram for SECOND order corr
end if;
else
x_dac_out_sig(10 downto 5)<= not x_dac_out_sig1(10 downto 5); --determine addr of block ram for FIRST order corr
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
process(clk_in1) -- Determine polarity of Y for determining quadrant and addr generation for 1 st level corr mem
begin
if(clk_in1'event and clk_in1='1')then
if(y_dac_out_sig1>2047)then
y_dac_out_sig(10 downto 5)<= y_dac_out_sig1(10 downto 5); --determine the addr of block ram for FIRST order corr
if (y_dac_out_sig(10 downto 0)<x_dac_out_sig(10 downto 0))then
addrby<= y_dac_out_sig1(10 downto 6); --determine the addr of block ram for SECOND order corr
end if;
else
y_dac_out_sig(10 downto 5)<= not y_dac_out_sig1(10 downto 5); --determine addr of block ram for FIRST order corr
---The second order correction is applied to remove the overlapping as shown in Figure 1, section “Implementation of Second Order Distortion”
process(clk_in1)
begin
if(clk_in1'event and clk_in1='1')then
if(y_dac_out_sig(10 downto 0)> x_dac_out_sig(10 downto 0))then
addrb<=addrby; --determine the addr of block ram for SECOND order corr
else
addrb<=addrbx;
end if;
end if;
end process;
-------------------------------------------------------- Block ROM mapped for 1st level correction-------------------------------------------------------------
pin_corr : pin_mem
port map (
clka => clk_in1,
addra => addra,
douta => douta
);
--------------------------------------------------------- Block ROM mapped for 2nd t level correction---------------------------------------------------------------
corr_2nd: corr_2ndodr
port map (
clka => clk_in1,
addra => addrb,
douta => second_level_corr_mem);
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
addra<=y_dac_out_sig(10 downto 5)& x_dac_out_sig(10 downto 5); -- addr for block ram for first level corr mem
y_sig<=douta(15 downto 8);
x_sig<=douta(7 downto 0);
sel<=x_dac_out_sig1(11)&y_dac_out_sig1(11);
---------------------------------------------------------------------------------------------
process(clk_in) -- 1st level correction accounting for k i.e. x_corr =x + kx(x*x + y*y) ; y_corr =y + ky(x*x + y*y)
begin
if(clk_in1'event and clk_in1='1')then
case (k) is
when"0000" =>
x_dac_out_pin<="0000"&x_sig; -- k=1
y_dac_out_pin<="0000"&y_sig;
when"0001" =>
x_dac_out_pin<=x_sig+("000"&x_sig(7 downto 3)); --k=1.125 = 1 + 1/8
y_dac_out_pin<=y_sig+("000"&y_sig(7 downto 3));
when"0010" =>
x_dac_out_pin<=x_sig+("00"&x_sig(7 downto 2)); --k=1.25 = 1 + 1/4
y_dac_out_pin<=y_sig+("00"&y_sig(7 downto 2));
when"0011" =>
x_dac_out_pin<=x_sig+("11"*("000"&x_sig(7 downto 3))); --k=1.375= 1+3/8
y_dac_out_pin<=y_sig+("11"*("000"&y_sig(7 downto 3)));
when"0100" =>
x_dac_out_pin<=x_sig+("0"&x_sig(7 downto 1)); --k=1.5 = 1+1/2
y_dac_out_pin<=y_sig+("0"&y_sig(7 downto 1));
when"0101" =>
x_dac_out_pin<=x_sig+("101"*("000"&x_sig(7 downto 3))); --k=1.625= 1+5/8
y_dac_out_pin<=y_sig+("101"*("000"&y_sig(7 downto 3)));
when "0110" =>
x_dac_out_pin<=x_sig+("110"*("000"&x_sig(7 downto 3))); --k=1.75= 1+6/8
y_dac_out_pin<=y_sig+("110"*("000"&y_sig(7 downto 3)));
when"0111" =>
x_dac_out_pin<=x_sig+("111"*("000"&x_sig(7 downto 3))); --k=1.875 = 1+7/8
y_dac_out_pin<=y_sig+("111"*("000"&y_sig(7 downto 3)));
when others=>
x_dac_out_pin<=x_sig+x_sig; --k=2
y_dac_out_pin<=y_sig+y_sig;
end case;
end if;
end process;
process(sel) -- apply (add/subtract) 2nd level corrections to the 1st level corrected values
begin
case(sel)is
when "10"=>x_dac_out1<=x_dac_out_sig1-x_dac_out_pin+second_level_corr; --Quadrant 2
y_dac_out1<=y_dac_out_sig1+y_dac_out_pin- second_level_corr;
when "11"=>x_dac_out1<=x_dac_out_sig1-x_dac_out_pin +second_level_corr; --Quadrant 3/1
y_dac_out1<=y_dac_out_sig1-y_dac_out_pin +second_level_corr;
when "00"=>x_dac_out1<=x_dac_out_sig1+x_dac_out_pin - second_level_corr; --Quadrant 1/3
y_dac_out1<=y_dac_out_sig1+y_dac_out_pin - second_level_corr;
when others=>x_dac_out1<=x_dac_out_sig1+x_dac_out_pin - second_level_corr; --Quadrant 4/2
y_dac_out1<=y_dac_out_sig1-y_dac_out_pin + second_level_corr;
-- when others=> NULL;
end case;
end process;
x_dac_out <=x_dac_out1; --Pincushion Xcorr
y_dac_out <=y_dac_out1; --Pincushion Ycorr
clk_dac1 <=clk_in1;
clk_dac2 <=clk_in1;
wr_dac1 <=clk_in1;
wr_dac2 <=clk_in1;
end Behavioral;
----------------------------------------------------------- PIN CUSION CORRECTION MODULE : ENDS -----------------------------------------
-- Actual square generation code ( which is included in the top module above )
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity square is
port(
clk_in : in std_logic; --- 54 MHZ
sw1 : out std_logic;
z : out std_logic;
x_dac_out : out std_logic_vector(11 downto 0);
y_dac_out : out std_logic_vector(11 downto 0);
clk_in1 : out std_logic
);
end square;
begin
clk1<=clk_in; --54 MHz
process(clk1)
begin
if clk1'event and clk1='1' then --divide by 4 circuit
cnt1<=cnt1+'1';
if 0<=cnt1 and cnt1<=1 then
clk3<='1';
elsif 2 <= cnt1 and cnt1 <=3 then
clk3<='0';
end if;
if cnt1= 3 then
cnt1<=(others=>'0');
end if;
end if;
end process;
process(clk3)
begin
if clk3'event and clk3='1' then
cnt<=cnt+'1';
if cnt= 0 then
rst<='1';
else
rst<='0';
end if;
if 1 <= cnt and cnt <=9930 then --- for onr square
sel <='0';
sel1 <='0';
sel2 <='0';
z_sig <='1';
z_sig_s <='0';
z_sig_l <='0';
z_sig_so<='0';
elsif (cnt>=9931 and cnt<=19862)then
sel <='1';
sel1 <='0';
sel2 <='0';
z_sig <='0';
z_sig_s <='1';
z_sig_l <='0';
z_sig_so<='0';
elsif (cnt>=19863 and cnt<=31448)then
sel <='0';
sel1 <='1';
sel2 <='0';
z_sig <='0';
z_sig_s <='0';
z_sig_l <='1';
z_sig_so<='0';
elsif (cnt>=31449 and cnt<=45435)then
sel <='1';
sel1 <='1';
sel2 <='0';
z_sig <='0';
z_sig_s <='0';
z_sig_l <='0';
z_sig_o <='1';
z_sig_so<='0';
else
z_sig <='0';
z_sig_s<='0';
z_sig_l<='0';
z_sig_o<='0';
z_sig_so<='0';
end if;
if cnt=270270 then
cnt<=(others=>'0');
end if;
end if;
end process;
---------------------------------------------------------------------------------------------------------------
clk_in1 <=clk3;
process(clk3)
begin
if clk3'event and clk3='1' then
if rst='1' then
----------------------------------------------Smallest Square-------------------------------------------
x_sig_s<="010110010100"; ---1428
y_sig_s<="010110010100";
elsif z_sig_s='1' then
if (x_sig_s>=1428 and x_sig_s<=2668) and y_sig_s= 1428 then
x_sig_s<= x_sig_s+'1';
y_sig_s<="010110010100"; ---1428
elsif x_sig_s= 2669 and (y_sig_s>= 1428 and y_sig_s<=2668) then
x_sig_s<="101001101101"; ---2669
y_sig_s<=y_sig_s+'1';
elsif (x_sig_s<=2669 and x_sig_s>1428) and y_sig_s=2669 then
x_sig_s<=x_sig_s-'1';
y_sig_s<="101001101101"; --2669
elsif x_sig_s=1428 and (y_sig_s <= 2669 and y_sig_s >=1428) then
x_sig_s<="010110010100"; ---1428
y_sig_s<=y_sig_s-'1';
end if;
end if;
end if;
end process;
process(clk3)
begin
if clk3'event and clk3='1' then
if rst='1' then
x_sig_so<="010001011110"; ---1118
y_sig_so<="010001011110";
elsif z_sig_so='1' then
if (x_sig_so>=1118 and x_sig_so<=2978) and y_sig_so= 1118 then
x_sig_so<= x_sig_so+'1';
y_sig_so<="010001011110"; ---1118
elsif x_sig_so= 2979 and (y_sig_so>= 1118 and y_sig_so<=2978) then
x_sig_so<="101110100011"; ---2979
y_sig_so<=y_sig_so+'1';
elsif (x_sig_so<=2979 and x_sig_so>1118) and y_sig_so=2979 then
x_sig_so<=x_sig_so-'1';
y_sig_so<="101110100011"; --2979
elsif x_sig_so=1118 and (y_sig_so <= 2979 and y_sig_so >=1118) then
x_sig_so<="010001011110"; ---1118
y_sig_so<=y_sig_so-'1';
end if;
end if;
end if;
end process;
------------------------------------------Bigger square--------------------------------------------------
process(clk3)
begin
if clk3'event and clk3='1' then
if rst='1' then
----------------
x_sig<="001100101000"; ---808
y_sig<="001100101000";
elsif z_sig='1' then
if (x_sig>=808 and x_sig<=3288) and y_sig= 808 then
x_sig<= x_sig+'1';
y_sig<="001100101000"; --808
elsif x_sig= 3289 and (y_sig>= 808 and y_sig<=3288) then
x_sig<="110011011001"; --3289
y_sig<=y_sig+'1';
elsif (x_sig<=3289 and x_sig>808) and y_sig=3289 then
x_sig<=x_sig-'1';
y_sig<="110011011001"; --3289
elsif x_sig=808 and (y_sig <= 3289 and y_sig >=808) then
x_sig<="001100101000"; --808
y_sig<=y_sig-'1';
end if;
end if;
end if;
end process;
------------------------------------------------------------------------------------------------------------------
process(clk3)
begin
if clk3'event and clk3='1' then
if rst='1' then
x_sig_l<="001001011000"; ---600
y_sig_l<="001001011000";
elsif z_sig_l='1' then
if (x_sig_l>= 600 and x_sig_l<=3496) and y_sig_l= 600 then
x_sig_l<= x_sig_l+'1';
y_sig_l<="001001011000"; ---600
elsif x_sig_l= 3497 and (y_sig_l>= 600 and y_sig_l<=3496) then
x_sig_l<="110110101001"; ---3497
y_sig_l<=y_sig_l+'1';
elsif (x_sig_l<=3497 and x_sig_l>600) and y_sig_l=3497 then
x_sig_l<=x_sig_l-'1';
y_sig_l<="110110101001"; --3497
elsif x_sig_l=600 and (y_sig_l <= 3497 and y_sig_l >=600) then
x_sig_l<="001001011000"; ---600
y_sig_l<=y_sig_l-'1';
end if;
end if;
end if;
end process;
process(clk3)
begin
if clk3'event and clk3='1' then
if rst='1' then
x_sig_o<="000100101100"; ---300
y_sig_o<="000100101100";
elsif z_sig_o='1' then
if (x_sig_o>=300 and x_sig_o<=3796) and y_sig_o= 300 then
x_sig_o<= x_sig_o+'1';
y_sig_o<="000100101100"; ---300
elsif x_sig_o= 3797 and (y_sig_o>= 300 and y_sig_o<=3796) then
x_sig_o<="111011010101"; ---3797
y_sig_o<=y_sig_o+'1';
elsif (x_sig_o<=3797 and x_sig_o>300) and y_sig_o=3797 then
x_sig_o<=x_sig_o-'1';
y_sig_o<="111011010101"; --3797
elsif x_sig_o=300 and (y_sig_o <= 3797 and y_sig_o >=300) then
x_sig_o<="000100101100"; ---300
y_sig_o<=y_sig_o-'1';
end if;
end if;
end if;
end process;
process(clk3)
begin
if clk3'event and clk3='1' then
if (sel='0' and sel1='0' and sel2='0')then
x_dac_out <= x_sig;
y_dac_out <= y_sig;
z <= z_sig;
elsif (sel='1' and sel1='0' and sel2='0')then
x_dac_out <= x_sig_s;
y_dac_out <= y_sig_s;
z <= z_sig_s;
elsif (sel='0' and sel1='1' and sel2='0')then
x_dac_out <= x_sig_l;
y_dac_out <= y_sig_l;
z <= z_sig_l;
elsif (sel='1' and sel1='1' and sel2='0')then
x_dac_out <= x_sig_o;
y_dac_out <= y_sig_o;
z <= z_sig_o;
elsif (sel='1' and sel1='1' and sel2='1')then
x_dac_out <= x_sig_so;
y_dac_out <= y_sig_so;
z <= z_sig_so;
else
x_dac_out <= (others=>'0');
y_dac_out <= (others=>'0');
z <= '0';
end if;
end if;
end process;
---------------------------------------------------------------------------------------------------------------------------------
process(cnt)
begin
if(cnt=270270) then
sw1_sig<=not sw1_sig;
end if;
sw1<=sw1_sig;
end process;
-----------------------------------------------------------------------------------------------------------------------------------------
end Behavioral;