Difference between revisions of "FPGA - Rotary Encoder"

From Steak Wiki
Jump to navigationJump to search
(Created page with "Reap what you sow. Here's some public domain code for a Spartan 3E, to interface with multiple rotary encoders. It's currently tested up to 8. It uses Block RAM to keep track...")
 
Line 2: Line 2:
  
 
I have different versions of this. I've had some issues with UART timing on a Spartan 3E 500, whereas the Papilio's 250 did not have such issues. I'll start with the one that's compatible with the Papilio board (including the pinout / constraints.ucf file).
 
I have different versions of this. I've had some issues with UART timing on a Spartan 3E 500, whereas the Papilio's 250 did not have such issues. I'll start with the one that's compatible with the Papilio board (including the pinout / constraints.ucf file).
 +
 +
There is Rotary_Top.vhd, which is the main code, then there are instances of rotaries.
 +
 +
 +
==Rotary_Top.vhd==
 +
<pre>
 +
library IEEE;
 +
use IEEE.STD_LOGIC_1164.ALL;
 +
use IEEE.STD_LOGIC_UNSIGNED.ALL;
 +
use IEEE.NUMERIC_STD.ALL;
 +
 +
-- TODO
 +
 +
--DONE test reading one address in RAM. make sure it is right.
 +
--DONE make sure output on UART is correct. Also bits are
 +
--DONE  in right order too. DONE.
 +
 +
--DONE (used counter, not loop) setup a read on 0-99 addresses of RAM . use loop.
 +
 +
--DONE have it output each memory address in uart 3 or 4 times before
 +
--going to the next.
 +
 +
--DONE EASY have it loop through the ram 24/7 EASY
 +
 +
--DONE: set default values of ram to be letters abcabcabcabc
 +
 +
 +
 +
--RAM
 +
-- idea
 +
-- have top level manage all ram and output
 +
-- have output only if cw or ccw
 +
-- if outputs, have that rotaryID(or memory address)
 +
-- be the chosen one to write to.
 +
 +
 +
--UART
 +
-- possible solution #1
 +
-- if a memory address is updated
 +
-- then output uart of new memory address only
 +
-- every rotary change, causes
 +
-- new ram write/ read, and uart output
 +
-- on as needed basis
 +
-- PROBLEMS: having trouble getting just one uart byte out
 +
-- noisy, and timing is off possibly (check timing)
 +
 +
 +
-- possible solution #2
 +
-- loop through all memory constantly
 +
-- output all values constantly
 +
-- any changes will be reflected in micro
 +
-- hopefully fast enough? (should be)(57600 is p fast)
 +
-- any rotaries that update will write to ram
 +
-- problems: if 100 rotaries updating at once,
 +
-- could not be fast enough? maybe? maybe not. maybe it
 +
-- is fast enough to read io, write ram.
 +
-- write RAM would be separate from read ram / UART here
 +
-- but need to adjust write enable flag as needed... maybe
 +
-- two port RAM is better? constantly write on port A
 +
-- constantly read from port b. no need to adjust write enable
 +
-- flag...
 +
-- Yes, you can use dual port RAM. one port always wea high
 +
-- other port always wea low. and they should only interfere
 +
-- if read is during a write. however,
 +
-- depending how fast I read the data, I may be able to get
 +
-- around htis. i could also average the values (say last 3
 +
-- values) from the serial for a given byte, and call that
 +
-- the true value. this way avoid any memory errors.
 +
 +
 +
 +
-- TODO
 +
 +
-- Need to writeup basic documentation and clean these at the
 +
-- very end.
 +
 +
-- look up what a memory latch is
 +
 +
 +
 +
-- output serial as BCD or ascii table bits
 +
-- i.e. instead of using straight hex (one byte each) for
 +
-- a number, convert it to its ascii equivalent (not as fast)
 +
-- (takes more bytes)
 +
 +
-- EDIT: just outputting raw 8 bits
 +
 +
entity rotary_top is
 +
--must map all 100 rotaries here
 +
  GENERIC(
 +
            RAMADDR : STD_LOGIC_VECTOR(7 downto 0) := x"FF";
 +
                  ROTARYID  : integer := 1
 +
            );
 +
  PORT( ROT          : in  STD_LOGIC_VECTOR(1 downto 0); -- semi colons
 +
        ROT2          : in  STD_LOGIC_VECTOR(1 downto 0); -- here
 +
                  ROT3          : in  STD_LOGIC_VECTOR(1 downto 0);
 +
                  ROT4          : in  STD_LOGIC_VECTOR(1 downto 0);
 +
                  ROT5          : in  STD_LOGIC_VECTOR(1 downto 0);
 +
                  ROT6          : in  STD_LOGIC_VECTOR(1 downto 0);
 +
                  ROT7          : in  STD_LOGIC_VECTOR(1 downto 0);
 +
                  ROT8          : in  STD_LOGIC_VECTOR(1 downto 0);
 +
        LED          : out  STD_LOGIC_VECTOR(7 downto 0); -- commas in
 +
                  --LEDWATCH      : out STD_LOGIC_VECTOR(7 downto 0); --instance
 +
                  clk          : in STD_LOGIC;
 +
                  --DATAOUTUART  : out STD_LOGIC;
 +
                  TX                            : out STD_LOGIC_VECTOR(0 downto 0)
 +
                  --RX                          : STD_LOGIC
 +
 +
                  );
 +
 +
end rotary_top;
 +
 +
        architecture Behavioral of rotary_top is
 +
        COMPONENT rotary
 +
  GENERIC(
 +
                RAMADDR : STD_LOGIC_VECTOR(7 downto 0) := x"FF";
 +
                ROTARYID  : STD_LOGIC_VECTOR(7 downto 0) := x"00"
 +
                );
 +
        PORT(
 +
                ROT : IN std_logic_vector(1 downto 0);
 +
                clk : IN std_logic;
 +
                LED : OUT std_logic_vector(3 downto 0);
 +
                -- LEDWATCH : OUT std_logic_vector(7 downto 0);
 +
                DATAOUT  : OUT STD_LOGIC_VECTOR(15 downto 0)
 +
                );
 +
        END COMPONENT;
 +
      COMPONENT DUALRAM
 +
  PORT (
 +
    clka : IN STD_LOGIC;
 +
    ena : IN STD_LOGIC;
 +
    wea : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
 +
    addra : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
 +
    dina : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
 +
    douta : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
 +
 +
    clkb : IN STD_LOGIC;
 +
    enb : IN STD_LOGIC;
 +
    web : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
 +
    addrb : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
 +
    dinb : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
 +
    doutb : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
 +
  );
 +
END COMPONENT;
 +
 +
 +
 +
        signal  resultsigtest    : STD_LOGIC_VECTOR(7 downto 0) ;
 +
        signal  RAMADDR_CURRENT  : STD_LOGIC_VECTOR(7 downto 0) := "00000000";
 +
        -- RAMADDR_0 is start byte (zz (LOWER CASE)) for pic to know when array starts
 +
        constant RAMADDR_1        : STD_LOGIC_VECTOR(7 downto 0) := "00000001";
 +
        constant ROTARYID_1      : STD_LOGIC_VECTOR(7 downto 0) := "00000001";
 +
        constant RAMADDR_2        : STD_LOGIC_VECTOR(7 downto 0) := "00000010";
 +
        constant ROTARYID_2      : STD_LOGIC_VECTOR(7 downto 0) := "00000010";
 +
        --signal  RAMADDR_CURRENT2 : STD_LOGIC_VECTOR(7 downto 0) := "00001000";
 +
        constant RAMADDR_3        : STD_LOGIC_VECTOR(7 downto 0) := "00000011";
 +
        constant ROTARYID_3      : STD_LOGIC_VECTOR(7 downto 0) := "00000011";
 +
 +
        constant RAMADDR_4        : STD_LOGIC_VECTOR(7 downto 0) := "00000100";
 +
        constant ROTARYID_4      : STD_LOGIC_VECTOR(7 downto 0) := "00000100";
 +
 +
        constant RAMADDR_5        : STD_LOGIC_VECTOR(7 downto 0) := "00000101";
 +
        constant ROTARYID_5      : STD_LOGIC_VECTOR(7 downto 0) := "00000101";
 +
 +
        constant RAMADDR_6        : STD_LOGIC_VECTOR(7 downto 0) := "00000110";
 +
        constant ROTARYID_6      : STD_LOGIC_VECTOR(7 downto 0) := "00000110";
 +
 +
        constant RAMADDR_7        : STD_LOGIC_VECTOR(7 downto 0) := "00000111";
 +
        constant ROTARYID_7      : STD_LOGIC_VECTOR(7 downto 0) := "00000111";
 +
 +
        constant RAMADDR_8        : STD_LOGIC_VECTOR(7 downto 0) := "00001000";
 +
        constant ROTARYID_8      : STD_LOGIC_VECTOR(7 downto 0) := "00001000";
 +
    -- these must be here or error. must translate output to
 +
        -- sig, then to output. can't directly go
 +
        -- from output to output
 +
 +
        signal ROT1OUT                  : STD_LOGIC_VECTOR(15 downto 0);
 +
        signal ROT2OUT                  : STD_LOGIC_VECTOR(15 downto 0);
 +
        --must be set to zero (or unequal to rot1out) at start
 +
        signal ROT1PREV        : STD_LOGIC_VECTOR(15 downto 0) := (others => '0');
 +
 +
        type t_ROTOUT is array (1 to 100) of std_logic_vector(15 downto 0);
 +
        signal r_ROTO : t_ROTOUT := (others => (others => '0'));
 +
 +
 +
 +
        signal wea                        : STD_LOGIC_VECTOR(0 DOWNTO 0)  := "0";
 +
        signal addra              : STD_LOGIC_VECTOR(7 DOWNTO 0)  := (others => '0');
 +
        signal dina                      : STD_LOGIC_VECTOR(15 DOWNTO 0) := (others => '0');
 +
        signal douta              : STD_LOGIC_VECTOR(15 DOWNTO 0) := (others => '0');
 +
        signal ena                        : STD_LOGIC                    := '0';
 +
        signal DINAPROXY          : STD_LOGIC_VECTOR(15 DOWNTO 0) := (others => '0');
 +
 +
        signal web                        : STD_LOGIC_VECTOR(0 DOWNTO 0)  := "0";
 +
        signal addrb              : STD_LOGIC_VECTOR(7 DOWNTO 0)  := (others => '0');
 +
        signal dinb                  : STD_LOGIC_VECTOR(15 DOWNTO 0) := (others => '0');
 +
        signal doutb              : STD_LOGIC_VECTOR(15 DOWNTO 0) := (others => '0');
 +
        signal enb                        : STD_LOGIC                    := '0';
 +
        signal ADDRAPROXY  : STD_LOGIC_VECTOR(7 DOWNTO 0)  := "00000001";
 +
        signal ADDRBPROXY  : STD_LOGIC_VECTOR(7 DOWNTO 0)  := (others => '0');
 +
        signal ADDR_RD_COUNTER  : STD_LOGIC_VECTOR(7 DOWNTO 0)  := (others => '0');
 +
 +
        signal WRITE_COUNTER1  : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
 +
        signal WRITE_COUNTER2 : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
 +
 +
        signal COUNTER        : STD_LOGIC_VECTOR(29 downto 0) := (others => '0');
 +
        signal READOUT      : STD_LOGIC_VECTOR(15 downto 0) := (others => '0'); --"1111111010110100"; --default data to test uart
 +
        signal BUSY          : STD_LOGIC                    := '0';
 +
        signal UART_COUNTER  : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
 +
        signal UART_COUNTER2 : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
 +
        signal UART_COUNTER3 : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
 +
        signal RAM_COUNTER  : STD_LOGIC_VECTOR(29 downto 0) := (others => '0');
 +
        --signal UART_COUNTER_SPACER : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
 +
        --signal UART_COUNTER4 : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
 +
  --signal UART_OFFON    : STD_LOGIC                    := '0';
 +
 +
