Commit f97b8bb6 authored by Paul Boven's avatar Paul Boven
Browse files

Including the VHDL for the 4096 samples (2048 bins) Line mode

parent acc55af3
......@@ -8,6 +8,8 @@ radio astronomy observations, such as live or recorded pulsar observations and
Design and realization by Paul Boven (p.boven@xs4all.nl).
(c) Paul Boven, released under the GPLv2.
This repository will contain the VHDL sources and helper scripts, PCB design files, and photographs.
### Specifications:
* 70 MS/s, real
* 10 bits
......
This diff is collapsed.
--------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date:
-- Design Name:
-- Module Name: LCD_Controller - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- A fist stab at controlling an LCD (44780 compatible) display via the FPGA.
-- This is written for a Digilent Spartan-3 kit, clocked at 50MHz.
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity LCD_Controller is
Port ( clk : in STD_LOGIC;
START: in STD_LOGIC;
DONE: out STD_LOGIC;
RS: in STD_LOGIC;
DATA: in STD_LOGIC_VECTOR(7 downto 0);
LCD_RS : out STD_LOGIC;
LCD_RW : out STD_LOGIC;
LCD_Data : out STD_LOGIC_VECTOR (7 downto 4);
LCD_E : out STD_LOGIC);
end;
architecture Behavioral of LCD_Controller is
type statetype is (Init, Init2, Setup, Enable, Hold);
signal state: statetype := Init;
signal counter: unsigned(12 downto 0) := (others => '0');
signal nybble: STD_LOGIC := '1';
signal low_nybble: STD_LOGIC_VECTOR(3 downto 0);
signal high_nybble: STD_LOGIC_VECTOR(3 downto 0);
begin -- Behavioral
-- A state machine to generate timing signals for an 44780 compatible LCD controller.
-- It uses a simplified timing diagram where data and RS are sampled at START and
-- sent to the LCD, then after a setup time of 60ns, Enable is activated.
-- After 240ns of enable time, it is lowered again. Although hold-time only needs to be 10ns,
-- it is stretched to 200ns so the 500ns cycle time of Enable can be met.
-- By using the same countdown counter for all states, and comparing with zero,
-- only one counter and one comparator will be instantiated, keeping this small.
process (clk) begin
if rising_edge(clk) then
if state = Init and nybble = '1' and START = '1' then
low_nybble <= DATA(3 downto 0);
high_nybble <= DATA(7 downto 4);
LCD_RS <= RS;
counter <= to_unsigned(3,counter'length); -- 60ns, setup time
state <= Setup;
elsif state = Init2 then
counter <= to_unsigned(3,counter'length); -- 60ns, setup again
state <= Setup;
elsif state = Setup then
if counter = 0 then
counter <= to_unsigned(12,counter'length); -- 240ns, enable high
state <= Enable;
else
counter <= counter - 1;
end if;
elsif state = Enable then
if counter = 0 then
counter <= to_unsigned(10,counter'length); -- 200ns, hold time
state <= Hold;
else
counter <= counter - 1;
end if;
elsif state = Hold then
if counter = 0 then
if nybble = '1' then
state <= Init2;
nybble <= '0';
else
state <= Init;
nybble <= '1';
end if;
else
counter <= counter - 1;
end if;
end if;
end if;
end process;
LCD_Data(7 downto 4) <= high_nybble when (nybble = '1') else low_nybble;
LCD_E <= '1' when (state = Enable) else '0';
DONE <= '1' when (state = Init) else '0';
LCD_RW <= '0';
end behavioral;
--------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date:
-- Design Name:
-- Module Name: LCD_Controller - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- A fist stab at controlling an LCD (44780 compatible) display via the FPGA.
-- This is written for a Digilent Spartan-3 kit, clocked at 50MHz.
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity LCD_Driver is
Generic (TN: integer := 6);
Port ( Clk : in STD_LOGIC;
-- LED: out STD_LOGIC;
-- BT0: in STD_LOGIC;
-- BT1: in STD_LOGIC;
LCD_RS : out STD_LOGIC;
LCD_RW : out STD_LOGIC;
LCD_Data : out STD_LOGIC_VECTOR (7 downto 4);
clk_1hz: in STD_LOGIC;
LCD_E : out STD_LOGIC);
end LCD_Driver;
-- A simple debouncer: press and release BT0 to arm the circuit,
-- Then press BT1 to send a single START pulse to the LCD controller.
-- Release both buttons before arming the circuit again.
-- Led zero shows when the circuit is armed.
architecture Behavioral of LCD_Driver is
type debouncetype is (Ready, Armed, Active, Disarmed);
signal debounce: debouncetype := Disarmed;
signal done: STD_LOGIC;
signal start: STD_LOGIC;
signal textcounter: unsigned(TN-1 downto 0) := (others => '0');
type text_type is array(0 to 2**TN-1) of STD_LOGIC_VECTOR(8 downto 0);
constant text_block: text_type := (
"0" & "00101000", -- Initialize
"0" & "00101000", -- Initialize
"0" & "00101000", -- Initialize: 4 bit, 2 line, 5*7
"0" & "00001100", -- Display on, cursor off, blink off
"0" & "00000001", -- Clear display
"0" & "01001000", -- CGram first character: create a "\"
"1" & "00000000", -- A cgram entry
"1" & "00010000", -- A cgram entry
"1" & "00001000", -- A cgram entry
"1" & "00000100", -- A cgram entry
"1" & "00000010", -- A cgram entry
"1" & "00000001", -- A cgram entry
"1" & "00000000", -- A cgram entry
"1" & "00000000", -- A cgram entry
"0" & "10000000", -- Home cursors, DDram 15
"1" & std_logic_vector(to_unsigned(character'pos('L'),8)), -- 16
"1" & std_logic_vector(to_unsigned(character'pos('i'),8)), -- 17
"1" & std_logic_vector(to_unsigned(character'pos('n'),8)), -- 18
"1" & std_logic_vector(to_unsigned(character'pos('e'),8)), -- 19
"1" & std_logic_vector(to_unsigned(character'pos(' '),8)), -- 20
"1" & std_logic_vector(to_unsigned(character'pos('M'),8)), -- 21
"1" & std_logic_vector(to_unsigned(character'pos('o'),8)), -- 22
"1" & std_logic_vector(to_unsigned(character'pos('d'),8)), -- 23
"1" & std_logic_vector(to_unsigned(character'pos('e'),8)), -- 24
"1" & std_logic_vector(to_unsigned(character'pos(' '),8)), -- 25
"1" & std_logic_vector(to_unsigned(character'pos(' '),8)), -- 26
"1" & x"20", -- (space) -- 27
"1" & std_logic_vector(to_unsigned(character'pos('v'),8)), -- 28
"1" & std_logic_vector(to_unsigned(character'pos('0'),8)), -- 29
"1" & std_logic_vector(to_unsigned(character'pos('.'),8)), -- 30
"1" & std_logic_vector(to_unsigned(character'pos('2'),8)), -- 31
"0" & "11000000", -- Newline
"1" & std_logic_vector(to_unsigned(character'pos('4'),8)), -- 33
"1" & std_logic_vector(to_unsigned(character'pos('k'),8)), -- 34
"1" & std_logic_vector(to_unsigned(character'pos(' '),8)), -- 35
"1" & std_logic_vector(to_unsigned(character'pos('b'),8)), -- 36
"1" & std_logic_vector(to_unsigned(character'pos('i'),8)), -- 37
"1" & std_logic_vector(to_unsigned(character'pos('n'),8)), -- 38
"1" & std_logic_vector(to_unsigned(character'pos('s'),8)), -- 39
"1" & x"20", -- (space) -- 40
"1" & std_logic_vector(to_unsigned(character'pos('1'),8)), -- 41
"1" & std_logic_vector(to_unsigned(character'pos('4'),8)), -- 42
"1" & std_logic_vector(to_unsigned(character'pos('0'),8)), -- 43
"1" & std_logic_vector(to_unsigned(character'pos('M'),8)), -- 44
"1" & std_logic_vector(to_unsigned(character'pos('H'),8)), -- 45
"1" & std_logic_vector(to_unsigned(character'pos('z'),8)), -- 46
"0" & "11001111", -- Last display pos
"1" & x"23"); -- #
signal text_block_buffer: STD_LOGIC_VECTOR(8 downto 0);
signal data: STD_LOGIC_VECTOR(7 downto 0);
signal rs: STD_LOGIC;
signal delay: unsigned(24 downto 0) := (others => '1');
signal spinner: unsigned(1 downto 0) := (others => '0');
signal clk_1hz_prev: std_logic := '0';
component LCD_Controller
Port ( clk : std_logic;
START: in STD_LOGIC;
DONE: out STD_LOGIC;
RS: in STD_LOGIC;
DATA: in STD_LOGIC_VECTOR(7 downto 0);
LCD_RS : out STD_LOGIC;
LCD_RW : out STD_LOGIC;
LCD_Data : out STD_LOGIC_VECTOR (7 downto 4);
LCD_E : out STD_LOGIC);
end component;
begin -- Behavioral
LCD_Controller_1: LCD_controller
port map( clk => clk,
DONE => DONE,
START => START,
DATA => DATA,
RS => RS,
LCD_DATA => LCD_DATA,
LCD_RW => LCD_RW,
LCD_E => LCD_E,
LCD_RS => LCD_RS);
data <= text_block_buffer(7 downto 0);
rs <= text_block_buffer(8);
process (clk) begin
if rising_edge(clk) then
if clk_1hz = not clk_1hz_prev then
spinner <= spinner + 1;
end if;
clk_1hz_prev <= clk_1hz;
if debounce = Ready and DONE = '1' then
debounce <= Active;
elsif debounce = Active then
debounce <= Disarmed;
elsif debounce = Disarmed then
if delay > 0 then
delay <= delay - 1;
else
delay <= to_unsigned(386265,delay'length); -- 15ms
debounce <= Ready;
if textcounter = 47 then
textcounter <= to_unsigned(46,textcounter'length);
case spinner is
when "00" => text_block_buffer <=
"1" & std_logic_vector(to_unsigned(character'pos('-'),8)); -- 48
when "01" => text_block_buffer <=
"1" & "00000001"; -- Special character, "\" from cgram
when "10" => text_block_buffer <=
"1" & std_logic_vector(to_unsigned(character'pos('|'),8)); -- 52
when others => text_block_buffer <=
"1" & std_logic_vector(to_unsigned(character'pos('/'),8)); -- 54
end case;
else
textcounter <= textcounter + 1;
text_block_buffer <= text_block(to_integer(textcounter));
end if;
end if;
end if;
end if;
end process;
START <= '1' when (debounce = Active) else '0';
end Behavioral;
# A Makefile to drive the Xilinx tools.
# This project reads 70MS/s data from a 10bit A/D, then applies a window
# and runs it trough a (coregen) FFT before sending the data out of
# the Ethernet port.
all: main.twr main.bit
# XST
main.ngc: main.xst main.prj main.vhd FFT_stream.vhd eth_tx.vhd PCK_CRC32_D4.vhd LCD_Driver.vhd LCD_Controller.vhd
xst -ifn main.xst -ofn main.syr
# Ngdbuild
main.ngd: main.ngc main.ucf
ngdbuild -dd _nog -nt timestamp -p xc3sd1800a-fg676-4 -uc main.ucf main.ngc main.ngd
# Map
main.pcf: main.ngd
map -p xc3sd1800a-fg676-4 -cm area -ir off -pr off -c 100 -o main_map.ncd main.ngd main.pcf
# PAR
main.ncd: main.pcf
par -w -ol std -t 1 main_map.ncd main.ncd main.pcf
# Timing Report
main.twr: main.ucf main.ncd
trce -v 3 -s 4 main.ncd -o main.twr main.pcf -ucf main.ucf
# Bitgen
main.bit: main.ut main.ncd
bitgen -f main.ut main.ncd
-----------------------------------------------------------------------
-- File: PCK_CRC32_D4.vhd
-- Date: Sun Aug 10 10:57:22 2008
--
-- Copyright (C) 1999-2003 Easics NV.
-- This source file may be used and distributed without restriction
-- provided that this copyright statement is not removed from the file
-- and that any derivative work contains the original copyright notice
-- and the associated disclaimer.
--
-- THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
-- OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
--
-- Purpose: VHDL package containing a synthesizable CRC function
-- * polynomial: (0 1 2 4 5 7 8 10 11 12 16 22 23 26 32)
-- * data width: 4
--
-- Info: tools@easics.be
-- http://www.easics.com
-----------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
package PCK_CRC32_D4 is
-- polynomial: (0 1 2 4 5 7 8 10 11 12 16 22 23 26 32)
-- data width: 4
-- convention: the first serial data bit is D(0)
-- WARNING: This is different from the default EASICS spec!!!
function nextCRC32_D4
( Data: std_logic_vector(3 downto 0);
CRC: std_logic_vector(31 downto 0) )
return std_logic_vector;
end PCK_CRC32_D4;
library IEEE;
use IEEE.std_logic_1164.all;
package body PCK_CRC32_D4 is
-- polynomial: (0 1 2 4 5 7 8 10 11 12 16 22 23 26 32)
-- data width: 4
-- convention: the first serial data bit is D(0)
-- WARNING: This is different from the default EASICS spec!!!
function nextCRC32_D4
( Data: std_logic_vector(3 downto 0);
CRC: std_logic_vector(31 downto 0) )
return std_logic_vector is
variable D: std_logic_vector(3 downto 0);
variable C: std_logic_vector(31 downto 0);
variable NewCRC: std_logic_vector(31 downto 0);
begin
D := Data;
C := CRC;
NewCRC(0) := D(3) xor C(28);
NewCRC(1) := D(2) xor D(3) xor C(28) xor C(29);
NewCRC(2) := D(1) xor D(2) xor D(3) xor C(28) xor C(29) xor C(30);
NewCRC(3) := D(0) xor D(1) xor D(2) xor C(29) xor C(30) xor C(31);
NewCRC(4) := D(0) xor D(1) xor D(3) xor C(0) xor C(28) xor C(30) xor
C(31);
NewCRC(5) := D(0) xor D(2) xor D(3) xor C(1) xor C(28) xor C(29) xor
C(31);
NewCRC(6) := D(1) xor D(2) xor C(2) xor C(29) xor C(30);
NewCRC(7) := D(0) xor D(1) xor D(3) xor C(3) xor C(28) xor C(30) xor
C(31);
NewCRC(8) := D(0) xor D(2) xor D(3) xor C(4) xor C(28) xor C(29) xor
C(31);
NewCRC(9) := D(1) xor D(2) xor C(5) xor C(29) xor C(30);
NewCRC(10) := D(0) xor D(1) xor D(3) xor C(6) xor C(28) xor C(30) xor
C(31);
NewCRC(11) := D(0) xor D(2) xor D(3) xor C(7) xor C(28) xor C(29) xor
C(31);
NewCRC(12) := D(1) xor D(2) xor D(3) xor C(8) xor C(28) xor C(29) xor
C(30);
NewCRC(13) := D(0) xor D(1) xor D(2) xor C(9) xor C(29) xor C(30) xor
C(31);
NewCRC(14) := D(0) xor D(1) xor C(10) xor C(30) xor C(31);
NewCRC(15) := D(0) xor C(11) xor C(31);
NewCRC(16) := D(3) xor C(12) xor C(28);
NewCRC(17) := D(2) xor C(13) xor C(29);
NewCRC(18) := D(1) xor C(14) xor C(30);
NewCRC(19) := D(0) xor C(15) xor C(31);
NewCRC(20) := C(16);
NewCRC(21) := C(17);
NewCRC(22) := D(3) xor C(18) xor C(28);
NewCRC(23) := D(2) xor D(3) xor C(19) xor C(28) xor C(29);
NewCRC(24) := D(1) xor D(2) xor C(20) xor C(29) xor C(30);
NewCRC(25) := D(0) xor D(1) xor C(21) xor C(30) xor C(31);
NewCRC(26) := D(0) xor D(3) xor C(22) xor C(28) xor C(31);
NewCRC(27) := D(2) xor C(23) xor C(29);
NewCRC(28) := D(1) xor C(24) xor C(30);
NewCRC(29) := D(0) xor C(25) xor C(31);
NewCRC(30) := C(26);
NewCRC(31) := C(27);
return NewCRC;
end nextCRC32_D4;
end PCK_CRC32_D4;
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 00:38:07 08/10/2008
-- Design Name:
-- Module Name: eth_tx - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use PCK_CRC32_D4.all;
entity eth_tx is
Port ( clk : in STD_LOGIC;
tx_d : out STD_LOGIC_VECTOR (3 downto 0);
tx_en : out STD_LOGIC;
tx_payload: in STD_LOGIC_VECTOR(3 downto 0);
tx_payload_ctr: out STD_LOGIC_VECTOR(13 downto 0);
tx_start: in std_logic);
end eth_tx;
architecture Behavioral of eth_tx is
constant eth_data_len: integer := 16384; -- Number of nibbles
type eth_preamble_type is array(0 to 15) of std_logic_vector(3 downto 0);
constant eth_preamble: eth_preamble_type := (
-- Preamble + SFD
x"5",x"5", x"5",x"5", x"5",x"5", x"5",x"5", x"5",x"5", x"5",x"5", x"5",x"5", x"D",x"5");
-- Header (Ether (14), IP (20) , UDP (8) -> 42)
type eth_header_type is array(0 to 83) of std_logic_vector(3 downto 0);
constant eth_header: eth_header_type := (
-- Destination Ether: 00:04:23:ac:df:87
x"0",x"0", x"0",x"4", x"2",x"3", x"a",x"c", x"d",x"f", x"8",x"7",
-- Source Ether: 08:00:20:C0:FF:EE
x"0",x"8", x"0",x"0", x"2",x"0", x"C",x"0", x"F",x"F", x"E",x"E",
-- Ether type
x"0",x"8", x"0",x"0",
-- IP header
x"4",x"5", x"0",x"0", x"2",x"0", x"1",x"C", x"0",x"0", x"0",x"0",
x"0",x"0", x"0",x"0", x"4",x"0", x"1",x"1", x"4",x"2", x"C",x"9",
-- Source IP (10.1.2.4), Dest IP (10.1.2.3)
x"0",x"A", x"0",x"1", x"0",x"2", x"0",x"4", x"0",x"A", x"0",x"1", x"0",x"2", x"0",x"3",
-- UDP header
x"2",x"3", x"2",x"3", x"5",x"6", x"5",x"6", x"2",x"0", x"0",x"8", x"0",x"0", x"0",x"0");
constant eth_header_len: integer := 84; -- Number of nibbles
signal crc_calc: std_logic_vector(31 downto 0);
constant tx_tail: integer := 200;
type tx_state_type is (preamble, header, data, crc, tail, idle);
signal tx_state: tx_state_type := idle;
signal tx_cnt: unsigned (13 downto 0) := (others => '0');
signal tx_start1: std_logic := '0';
signal tx_start2: std_logic := '0';
begin
tx_payload_ctr <= std_logic_vector(tx_cnt);
process(clk)
variable txd: std_logic_vector(3 downto 0);
begin
if clk'event and clk='1' then
tx_start1 <= tx_start;
tx_start2 <= tx_start1;
case tx_state is
when preamble =>
tx_en <= '1';
tx_d <= eth_preamble(to_integer(tx_cnt(7 downto 1) & not tx_cnt(0)));
if tx_cnt < 15 then
tx_cnt <= tx_cnt + 1;
else
tx_cnt <= (others => '0');
tx_state <= header;
crc_calc <= (others => '1'); -- Preset the CRC with all '1'
end if;
when header =>
tx_en <= '1';
txd := eth_header(to_integer(tx_cnt(7 downto 1) & not tx_cnt(0)));
tx_d <= txd;
crc_calc <= nextCRC32_D4(txd, crc_calc);
if tx_cnt < eth_header_len - 1 then
tx_cnt <= tx_cnt + 1;
else
tx_cnt <= (others => '0');
tx_state <= data;
end if;
when data =>
tx_en <= '1';
-- txd := eth_data(to_integer(tx_cnt(7 downto 1) & not tx_cnt(0)));
txd := tx_payload;
tx_d <= txd;
crc_calc <= nextCRC32_D4(txd, crc_calc);
if tx_cnt < eth_data_len - 1 then
tx_cnt <= tx_cnt + 1;
else
tx_cnt <= (others => '0');
tx_state <= crc;
end if;
when crc =>
tx_en <= '1';
tx_cnt <= tx_cnt + 1;
case tx_cnt is
when "00000000000000" =>
txd := crc_calc(31 downto 28);
when "00000000000001" =>
txd := crc_calc(27 downto 24);
when "00000000000010" =>
txd := crc_calc(23 downto 20);
when "00000000000011" =>
txd := crc_calc(19 downto 16);
when "00000000000100" =>
txd := crc_calc(15 downto 12);
when "00000000000101" =>
txd := crc_calc(11 downto 8);
when "00000000000110" =>
txd := crc_calc(7 downto 4);
when others =>
txd := crc_calc(3 downto 0);
tx_cnt <= (others => '0');
tx_state <= tail;
end case;
-- Invert the CRC before transmitting
-- Bitswap so bit C(32) is the first to be transmitted
tx_d(0) <= not txd(3);
tx_d(1) <= not txd(2);
tx_d(2) <= not txd(1);
tx_d(3) <= not txd(0);
when tail =>
tx_en <= '0';
tx_d <= "0000";
if tx_cnt < tx_tail - 1 then
tx_cnt <= tx_cnt + 1;
else
tx_cnt <= (others => '0');
tx_state <= idle;
end if;
when idle =>
tx_en <= '0';
tx_d <= "0000";
if tx_start2 = '1' then
tx_state <= preamble;
end if;
end case;
end if;
end process;
end Behavioral;
vhdl work "PCK_CRC32_D4.vhd"
vhdl work "LCD_Controller.vhd"
vhdl work "LCD_Driver.vhd"
vhdl work "window.vhd"
vhdl work "FFT_stream.vhd"
vhdl work "eth_tx.vhd"
vhdl work "main.vhd"
NET "eth_rst" LOC = G4;
NET "eth*" IOSTANDARD = "LVCMOS18";