Search code examples
vhdlice40

Using the SB_RGBA_DRV primitive in VHDL


I'm having trouble using the SB_RGBA_DRV primitive provided for the Lattice ICE40UP fpga. The Technology Library provides a verilog example which I got to work but when i try using it in VHDL the P&R fails, outputting the following message:

Error: Illegal Connection: Pin 'RGB2' of instance 'myrgb' of type 'SB_RGBA_DRV' should be connected to only one top module port. It is connected to the following terminals : LED2_obuf/DOUT0

This is my .vhdl file:

library ieee;
use ieee.std_logic_1164.all;

entity led is
    port (
        LED0        : out   std_logic;
        LED1        : out   std_logic;
        LED2        : out   std_logic
    );
end entity led;

architecture rtl of led is

component SB_HFOSC is
    port (
        CLKHFEN : in std_logic;
        CLKHFPU : in std_logic;
        CLKHF   : out std_logic 
    );
end component;

component SB_RGBA_DRV is
    generic (
        RGB0_CURRENT: string:="0b000000"; 
        RGB1_CURRENT: string:="0b000000";
        RGB2_CURRENT: string:="0b000000"
    );
    port (  
        RGBPU : in std_logic;
        RGBLEDEN : in std_logic;
        RGB0PWM : in std_logic;
        RGB1PWM : in std_logic;
        RGB2PWM : in std_logic;
        RGB0 : out std_logic;
        RGB1 : out std_logic;
        RGB2 : out std_logic    
        );
end component;

signal int_osc : std_logic;

begin

myosc : SB_HFOSC
    PORT MAP (
        CLKHFEN => '1',
        CLKHFPU => '1',
        CLKHF => int_osc
    );

    myrgb : SB_RGBA_DRV
    GENERIC MAP (
        RGB0_CURRENT => "0b111111",
        RGB1_CURRENT => "0b111111",
        RGB2_CURRENT => "0b111111"
    )
    PORT MAP (
        RGBPU => '1',
        RGBLEDEN => '1',
        RGB0PWM => '1',
        RGB1PWM => '1',
        RGB2PWM => '1',
        RGB0    => LED0,
        RGB1    => LED1,
        RGB2    => LED2
    );

process
    begin
        wait until int_osc'event;
end process;


end rtl;

Solution

  • The answer to your question is here:

    http://we.easyelectronics.ru/teplofizik/podklyuchenie-vstroennogo-modulya-tokovogo-drayvera-fpga-serii-ice5-ice40-ultra.html

    (Scroll down.) Yes, it's in Russian. The key is to add the following declaration at the top of your design file:

    library sb_ice40_components_syn;
    use sb_ice40_components_syn.components.all;
    

    The other things that Teplofizik mentions may be useful to know but aren't entirely necessary.

    Your code is almost correct with the above addition. I didn't try to build and run Teplofizik's sample code, but I did modify your code (to actually use the on-chip oscillator) and that code is happily running on an "iCE40UP Breakout" board:

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    library sb_ice40_components_syn;
    use sb_ice40_components_syn.components.all;
    
    entity led is
        port (
            LED0        : out   std_logic;
            LED1        : out   std_logic;
            LED2        : out   std_logic
        );
    end entity led;
    
    architecture rtl of led is
    
    -- not necessary - declared in library
    --component SB_HFOSC is
    --    port (
    --        CLKHFEN : in std_logic;
    --        CLKHFPU : in std_logic;
    --        CLKHF   : out std_logic 
    --    );
    --end component;
    --
    --component SB_RGBA_DRV is
    --    generic (
    --        RGB0_CURRENT: string:="0b000000"; 
    --        RGB1_CURRENT: string:="0b000000";
    --        RGB2_CURRENT: string:="0b000000"
    --    );
    --    port (  
    --        RGBPU : in std_logic;
    --        RGBLEDEN : in std_logic;
    --        RGB0PWM : in std_logic;
    --        RGB1PWM : in std_logic;
    --        RGB2PWM : in std_logic;
    --        RGB0 : out std_logic;
    --        RGB1 : out std_logic;
    --        RGB2 : out std_logic    
    --        );
    --end component;
    
    signal int_osc : std_logic;
    signal count:   unsigned(25 downto 0);
    signal led0_en: std_logic;
    signal led1_en: std_logic;
    signal led2_en: std_logic;
    
    begin
    
    myosc : SB_HFOSC
        generic map(
            CLKHF_DIV => "0b00"     -- 00 = 48 MHz, 01 = 24 MHz, 10 = 12 MHZ, 11 = 6 MHz
        )
        PORT MAP (
            CLKHFEN => '1',
            CLKHFPU => '1',
            CLKHF => int_osc
        );
    
        myrgb : SB_RGBA_DRV
        GENERIC MAP (
    --        RGB0_CURRENT => "0b111111",
    --        RGB1_CURRENT => "0b111111",
    --        RGB2_CURRENT => "0b111111"
            CURRENT_MODE => "0b0",      -- 0 = full current, 1 = halve the current
            RGB0_CURRENT => "0b000001", -- 4 mA is more than enough
            RGB1_CURRENT => "0b000001",
            RGB2_CURRENT => "0b000001"
        )
        PORT MAP (
    --        RGBPU => '1',     -- this is an SB_RGB_DRV parameter
            CURREN => '1',
            RGBLEDEN => '1',
    --        RGB0PWM => '1',   -- boring
    --        RGB1PWM => '1',
    --        RGB2PWM => '1',
            RGB0PWM => led0_en,
            RGB1PWM => led1_en,
            RGB2PWM => led2_en,
            RGB0    => LED0,
            RGB1    => LED1,
            RGB2    => LED2
        );
    
        -- boring
    --process
    --    begin
    --        wait until int_osc'event;
    --end process;
    
        -- cycle through LED's
    
        led0_en <= count(25) and count(24);
        led1_en <= count(25) and not count(24);
        led2_en <= not count(25) and count(24);
    
        count_proc: process(int_osc)
        begin
            if rising_edge(int_osc) then
                count <= count+1;
            end if;
        end process;
    
    end rtl;