FPGARelated.com
Forums

Counter: natural VS std_logic_vector

Started by aleksa January 13, 2009
I need a 1kHz IRQ in my project.
My main clock is 20MHz.

I define my counter in 3 diff ways.

Counting the IRQs FPGA has generated with my
CPU IRQ routine for 10 minutes,
I get 3 diff results:


1.
constant reload : natural := 20000;
signal counter : natural range 0 to 32767;  --15 bit

result= 605000 IRQs generated


2.
constant reload : natural := 20000;
signal counter : natural range 0 to 65535; -- 16 bit

result= 610000 IRQs generated

3.
constant reload : STD_LOGIC_VECTOR (15 downto 0) :=
"0100111000100000"; -- 20000 decimal
signal counter : STD_LOGIC_VECTOR (15 downto 0);

result= 600000 IRQs generated

Only the STD_LOGIC_VECTOR is correct.
Why?

P.S.
How do I write 20000 decimal with STD_LOGIC_VECTOR?
(instead of those ones and zeros)
> > P.S. > How do I write 20000 decimal with STD_LOGIC_VECTOR? > (instead of those ones and zeros)
use ieee.numeric_std.all; constant reload : std_logic_vector(15 downto 0) := std_logic_vector (to_unsigned(20000,16));
>How do I write 20000 decimal with STD_LOGIC_VECTOR? >(instead of those ones and zeros)
hex may appeal to you:20000 = x"4E20"; Where is your counter code? I think you are not counting correctly
On Jan 13, 9:47=A0am, aleksa <aleks...@gmail.com> wrote:
> I need a 1kHz IRQ in my project. > My main clock is 20MHz. > > I define my counter in 3 diff ways. > > Counting the IRQs FPGA has generated with my > CPU IRQ routine for 10 minutes, > I get 3 diff results: > > 1. > constant reload : natural :=3D 20000; > signal counter : natural range 0 to 32767; =A0--15 bit > > result=3D 605000 IRQs generated > > 2. > constant reload : natural :=3D 20000; > signal counter : natural range 0 to 65535; -- 16 bit > > result=3D 610000 IRQs generated > > 3. > constant reload : STD_LOGIC_VECTOR (15 downto 0) :=3D > "0100111000100000"; -- 20000 decimal > signal counter : STD_LOGIC_VECTOR (15 downto 0); > > result=3D 600000 IRQs generated > > Only the STD_LOGIC_VECTOR is correct. > Why? >
I'll guess that the fpga irq output is not the output of a flip flop. Instead it is a combinatorial output that depends on the state of the counter bits and the only reason it 'works' with std_logic_vector is because you got lucky. If so, your luck will run out on some subsequent build. KJ
On Jan 13, 6:13=A0pm, KJ <kkjenni...@sbcglobal.net> wrote:
> On Jan 13, 9:47=A0am, aleksa <aleks...@gmail.com> wrote: > > > > > I need a 1kHz IRQ in my project. > > My main clock is 20MHz. > > > I define my counter in 3 diff ways. > > > Counting the IRQs FPGA has generated with my > > CPU IRQ routine for 10 minutes, > > I get 3 diff results: > > > 1. > > constant reload : natural :=3D 20000; > > signal counter : natural range 0 to 32767; =A0--15 bit > > > result=3D 605000 IRQs generated > > > 2. > > constant reload : natural :=3D 20000; > > signal counter : natural range 0 to 65535; -- 16 bit > > > result=3D 610000 IRQs generated > > > 3. > > constant reload : STD_LOGIC_VECTOR (15 downto 0) :=3D > > "0100111000100000"; -- 20000 decimal > > signal counter : STD_LOGIC_VECTOR (15 downto 0); > > > result=3D 600000 IRQs generated > > > Only the STD_LOGIC_VECTOR is correct. > > Why? > > I'll guess that the fpga irq output is not the output of a flip flop. > Instead it is a combinatorial output that depends on the state of the > counter bits and the only reason it 'works' with std_logic_vector is > because you got lucky. =A0If so, your luck will run out on some > subsequent build. > > KJ- Hide quoted text - > > - Show quoted text -
Counter: if falling_edge(CLKMAIN) then if counter=3D0 then mIRQ <=3D not mIRQ; counter <=3D reload; else counter <=3D counter - 1; end if; end if; CPU ACK: if rising_edge(RD) and ADDR=3DACKADR then mACK <=3D not mACK; end if; Slave tracks master: if falling_edge(CLKMAIN) then if sIRQ /=3D mIRQ then sIRQ <=3D not sIRQ; end if; if sACK /=3D mACK then sACK <=3D not sACK; end if; end if; IRQFLAG: if falling_edge(CLKMAIN) then if sACK /=3D mACK then fIRQ <=3D '0'; elsif sIRQ /=3D mIRQ then fIRQ <=3D '1'; end if; end if; (I have similar code for 3 more counters) IRQ: fIRQANY <=3D fIRQ or fIRQ1 or fIRQ2 or fIRQ3; if falling_edge(CLKMAIN) then if fIRQANY=3D'1' and IRQALLOWED=3D'1' then irqA <=3D '1'; else irqA <=3D '0'; end if; last_fIRQANY <=3D fIRQANY; -- host ACK'ed all flags? if last_fIRQANY=3D'1' and fIRQANY=3D'0' then IRQALLOWED <=3D '0'; elsif IRQCOUNTER=3D7 then -- 400nS inactive irqA IRQALLOWED <=3D '1'; end if; if IRQALLOWED=3D'0' then IRQCOUNTER <=3D IRQCOUNTER+1; end if; end if; Internal signal: IRQ0 <=3D irqA when MODE=3DMODE_A else irqB; Output pin: IRQ <=3D IRQ0 when IEN=3D'1' else 'Z';
I've realized that "Slave tracks master"
can be changed to:

  if falling_edge(CLKMAIN) then
    sIRQ <= mIRQ;
    sACK <= mACK;
  end if;

