diff --git a/controller.vhd b/controller.vhd index 5ff7318..93a393d 100644 --- a/controller.vhd +++ b/controller.vhd @@ -25,44 +25,47 @@ entity controller is end controller; architecture Behavioral of controller is - type states is(S_WAIT, + -- FSM with the following states: + type states is(S_WAIT, -- wait till the lcd is no longer busy, and returns in a specific state afterwards S_FORM_PREF, -- prints the form prefix ("Form:") S_FREQ_PREF, -- frequenz prefix ("Freq: 00000 Hz") S_FORM_CONT, -- form content ("Rechteck, Sinus...") S_FREQ_CONT, -- frequenz content ("-----") - S_IDLE ); + S_IDLE ); -- controller is idle and waits on user input - signal state_reg, state_next : states := S_WAIT; - signal ret_state_reg, ret_state_next: states := S_FORM_PREF; + signal state_reg, state_next : states := S_WAIT; -- Current State + signal ret_state_reg, ret_state_next: states := S_FORM_PREF; -- State to return to, after S_WAIT ----- Edge detection registers ----- signal btn_old_reg, btn_old_next : std_logic := '0'; signal enc_old_reg, enc_old_next: std_logic :='0'; - signal busy_old_reg, busy_old_next : std_logic := '0'; signal form_old_reg, form_old_next : unsigned (1 downto 0) := (others => '0'); - --digitnr which is currently edited 0-4 - signal digpos_reg, digpos_next : unsigned(2 downto 0) := (others => '0'); - signal charcnt_reg, charcnt_next : unsigned(3 downto 0) := (others => '0'); - -- array 5x 4bit(0-9) + signal digpos_reg, digpos_next : unsigned(2 downto 0) := (others => '0'); -- digitnr which is currently edited 0-4 + signal charcnt_reg, charcnt_next : unsigned(3 downto 0) := (others => '0'); -- character number which is currently being written out + + -- Decimal value (0-9) of the sigle frequency digits (array 5x 4bit) type storage_digit is array (0 to 7) of unsigned (3 downto 0); signal digit_reg, digit_next : storage_digit := (others => (others => '0')); - signal lcd_newchar_reg,lcd_newchar_next : std_logic := '0'; - signal lcd_newpos_reg,lcd_newpos_next : std_logic := '0'; - signal lcd_data_reg, lcd_data_next: unsigned(7 downto 0) :=(others => '0'); + signal lcd_newchar_reg,lcd_newchar_next : std_logic := '0'; -- Register for the LCD Newchar signal + signal lcd_newpos_reg,lcd_newpos_next : std_logic := '0'; -- Register for the LCD Newpos signal + signal lcd_data_reg, lcd_data_next: unsigned(7 downto 0) :=(others => '0'); -- Register for the LCD Databus signal - signal freq_out_reg, freq_out_next : unsigned (16 downto 0) := (others => '0'); + signal freq_out_reg, freq_out_next : unsigned (16 downto 0) := (others => '0'); -- Register for the frequency ouput (in hz) ----------------Constants--------------------------------- - + + -- Signal Form Prefix: type character_array_short is array (0 to 7) of character; constant str_form_pref : character_array_short := ( 'F', 'o', 'r','m',':', others => ' ' ); + -- Signal Frequency Prefix/Postfix: type character_array_long is array (0 to 15) of character; constant str_freq_pref : character_array_long := ( 'F', 'r', 'e','q',':',' ','0','0','0','0','0',' ','H','z', others => ' ' ); + -- Signal Form names: type character_form_array is array (0 to 3, 0 to 7) of character; constant str_form : character_form_array := ( ('S','q','u','a','r','e',' ',' '), @@ -71,9 +74,11 @@ architecture Behavioral of controller is ('S','i','n','e',' ',' ',' ',' ') ); + -- Possible improvement: Write a helper function which initializes those character arrays from a string begin + -- State register process (sequential) proc1: process(clk,rst) begin if(rst='1') then @@ -82,7 +87,6 @@ begin btn_old_reg <= '0'; enc_old_reg <='0'; - busy_old_reg <= '0'; form_old_reg <= "00"; charcnt_reg <= (others => '0'); @@ -92,6 +96,7 @@ begin freq_out_reg <=(others => '0'); + -- On reset: wait on display startup and then start with S_FORM_PREF state state_reg <= S_WAIT; ret_state_reg <= S_FORM_PREF; @@ -101,7 +106,6 @@ begin btn_old_reg <= btn_old_next; enc_old_reg <= enc_old_next; - busy_old_reg <= busy_old_next; form_old_reg <= form_old_next; charcnt_reg <= charcnt_next; @@ -117,143 +121,142 @@ begin end if; end process proc1; - - freq_out <= freq_out_reg; lcd_data <= lcd_data_reg; lcd_newchar <= lcd_newchar_reg; lcd_newpos <= lcd_newpos_reg; - NSL: process(digit_reg,enc_right,enc_ce,enc_btn,digpos_reg,btn_old_reg, charcnt_reg, lcd_busy, lcd_data_reg, busy_old_reg, state_reg, ret_state_reg, enc_ce,enc_old_reg, form_old_reg, form) + -- Next State logic process (combinational) + NSL: process(digit_reg,enc_right,enc_ce,enc_btn,digpos_reg,btn_old_reg, charcnt_reg, lcd_busy, lcd_data_reg, state_reg, ret_state_reg, enc_ce,enc_old_reg, form_old_reg, form) begin + -- To avoid latches the most signals are assigned with their previous value (Exceptions marked) digit_next <= digit_reg; digpos_next <= digpos_reg; - - busy_old_next <= lcd_busy; btn_old_next <= btn_old_reg; enc_old_next <= enc_old_reg; form_old_next <= form_old_reg; - charcnt_next <= charcnt_reg; - lcd_newchar_next <= '0'; - lcd_newpos_next <= '0'; + lcd_newchar_next <= '0'; -- next newchar is always 0, becasue normally we dont want to send anything + lcd_newpos_next <= '0'; -- same for newpos lcd_data_next <= lcd_data_reg; - state_next <= state_reg; ret_state_next <= ret_state_reg; -- The next statement produces two warnings which can be safely ignored: -- xst:643 - The result of a <...>-bit multiplication is partially used... - freq_out_next <= resize( - resize(digit_reg(0), 4) - + resize(digit_reg(1) ,4)* 10 - + resize(digit_reg(2) ,7)* 100 - + resize(digit_reg(3) ,10) * 1000 - + resize(digit_reg(4) ,14) * 10000 - , 17); + -- Put together the frequency as a 17 bit vector (in hz) out of the single decimal places + freq_out_next <= resize( resize(digit_reg(0), 4) + + resize(digit_reg(1) ,4)* 10 + + resize(digit_reg(2) ,7)* 100 + + resize(digit_reg(3) ,10) * 1000 + + resize(digit_reg(4) ,14) * 10000 + ,17); + - - case state_reg is - when S_WAIT => -- switch on current state - if(lcd_busy = '0' and busy_old_reg ='1' ) then - state_next<= ret_state_reg; + case state_reg is -- switch on current state + when S_WAIT => -- lcd is currently busy + if(lcd_busy = '0') then --lcd is no longer busy + state_next<= ret_state_reg; -- return to state given by ret_state end if; - when S_FORM_PREF => - state_next <= S_WAIT; - if(charcnt_reg < 7 ) then - charcnt_next <= charcnt_reg + 1; - ret_state_next <= S_FORM_PREF; + when S_FORM_PREF => -- print the form prefix + state_next <= S_WAIT; -- always wait for lcd_busy=0 after this state + if(charcnt_reg < 7 ) then -- not 8 characters written yet: Send characters + charcnt_next <= charcnt_reg + 1; -- increase character position + ret_state_next <= S_FORM_PREF; -- return into this state after wait + -- Output current character (Multiplexer). Implemented as an array lookup with cast from character to ascii value lcd_data_next <= to_unsigned(character'pos(str_form_pref(to_integer(resize(charcnt_reg,3)))),8); - lcd_newchar_next <= '1'; - else - charcnt_next <= (others => '0'); - lcd_data_next <= x"40"; --Start adress for line 2 - lcd_newpos_next <= '1'; - ret_state_next <= S_FREQ_PREF; + lcd_newchar_next <= '1'; -- signal the lcd driver that a new character is ready for writing + else -- all 8 characters written: Change adress to line 2 (as preparation for S_FREQ_PREF) + charcnt_next <= (others => '0'); -- reset charcnt + lcd_data_next <= x"40"; -- Start adress for line 2 + lcd_newpos_next <= '1'; -- signal the lcd driver that a new position is available + ret_state_next <= S_FREQ_PREF; -- continue with S_FREQ_PREF state end if; - when S_FREQ_PREF => - if(charcnt_reg < 15 ) then + + when S_FREQ_PREF => -- print the frequency prefix/postfix + if(charcnt_reg < 15 ) then -- not all 16 characters written yet charcnt_next <= charcnt_reg + 1; state_next <= S_WAIT; ret_state_next <= S_FREQ_PREF; lcd_data_next <= to_unsigned(character'pos(str_freq_pref(to_integer(charcnt_reg))),8); lcd_newchar_next <= '1'; - else + else -- all charcters written charcnt_next <= (others => '0'); - state_next <= S_FORM_CONT; + state_next <= S_FORM_CONT; -- print the Form content now end if; - - - when S_FORM_CONT => + + when S_FORM_CONT => -- print the form content state_next <= S_WAIT; ret_state_next <= S_FORM_CONT; charcnt_next <= charcnt_reg + 1; - if(charcnt_reg < 1 ) then - lcd_data_next <= x"06"; --adress character 7 on line 1 + if(charcnt_reg < 1 ) then -- Step 1: Set address + lcd_data_next <= x"06"; -- adress character 7 on line 1 lcd_newpos_next <= '1'; - elsif(charcnt_reg < 9) then + elsif(charcnt_reg < 9) then -- Step 2 (8x): Print a character of the form lcd_data_next <= to_unsigned(character'pos(str_form(to_integer(form),to_integer(resize(charcnt_reg-1,3)))),8); lcd_newchar_next <= '1'; - else + else -- Step 3: Set adress/cursor back to current digit charcnt_next <= (others => '0'); lcd_data_next <= x"4A" - digpos_reg; -- adress character 11 on line 2 - digit position lcd_newpos_next <= '1'; ret_state_next <= S_IDLE; end if; - when S_FREQ_CONT => + + when S_FREQ_CONT => -- print the frequency content state_next <= S_WAIT; - if(charcnt_reg < 1 ) then + if(charcnt_reg < 1 ) then -- Step 1: Set address for current digit charcnt_next <= charcnt_reg + 1; ret_state_next <= S_FREQ_CONT; lcd_data_next <= x"4A" - digpos_reg; -- adress character 11 on line 2 - digit position lcd_newpos_next <= '1'; - elsif(charcnt_reg = 1) then + elsif(charcnt_reg = 1) then -- Step 2: Print current digit charcnt_next <= charcnt_reg + 1; ret_state_next <= S_FREQ_CONT; lcd_data_next <= to_unsigned(character'pos('0'),8) + digit_reg(to_integer(digpos_reg)); lcd_newchar_next <= '1'; - else + else -- Step 3: Reset adress/cursor back to current digit (auto increment of display cannot be disabled) ret_state_next <= S_IDLE; charcnt_next <= (others => '0'); lcd_data_next <= x"4A" - digpos_reg; -- adress character 11 on line 2 - digit position lcd_newpos_next <= '1'; end if; - when S_IDLE => + + when S_IDLE => -- Controller is idle and wait on user input + -- Update edge dectection helper registers: btn_old_next <= enc_btn; enc_old_next <= enc_ce; form_old_next <= form; - if(form /= form_old_reg) then - state_next <= S_FORM_CONT; - elsif(enc_ce='1' and enc_old_reg ='0') then - if(enc_right='1') then - if(digit_reg(to_integer(digpos_reg)) = to_unsigned(9,4)) then - digit_next(to_integer(digpos_reg)) <= to_unsigned(0,4); - else - digit_next(to_integer(digpos_reg)) <= digit_reg(to_integer(digpos_reg)) + 1; + if(form /= form_old_reg) then -- form changed + state_next <= S_FORM_CONT; -- print form + elsif(enc_ce='1' and enc_old_reg ='0') then -- positive egde on encoder clock enable + if(enc_right='1') then -- encoder was turned right + if(digit_reg(to_integer(digpos_reg)) = to_unsigned(9,4)) then -- digit value = 9 + digit_next(to_integer(digpos_reg)) <= to_unsigned(0,4); -- set digit value to 0 + else -- digit value < 9 + digit_next(to_integer(digpos_reg)) <= digit_reg(to_integer(digpos_reg)) + 1; -- increase digit value end if; - else - if(digit_reg(to_integer(digpos_reg)) = to_unsigned(0,4)) then - digit_next(to_integer(digpos_reg)) <= to_unsigned(9,4); - else - digit_next(to_integer(digpos_reg)) <= digit_reg(to_integer(digpos_reg)) -1; + else -- encoder was turned left + if(digit_reg(to_integer(digpos_reg)) = to_unsigned(0,4)) then -- digit value = 0 + digit_next(to_integer(digpos_reg)) <= to_unsigned(9,4); -- set digit value to 9 + else -- digit value > 0 + digit_next(to_integer(digpos_reg)) <= digit_reg(to_integer(digpos_reg)) -1; -- decrease digit value end if; end if; - state_next <= S_FREQ_CONT; - elsif(enc_btn ='1' and btn_old_reg='0') then - if(digpos_reg = to_unsigned(4,3)) then - digpos_next <= to_unsigned(0,3); - else - digpos_next <= digpos_reg + 1; + state_next <= S_FREQ_CONT; -- print frequency + elsif(enc_btn ='1' and btn_old_reg='0') then -- positive edge on push button + if(digpos_reg = to_unsigned(4,3)) then -- digit_pos = 4 + digpos_next <= to_unsigned(0,3); -- set digit pos = 0 + else -- digit pos < 4 + digpos_next <= digpos_reg + 1; -- increase digit pos end if; - state_next <= S_FREQ_CONT; + state_next <= S_FREQ_CONT; -- print frequency (also updates the cursor position) end if; - when others => null; -- do nothing, if we are in a different state end case; diff --git a/dds.vhd b/dds.vhd index d360d60..c03ff9e 100644 --- a/dds.vhd +++ b/dds.vhd @@ -25,66 +25,72 @@ entity dds is end dds; architecture Behavioral of dds is - signal m, idx : unsigned(acc_res -1 downto 0):= (others => '0'); - signal idx_phase : unsigned(phase_res-1 downto 0) := (others => '0'); - signal amp_rect, amp_saw, amp_tria, amp_sin : unsigned (adc_res-1 downto 0); + signal m, idx : unsigned(acc_res -1 downto 0):= (others => '0'); -- phase jump size and accumulator (see Fundamentals of Direct Digital Synthesis for details about their function) + signal idx_phase : unsigned(phase_res-1 downto 0) := (others => '0'); -- relevant (=leftmost) bits of the phase acccumulator + signal amp_rect, amp_saw, amp_tria, amp_sin : unsigned (adc_res-1 downto 0); -- the current amplitudes of all 4 signal forms + -- Function to genenerate and store the sine wave in the rom. + -- Current code: Only store 1/4 of a sine wave and use symmetries. + -- Uncommented code: Store the entire sine wave (decrease adc_width to 8) type storage is array (((2**phase_res)/4)-1 downto 0) of unsigned (adc_res-2 downto 0); --type storage is array (((2**phase_res))-1 downto 0) of unsigned (adc_res-1 downto 0); function gen_sin_wave return storage is variable temp : storage; begin - forLoop: for i in 0 to temp'high loop + forLoop: for i in 0 to temp'high loop -- for each element in the array temp(i) := to_unsigned(integer(real((2**(adc_res-1))-1)*sin((real(i)*MATH_PI/2.0)/real(temp'high))),adc_res-1); - --temp(i) := to_unsigned(integer(real(2**(adc_res-1) -1) + real((2**(adc_res-1))-1)*sin((real(i)*MATH_PI*2.0)/real(temp'high))),adc_res); - + --temp(i) := to_unsigned(integer(real(2**(adc_res-1) -1) + real((2**(adc_res-1))-1)*sin((real(i)*MATH_PI*2.0)/real(temp'high))),adc_res); end loop; return temp; end function gen_sin_wave; - constant sin_wave : storage := gen_sin_wave; + constant sin_wave : storage := gen_sin_wave; -- rom for sin wave begin + -- Calculate jump size according to input frequency -- m = fout*(2^n)/fclk = fout*((2^n)*(2^k)/fclk)/(2^k) with k=ceil(log2(fclk)), n=acc_res m <= resize( (resize(freq,64) * (shift_left(to_unsigned(1,64),acc_res + log2_int(clk_freq)) / clk_freq)) /to_unsigned(2**log2_int(clk_freq),64),acc_res); + -- Amplitude of the square wave + amp_rect <= to_unsigned(0,adc_res) when idx(acc_res-1)='0' else -- 0 for half of the time + to_unsigned((2**adc_res)-1,adc_res); --1 for the rest + + -- Amplitude of the sawtooth wave + amp_saw <= idx(acc_res -1 downto acc_res - adc_res); -- Exactly the value of the uppermost bits of the phase acc + + -- Amplitude of the triangle wave + amp_tria <= idx(acc_res -2 downto acc_res - adc_res - 1) -- The value of the uppermost bits, except the uppermost one (= double the frequency) + when idx(acc_res-1)='0' else -- during half of the time + ((2**adc_res)-1)- (idx(acc_res -2 downto acc_res - adc_res - 1)); -- and the complement, the rest of the time - amp_rect <= to_unsigned(0,adc_res) when idx(acc_res-1)='0' else - to_unsigned((2**adc_res)-1,adc_res); - - amp_saw <= idx(acc_res -1 downto acc_res - adc_res); - - amp_tria <= idx(acc_res -2 downto acc_res - adc_res) & "0" - when idx(acc_res-1)='0' else - ((2**adc_res)-1)- (idx(acc_res -2 downto acc_res - adc_res) & "0"); - + idx_phase <= idx(acc_res -1 downto acc_res - phase_res); -- take only the uppermost bits for the sine lookup - - idx_phase <= idx(acc_res -1 downto acc_res - phase_res); - - --amp_sin <= sin_wave(to_integer(idx_phase)); + -- Amplitude of the sine wave + -- Code if we had stored the whole sinewave: + -- amp_sin <= sin_wave(to_integer(idx_phase)); + -- Current Code (only 1/4 of the sine wave stored) amp_sin <= to_unsigned((2**(adc_res-1)) - 1,adc_res) + sin_wave(to_integer(idx_phase(phase_res-3 downto 0))) when idx_phase(phase_res-1 downto phase_res-2)="00" else to_unsigned((2**(adc_res-1)) - 1,adc_res) + sin_wave(to_integer(((2**(phase_res-2))-1) - idx_phase(phase_res-3 downto 0))) when idx_phase(phase_res-1 downto phase_res-2)="01" else to_unsigned((2**(adc_res-1)) - 1,adc_res) - sin_wave(to_integer(idx_phase(phase_res-3 downto 0))) when idx_phase(phase_res-1 downto phase_res-2)="10" else to_unsigned((2**(adc_res-1)) - 1,adc_res) - sin_wave(to_integer(((2**(phase_res-2))-1) - idx_phase(phase_res-3 downto 0))); - + + -- Output the selected amplitue using a multiplexer (00=Rectancle, 01=Sawtooth, 10=Triangle, 11=Sine) amp <= to_unsigned(0,adc_res) when freq = to_unsigned(0,freq_res) else amp_rect when form = "00" else amp_saw when form ="01" else amp_tria when form = "10" else amp_sin; + -- Process for the phase accumulator (sequential) P1: process(clk) begin if(rising_edge(clk)) then - idx <= (idx+m); + idx <= (idx+m); -- increment phase accumulator according to jump size. overflow is wanted. end if; end process P1; - - end Behavioral; diff --git a/rotary.vhd b/rotary.vhd index b7c1f87..b9b5745 100644 --- a/rotary.vhd +++ b/rotary.vhd @@ -14,7 +14,7 @@ entity rotary_dec is Port ( clk : in std_logic; -- Clock Input A : in std_logic; -- Signal A B : in std_logic; -- Signal B - btn : in std_logic; -- Button Input + btn : in std_logic; -- Button Input btn_deb : out std_logic; -- Button Output Debonced enc_right: out std_logic; -- Direction Output: 1=right enc_ce : out std_logic); -- Clock Enable Output for signal above @@ -23,44 +23,48 @@ end rotary_dec; architecture Behavioral of rotary_dec is -signal a_old, b_old: std_logic := '0'; -signal a_debounced_reg, a_debounced_next, b_debounced_reg, b_debounced_next : std_logic := '0'; -signal btn_reg, btn_next: std_logic :='0'; -signal counter_a_reg, counter_a_next, +signal a_old, b_old: std_logic := '0'; -- Registers for edge detection on debounced A, B signals +signal a_debounced_reg, a_debounced_next, -- Registers for debouncing A, B signals + b_debounced_reg, b_debounced_next : std_logic := '0'; +signal btn_reg, btn_next: std_logic :='0'; -- Registers for debouncing Button Press signal +signal counter_a_reg, counter_a_next, -- Counters to smooth chittering = debounce signals counter_b_reg, counter_b_next, counter_btn_reg, counter_btn_next: unsigned(23 downto 0) := (others => '0'); -constant count_max: unsigned(23 downto 0) := to_unsigned(500000,24); --10ms +constant count_max: unsigned(23 downto 0) := to_unsigned(500000,24); --Number of cycles during which a signal can't change it's value 50mhz*10ms= 500000 cycles begin +-- State register process (sequential) process(clk) begin if rising_edge(clk) then counter_a_reg <= counter_a_next; counter_b_reg <= counter_b_next; counter_btn_reg <= counter_btn_next; + a_debounced_reg <= a_debounced_next; b_debounced_reg <= b_debounced_next; + btn_reg <= btn_next; + a_old <= a_debounced_reg; b_old <= b_debounced_reg; - btn_reg <= btn_next; end if; end process; - -btn_deb <= btn_reg; - +-- Debounce process (combinational) process(A,B, a_debounced_reg, b_debounced_reg, counter_a_reg, counter_b_reg, btn_reg, btn, counter_btn_reg) begin + -- If signal a has changed (edge detection) and enough time passed since the last change if(A /= a_debounced_reg and counter_a_reg > count_max) then - a_debounced_next <= A; - counter_a_next <= (others => '0'); - else - a_debounced_next <= a_debounced_reg; - counter_a_next <= counter_a_reg + 1; + a_debounced_next <= A; -- accept change + counter_a_next <= (others => '0'); -- reset counter + else -- singal has not changed, or not enough time has passed + a_debounced_next <= a_debounced_reg; -- keep old signal value + counter_a_next <= counter_a_reg + 1; -- increase counter by one end if; + -- Same as above for signal B if(B /= b_debounced_reg and counter_b_reg > count_max) then b_debounced_next <= B; counter_b_next <= (others => '0'); @@ -69,6 +73,7 @@ begin counter_b_next <= counter_b_reg + 1; end if; + -- Same as above for button press signal if(btn /= btn_reg and counter_btn_reg > count_max) then btn_next <= btn; counter_btn_next <= (others => '0'); @@ -79,17 +84,20 @@ begin end process; + +btn_deb <= btn_reg; --Output debounced btn reg --- Dekodierung der Ausgaenge - +-- Ouput decode for Rotary Signals (A,B) process(a_debounced_reg, b_debounced_reg, a_old, b_old) variable state: std_logic_vector(3 downto 0); begin - state := a_debounced_reg & b_debounced_reg & a_old & b_old; + state := a_debounced_reg & b_debounced_reg & a_old & b_old; -- Concat to vector case state is when "0001" => enc_right <= '0'; enc_ce <= '1'; when "0010" => enc_right <= '1'; enc_ce <= '1'; when others => enc_right <= '0'; enc_ce <= '0'; + -- If you want a finer resolution you can simply add more cases here. + -- In our case we only have 1 case for left, and one for right, which works fine. end case; end process; diff --git a/spi_driver.vhd b/spi_driver.vhd index 2756661..7d7ee0f 100644 --- a/spi_driver.vhd +++ b/spi_driver.vhd @@ -22,11 +22,12 @@ entity spi_driver is end spi_driver; architecture Behavioral of spi_driver is - type states is(S_IDLE, S_WORK); - signal state_reg, state_next: states := S_IDLE; - signal counter_reg, counter_next: unsigned(5 downto 0) := (others => '0'); - signal shift_reg, shift_next: unsigned(19 downto 0):= (others => '0'); + type states is(S_IDLE, S_WORK); -- FSM: Idle and Work State + signal state_reg, state_next: states := S_IDLE; -- Current and next state register + signal counter_reg, counter_next: unsigned(5 downto 0) := (others => '0'); -- Counter for the bit nr + signal shift_reg, shift_next: unsigned(19 downto 0):= (others => '0'); -- Shift reg for the ouput begin + -- State register process (combinational) REGS: process (clk, rst) is begin -- process start if rst = '1' then -- asynchronous reset (active high) @@ -40,32 +41,35 @@ begin end if; end process REGS; - mosi <= shift_reg(shift_reg'high) when state_reg=S_WORK else '0'; - sck <= '1' when state_reg=S_WORK and counter_reg(0)='1' else '0'; - cs <= '1' when state_reg =S_IDLE else '0'; + mosi <= shift_reg(shift_reg'high) when state_reg=S_WORK else '0'; -- Mosi: Highest value of shift reg when in Work state, otherwise 0 + sck <= '1' when state_reg=S_WORK and counter_reg(0)='1' else '0'; -- Sck: High when in work state and lowest bit 1 (shift will be performed when lowest bit = 0) + cs <= '0' when state_reg =S_WORK else '1'; -- Cs (low active): Low when in state work + -- Next State logic process (combinational) NSL: process (state_reg, counter_reg, shift_reg, val) is begin state_next <= state_reg; counter_next <= counter_reg; shift_next <= shift_reg; + case state_reg is -- switch on current state when S_IDLE => -- currently in idle state state_next <= S_WORK; counter_next <= to_unsigned(0,counter_reg'length); - shift_next(19 downto 16) <= "0011"; --Command: Write to and Update (Power Up) - shift_next(15 downto 12) <= "0000"; --Adress: DAC0 - shift_next(11 downto 0) <= val; -- DAC Value (12bit) + -- Initialize shift reg + shift_next(19 downto 16) <= "0011"; -- Command: Write to and Update (Power Up) + shift_next(15 downto 12) <= "0000"; -- Adress: DAC0 + shift_next(11 downto 0) <= val; -- DAC Value (12bit) --shift_next(0 downto -3) <= "XXXX"; -- 4x don't care when S_WORK => -- currently in work state - if(counter_reg = 24*2 -1) then - state_next <= S_IDLE; - else - counter_next<= counter_reg + 1; + if(counter_reg = 24*2 -1) then -- all bits sent + state_next <= S_IDLE; -- return to idle state + else -- not all bits sent + counter_next<= counter_reg + 1; -- increase bit counter end if; - if(counter_reg(0)='1') then + if(counter_reg(0)='1') then -- peform shift when lowest bit = 1, shift will be performed when bit = 0 shift_next <= shift_left(shift_reg,1); end if; when others => null; -- do nothing, if we are in a different state