begin
Prescaler : process (compclk)
variable counter : natural range 0 to divider-1 :=0;
variable outx : std_logic := '0';
begin
if (rising_edge(compclk)) then
if counter=divider-1 then
outx := not outx;
counter:=0;
else
counter:=counter+1;
end if;
end if;
clkout <= outx;
end process Prescaler;
dout: out std_logic := '0' --Data Output
....
variable data_register : std_logic_vector(size+1 downto 0) := (others => '0');
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity Trigger is
generic (
cycles : natural := 1
);
port(
compclk: in std_logic;
key : in std_logic; --Clock with witch the Data are Output
cmd : out std_logic := '0' --Enables the Clock Input
);
end Trigger;
architecture Trigger_arch of Trigger is
signal debounce : integer range 0 to cycles-1 :=0;
begin
Trigger : process (compclk)
begin
if (rising_edge(compclk) ) then
if debounce = cycles-1 then
cmd <= '1';
debounce <= 0;
else
cmd <= '0';
if debounce = 0 then
if(key='1') then
debounce <= 1;
end if;
elsif debounce > 0 then
debounce <= debounce+1;
end if;
end if;
end if;
end process Trigger;
end Trigger_arch;
i_PISOsr: PISOsr
generic map ( size => 23)
port map(
compclk => compclk,
assign=> start,
empty=> RegEmpty,
din => DACData, --Data Input
dout=> SOut --Data Output
);
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity maf_serialiser is
Port ( clk : in STD_LOGIC;
trigger : in STD_LOGIC;
sclk : out STD_LOGIC := '1';
sync : out STD_LOGIC := '1';
sout : out STD_LOGIC := '1');
end maf_serialiser;
architecture Behavioral of maf_serialiser is
signal clk_divide : unsigned(7 downto 0) := (others => '0');
constant termincal_count : unsigned(7 downto 0) := to_unsigned(100-1,8);
signal busy_sr: std_logic_vector(24 downto 0) := (others => '1');
signal sync_sr: std_logic_vector(24 downto 0) := (others => '1');
signal data_sr: std_logic_vector(24 downto 0) := (others => '1');
signal trigger_sync : std_logic := '0';
signal trigger_safe : std_logic := '0';
signal phase : std_logic := '0';
signal clk_enable : std_logic := '0';
begin
sync <= sync_sr(sync_sr'high);
sout <= data_sr(data_sr'high);
process(clk)
begin
if rising_edge(clk) then
-- Transmit data in the shift registers
if clk_enable = '1' then
if clk_enable = '1' then
if phase = '1' then
busy_sr <= busy_sr(busy_sr'high-1 downto 0) & '0';
data_sr <= data_sr(busy_sr'high-1 downto 0) & '1';
sync_sr <= sync_sr(busy_sr'high-1 downto 0) & '1';
sclk <= '0';
phase <= '0';
else
sclk <= '1';
phase <= '1';
end if;
end if;
end if;
-- Are in a state that we can accept new data?
if busy_sr(24) = '0' and trigger_safe = '1' then
-- move the new data into the shift registers
busy_sr <= (others => '1');
sync_sr(23 downto 0) <= (others => '0');
data_sr(23 downto 0) <= x"AAAAAA";
end if;
-- Generate the clock enable
if clk_divide = termincal_count then
clk_enable <= '1';
clk_divide <= (others => '0');
else
clk_enable <= '0';
clk_divide <= clk_divide+1;
end if;
-- Synchronise trigger
trigger_safe <= trigger_sync;
trigger_sync <= trigger;
end if;
end process;
end Behavioral;
In PISOsr, you should set the initial value of data_register and dout:
I couldn't get 'trigger' to work, so I rewrote it with what it seems you are trying to do, but closer to my usual style
But here is the most likely problem - the Serialiser and Trigger are being driven by compclk, when maybe it should be driven by sck_clk?
To me it looks like the serialiser (PISOsr) is sending out a very short burst of data very fast, much faster than SCLK.
Also, the input to trigger (key) is not synchronized by back-to-back flipflops. You might end up with intermittent behavior.
A really the cause for your problems may be that you have made three clocks where you only really need one.
As for the traces, what you say is SCLK looks very much like SOut in my simulation.
Here is a contrasting design I knocked up. To send x"AAAAAA" out over the serial port, MSB first.
Uses only one clock domain, and synchornizes the trigger pulse (which can be as short as a single clock cycle).Code: [Select]library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity maf_serialiser is
Port ( clk : in STD_LOGIC;
trigger : in STD_LOGIC;
sclk : out STD_LOGIC := '1';
sync : out STD_LOGIC := '1';
sout : out STD_LOGIC := '1');
end maf_serialiser;
architecture Behavioral of maf_serialiser is
signal clk_divide : unsigned(7 downto 0) := (others => '0');
constant termincal_count : unsigned(7 downto 0) := to_unsigned(100-1,8);
signal busy_sr: std_logic_vector(24 downto 0) := (others => '1');
signal sync_sr: std_logic_vector(24 downto 0) := (others => '1');
signal data_sr: std_logic_vector(24 downto 0) := (others => '1');
signal trigger_sync : std_logic := '0';
signal trigger_safe : std_logic := '0';
signal phase : std_logic := '0';
signal clk_enable : std_logic := '0';
begin
sync <= sync_sr(sync_sr'high);
sout <= data_sr(data_sr'high);
process(clk)
begin
if rising_edge(clk) then
-- Transmit data in the shift registers
if clk_enable = '1' then
if clk_enable = '1' then
if phase = '1' then
busy_sr <= busy_sr(busy_sr'high-1 downto 0) & '0';
data_sr <= data_sr(busy_sr'high-1 downto 0) & '1';
sync_sr <= sync_sr(busy_sr'high-1 downto 0) & '1';
sclk <= '0';
phase <= '0';
else
sclk <= '1';
phase <= '1';
end if;
end if;
end if;
-- Are in a state that we can accept new data?
if busy_sr(24) = '0' and trigger_safe = '1' then
-- move the new data into the shift registers
busy_sr <= (others => '1');
sync_sr(23 downto 0) <= (others => '0');
data_sr(23 downto 0) <= x"AAAAAA";
end if;
-- Generate the clock enable
if clk_divide = termincal_count then
clk_enable <= '1';
clk_divide <= (others => '0');
else
clk_enable <= '0';
clk_divide <= clk_divide+1;
end if;
-- Synchronise trigger
trigger_safe <= trigger_sync;
trigger_sync <= trigger;
end if;
end process;
end Behavioral;
It is missing some ASYNC_REG attributes to make the best of the synchroniser.
if data_register(size downto 0)= 0 then
The Prescaler and PrescalerSCK entities do exactly the same thing, so you don't need to define the two. Just instantiate Prescaler twice. Entities can be instantiated as many times as you wish.
There are some things i have changed in the meantime:
- removed the file PescalerSCK and instead made a new instance of "Prescaler"
-> no effect
The serializer: as I got it, you're using an extra bit to test for the end of transmission instead of using a counter. Why not.
The or_reduce() can be replaced with a simple comparison to 0.Code: [Select]if data_register(size downto 0)= 0 then
You're clocking the serializer with compclk, shouldn't it be with sck_clk?
I really don't like designs with no explicit reset signals. Signal initialization without explicit reset usually works on most FPGAs due to their internal structures, but would most likely fail on bare-metal targets such as ASICs, so I don't recommend doing this for portability reasons.
Since you seem to have issues with sck_clk, have you tried removing everything in your top-level unit except the two prescalers and just output the clocks on IOs?
I did strip it to the internal OSC and the two prescalers. No difference in the Outputs.
Yes that is correct.
Yes that is correct.
That seems really odd. I still suspect that you have somehow got pins mixed up, as there is no way that your code can generate anything but a steady clock with 50% duty cycle.
Simulate it if at all possible.
Yeah, it's odd. I took a look at the .lpf file and there seems to be nothing odd with your pin attribution.
If I get it right, you said you're having this odd problem when using LSE but not with Synplify?
I have encountered a bug in LSE in the past but certainly not on something as trivial as a clock divider... so that's very odd. Have you tried updating Diamond? Your version is a bit dated.
I did strip it to the internal OSC and the two prescalers. No difference in the Outputs.
QuoteI did strip it to the internal OSC and the two prescalers. No difference in the Outputs.
Nothing happens after recompile ?... there is something there: Clean generated files, if needed erase the implementation directory (be careful not to delete your source files!). And re-run the synthesizer: read all messages ! maybe there is something funny with your code. And yes, sometimes if you modify the source files externally (don't know if you did that), they seem to not trigger a full recompile.
You can use the LEDs on the breakboard to show you a version number, that way you can be sure that you run your most recent code.
Simulation alone is sadly not a proof that the "code" works on a real FPGA, but a strong indication.
I'll run a cleanup and recompile, but i am quite shure that i got the right Version, i can change things by changing the Synthesis tool inside of Diamond so the file picked should be correct. But i'll try anyway.
It moaned something like "there is a newer version" but i usualy try to avoide this kind of updates, they mostly do more harm than good. But now facing this kind of trouble one can argue to do the update, but i am still not happy with it.
As you said, a simple clock divider should be possible with either version, shouldn't it?
Had a MachXO2 breakout board (1200ZE) lying in a drawer. So I checked (using Diamond 3.10). And I get exactly the same issue as you.
I added a reset signal, in hope that could be a flip-flop reset problem. Didn't change anything.
I compared the way LSE and Synplify synthesize this, and it's significantly different, but I don't get what's wrong yet. That's puzzling.
What is the frequency of the OSCH clock output? Is it 2.08MHz?
Because that is what the design is constrained for...
Edit: (Just looked at the screen shot, and that seems true).
It moaned something like "there is a newer version" but i usualy try to avoide this kind of updates, they mostly do more harm than good. But now facing this kind of trouble one can argue to do the update, but i am still not happy with it.
Well, I usually update my tools on a regular basis, but before I do, I take a look at the change log to figure out if this is worth it.
Diamond 3.7 is a few minor versions behind, don't remember exactly but it may be 2 years old or something.As you said, a simple clock divider should be possible with either version, shouldn't it?
Yes. I have used version 3.7 and never ran into any issue that I can remember. (The bug I was mentioning was with EBR when using LSE with version 3.9)
Ok, got it.
First, you may notice that the "optimize for area" goal gives a correct behavior with LSE, but not the 2 others (balanced, timing). YMMV depending on your version I guess.
This is a common issue with most FPGAs actually. Clocks generated this way tend to have excessive skew, particularly when using rather "big" counters (10 bits here). Excessive skew can lead to unwillingly creating several clock domains. Some synthesis tools are better than others at minimizing clock skew. And in this particular case, I would at least expect a warning from LSE - and we don't get any. That's bad.
But the only guaranteed way of keeping several derived clocks synchronized is to use the FPGA's embedded clock resources. You can try forcing synthesis to behave with timing constraints, but that's often in vain. (I tried several constraints but to no avail in this case.) LSE does NOT automatically map these dividers to the appropriate clock resources.
I usually use the embedded PLL(s) to generate several synchronized clocks in my designs. You may take a look at the PLL IP of the MachXO2. It's pretty flexible and guarantees clock synchronization.
If you still want to implement dividers "manually", one thing you can do is to do as you would for signals coming from different clock domains: resynchronize the output of your dividers to the same source clock. Another way that works is to clock all your processes from the same clock, and use enable signals to make some processes run slower (once every N clock pulses). That would seem exactly the same, but it's not: when doing this, you don't have clock skew issues.
The Ouptput Frequency seems to be rather limited what means it is not as slow as i wanted it to be but regardless it puts out 800kHz and works.
But now the Crap is coming out of my 'Sync' signal! It drives me f****** mad! Any Ideas?
if(data_register(size-1 downto 0)=0) then
if (data_register(size downto 0)=0) then