After doing that, even the std_logic_vector
doesn't work as supposed.

Anyone?
"aleksa" <aleksaZR@gmail.com> wrote in message 
news:d00953ce-136d-4644-8e90-662fd3ebc697@r40g2000yqj.googlegroups.com...
> I've realized that "Slave tracks master" > can be changed to: > > if falling_edge(CLKMAIN) then > sIRQ <= mIRQ; > sACK <= mACK; > end if; > > After doing that, even the std_logic_vector > doesn't work as supposed. > > Anyone?
1. Have you simulated your design, and does it work? 2. Have you run static timing analysis and does it pass? 3. As I alluded to in my first post, Irq coming out of combinatorial logic can be a problem since it could easily glitch and thereby cause a false interrupt to occur. If your processor has an internal timer you can log the times when your FPGA interrupts occur. If there are some that differ significantly from 1ms than you'll be hot on the trail. Kevin Jennings
Try something like..........

use ieee.numeric_std.all;

signal counter : unsigned(big_enough_for_max_value downto 0);
signal irq     : std_logic_vector;


process(clk,rst)
begin
  if(rst = '1') then
    counter <= max_value;
    irq     <= '0';
  elsif(rising_edge(clk)) then
    if(counter = x"00..0") then
        counter <= max_value;
        irq     <= '1';
    else
        counter <= counter - 1;
        irq     <= '0';
    end if;
  end if;
end process;



......simple, compact, synchronous.

Should work (barring typos). Don't forget if you need a count of
X then load the counter with X-1 if you're counting to 0.


Nial 