---variable ROT_INCREASE : integer range 0 to 255 := 1;
 +
        signal ROT_INCREASE : STD_LOGIC_VECTOR(7 downto 0) := x"01";
 +
 +
        --signal UARTOUT    : STD_LOGIC_VECTOR(15 downto        0) := "1111111010110100"; --default data to test uart without reading rotary
 +
        --signal UARTOUT    : STD_LOGIC_VECTOR(29 downto 0) := "111110101101001111111010110100"; --Y then Z -- WORKS
 +
        signal UARTOUT      : STD_LOGIC_VECTOR(199 downto 0) := (others => '1');
 +
 +
        --debugging uart
 +
        --signal UARTOUT    : STD_LOGIC_VECTOR(29 downto 0) := "101010101010101010101010101010";
 +
 +
 +
 +
 +
-- must map all 100 instances of rotary module here
 +
--TODO
 +
-- input a value for rotary (i.e. rotary1= 1, as 8 bit value)
 +
-- output that value somewhere else, and put it into uart
 +
-- output the value for rotary plus or minus into
 +
-- a specific 8 bit register. output into uart when called.
 +
-- After uart reads, erase these banks.
 +
 +
-- OR, need to find how to write to RAM. Then I need to
 +
-- programatically write the rotary to a specific ram register
 +
-- then read the registers
 +
begin
 +
 +
Inst_DUALRAM: DUALRAM
 +
  PORT MAP (
 +
    clka => clk,
 +
    ena => ena,
 +
    wea => wea,
 +
    addra => addra,
 +
    dina => dina,
 +
    douta => douta,
 +
  clkb => clk,
 +
    enb => enb,
 +
    web => web,
 +
    addrb => addrb,
 +
    dinb => dinb,
 +
    doutb => doutb
 +
  );
 +
 +
 +
Inst_ROTARY_1: rotary
 +
        GENERIC MAP(
 +
        RAMADDR => RAMADDR_1,
 +
        ROTARYID  => ROTARYID_1
 +
        )
 +
        PORT MAP(
 +
                ROT => ROT,
 +
                LED => open,
 +
                clk => clk,
 +
                DATAOUT => r_ROTO(1)
 +
                );
 +
 +
Inst_ROTARY_2: rotary
 +
        GENERIC MAP(
 +
        RAMADDR => RAMADDR_2,
 +
        ROTARYID  => ROTARYID_2
 +
        )
 +
        PORT MAP(
 +
                ROT => ROT2,
 +
                LED => open,
 +
                clk => clk,
 +
                DATAOUT => r_ROTO(2)
 +
        );
 +
 +
Inst_ROTARY_3: rotary
 +
        GENERIC MAP(
 +
        RAMADDR => RAMADDR_3,
 +
        ROTARYID  => ROTARYID_3
 +
        )
 +
        PORT MAP(
 +
                ROT => ROT3,
 +
                LED => open,
 +
                clk => clk,
 +
                DATAOUT => r_ROTO(3)
 +
        );
 +
 +
Inst_ROTARY_4: rotary
 +
        GENERIC MAP(
 +
        RAMADDR => RAMADDR_4,
 +
        ROTARYID  => ROTARYID_4
 +
        )
 +
        PORT MAP(
 +
                ROT => ROT4,
 +
                LED => open,
 +
                clk => clk,
 +
                DATAOUT => r_ROTO(4)
 +
        );
 +
 +
Inst_ROTARY_5: rotary
 +
        GENERIC MAP(
 +
        RAMADDR => RAMADDR_5,
 +
        ROTARYID  => ROTARYID_5
 +
        )
 +
        PORT MAP(
 +
                ROT => ROT5,
 +
                LED => open,
 +
                clk => clk,
 +
                DATAOUT => r_ROTO(5)
 +
        );
 +
Inst_ROTARY_6: rotary
 +
        GENERIC MAP(
 +
        RAMADDR => RAMADDR_6,
 +
        ROTARYID  => ROTARYID_6
 +
        )
 +
        PORT MAP(
 +
                ROT => ROT6,
 +
                LED => open,
 +
                clk => clk,
 +
                DATAOUT => r_ROTO(6)
 +
        );
 +
 +
Inst_ROTARY_7: rotary
 +
        GENERIC MAP(
 +
        RAMADDR => RAMADDR_7,
 +
        ROTARYID  => ROTARYID_7
 +
        )
 +
        PORT MAP(
 +
                ROT => ROT7,
 +
                LED => open,
 +
                clk => clk,
 +
                DATAOUT => r_ROTO(7)
 +
        );
 +
 +
Inst_ROTARY_8: rotary
 +
        GENERIC MAP(
 +
        RAMADDR => RAMADDR_8,
 +
        ROTARYID  => ROTARYID_8
 +
        )
 +
        PORT MAP(
 +
                ROT => ROT8,
 +
                LED => open,
 +
                clk => clk,
 +
                DATAOUT => r_ROTO(8)
 +
        );
 +
-- LEDWATCH <=READOUT(7 downto 0);  --works
 +
-- this means i'm passing rotary values succesfully through
 +
-- to ROT1OUT and the rotary ID as well.
 +
 +
--LEDWATCH <= READOUT(7 downto 0);
 +
 +
--put everything in a process because why not.
 +
 +
 +
--try this out of the clock for starters...
 +
--RAMWRITE: process(r_ROTO(1))
 +
----variable ROT_INCREASE : integer range 0 to 255 := 1;
 +
--begin
 +
--
 +
--                                      DINAPROXY  <= ROT1OUT;
 +
--                                      ADDRAPROXY <= RAMADDR_1;
 +
--
 +
----            --if rising_edge(clk) then      this breaks things
 +
----                                    ROT_INCREASE <= x"01";
 +
