Emperor Napoleon Posted April 28, 2013 Report Share Posted April 28, 2013 Hi, the emperor would like to ask for your thoughts on how best to buffer the ZPUino's compare values (prescaler too but less critical). Yes, I am a VHDL n00b. The idea is that any compare value settings would not take effect until the next overflow event. This is helpful when changing the frequency of the timer to avoid unnatural states. Below is a diff on how to turn a "timer" into a "timer2", the difference being, a "timer2" should buffer its prescaler and compare registers (just like the PWM channels). I am not sure if anything is wrong with the below code, although i have run into an apparent issue where I hear audio pops when i listen to PWM output and I make little changes to the timer frequency. * Not actually an audio project, this is just how I debug.* It doesn't happen when buffering is disabled, or when I set the update mode to "NOW", or when I just swap in the "timer" for the "timer2"* I still think buffering is important for smooth frequency adjustments without occasional glitches ..... is this true? That is unfortunately all I know... I don't know how to simulate anything and I don't know whats going on inside the fpga's head. Nothing helpful to be seen on the scope because the pops are too brief. The emperor would like to thank you for any insights, advice, or harsh criticism. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; library work; use work.zpu_config.all; use work.zpupkg.all; use work.zpuinopkg.all; -entity timer is+entity timer2 is generic ( TSCENABLED: boolean := false; PWMCOUNT: integer range 1 to 8 := 2; WIDTH: integer range 1 to 32 := 16; PRESCALER_ENABLED: boolean := true; BUFFERS: boolean := true ); port ( wb_clk_i: in std_logic; wb_rst_i: in std_logic;@@ -59,23 +59,23 @@ wb_adr_i: in std_logic_vector(5 downto 0); wb_we_i: in std_logic; wb_cyc_i: in std_logic; wb_stb_i: in std_logic; wb_ack_o: out std_logic; wb_inta_o: out std_logic; pwm_out: out std_logic_vector(PWMCOUNT-1 downto 0) );-end entity timer;+end entity timer2; -architecture behave of timer is+architecture behave of timer2 is component prescaler is port ( clk: in std_logic; rst: in std_logic; prescale: in std_logic_vector(2 downto 0); event: out std_logic ); end component prescaler; @@ -93,20 +93,22 @@ ccm: std_logic; -- clear on compare match en: std_logic; -- enable dir: std_logic; -- direction ien: std_logic; -- interrupt enable intr: std_logic; -- interrupt pres: std_logic_vector(2 downto 0); -- Prescaler updp: std_logic_vector(1 downto 0); presrst: std_logic; pwmr: pwmregs; pwmrb:pwmregs;+ cmpb: unsigned(WIDTH-1 downto 0);+ presb: std_logic_vector(2 downto 0); end record; constant UPDATE_NOW: std_logic_vector(1 downto 0) := "00"; constant UPDATE_ZERO_SYNC: std_logic_vector(1 downto 0) := "01"; constant UPDATE_LATER: std_logic_vector(1 downto 0) := "10"; signal tmr0_prescale_rst: std_logic; --signal tmr0_prescale: std_logic_vector(2 downto 0); signal tmr0_prescale_event: std_logic;@@ -214,50 +216,58 @@ do_interrupt <= '0'; if wb_rst_i='1' then w.en := '0'; w.ccm := '0'; w.dir := '0'; w.ien := '0'; w.pres := (others => '0'); w.presrst := '1';- w.updp := UPDATE_ZERO_SYNC;+ w.updp := UPDATE_NOW; for i in 0 to PWMCOUNT-1 loop w.pwmrb(i).en :='0'; w.pwmr(i).en :='0'; end loop; else if do_interrupt='1' then w.intr := '1'; end if; w.presrst := '0'; -- Wishbone access if write_ctrl='1' then w.en := wb_dat_i(0); w.ccm := wb_dat_i(1); w.dir := wb_dat_i(2); w.ien := wb_dat_i(3);+ if BUFFERS then+ w.presb:= wb_dat_i(6 downto 4);+ else w.pres:= wb_dat_i(6 downto 4);+ end if; w.updp := wb_dat_i(10 downto 9); if wb_dat_i(7)='0' then w.intr:='0'; end if; end if; if write_cmp='1' then+ if BUFFERS then+ w.cmpb := unsigned(wb_dat_i(WIDTH-1 downto 0));+ else w.cmp := unsigned(wb_dat_i(WIDTH-1 downto 0)); end if;+ end if; if write_cnt='1' then w.cnt := unsigned(wb_dat_i(WIDTH-1 downto 0)); else if tmrr.en='1' and tmr0_prescale_event='1' then -- If output matches, set interrupt if ovf='1' then if tmrr.ien='1' then do_interrupt<='1'; end if;@@ -313,23 +323,27 @@ end if; end if; end loop; end if; if BUFFERS then for i in 0 to PWMCOUNT-1 loop case tmrr.updp is when UPDATE_NOW => w.pwmr(i) := tmrr.pwmrb(i);+ w.cmp := w.cmpb;+ w.pres := w.presb; when UPDATE_ZERO_SYNC => if ovf='1' then w.pwmr(i) := tmrr.pwmrb(i);+ w.cmp := w.cmpb;+ w.pres := w.presb; end if; when UPDATE_LATER => --if wb_adr_i(3 downto 2) = std_logic_vector(to_unsigned(i,2)) then -- if wb_adr_i(1 downto 0)="11" then -- w.pwmr(i) := tmrr.pwmrb(i); -- end if; -- end if; when others => --w.pwmr(i) := tmrr.pwmrb(i); Link to comment Share on other sites More sharing options...
This topic is now archived and is closed to further replies.