On Jan 14, 2:37=A0pm, "Nial Stewart"
<nial*REMOVE_TH...@nialstewartdevelopments.co.uk> wrote:
> Try something like.......... > > use ieee.numeric_std.all; > > signal counter : unsigned(big_enough_for_max_value downto 0); > signal irq =A0 =A0 : std_logic_vector; > > process(clk,rst) > begin > =A0 if(rst =3D '1') then > =A0 =A0 counter <=3D max_value; > =A0 =A0 irq =A0 =A0 <=3D '0'; > =A0 elsif(rising_edge(clk)) then > =A0 =A0 if(counter =3D x"00..0") then > =A0 =A0 =A0 =A0 counter <=3D max_value; > =A0 =A0 =A0 =A0 irq =A0 =A0 <=3D '1'; > =A0 =A0 else > =A0 =A0 =A0 =A0 counter <=3D counter - 1; > =A0 =A0 =A0 =A0 irq =A0 =A0 <=3D '0'; > =A0 =A0 end if; > =A0 end if; > end process; > > ......simple, compact, synchronous. > > Should work (barring typos). Don't forget if you need a count of > X then load the counter with X-1 if you're counting to 0. > > Nial
That is how I started, but didn't know how to finish it. (how to generate several IRQs on one pin) I've added two checks in my IRQ routine: 1. read status reg and check if at least one flag is set. (check for glitch - never happened) 2. after servicing each IRQ, issue ACK and re-check if flag still set. That happened (the flag was set even though I've issued ACK) so I've reorganized everything like this: TIMER : process (CLKMAIN) begin -- toggle count-flag when zero if falling_edge(CLKMAIN) then if counterA=3D0 then cIRQA <=3D not cIRQA; counterA <=3D reloadA; else counterA <=3D counterA -1; end if; if counterB=3D0 then cIRQB <=3D not cIRQB; counterB <=3D reloadB; else counterB <=3D counterB -1; end if; if counterC=3D0 then cIRQC <=3D not cIRQC; counterC <=3D reloadC; else counterC <=3D counterC -1; end if; end if; end process TIMER; IRQFLAGS : process (CLKMAIN, RD) begin -- check if count-flag & ack-flag differ if falling_edge(CLKMAIN) then if cIRQA /=3D aIRQA then fIRQA <=3D '1'; else fIRQA <=3D '0'; end if; if cIRQB /=3D aIRQB then fIRQB <=3D '1'; else fIRQB <=3D '0'; end if; if cIRQC /=3D aIRQC then fIRQC <=3D '1'; else fIRQC <=3D '0'; end if; end if; -- SYNCHRONIZE ack flags if rising_edge(CLKMAIN) then aIRQA <=3D aIRQA0; aIRQB <=3D aIRQB0; aIRQC <=3D aIRQC0; end if; -- ACK if rising_edge(RD) and ADDR=3DADRA then aIRQA0 <=3D not aIRQA0; end if; if rising_edge(RD) and ADDR=3DADRB then aIRQB0 <=3D not aIRQB0; end if; if rising_edge(RD) and ADDR=3DADRC then aIRQC0 <=3D not aIRQC0; end if; end process IRQFLAGS; IRQPROC : process (CLKMAIN) begin -- synchro flagIRQ and last_flagIRQ if rising_edge(CLKMAIN) then fIRQANY <=3D fIRQA or fIRQB or fIRQC; lfIRQANY <=3D fIRQANY; end if; -- the IRQ output is connected to a 8259, level sensitive channel. -- keep at least 400nS LOW (inactive) signal. if falling_edge(CLKMAIN) then if fIRQANY=3D'1' and nIRQALLOWED=3D'0' then irqA <=3D '1'; else irq= A <=3D '0'; end if; if lfIRQANY=3D'1' and fIRQANY=3D'0' then nIRQALLOWED <=3D '1'; elsif IRQCOUNTER=3D7 then nIRQALLOWED <=3D '0'; end if; if nIRQALLOWED=3D'1' then IRQCOUNTER <=3D IRQCOUNTER +1; end if; end if; end process IRQPROC; Now the ACK problem is gone, I never see a flag after ACKing it. If all 3 timers are set to 20000, all of them generate exactly the same number of IRQs. If, however, timerA is set to 10000, timerB=3D20000 and timerC=3D30000, then, after 10 minutes, timerA generates 1200115 IRQs, timerB generates 600087 IRQs, timerC generates 400065 IRQs. 400065*3=3D1200195 (80 IRQs diff, should be 1200115) 600087*2=3D1200174 (59 IRQs diff, should be 1200115) The sequence is started/stopped with keyboard and using the hand-watch as a timer for 10 mins, but there should be no more the 1-2 IRQs diff. What can I do to correct this?
> 1. Have you simulated your design, and does it work?
Yes, I've simulated it, and I think it works.
> 2. Have you run static timing analysis and does it pass?
No, don't know how...
> 3. As I alluded to in my first post, Irq coming out of combinatorial logi=
c
> can be a problem since it could easily glitch and thereby cause a false > interrupt to occur. =A0If your processor has an internal timer you can lo=
g the
> times when your FPGA interrupts occur. =A0If there are some that differ > significantly from 1ms than you'll be hot on the trail.
The problem was that my ACKing didn't cleared the IRQflag. I've fixed that, please read my reply to Nial Stewart.