----                                    --RAMADDR_CURRENT <= std_logic_vector(to_unsigned(ROT_INCREASE, RAMADDR_CURRENT'length));
 +
----                                    RAMADDR_CURRENT <= ROT_INCREASE;
 +
----                                    --write to ram
 +
----                                    dina  <= r_ROTO(to_integer(unsigned(ROT_INCREASE)));
 +
----                                    ADDRAPROXY <= RAMADDR_CURRENT;
 +
----                                    --ROT_INCREASE := ROT_INCREASE + 1;
 +
----            --end if;
 +
--
 +
--
 +
----                    ROT_INCREASE <= x"00";
 +
----                            if ROT_INCREASE = x"00" then
 +
----                                    ROT_INCREASE <= x"01";
 +
----                                    RAMADDR_CURRENT <= ROT_INCREASE;
 +
----                                    dina  <= r_ROTO(to_integer(unsigned(ROT_INCREASE)));
 +
----                                    ADDRAPROXY <= RAMADDR_CURRENT;
 +
----                            elsif ROT_INCREASE = x"01" then
 +
----                                    ROT_INCREASE <= x"02";
 +
----                                    RAMADDR_CURRENT <= ROT_INCREASE;
 +
----                                    dina  <= r_ROTO(to_integer(unsigned(ROT_INCREASE)));
 +
----                                    ADDRAPROXY <= RAMADDR_CURRENT;
 +
----                            elsif ROT_INCREASE = x"02" then
 +
----                                    ROT_INCREASE <= x"00";
 +
----                            end if;
 +
----
 +
----                    ROT_INCREASE <= x"00";
 +
----                            if ROT_INCREASE = x"00" then
 +
----                                    ROT_INCREASE <= x"01";
 +
----                                    RAMADDR_CURRENT <= RAMADDR_1;
 +
----                                    dina  <= r_ROTO(1);
 +
----                                    ADDRAPROXY <= RAMADDR_CURRENT;
 +
------                          elsif ROT_INCREASE = x"01" then
 +
------                                  ROT_INCREASE <= x"02";
 +
------                                  RAMADDR_CURRENT <= RAMADDR_2;
 +
------                                  dina  <= r_ROTO(2);
 +
------                                  ADDRAPROXY <= RAMADDR_CURRENT;
 +
----                            elsif ROT_INCREASE = x"01" then
 +
----                                    ROT_INCREASE <= x"00";
 +
----                            end if;
 +
----
 +
--
 +
--                              --ROT_INCREASE := ROT_INCREASE + 1;
 +
--
 +
----                            for x in 1 to 50 loop
 +
----                                    ROT_INCREASE := 2;
 +
----                                    RAMADDR_CURRENT <= std_logic_vector(to_unsigned(ROT_INCREASE, RAMADDR_CURRENT'length));
 +
----                                    --write to ram
 +
----                                    dina  <= r_ROTO(ROT_INCREASE);
 +
----                                    ADDRAPROXY <= RAMADDR_CURRENT;
 +
----                                    --ROT_INCREASE := ROT_INCREASE + 1;
 +
----                            end loop;
 +
--
 +
--
 +
--                      --end if;
 +
--
 +
--      --maybe just add rot1out to a queue? or variable
 +
--              -- put it in its own process instead of clk?
 +
--
 +
--
 +
--              -- is this if statement needed here? I don't think so.
 +
--              -- I think the process(ROT1OUT) assumes it will run
 +
--              -- should anything change on ROT1OUT. or i could do an if with a explicit change detected i think
 +
--              --if ROT1PREV /= ROT1OUT and BUSY = '0' then --put in fms
 +
--              --if BUSY = '0' then --if some aren't detected, try removing busy...
 +
--                      --BUSY <= '1';
 +
--
 +
--                      --for loop: upon a change in anything, loop
 +
--                      --through all values, and write to block ram
 +
--                      --using variables
 +
--
 +
--
 +
--                      --ADDRBPROXY <= RAMADDR_CURRENT;
 +
--
 +
----            ROT1PREV <= doutb; -- this needs to be somewhere else
 +
----                    READOUT  <= doutb; -- RAM reads are all done at once
 +
--                                                                      -- in main read loop
 +
--                      --BUSY <= '0';
 +
--              --end if;
 +
--
 +
--end process;
 +
--
 +
 +
--ALL RAM writes must be in same processper mikes electiceev forum
 +
 +
--RAMWRITE2: process(r_ROTO(2))
 +
--begin
 +
--                                      DINAPROXY  <= ROT2OUT;
 +
--                                      ADDRAPROXY <= RAMADDR_2;
 +
--end process;
 +
 +
 +
rotarytop: process (clk)
 +
        begin
 +
        if rising_edge(clk) then
 +
 +
        --if rot1out goes to dinaproxy (which is not connected
 +
        --to anything) then nothing happens. I htink it was over
 +
        --writing the zs
 +
--this works
 +
        if WRITE_COUNTER1    < 100000 then
 +
                ADDRAPROXY    <= x"8C";
 +
                WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
 +
        elsif WRITE_COUNTER1 < 8000000 then
 +
                dina          <= r_ROTO(to_integer(unsigned(ROT_INCREASE)));
 +
                ADDRAPROXY    <= ROT_INCREASE;
 +
                WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
 +
        elsif WRITE_COUNTER1 = 10000000 then
 +
                ROT_INCREASE  <= ROT_INCREASE + 1;
 +
                WRITE_COUNTER1 <= (others => '0');
 +
        else
 +
                WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
 +
        end if;
 +
 +
        if ROT_INCREASE > x"09" then
 +
                ROT_INCREASE <= x"01";
 +
        end if;
 +
--      if ROT_INCREASE = x"00" then
 +
--              ROT_INCREASE <= x"01";
 +
--      end if; --NOT NEEDED. Be careful NOT to set ROT_INCREASE
 +
                        -- TO ZERO ON STARTUP. SET TO x"01".
 +
  --this works
 +
--      if WRITE_COUNTER2 < 2 then
 +
--              WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
 +
--              ADDRAPROXY    <= x"8C";
 +
--              ROT_INCREASE  <= x"01";
 +
--      elsif WRITE_COUNTER2 < 10 then
 +
--              dina          <= r_ROTO(to_integer(unsigned(ROT_INCREASE)));
 +
--              ADDRAPROXY    <= ROT_INCREASE;
 +
--              WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
 +
--      --use elsif here to keep writes exclusive
 +
--      elsif WRITE_COUNTER2 < 12 then
 +
--              ADDRAPROXY    <= x"8C";
 +
--              ROT_INCREASE  <= x"02";
 +
--              WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
 +
--      elsif WRITE_COUNTER2 < 25 then
 +
--              dina          <= r_ROTO(to_integer(unsigned(ROT_INCREASE)));
 +
--              ADDRAPROXY    <= ROT_INCREASE;
 +
--              WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
 +
--      elsif WRITE_COUNTER2 < 30 then
 +
--              ADDRAPROXY    <= x"8C";
 +
--              WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
 +
--      else
 +
--              WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
 +
--      end if;
 +
--
 +
--      if WRITE_COUNTER1 > 1000000 then
 +
--              WRITE_COUNTER2 <= WRITE_COUNTER2 + 1;
 +
--              WRITE_COUNTER1 <= (others => '0');
 +
--      end if;
 +
--      if WRITE_COUNTER2 > 30 then
 +
--              WRITE_COUNTER2 <= (others => '0');
 +
--      end if;
 +
 +
--      if WRITE_COUNTER2 = 10 then
 +
--                              --write to ram
 +
--                              dina  <= ROT1OUT;
 +
--                              ADDRAPROXY <= RAMADDR_1;
 +
--                              --RAMADDR_CURRENT <= RAMADDR_CURRENT + 1;
 +
--                      end if;
 +
--
 +
--                      if WRITE_COUNTER1 = 500 then
 +
--
 +
--                                      WRITE_COUNTER2 <= WRITE_COUNTER2 + 1;
 +
--                              else
 +
--                                      WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
 +
--                              end if;
 +
 +
 +
 +
--                                              ALWAYS                          --
 +
 +
 +
        ena <= '1';                            -- ram enable high always
 +
        enb <= '1';
 +
        wea <= "1";                            -- write port, never reads
 +
        web <= "0";                            -- read port, never writes
 +
 +
 +
        addra <= ADDRAPROXY;
 +
        --addrb <= ADDRBPROXY;
 +
        TX(0) <= UARTOUT(0);
 +
 +
 +
--                                              DEBUG                                  --
 +
        --LEDWATCH <= READOUT(7 downto 0);
 +
 +
        --check values are as expected
 +
        --LEDWATCH <= ROT1PREV(7 downto 0); --rot1prev WORKING
 +
        --LEDWATCH <= ROT1OUT(7 downto 0);      --rot1out WORKING only 8
 +
        --LEDWATCH <= doutb(7 downto 0);
 +
        --LEDWATCH(7 downto 4) <= READOUT(3 downto 0);
 +
--      LED(0) <= r_ROTO(1)(0); --green
 +
--      LED(1) <= r_ROTO(2)(0); --red
 +
--      LED(2) <= ADDRAPROXY(0);
 +
--      LED(3) <= WEA(0);
 +
--      LED(4) <= ROT_INCREASE(0);      --green
 +
--      LED(5) <= ROT_INCREASE(1); --red
 +
--      LED(6) <= ROT_INCREASE(2);
 +
--      LED(7) <= ROT_INCREASE(3);
 +
 +
        --LED(0) <= r_ROTO(1)(0);      --green
 +
 +
        --seems to be skipping on two sometimes
 +
        --LED    <= r_ROTO(2)(7 downto 0);
 +
 +
        LED    <= r_ROTO(3)(7 downto 0);
 +
 +
--case state is
 +
 +
 +
 +
--                                      idle state                                      --
 +
--              when state_start =>
 +
                -- ROT1PREV starts as zero, state_RAM as soon as ROT1OUT change
 +
----            if ROT1PREV /= ROT1OUT and BUSY = '0' and UARTOFF = '0' then
 +
--                      state <= state_RAM;
 +
--              else
 +
--                      state <= state_start;
 +
--              end if;
 +
 +
 +
 +
------------- RAM WRITE & READ ------------------
 +
 +
 +
                -- if rot1out has a change?
 +
                -- put it in its own process instead of clk?
 +
--              if ROT1PREV /= ROT1OUT and BUSY = '0' then --put in fms
 +
--
 +
--                      BUSY <= '1';
 +
--
 +
--                      dina  <= ROT1OUT;
 +
--                      addra <= RAMADDR_1;
 +
--
 +
--                      RAMADDR_CURRENT <= RAMADDR_1;
 +
--                      addrb <= RAMADDR_1;
 +
--
 +
--              ROT1PREV <= doutb;
 +
--                      --in here
 +
--                      -- then write new data output to uart
 +
--                      -- put loops in to keep it to appropriate baud
 +
--                      -- use a for loop (of say 1000 times)
 +
--                      -- and a counter that counts up, then down
 +
--                      -- as delay with an outer for loop
 +
--                      -- that shifts bits out once every loop (nested loops)
 +
--
 +
--
 +
--                      BUSY <= '0';
 +
--              end if;
 +
 +
--                                      RAM READ                                        --
 +
-- This will be separate process / module
 +
-- that will read constantly from all memory addresses
 +
-- and output the results to UART pin. need to time correctly.
 +
 +
--      if RAM_COUNTER = 1000000 then
 +
--
 +
----            addrb    <= RAMADDR_CURRENT;
 +
----            READOUT  <= doutb;
 +
--
 +
--                      -- "0000 0000 0000 0000 0000 0000 0000 00"
 +
--              --  xxxxxx8  5    1sxx xxxx x8  5    1s
 +
--              --
 +
----            UARTOUT(0)                              <= '0';
 +
----            UARTOUT(8 downto 1)  <= READOUT(7 downto 0);
 +
----            UARTOUT(15 downto 9)  <= (others => '1'); --spacing to allow settling
 +
----            UARTOUT(16)          <= '0';
 +
----            UARTOUT(24 downto 17) <= READOUT(15 downto 8);
 +
----            UARTOUT(29 downto 25) <= (others => '1');
 +
--              RAM_COUNTER <= (others => '0');
 +
--      else
 +
--              RAM_COUNTER <= RAM_COUNTER + 1;
 +
--
 +
--      end if;
 +
      -- BEWARE
 +
                -- When using jumper leads with uart
 +
                -- you can't go over like a few inches.
 +
                -- or signal fails. BEWARE
 +
 +
 +
--                                      UART                                            --
 +
 +
--                                      SHIFTING                                                --
 +
 +
-- We always shift whatever is in the UART register out
 +
-- When we are idling, we fill UART register with 1's (idle high
 +
-- is normal). Every so often (further down), we read an address
 +
-- and output the value into UART register IF uart is on.
 +
-- Otherwise nothing happens.
 +
 +
                  -- I think timing is wrong on this. need a scope.
 +
              --if OUTPUTHIGH = '1' then --this broke things
 +
                        --if UART_COUNTER = 3333 then --9600
 +
                        --if UART_COUNTER = 278 then -- 115200 --maybe too fast. maybe not.
 +
                        --if UART_OFFON = '0' then --this spaces out groups of bytes. not what I'm intending
 +
                        --uart offon didn't work.
 +
                                if UART_COUNTER = 555 then -- 57600 -- pretty good.
 +
                                                --shift bit over every 3332 cycles or 9600 bits per second
 +
                                                UARTOUT <= UARTOUT(0) & UARTOUT(199 downto 1);
 +
                                                UART_COUNTER <= (others => '0');
 +
                                                UART_COUNTER3 <= UART_COUNTER3 + 1;
 +
                                                --UART_COUNTER4 <= UART_COUNTER4 + 1; --with uartoffon
 +
                                else
 +
                                        UART_COUNTER <= UART_COUNTER + 1;
 +
                                end if;
 +
                        --end if; --with uart offon
 +
 +
 +
--                      --shift one sequence, then stop
 +
--                      if UART_COUNTER4 = 1 then
 +
--                              UART_OFFON <= '1';
 +
--                      end if;
 +
--
 +
--                      --idle high while uart_offon is high
 +
--                      if UART_OFFON = '1' then
 +
--                              UARTOUT <= (others => '1');
 +
--                      end if;
 +
 +
                -- for 9600 baud, or 3333 cycles
 +
                --
 +
                --approach 1
 +
--                      if UART_COUNTER2 = 99990 then
 +
--                              addrb    <= RAMADDR_CURRENT;
 +
--                              READOUT  <= doutb;
 +
--                              UARTOUT(0)                              <= '0';
 +
--                              UARTOUT(8 downto 1)  <= READOUT(7 downto 0);
 +
--                              UARTOUT(15 downto 9)  <= (others => '1'); --spacing to allow settling
 +
--                              UARTOUT(16)          <= '0';
 +
--                              UARTOUT(24 downto 17) <= READOUT(15 downto 8);
 +
--                              UARTOUT(29 downto 25) <= (others => '1');
 +
--                              UART_COUNTER2  <= (others => '0');
 +
--                              UART_COUNTER <= (others => '0');
 +
--                      else
 +
--                              UART_COUNTER2  <= UART_COUNTER2 + 1;
 +
--                      end if;
 +
              RAM READ                                        --
 +
 +
 +
-- APPROACH 1
 +
-- read all memory addresses, at the speed of if uart counter3
 +
-- equals 90.
 +
-- for i in 0 to 99 loop
 +
-- addrb <= i;
 +
-- READOUT <= doutb;
 +
-- end loop;
 +
 +
-- APPROACH 2
 +
-- use counter
 +
-- if uartcOunter3=90 then
 +
-- addrb <= ADDRCOUNTER (starts at zero)
 +
-- READOUT <= doutb
 +
-- ADDRCOUNTER <= ADDRCOUNTER + 1;
 +
        -- if ADDRCOUNTER = 100 then
 +
        -- ADDRCOUNTER <= (others to 0)
 +
        -- end if
 +
-- end if;
 +
 +
--approach 2 for ram read                --read ram for every three txout
 +
                        if UART_COUNTER3 = 199 then --after one sequence
 +
                                --if UART_OFFON = '0' then --only do if on
 +
 +
                                        addrb    <= ADDR_RD_COUNTER;
 +
                                        READOUT  <= doutb;
 +
                                        ADDR_RD_COUNTER <= ADDR_RD_COUNTER + 1;
 +
 +
                                        -- send two bits. one id, one value
 +
                                        --UARTOUT(0)                            <= '0';
 +
                                        --UARTOUT(8 downto 1)  <= READOUT(7 downto 0);
 +
                                        --UARTOUT(15 downto 9)  <= (others => '1'); --spacing to allow settling
 +
                                        --UARTOUT(16)          <= '0';
 +
                                        --UARTOUT(24 downto 17) <= READOUT(15 downto 8);
 +
                                        --UARTOUT(29 downto 25) <= (others => '1');
 +
  -- send RotaryID and Count
 +
                                        UARTOUT(3 downto 0)    <= (others => '1'); --idle when high
 +
                                        UARTOUT(4)                            <= '0'; --start bit
 +
                                        UARTOUT(12 downto 5)    <= READOUT(15 downto 8); -- ROTARYID first
 +
                                        UARTOUT(102 downto 13)  <= (others => '1'); --idle when high
 +
                                        UARTOUT(103)                      <= '0'; --start bit
 +
                                        UARTOUT(111 downto 104) <= READOUT(7 downto 0); -- ROTARYCOUNT second
 +
                                        UARTOUT(199 downto 112) <= (others => '1'); --idle when high
 +
 +
                                        UART_COUNTER3 <= (others => '0');
 +
                                  --UART_COUNTER4 <= UART_COUNTER4 + 1;
 +
 +
                                        if ADDR_RD_COUNTER = 100 then
 +
                                                ADDR_RD_COUNTER <= (others => '0');
 +
                                        end if;
 +
 +
                                --end if; --end uartoffon
 +
                        end if;
 +
 +
 +
--              COUNTER <= COUNTER +1;
 +
--              if (COUNTER= 100000) then
 +
--                      COUNTER <= (others => '0');
 +
--                      UART_OFFON <= '0';
 +
--                      UART_COUNTER4 <= (others => '0');
 +
--              end if;
 +
--              if (COUNTER(12) = '1') then
 +
--                      UART_COUNTER_SPACER <= UART_COUNTER_SPACER +1;
 +
--              end if;
 +
--              if (UART_COUNTER_SPACER = 4) then
 +
--                      UART_COUNTER_SPACER <= (others => '0');
 +
--              end if;
 +
 +
 +
 +
        end if; --  rising clk end
 +
        end process;
 +
</pre>
 +
 +
==Rotary.vhd==
 +
<pre>
 +
--------------------------------------
 +
library IEEE;
 +
use IEEE.STD_LOGIC_1164.ALL;
 +
use IEEE.STD_LOGIC_UNSIGNED.ALL;
 +
 +
-- todo: IO of rotary needs communication
 +
-- need to store values in signals
 +
-- need to output signals with distinct ID (generic passed
 +
-- holds the ID number)
 +
-- one byte output, with 1 bits for left/right (either 1 or 0)
 +
-- 7 bits for rotary ID, one bit for stop (i.e. normal uart)
 +
 +
--the idea will be. each rotary has a unique ID, and a unique
 +
--signal (ROTSIG1, ROTSIG2) in each instance
 +
--which will output direction bit and id bits.
 +
--there will be a uart to send out bits. Or preferably
 +
--some way to read registers (see hamsterbook) beyond uart.
 +
--there will be a busy flag, which all rotary instances share
 +
--and when a byte is being sent, other rotary instances wait
 +
--until it is cleared. after each sends a byte, it clears
 +
--it. each rotary stores the direction / id in a signal and
 +
--after outputting, it erases the direction. there will be
 +
--another flag to determine if data needs to be sent or not.
 +
--if dataoutputneededflag is 0, then no data is sent.
 +
 +
--signals are specified in top level module and mapped in
 +
--instance. you can map the ports in the instance to signals.
 +
 +
 +
-- Outputs ROTARYCOUNT (7 to 0)
 +
-- and    ROTARYID (15 to 8)
 +
-- to DATAOUT
 +
 +
entity rotary is
 +
 +
GENERIC(
 +
            RAMADDR    : STD_LOGIC_VECTOR(7 downto 0) := "11001100";
 +
                  ROTARYID  : STD_LOGIC_VECTOR(7 downto 0) := "01100110"
 +
            );
 +
PORT ( ROT        : in  STD_LOGIC_VECTOR(1 downto 0);
 +
        LED        : out  STD_LOGIC_VECTOR(3 downto 0);
 +
                  --LEDWATCH  : out STD_LOGIC_VECTOR(7 downto 0);
 +
                  clk        : in STD_LOGIC;
 +
                  DATAOUT    : out STD_LOGIC_VECTOR(15 downto 0)
 +
                  );
 +
 +
end rotary;
 +
 +
architecture Behavioral of rotary is
 +
 +
 +
 +
-- logic_vector takes double quotes for single num
 +
-- std_logic takes single for single num
 +
signal current      : STD_LOGIC_VECTOR(1 downto 0);
 +
signal previous    : STD_LOGIC_VECTOR(1 downto 0);
 +
signal target      : STD_LOGIC_VECTOR(1 downto 0) := "00";
 +
signal truetarget  : STD_LOGIC_VECTOR(1 downto 0) := "00";
 +
signal xortest      : STD_LOGIC_VECTOR(1 downto 0);
 +
signal counter      : STD_LOGIC_VECTOR(29 downto 0) := (others => '0');
 +
signal shiftreg  : STD_LOGIC_VECTOR(9 downto 0) := "1010110100";
 +
signal counter2    : STD_LOGIC_VECTOR(29 downto 0) := (others => '0');
 +
signal ROTARYCOUNT  : STD_LOGIC_VECTOR(6 downto 0) := "0000000";
 +
signal counter3    : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');
 +
signal ROTARYMEMWRITE    : STD_LOGIC_VECTOR(15 downto 0)  := x"0101";
 +
signal counter4    : STD_LOGIC_VECTOR(29 downto 0) := (others => '0');
 +
signal counter5    : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');
 +
signal writeenable  : STD_LOGIC_VECTOR(0 downto 0) := (others => '0');
 +
signal memoutput    : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');
 +
 +
constant CCWPIN : STD_LOGIC_VECTOR(1 downto 0) := "10";
 +
constant CWPIN  : STD_LOGIC_VECTOR(1 downto 0) := "01";
 +
constant PINS  : STD_LOGIC_VECTOR(1 downto 0) := "11";
 +
 +
begin
 +
 +
 +
-- hamster page 103 section 20.1 what is rs232
 +
 +
rotarywatch: process (clk)
 +
        begin
 +
        if rising_edge(clk) then
 +
 +
        DATAOUT(6 downto 0)  <= ROTARYCOUNT;
 +
        DATAOUT(7)                              <= '0';
 +
        DATAOUT(15 downto 8)  <= ROTARYID;
 +
 +
        --LED(1) <= douta(0);  --red
 +
        --LED(0) <= wea(0); -- green
 +
        --ena <= '1';
 +
        --if counter(8) = '1' then
 +
        --      wea <= "1" ; -- this works. but lower down make sure it has
 +
        -- enough time. EDIT: seems its easier to leave it up
 +
        -- and pull it down for reads than vice versa.
 +
        -- THIS WORKS
 +
        -- note how i had to leave wea to write high occasionally
 +
        -- otherwise it will allow enough time to read
 +
        --end if;
 +
 +
 +
        -- use ledwatch to check addra  (CHECKEDOU T)
 +
        -- then check dina (CHECKED OUT)
 +
        -- then check wea (NOT CHANGING FAST ENOUGH)
 +
        -- then check douta etc etc make sure it all lines up
 +
        -- douta is not going high, last thing I did last night.
 +
        --LEDWATCH(6 downto 0) <= douta(6 downto 0);
 +
        --LEDWATCH(6) <= ena;
 +
        --LEDWATCH(6) <= douta(0);
 +
        --LEDWATCH(7) <= wea(0);
 +
 +
 +
        -- how to write to mem?
 +
        -- make write enable high
 +
        -- specify address
 +
        -- output to data in?
 +
        -- need to read xapp463 which is the data sheet and
 +
        -- copy the pins
 +
 +
  --LEDWATCH(7 downto 0) <= counter3(31 downto 24);
 +
        --LEDWATCH(7 downto 6) <= previous;
 +
        --LEDWATCH(5 downto 4) <= current;
 +
        --LEDWATCH(3 downto 2) <= xortest;
 +
        --LEDWATCH(1 downto 0) <= target;
 +
        --LEDWATCH <= rotarycount;
 +
        xortest <= current xor previous; --have it run constnatly
 +
        -- so we don't have to worry when debugging whether target
 +
        -- equals current
 +
 +
 +
                if counter(0) = '1' then
 +
                        current(0) <= ROT(0);
 +
                        current(1) <= ROT(1);
 +
                        if current = target then
 +
 +
                                if current = truetarget then
 +
                                --wea <= "1"; --this doesn't work. not enough time see above for better spot for wea
 +
                                        if xortest = CCWPIN then
 +
                                                --LED(2) <= '1';
 +
                                                ROTARYCOUNT <= ROTARYCOUNT-1;
 +
                                                --dina <= rotarycount;
 +
                                        end if;
 +
                                        if xortest = CWPIN then
 +
                                                --LED(3) <= '1'; -- leds are NOT reliable
 +
                                                                                        -- for any fast signals
 +
                                                                                        -- as these missed many
 +
                                                ROTARYCOUNT <= ROTARYCOUNT+1;
 +
 +
                                                -- if write enabled
 +
                                                -- address?
 +
                                                --wea <= "1" ;
 +
                                                --dina <= rotarycount;
 +
 +
                                        end if;
 +
                                        --LED(2) <= '1'; --debug (yellow ch1)
 +
                                        --wea <= "0"; enable this to only read when change
 +
                                end if;
 +
                        target <= PINS XOR target; --invert if equal to target (not truetarget)
 +
                        end if;
 +
                previous <= current;
 +
                --wea <= "0"; enable this to read at all times
 +
 +
 +
                end if;
 +
 +
                if counter = 64000000 then --runs every 0.5 or .4 second
 +
                        --previous <= current; --debug only
 +
 +
                        counter <= (others => '0');
 +
                        --target <= PINS XOR target; works
 +
                else
 +
                        counter  <= counter+1;
 +
                        counter2 <= counter2+1;
 +
                end if;
 +
                if counter2 = 500000000 then
 +
 +
                        counter2 <= (others => '0');
 +
                end if;
 +
        end if;
 +
end process;
 +
 +
 +
end Behavioral;
 +
 +
 +
 +
 +
 +
 +
 +
</pre>
 +
 +
 +
 +
 +
==Resources==
 +
* [http://papilio.cc/] While the Papilio is obsolete now, and you should probably start with a newer FPGA, it's still now a bad place to start.
 +
* [http://hamsterworks.co.nz]

Revision as of 05:20, 18 October 2019

Reap what you sow. Here's some public domain code for a Spartan 3E, to interface with multiple rotary encoders. It's currently tested up to 8. It uses Block RAM to keep track of a Rotary ID and Value for the rotary (between 0-127). It outputs the rotary values via UART on 57600 baud. Based off of the Papilio and also HamsterNZ's introductory PDF on FPGAs.

I have different versions of this. I've had some issues with UART timing on a Spartan 3E 500, whereas the Papilio's 250 did not have such issues. I'll start with the one that's compatible with the Papilio board (including the pinout / constraints.ucf file).

There is Rotary_Top.vhd, which is the main code, then there are instances of rotaries.


Rotary_Top.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;

-- TODO

--DONE test reading one address in RAM. make sure it is right.
--DONE make sure output on UART is correct. Also bits are
--DONE  in right order too. DONE.

--DONE (used counter, not loop) setup a read on 0-99 addresses of RAM . use loop.

--DONE have it output each memory address in uart 3 or 4 times before
--going to the next.

--DONE EASY have it loop through the ram 24/7 EASY

--DONE: set default values of ram to be letters abcabcabcabc



--RAM
-- idea
-- have top level manage all ram and output
-- have output only if cw or ccw
-- if outputs, have that rotaryID(or memory address)
-- be the chosen one to write to.


--UART
-- possible solution #1
-- if a memory address is updated
-- then output uart of new memory address only
-- every rotary change, causes
-- new ram write/ read, and uart output
-- on as needed basis
-- PROBLEMS: having trouble getting just one uart byte out
-- noisy, and timing is off possibly (check timing)


-- possible solution #2
-- loop through all memory constantly
-- output all values constantly
-- any changes will be reflected in micro
-- hopefully fast enough? (should be)(57600 is p fast)
-- any rotaries that update will write to ram
-- problems: if 100 rotaries updating at once,
-- could not be fast enough? maybe? maybe not. maybe it
-- is fast enough to read io, write ram.
-- write RAM would be separate from read ram / UART here
-- but need to adjust write enable flag as needed... maybe
-- two port RAM is better? constantly write on port A
-- constantly read from port b. no need to adjust write enable
-- flag...
-- Yes, you can use dual port RAM. one port always wea high
-- other port always wea low. and they should only interfere
-- if read is during a write. however,
-- depending how fast I read the data, I may be able to get
-- around htis. i could also average the values (say last 3
-- values) from the serial for a given byte, and call that
-- the true value. this way avoid any memory errors.



-- TODO

-- Need to writeup basic documentation and clean these at the
-- very end.

-- look up what a memory latch is



-- output serial as BCD or ascii table bits
-- i.e. instead of using straight hex (one byte each) for
-- a number, convert it to its ascii equivalent (not as fast)
-- (takes more bytes)

-- EDIT: just outputting raw 8 bits

entity rotary_top is
--must map all 100 rotaries here
   GENERIC(
             RAMADDR : STD_LOGIC_VECTOR(7 downto 0) := x"FF";
                  ROTARYID   : integer := 1
             );
  PORT( ROT           : in  STD_LOGIC_VECTOR(1 downto 0); -- semi colons
        ROT2          : in  STD_LOGIC_VECTOR(1 downto 0); -- here
                  ROT3          : in  STD_LOGIC_VECTOR(1 downto 0);
                  ROT4          : in  STD_LOGIC_VECTOR(1 downto 0);
                  ROT5          : in  STD_LOGIC_VECTOR(1 downto 0);
                  ROT6          : in  STD_LOGIC_VECTOR(1 downto 0);
                  ROT7          : in  STD_LOGIC_VECTOR(1 downto 0);
                  ROT8          : in  STD_LOGIC_VECTOR(1 downto 0);
        LED           : out  STD_LOGIC_VECTOR(7 downto 0); -- commas in
                  --LEDWATCH      : out STD_LOGIC_VECTOR(7 downto 0); --instance
                  clk           : in STD_LOGIC;
                  --DATAOUTUART   : out STD_LOGIC;
                  TX                             : out STD_LOGIC_VECTOR(0 downto 0)
                  --RX                           : STD_LOGIC

                  );

end rotary_top;

        architecture Behavioral of rotary_top is
        COMPONENT rotary
   GENERIC(
                RAMADDR : STD_LOGIC_VECTOR(7 downto 0) := x"FF";
                ROTARYID   : STD_LOGIC_VECTOR(7 downto 0) := x"00"
                );
        PORT(
                ROT : IN std_logic_vector(1 downto 0);
                clk : IN std_logic;
                LED : OUT std_logic_vector(3 downto 0);
                -- LEDWATCH : OUT std_logic_vector(7 downto 0);
                 DATAOUT  : OUT STD_LOGIC_VECTOR(15 downto 0)
                );
        END COMPONENT;
      COMPONENT DUALRAM
  PORT (
    clka : IN STD_LOGIC;
    ena : IN STD_LOGIC;
    wea : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
    addra : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
    dina : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
    douta : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);

    clkb : IN STD_LOGIC;
    enb : IN STD_LOGIC;
    web : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
    addrb : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
    dinb : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
    doutb : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
  );
END COMPONENT;



        signal   resultsigtest    : STD_LOGIC_VECTOR(7 downto 0) ;
        signal   RAMADDR_CURRENT  : STD_LOGIC_VECTOR(7 downto 0) := "00000000";
        -- RAMADDR_0 is start byte (zz (LOWER CASE)) for pic to know when array starts
        constant RAMADDR_1        : STD_LOGIC_VECTOR(7 downto 0) := "00000001";
        constant ROTARYID_1       : STD_LOGIC_VECTOR(7 downto 0) := "00000001";
        constant RAMADDR_2        : STD_LOGIC_VECTOR(7 downto 0) := "00000010";
        constant ROTARYID_2       : STD_LOGIC_VECTOR(7 downto 0) := "00000010";
        --signal   RAMADDR_CURRENT2 : STD_LOGIC_VECTOR(7 downto 0) := "00001000";
        constant RAMADDR_3        : STD_LOGIC_VECTOR(7 downto 0) := "00000011";
        constant ROTARYID_3       : STD_LOGIC_VECTOR(7 downto 0) := "00000011";

        constant RAMADDR_4        : STD_LOGIC_VECTOR(7 downto 0) := "00000100";
        constant ROTARYID_4       : STD_LOGIC_VECTOR(7 downto 0) := "00000100";

        constant RAMADDR_5        : STD_LOGIC_VECTOR(7 downto 0) := "00000101";
        constant ROTARYID_5       : STD_LOGIC_VECTOR(7 downto 0) := "00000101";

        constant RAMADDR_6        : STD_LOGIC_VECTOR(7 downto 0) := "00000110";
        constant ROTARYID_6       : STD_LOGIC_VECTOR(7 downto 0) := "00000110";

        constant RAMADDR_7        : STD_LOGIC_VECTOR(7 downto 0) := "00000111";
        constant ROTARYID_7       : STD_LOGIC_VECTOR(7 downto 0) := "00000111";

        constant RAMADDR_8        : STD_LOGIC_VECTOR(7 downto 0) := "00001000";
        constant ROTARYID_8       : STD_LOGIC_VECTOR(7 downto 0) := "00001000";
     -- these must be here or error. must translate output to
        -- sig, then to output. can't directly go
        -- from output to output

        signal ROT1OUT                  : STD_LOGIC_VECTOR(15 downto 0);
        signal ROT2OUT                  : STD_LOGIC_VECTOR(15 downto 0);
        --must be set to zero (or unequal to rot1out) at start
        signal ROT1PREV         : STD_LOGIC_VECTOR(15 downto 0) := (others => '0');

        type t_ROTOUT is array (1 to 100) of std_logic_vector(15 downto 0);
        signal r_ROTO : t_ROTOUT := (others => (others => '0'));



        signal wea                        : STD_LOGIC_VECTOR(0 DOWNTO 0)  := "0";
        signal addra              : STD_LOGIC_VECTOR(7 DOWNTO 0)  := (others => '0');
        signal dina                       : STD_LOGIC_VECTOR(15 DOWNTO 0) := (others => '0');
        signal douta              : STD_LOGIC_VECTOR(15 DOWNTO 0) := (others => '0');
        signal ena                        : STD_LOGIC                     := '0';
        signal DINAPROXY          : STD_LOGIC_VECTOR(15 DOWNTO 0) := (others => '0');

        signal web                        : STD_LOGIC_VECTOR(0 DOWNTO 0)  := "0";
        signal addrb              : STD_LOGIC_VECTOR(7 DOWNTO 0)  := (others => '0');
        signal dinb                  : STD_LOGIC_VECTOR(15 DOWNTO 0) := (others => '0');
        signal doutb              : STD_LOGIC_VECTOR(15 DOWNTO 0) := (others => '0');
        signal enb                        : STD_LOGIC                     := '0';
        signal ADDRAPROXY   : STD_LOGIC_VECTOR(7 DOWNTO 0)  := "00000001";
        signal ADDRBPROXY   : STD_LOGIC_VECTOR(7 DOWNTO 0)  := (others => '0');
        signal ADDR_RD_COUNTER   : STD_LOGIC_VECTOR(7 DOWNTO 0)  := (others => '0');

        signal WRITE_COUNTER1  : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
        signal WRITE_COUNTER2 : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');

        signal COUNTER        : STD_LOGIC_VECTOR(29 downto 0) := (others => '0');
        signal READOUT       : STD_LOGIC_VECTOR(15 downto 0) := (others => '0'); --"1111111010110100"; --default data to test uart
        signal BUSY          : STD_LOGIC                     := '0';
        signal UART_COUNTER  : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
        signal UART_COUNTER2 : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
        signal UART_COUNTER3 : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
        signal RAM_COUNTER   : STD_LOGIC_VECTOR(29 downto 0) := (others => '0');
        --signal UART_COUNTER_SPACER : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
        --signal UART_COUNTER4 : STD_LOGIC_VECTOR(12 downto 0) := (others => '0');
   --signal UART_OFFON    : STD_LOGIC                     := '0';

---variable ROT_INCREASE : integer range 0 to 255 := 1;
        signal ROT_INCREASE : STD_LOGIC_VECTOR(7 downto 0) := x"01";

        --signal UARTOUT    : STD_LOGIC_VECTOR(15 downto        0) := "1111111010110100"; --default data to test uart without reading rotary
        --signal UARTOUT    : STD_LOGIC_VECTOR(29 downto 0) := "111110101101001111111010110100"; --Y then Z -- WORKS
        signal UARTOUT      : STD_LOGIC_VECTOR(199 downto 0) := (others => '1');

        --debugging uart
        --signal UARTOUT    : STD_LOGIC_VECTOR(29 downto 0) := "101010101010101010101010101010";




-- must map all 100 instances of rotary module here
--TODO
-- input a value for rotary (i.e. rotary1= 1, as 8 bit value)
-- output that value somewhere else, and put it into uart
-- output the value for rotary plus or minus into
-- a specific 8 bit register. output into uart when called.
-- After uart reads, erase these banks.

-- OR, need to find how to write to RAM. Then I need to
-- programatically write the rotary to a specific ram register
-- then read the registers
begin

Inst_DUALRAM: DUALRAM
  PORT MAP (
    clka => clk,
    ena => ena,
    wea => wea,
    addra => addra,
    dina => dina,
    douta => douta,
  clkb => clk,
    enb => enb,
    web => web,
    addrb => addrb,
    dinb => dinb,
    doutb => doutb
  );


Inst_ROTARY_1: rotary
        GENERIC MAP(
        RAMADDR => RAMADDR_1,
        ROTARYID   => ROTARYID_1
        )
        PORT MAP(
                ROT => ROT,
                LED => open,
                clk => clk,
                DATAOUT => r_ROTO(1)
                );

Inst_ROTARY_2: rotary
        GENERIC MAP(
        RAMADDR => RAMADDR_2,
        ROTARYID   => ROTARYID_2
        )
        PORT MAP(
                ROT => ROT2,
                LED => open,
                clk => clk,
                DATAOUT => r_ROTO(2)
        );

Inst_ROTARY_3: rotary
        GENERIC MAP(
        RAMADDR => RAMADDR_3,
        ROTARYID   => ROTARYID_3
        )
        PORT MAP(
                ROT => ROT3,
                LED => open,
                clk => clk,
                DATAOUT => r_ROTO(3)
        );

Inst_ROTARY_4: rotary
        GENERIC MAP(
        RAMADDR => RAMADDR_4,
        ROTARYID   => ROTARYID_4
        )
        PORT MAP(
                ROT => ROT4,
                LED => open,
                clk => clk,
                DATAOUT => r_ROTO(4)
        );

Inst_ROTARY_5: rotary
        GENERIC MAP(
        RAMADDR => RAMADDR_5,
        ROTARYID   => ROTARYID_5
        )
        PORT MAP(
                ROT => ROT5,
                LED => open,
                clk => clk,
                DATAOUT => r_ROTO(5)
        );
Inst_ROTARY_6: rotary
        GENERIC MAP(
        RAMADDR => RAMADDR_6,
        ROTARYID   => ROTARYID_6
        )
        PORT MAP(
                ROT => ROT6,
                LED => open,
                clk => clk,
                DATAOUT => r_ROTO(6)
        );

Inst_ROTARY_7: rotary
        GENERIC MAP(
        RAMADDR => RAMADDR_7,
        ROTARYID   => ROTARYID_7
        )
        PORT MAP(
                ROT => ROT7,
                LED => open,
                clk => clk,
                DATAOUT => r_ROTO(7)
        );

Inst_ROTARY_8: rotary
        GENERIC MAP(
        RAMADDR => RAMADDR_8,
        ROTARYID   => ROTARYID_8
        )
        PORT MAP(
                ROT => ROT8,
                LED => open,
                clk => clk,
                DATAOUT => r_ROTO(8)
        );
-- LEDWATCH <=READOUT(7 downto 0);  --works
-- this means i'm passing rotary values succesfully through
-- to ROT1OUT and the rotary ID as well.

--LEDWATCH <= READOUT(7 downto 0);

--put everything in a process because why not.


--try this out of the clock for starters...
--RAMWRITE: process(r_ROTO(1))
----variable ROT_INCREASE : integer range 0 to 255 := 1;
--begin
--
--                                      DINAPROXY  <= ROT1OUT;
--                                      ADDRAPROXY <= RAMADDR_1;
--
----            --if rising_edge(clk) then       this breaks things
----                                    ROT_INCREASE <= x"01";
----                                    --RAMADDR_CURRENT <= std_logic_vector(to_unsigned(ROT_INCREASE, RAMADDR_CURRENT'length));
----                                    RAMADDR_CURRENT <= ROT_INCREASE;
----                                    --write to ram
----                                    dina  <= r_ROTO(to_integer(unsigned(ROT_INCREASE)));
----                                    ADDRAPROXY <= RAMADDR_CURRENT;
----                                    --ROT_INCREASE := ROT_INCREASE + 1;
----            --end if;
--
--
----                    ROT_INCREASE <= x"00";
----                            if ROT_INCREASE = x"00" then
----                                    ROT_INCREASE <= x"01";
----                                    RAMADDR_CURRENT <= ROT_INCREASE;
----                                    dina  <= r_ROTO(to_integer(unsigned(ROT_INCREASE)));
----                                    ADDRAPROXY <= RAMADDR_CURRENT;
----                            elsif ROT_INCREASE = x"01" then
----                                    ROT_INCREASE <= x"02";
----                                    RAMADDR_CURRENT <= ROT_INCREASE;
----                                    dina  <= r_ROTO(to_integer(unsigned(ROT_INCREASE)));
----                                    ADDRAPROXY <= RAMADDR_CURRENT;
----                            elsif ROT_INCREASE = x"02" then
----                                    ROT_INCREASE <= x"00";
----                            end if;
----
----                    ROT_INCREASE <= x"00";
----                            if ROT_INCREASE = x"00" then
----                                    ROT_INCREASE <= x"01";
----                                    RAMADDR_CURRENT <= RAMADDR_1;
----                                    dina  <= r_ROTO(1);
----                                    ADDRAPROXY <= RAMADDR_CURRENT;
------                          elsif ROT_INCREASE = x"01" then
------                                  ROT_INCREASE <= x"02";
------                                  RAMADDR_CURRENT <= RAMADDR_2;
------                                  dina  <= r_ROTO(2);
------                                  ADDRAPROXY <= RAMADDR_CURRENT;
----                            elsif ROT_INCREASE = x"01" then
----                                    ROT_INCREASE <= x"00";
----                            end if;
----
--
--                              --ROT_INCREASE := ROT_INCREASE + 1;
--
----                            for x in 1 to 50 loop
----                                    ROT_INCREASE := 2;
----                                    RAMADDR_CURRENT <= std_logic_vector(to_unsigned(ROT_INCREASE, RAMADDR_CURRENT'length));
----                                    --write to ram
----                                    dina  <= r_ROTO(ROT_INCREASE);
----                                    ADDRAPROXY <= RAMADDR_CURRENT;
----                                    --ROT_INCREASE := ROT_INCREASE + 1;
----                            end loop;
--
--
--                      --end if;
--
--      --maybe just add rot1out to a queue? or variable
--              -- put it in its own process instead of clk?
--
--
--              -- is this if statement needed here? I don't think so.
--              -- I think the process(ROT1OUT) assumes it will run
--              -- should anything change on ROT1OUT. or i could do an if with a explicit change detected i think
--              --if ROT1PREV /= ROT1OUT and BUSY = '0' then --put in fms
--              --if BUSY = '0' then --if some aren't detected, try removing busy...
--                      --BUSY <= '1';
--
--                      --for loop: upon a change in anything, loop
--                      --through all values, and write to block ram
--                      --using variables
--
--
--                      --ADDRBPROXY <= RAMADDR_CURRENT;
--
----            ROT1PREV <= doutb; -- this needs to be somewhere else
----                    READOUT  <= doutb; -- RAM reads are all done at once
--                                                                       -- in main read loop
--                      --BUSY <= '0';
--              --end if;
--
--end process;
--

--ALL RAM writes must be in same processper mikes electiceev forum

--RAMWRITE2: process(r_ROTO(2))
--begin
--                                      DINAPROXY  <= ROT2OUT;
--                                      ADDRAPROXY <= RAMADDR_2;
--end process;


rotarytop: process (clk)
        begin
        if rising_edge(clk) then

        --if rot1out goes to dinaproxy (which is not connected
        --to anything) then nothing happens. I htink it was over
        --writing the zs
--this works
        if WRITE_COUNTER1     < 100000 then
                ADDRAPROXY     <= x"8C";
                WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
        elsif WRITE_COUNTER1 < 8000000 then
                dina           <= r_ROTO(to_integer(unsigned(ROT_INCREASE)));
                ADDRAPROXY     <= ROT_INCREASE;
                WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
        elsif WRITE_COUNTER1 = 10000000 then
                ROT_INCREASE   <= ROT_INCREASE + 1;
                WRITE_COUNTER1 <= (others => '0');
        else
                WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
        end if;

        if ROT_INCREASE > x"09" then
                ROT_INCREASE <= x"01";
        end if;
--      if ROT_INCREASE = x"00" then
--              ROT_INCREASE <= x"01";
--      end if; --NOT NEEDED. Be careful NOT to set ROT_INCREASE
                        -- TO ZERO ON STARTUP. SET TO x"01".
   --this works
--      if WRITE_COUNTER2 < 2 then
--              WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
--              ADDRAPROXY     <= x"8C";
--              ROT_INCREASE   <= x"01";
--      elsif WRITE_COUNTER2 < 10 then
--              dina           <= r_ROTO(to_integer(unsigned(ROT_INCREASE)));
--              ADDRAPROXY     <= ROT_INCREASE;
--              WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
--      --use elsif here to keep writes exclusive
--      elsif WRITE_COUNTER2 < 12 then
--              ADDRAPROXY     <= x"8C";
--              ROT_INCREASE   <= x"02";
--              WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
--      elsif WRITE_COUNTER2 < 25 then
--              dina           <= r_ROTO(to_integer(unsigned(ROT_INCREASE)));
--              ADDRAPROXY     <= ROT_INCREASE;
--              WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
--      elsif WRITE_COUNTER2 < 30 then
--              ADDRAPROXY     <= x"8C";
--              WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
--      else
--              WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
--      end if;
--
--      if WRITE_COUNTER1 > 1000000 then
--              WRITE_COUNTER2 <= WRITE_COUNTER2 + 1;
--              WRITE_COUNTER1 <= (others => '0');
--      end if;
--      if WRITE_COUNTER2 > 30 then
--              WRITE_COUNTER2 <= (others => '0');
--      end if;

--      if WRITE_COUNTER2 = 10 then
--                              --write to ram
--                              dina  <= ROT1OUT;
--                              ADDRAPROXY <= RAMADDR_1;
--                              --RAMADDR_CURRENT <= RAMADDR_CURRENT + 1;
--                      end if;
--
--                      if WRITE_COUNTER1 = 500 then
--
--                                      WRITE_COUNTER2 <= WRITE_COUNTER2 + 1;
--                              else
--                                      WRITE_COUNTER1 <= WRITE_COUNTER1 + 1;
--                              end if;



--                                              ALWAYS                          --


        ena <= '1';                             -- ram enable high always
        enb <= '1';
        wea <= "1";                             -- write port, never reads
        web <= "0";                             -- read port, never writes


        addra <= ADDRAPROXY;
        --addrb <= ADDRBPROXY;
        TX(0) <= UARTOUT(0);


--                                              DEBUG                                   --
        --LEDWATCH <= READOUT(7 downto 0);

        --check values are as expected
        --LEDWATCH <= ROT1PREV(7 downto 0); --rot1prev WORKING
        --LEDWATCH <= ROT1OUT(7 downto 0);       --rot1out WORKING only 8
        --LEDWATCH <= doutb(7 downto 0);
        --LEDWATCH(7 downto 4) <= READOUT(3 downto 0);
--      LED(0) <= r_ROTO(1)(0); --green
--      LED(1) <= r_ROTO(2)(0); --red
--      LED(2) <= ADDRAPROXY(0);
--      LED(3) <= WEA(0);
--      LED(4) <= ROT_INCREASE(0);      --green
--      LED(5) <= ROT_INCREASE(1); --red
--      LED(6) <= ROT_INCREASE(2);
--      LED(7) <= ROT_INCREASE(3);

        --LED(0) <= r_ROTO(1)(0);       --green

        --seems to be skipping on two sometimes
        --LED    <= r_ROTO(2)(7 downto 0);

        LED    <= r_ROTO(3)(7 downto 0);

--case state is



--                                      idle state                                      --
--              when state_start =>
                -- ROT1PREV starts as zero, state_RAM as soon as ROT1OUT change
----            if ROT1PREV /= ROT1OUT and BUSY = '0' and UARTOFF = '0' then
--                      state <= state_RAM;
--              else
--                      state <= state_start;
--              end if;



------------- RAM WRITE & READ ------------------


                -- if rot1out has a change?
                -- put it in its own process instead of clk?
--              if ROT1PREV /= ROT1OUT and BUSY = '0' then --put in fms
--
--                      BUSY <= '1';
--
--                      dina  <= ROT1OUT;
--                      addra <= RAMADDR_1;
--
--                      RAMADDR_CURRENT <= RAMADDR_1;
--                      addrb <= RAMADDR_1;
--
--              ROT1PREV <= doutb;
--                      --in here
--                      -- then write new data output to uart
--                      -- put loops in to keep it to appropriate baud
--                      -- use a for loop (of say 1000 times)
--                      -- and a counter that counts up, then down
--                      -- as delay with an outer for loop
--                      -- that shifts bits out once every loop (nested loops)
--
--
--                      BUSY <= '0';
--              end if;

--                                      RAM READ                                        --
-- This will be separate process / module
-- that will read constantly from all memory addresses
-- and output the results to UART pin. need to time correctly.

--      if RAM_COUNTER = 1000000 then
--
----            addrb    <= RAMADDR_CURRENT;
----            READOUT  <= doutb;
--
--                      -- "0000 0000 0000 0000 0000 0000 0000 00"
--              --  xxxxxx8   5    1sxx xxxx x8   5    1s
--              --
----            UARTOUT(0)                               <= '0';
----            UARTOUT(8 downto 1)   <= READOUT(7 downto 0);
----            UARTOUT(15 downto 9)  <= (others => '1'); --spacing to allow settling
----            UARTOUT(16)           <= '0';
----            UARTOUT(24 downto 17) <= READOUT(15 downto 8);
----            UARTOUT(29 downto 25) <= (others => '1');
--              RAM_COUNTER <= (others => '0');
--      else
--              RAM_COUNTER <= RAM_COUNTER + 1;
--
--      end if;
      -- BEWARE
                -- When using jumper leads with uart
                -- you can't go over like a few inches.
                -- or signal fails. BEWARE


--                                      UART                                            --

--                                      SHIFTING                                                --

-- We always shift whatever is in the UART register out
-- When we are idling, we fill UART register with 1's (idle high
-- is normal). Every so often (further down), we read an address
-- and output the value into UART register IF uart is on.
-- Otherwise nothing happens.

                   -- I think timing is wrong on this. need a scope.
              --if OUTPUTHIGH = '1' then --this broke things
                        --if UART_COUNTER = 3333 then --9600
                        --if UART_COUNTER = 278 then -- 115200 --maybe too fast. maybe not.
                        --if UART_OFFON = '0' then --this spaces out groups of bytes. not what I'm intending
                        --uart offon didn't work.
                                if UART_COUNTER = 555 then -- 57600 -- pretty good.
                                                --shift bit over every 3332 cycles or 9600 bits per second
                                                UARTOUT <= UARTOUT(0) & UARTOUT(199 downto 1);
                                                UART_COUNTER <= (others => '0');
                                                UART_COUNTER3 <= UART_COUNTER3 + 1;
                                                --UART_COUNTER4 <= UART_COUNTER4 + 1; --with uartoffon
                                else
                                        UART_COUNTER <= UART_COUNTER + 1;
                                end if;
                        --end if; --with uart offon


--                      --shift one sequence, then stop
--                      if UART_COUNTER4 = 1 then
--                              UART_OFFON <= '1';
--                      end if;
--
--                      --idle high while uart_offon is high
--                      if UART_OFFON = '1' then
--                              UARTOUT <= (others => '1');
--                      end if;

                -- for 9600 baud, or 3333 cycles
                --
                --approach 1
--                      if UART_COUNTER2 = 99990 then
--                              addrb    <= RAMADDR_CURRENT;
--                              READOUT  <= doutb;
--                              UARTOUT(0)                               <= '0';
--                              UARTOUT(8 downto 1)   <= READOUT(7 downto 0);
--                              UARTOUT(15 downto 9)  <= (others => '1'); --spacing to allow settling
--                              UARTOUT(16)           <= '0';
--                              UARTOUT(24 downto 17) <= READOUT(15 downto 8);
--                              UARTOUT(29 downto 25) <= (others => '1');
--                              UART_COUNTER2  <= (others => '0');
--                              UART_COUNTER <= (others => '0');
--                      else
--                              UART_COUNTER2  <= UART_COUNTER2 + 1;
--                      end if;
               RAM READ                                        --


-- APPROACH 1
-- read all memory addresses, at the speed of if uart counter3
-- equals 90.
-- for i in 0 to 99 loop
-- addrb <= i;
-- READOUT <= doutb;
-- end loop;

-- APPROACH 2
-- use counter
-- if uartcOunter3=90 then
-- addrb <= ADDRCOUNTER (starts at zero)
-- READOUT <= doutb
-- ADDRCOUNTER <= ADDRCOUNTER + 1;
        -- if ADDRCOUNTER = 100 then
        -- ADDRCOUNTER <= (others to 0)
        -- end if
-- end if;

--approach 2 for ram read                 --read ram for every three txout
                        if UART_COUNTER3 = 199 then --after one sequence
                                --if UART_OFFON = '0' then --only do if on

                                        addrb    <= ADDR_RD_COUNTER;
                                        READOUT  <= doutb;
                                        ADDR_RD_COUNTER <= ADDR_RD_COUNTER + 1;

                                        -- send two bits. one id, one value
                                        --UARTOUT(0)                             <= '0';
                                        --UARTOUT(8 downto 1)   <= READOUT(7 downto 0);
                                        --UARTOUT(15 downto 9)  <= (others => '1'); --spacing to allow settling
                                        --UARTOUT(16)           <= '0';
                                        --UARTOUT(24 downto 17) <= READOUT(15 downto 8);
                                        --UARTOUT(29 downto 25) <= (others => '1');
  -- send RotaryID and Count
                                        UARTOUT(3 downto 0)     <= (others => '1'); --idle when high
                                        UARTOUT(4)                            <= '0'; --start bit
                                        UARTOUT(12 downto 5)    <= READOUT(15 downto 8); -- ROTARYID first
                                        UARTOUT(102 downto 13)  <= (others => '1'); --idle when high
                                        UARTOUT(103)                       <= '0'; --start bit
                                        UARTOUT(111 downto 104) <= READOUT(7 downto 0); -- ROTARYCOUNT second
                                        UARTOUT(199 downto 112) <= (others => '1'); --idle when high

                                        UART_COUNTER3 <= (others => '0');
                                   --UART_COUNTER4 <= UART_COUNTER4 + 1;

                                        if ADDR_RD_COUNTER = 100 then
                                                ADDR_RD_COUNTER <= (others => '0');
                                        end if;

                                --end if; --end uartoffon
                        end if;


--              COUNTER <= COUNTER +1;
--              if (COUNTER= 100000) then
--                      COUNTER <= (others => '0');
--                      UART_OFFON <= '0';
--                      UART_COUNTER4 <= (others => '0');
--              end if;
--              if (COUNTER(12) = '1') then
--                      UART_COUNTER_SPACER <= UART_COUNTER_SPACER +1;
--              end if;
--              if (UART_COUNTER_SPACER = 4) then
--                      UART_COUNTER_SPACER <= (others => '0');
--              end if;



        end if; --  rising clk end
        end process;

Rotary.vhd

--------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- todo: IO of rotary needs communication
-- need to store values in signals
-- need to output signals with distinct ID (generic passed
-- holds the ID number)
-- one byte output, with 1 bits for left/right (either 1 or 0)
-- 7 bits for rotary ID, one bit for stop (i.e. normal uart)

--the idea will be. each rotary has a unique ID, and a unique
--signal (ROTSIG1, ROTSIG2) in each instance
--which will output direction bit and id bits.
--there will be a uart to send out bits. Or preferably
--some way to read registers (see hamsterbook) beyond uart.
--there will be a busy flag, which all rotary instances share
--and when a byte is being sent, other rotary instances wait
--until it is cleared. after each sends a byte, it clears
--it. each rotary stores the direction / id in a signal and
--after outputting, it erases the direction. there will be
--another flag to determine if data needs to be sent or not.
--if dataoutputneededflag is 0, then no data is sent.

--signals are specified in top level module and mapped in
--instance. you can map the ports in the instance to signals.


-- Outputs ROTARYCOUNT (7 to 0)
-- and     ROTARYID (15 to 8)
-- to DATAOUT

entity rotary is

 GENERIC(
             RAMADDR     : STD_LOGIC_VECTOR(7 downto 0) := "11001100";
                  ROTARYID   : STD_LOGIC_VECTOR(7 downto 0) := "01100110"
             );
 PORT ( ROT        : in  STD_LOGIC_VECTOR(1 downto 0);
        LED        : out  STD_LOGIC_VECTOR(3 downto 0);
                  --LEDWATCH   : out STD_LOGIC_VECTOR(7 downto 0);
                  clk        : in STD_LOGIC;
                  DATAOUT    : out STD_LOGIC_VECTOR(15 downto 0)
                  );

end rotary;

architecture Behavioral of rotary is



-- logic_vector takes double quotes for single num
-- std_logic takes single for single num
signal current      : STD_LOGIC_VECTOR(1 downto 0);
signal previous     : STD_LOGIC_VECTOR(1 downto 0);
signal target       : STD_LOGIC_VECTOR(1 downto 0) := "00";
signal truetarget   : STD_LOGIC_VECTOR(1 downto 0) := "00";
signal xortest      : STD_LOGIC_VECTOR(1 downto 0);
signal counter      : STD_LOGIC_VECTOR(29 downto 0) := (others => '0');
signal shiftreg   : STD_LOGIC_VECTOR(9 downto 0) := "1010110100";
signal counter2     : STD_LOGIC_VECTOR(29 downto 0) := (others => '0');
signal ROTARYCOUNT  : STD_LOGIC_VECTOR(6 downto 0) := "0000000";
signal counter3     : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');
signal ROTARYMEMWRITE    : STD_LOGIC_VECTOR(15 downto 0)  := x"0101";
signal counter4     : STD_LOGIC_VECTOR(29 downto 0) := (others => '0');
signal counter5     : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');
signal writeenable  : STD_LOGIC_VECTOR(0 downto 0) := (others => '0');
signal memoutput    : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');

constant CCWPIN : STD_LOGIC_VECTOR(1 downto 0) := "10";
constant CWPIN  : STD_LOGIC_VECTOR(1 downto 0) := "01";
constant PINS   : STD_LOGIC_VECTOR(1 downto 0) := "11";

begin


-- hamster page 103 section 20.1 what is rs232

rotarywatch: process (clk)
        begin
        if rising_edge(clk) then

        DATAOUT(6 downto 0)   <= ROTARYCOUNT;
        DATAOUT(7)                               <= '0';
        DATAOUT(15 downto 8)  <= ROTARYID;

        --LED(1) <= douta(0);  --red
        --LED(0) <= wea(0); -- green
        --ena <= '1';
        --if counter(8) = '1' then
        --      wea <= "1" ; -- this works. but lower down make sure it has
        -- enough time. EDIT: seems its easier to leave it up
        -- and pull it down for reads than vice versa.
        -- THIS WORKS
        -- note how i had to leave wea to write high occasionally
        -- otherwise it will allow enough time to read
        --end if;


        -- use ledwatch to check addra  (CHECKEDOU T)
        -- then check dina (CHECKED OUT)
        -- then check wea (NOT CHANGING FAST ENOUGH)
        -- then check douta etc etc make sure it all lines up
        -- douta is not going high, last thing I did last night.
        --LEDWATCH(6 downto 0) <= douta(6 downto 0);
        --LEDWATCH(6) <= ena;
        --LEDWATCH(6) <= douta(0);
        --LEDWATCH(7) <= wea(0);


        -- how to write to mem?
        -- make write enable high
        -- specify address
        -- output to data in?
        -- need to read xapp463 which is the data sheet and
        -- copy the pins

  --LEDWATCH(7 downto 0) <= counter3(31 downto 24);
        --LEDWATCH(7 downto 6) <= previous;
        --LEDWATCH(5 downto 4) <= current;
        --LEDWATCH(3 downto 2) <= xortest;
        --LEDWATCH(1 downto 0) <= target;
        --LEDWATCH <= rotarycount;
        xortest <= current xor previous; --have it run constnatly
        -- so we don't have to worry when debugging whether target
        -- equals current


                if counter(0) = '1' then
                        current(0) <= ROT(0);
                        current(1) <= ROT(1);
                        if current = target then

                                if current = truetarget then
                                --wea <= "1"; --this doesn't work. not enough time see above for better spot for wea
                                        if xortest = CCWPIN then
                                                --LED(2) <= '1';
                                                ROTARYCOUNT <= ROTARYCOUNT-1;
                                                --dina <= rotarycount;
                                        end if;
                                        if xortest = CWPIN then
                                                --LED(3) <= '1'; -- leds are NOT reliable
                                                                                        -- for any fast signals
                                                                                        -- as these missed many
                                                ROTARYCOUNT <= ROTARYCOUNT+1;

                                                -- if write enabled
                                                -- address?
                                                --wea <= "1" ;
                                                --dina <= rotarycount;

                                        end if;
                                        --LED(2) <= '1'; --debug (yellow ch1)
                                        --wea <= "0"; enable this to only read when change
                                end if;
                        target <= PINS XOR target; --invert if equal to target (not truetarget)
                        end if;
                previous <= current;
                --wea <= "0"; enable this to read at all times


                end if;

                if counter = 64000000 then --runs every 0.5 or .4 second
                        --previous <= current; --debug only

                        counter <= (others => '0');
                        --target <= PINS XOR target; works
                else
                        counter  <= counter+1;
                        counter2 <= counter2+1;
                end if;
                if counter2 = 500000000 then

                        counter2 <= (others => '0');
                end if;
        end if;
end process;


end Behavioral;









Resources

  • [1] While the Papilio is obsolete now, and you should probably start with a newer FPGA, it's still now a bad place to start.
  • [2]