Golborne Vintage Radio

Full Version: Building a Standards Converter
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
Hi Trevor
Its all new to me, I am just stumbling my way through it and there's lots to learn but it is all good fun.
Like many of my projects this is a slow burner and will probably be many months before I get it finished.

Frank
Glad to see you've given yourself more programmable resources to play with. I've done more than enough of trying to cram a design into a device that's only marginally big enough. Not fun. Usually happens when the client wants extra functions added to an existing product.

VHDL is definitely the way to go. Or Verilog if you prefer, but I've not studied that at all. It alows you to concentrate on the logic of what you're trying to do rather than piece together a schematic of so-called standard parts.

The attached file is incredibly useful. It was given to me by a friendly engineer. You can use it as part of a project or simply take the VHDL from it an use it as part of another module. There are many occasions when you will need to convert between boolean and std_logic. Any comparison result is inherently boolean so if you want to use that result as a simple std_logic you need this function.

For example comparing a pair of std_logic_vectors and converting the result to std_logic:
my_std_logic_signal <= to_std_logic(slv1 > slv2);

The other way round, std_logic to boolean is most easily done inline as you need it:
my_boolean <= (my_std_logic = '1');

You've already found that conditional functions such as "if" must have a boolean argument. It's often OK to write things such as:
if CARRY = '1' then COUNT <= COUNT + 1;
end if;

But if CARRY is a boolean type
if CARRY then COUNT <= COUNT + 1;
end if;

A reminder that boolean signals can only take 2 values: true or false. As against std_logic whch usually takes the values 0 or 1. Though it can take others such as U (undefined).
Hi Jeffrey
Thanks for file it will come in extremely useful as things progress.
Schematic entry looked limited in what could be done, creating an array for example would be difficult. Where in VHLD it just takes a couple of lines. 

Schematic entry is a good and fast way of getting an idea of how CPLD's can work. If I hadn’t tried schematic entry first I believe I would have found VHLD much more difficult to grasp. The idea of the processes being executed in parallel is a foreign one to me and would be very difficult to visualize but for I had seen the schematic first.        

Frank
Glad to hear you're getting on OK with VHDL. I'll try to add a few handy hints over the following days. These should include:

Use of clock enables
Correct use of conditional statements (IF, WHEN, WITH and CASE)
Avoiding transparent latches
Libraries and arithmetic.

In many cases you hardly need to know about the physical structure of the device. Just let the tools translate your logical thoughts from VHDL to hardware. Of course if you're going for high performance or short of space then you have more need to know.
As far as possible minimise the number of clocks used in a design. For example when cascading 2 counters the correct way to do it is:

Code:
process (CK) begin
    if rising_edge(CK) then    

-- Count from 0 to 1011, then reset to zero              
               if ACOUNT = "1011" then ACOUNT <= "0000";
               else ACOUNT <= ACOUNT + 1;

    end if; -- CK
end process;


process (CK) begin
    if rising_edge(CK) then    
                  if ACOUNT = "1011" then -- CLock enable

               BCOUNT <= BCOUNT + 1;

               end if;
    end if; -- CK
end process;

Even better, epecially for long counters and high clock speeds, pipeline the terminal count. So within the clocked process write:
A_TERMINAL_COUNT <= ACOUNT = "1010"; -- Note one less due to pipeline

A_TERMINAL_COUNT is conveniently a boolean type.

For long counters it gets tedious writing out the terminal count in binary. You can write in hex but only for exact multiples of 4 bits. You can even write horrors like:
"10" & X"B" for "101011". The nice way to do it is:
conv_std_logic_vector(43,6)
You specify the value as an integer and convert to an SLV. you have to specify the length of the SLV .

Of course you could have specified the counter as an integer in the first place which is fine. Until you need to access individual bits of the counter when you end up with a conversion to SLV (or UNSIGNED) before you can get at the bits separately.

The one occasion where you might want to cascade counters without using colck enables is if you're using a prescaler. This is a real example from a CPLD board that had a 25MHz clock oscillator. This was far higher than I needed so I divided down quite heavily to make the main clock for the design. Meant I didn't have to clock enable everything/

Code:
-------------------------------- Central counters ----------------------------------------------
-- 25MHz down to something more useful
process (CK25MHz) begin
    if rising_edge(CK25MHz) then
    
        CK25MHZ_DIVIDER <= CK25MHZ_DIVIDER + 1;

    end if; -- CK25MHz
end process;

-- Assign main internal clock
CK <= CK25MHZ_DIVIDER(9);

-- Central counter
process (CK) begin
    if rising_edge(CK) then
        CENTRAL_COUNTER <= CENTRAL_COUNTER + 1;    -- 8 bit should be enough
    end if; -- CK
end process;
--===================================================================================================================

One warning when doing this. If you prescale by (say) 10 you'll have a

COUNT = "1001" type of statement. Don't use this as a clock signal until you have put it through a register. It will have glitches on it which will give you random grief.

So just put TERMNAL_COUNT <= "1000" inside the clocked process, thus pipelining it and registering it at the same time. Then you can safely say this outside the clocked process:

MAIN_CLOCK <= TERMINAL_COUNT;

Incidentally, type casting (from boolean to SL, SLV to integer etc does not generate any logic. It's simply changing the way you describe a signal or set of signals. Similarly that statement: MAIN_CLOCK <= TERMINAL_COUNT; doesn't generate any logic though the synthesis engine may introduce a global clock buffer. If I'm doing that sort of thing I will usually instantiate the global buffer explicitly. This can be device dependent, here's a real life example from one of my Xilinx designs:

BLACK2_CLOCK_BUFFER : BUFG port map ( O => BLACK2_CK, I => BLACK2_CK_PRE_BUFG);

PS: The forum software deletes all the indenting Sad
Frank, your comment about processes executing in parallel is a good one. Just because VHDL looks a bit like a procedural computer language (like C or BASIC) doesn't mean that it is one. VHDL and Verilog are primarily hardware description languages. Fortuantely for me I think mainly in hardware rather than software so it comes naturally. On the odd occasions I'm writing procedural software I have to remember the difference.
(14-03-2017, 07:26 AM)ppppenguin Wrote: [ -> ]PS: The forum software deletes all the indenting Sad

No it doesn't; the web browser does.

Surround it in code tags to preserve indents...
Mark, thanks for the hint and also for editing my post to include code tags.
Hi Jeffrey
Thanks again for the tips they are appreciated, I will spend some time studying them.
I haven’t done any more writing yet. Anytime that I’ve had I have spent doing out a spread sheet, to show where the 405 lines lay in relation to the 625 ones.
This in its self is instructive as it shows why the 50:50 interpolater don’t work as well as I had hoped.
When I get the spread sheet finished, from it I will be able to work out the write sequence for the FIFO's and also a table for the interpolater coefficients.

Frank
There's a simple trick for working out the relationship between 405 & 625 on the fly. More information tomorrow
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36