How to use the internal oscillator in an FPGA (Lattice MachXO3)?

2.3k Views Asked by At

I'm trying to make a Blink-LED program for a Lattice MachXO3L breakout board. I believe I have the internal-oscillator set up, I just don't know how to connect to its output and make use of it, I get errors when I try. This is on a breakout board which has an LED and a switch. It should oscillate at 1Hz when the switch is flipped one way, and be off when the switch is flipped the other way.

I'e read the PLL usage guide and searched for answers on the internet. I believe I'm close, and just hung up on some syntax issue due to being new to VHDL & FPGAs. Basically, my main code is the 'process and all code below it. Anything above that is basically stuff from the PLL usage guide.

library ieee;
use ieee.std_logic_1164.all;
library machxo3l;
use machxo3l.all;

entity led_blink is
    port (
        i_switch_1  : in std_logic;
        o_led_1     : out std_logic;
        i_clock     : in std_logic;
        osc_int     : out std_logic
    );
end led_blink;

architecture rtl of led_blink is
    COMPONENT OSCH
    -- synthesis translate_off
    GENERIC (NOM_FREQ: string := "12.09");
    -- synthesis translate on
    PORT (  STDBY:IN std_logic;
            OSC:OUT std_logic);
    END COMPONENT;

    attribute NOM_FREQ : string;
    attribute NOM_FREQ of OSCHinst0 : label is "12.09";

    constant C_CNT_1HZ      : natural := 6000000;

    signal R_CNT_1HZ        : natural range 0 to C_CNT_1HZ;

    signal R_1HZ            : std_logic := '0';

begin

OSCHInst0: OSCH
-- synthesis translate_off
    GENERIC MAP(NOM_FREQ => "12.09")
-- synthesis translate on
    PORT MAP (STDBY => '0',
    OSC             => osc_int
    );

p_1HZ : process (i_clock) is
begin
    if rising_edge(i_clock) then
        if R_CNT_1HZ     = C_CNT_100HZ-1 then
            R_1HZ       <= not R_1Hz;
            R_CNT_1HZ       <= 0;
        else
            R_CNT_1HZ   <= R_CNT_1HZ + 1;
        end if;
    end if;
end process;

osc_int <= i_clock;

o_led_1     <= R_1HZ        when (i_switch_1 = '0') else not R_1HZ;
end rtl;

If I try and assign osc_int to the sensitivity list of the p_1Hz process, I get an error stating that I can not read from an output.

Just a side-note in case other viewers get confused like me, driving i_clock from osc_int appears illogical, because it uses an assignment that seems to suggest the reverse occurs osc_int <= i_clock. Correct me if I'm wrong, but it's assigning an input, to an output, which appears confusing to non-hdl programmers because the direction is decided by the input/output types, rather than the assignment operator itself.

When I do this (link i_clk to osc_int), it saves without giving me errors, it isn't until I try to synthesize the code that it says there are multiple non-tristate drivers for i_clock. The only way I can imagine this being true is if the 'port' from the 'component' section named OSC, being mapped to osc_int, creates two driving signals both linked to i_clock in that single osc_int <= i_clock; statement. But if that's true, how would you access the clock's output at all?

If I just remove the osc_int <= i_clock statement, it works, just with the LED constantly-on/constantly-off, not oscillating/constantly-off.

1

There are 1 best solutions below

0
On

The clock generated came from inside the OSCH component. Then you don't need any i_clock to achieve what you want. The output of the internal oscillator is the OUT port of the OSCH component.

you can try this :

entity led_blink is
    port (
        i_switch_1  : in std_logic;    -- from the input switch : OK
        o_led_1     : out std_logic    -- to the blinking led   : OK 
    );
end led_blink;
architecture rtl of led_blink is
    COMPONENT OSCH
      -- synthesis translate_off
      GENERIC (NOM_FREQ: string := "12.09");
      -- synthesis translate on
      PORT (  STDBY:IN std_logic;
              OSC:OUT std_logic);
    END COMPONENT;

    attribute NOM_FREQ : string;
    attribute NOM_FREQ of OSCHinst0 : label is "12.09";

    constant C_CNT_1HZ      : natural := 6000000;

    signal R_CNT_1HZ        : natural range 0 to C_CNT_1HZ := 0;

    signal R_1HZ            : std_logic := '0';

begin

OSCHInst0: OSCH
-- synthesis translate_off
    GENERIC MAP(NOM_FREQ => "12.09")
-- synthesis translate on
    PORT MAP (STDBY => '0',
    OSC             => osc_int -- <= this is the 12.09MHz internal clock from the internal oscillator
    );

p_1HZ : process (osc_int) is
begin
    if rising_edge(osc_int) then
        if R_CNT_1HZ     = C_CNT_100HZ-1 then
            R_1HZ       <= not R_1Hz;
            R_CNT_1HZ       <= 0;
        else
            R_CNT_1HZ   <= R_CNT_1HZ + 1;
        end if;
    end if;
end process;


o_led_1     <= R_1HZ        when (i_switch_1 = '0') else '0';
end rtl;