Damien
Damien

Reputation: 1552

Verilog ICE40 LED Driver as IO - SB_IO_OD, how to assign

New to verilog here.

The Ice40 has an RGB led driver that can also be assigned as a normal IO.

Trying to access the pin without setting it as IO will give this error one IceCube2

Error during constrained IO placement E2792: Instance ipInertedIOPad_LED_B incorrectly constrained at SB_IO_OD location

To do so, the following verilog is used:

    SB_IO_OD #(             // open drain IP instance
    .PIN_TYPE(6'b011001)  // configure as output
    ) pin_out_driver (
    .PACKAGEPIN(LED_B), // connect to this pin
    .DOUT0(ledb)           // output the state of "led"
    );

So the final verilog code looks like (simplified to 1 led):

module top (output LED_R, output LED_G, output LED_B);

    reg ledb = 0;

    reg [3:0] cnt;

    SB_IO_OD #(             // open drain IP instance
    .PIN_TYPE(6'b011001)  // configure as output
    ) pin_out_driver (
    .PACKAGEPIN(LED_B), // connect to this pin
    .DOUT0(ledb)           // output the state of "led"
    );

    always
    begin
        ledb = ~cnt[2];
    end

    always @(posedge clkout)
    begin
        cnt <= cnt + 1;
    end

endmodule

and it does work.

However, I assign the led in an always block, which is sequential as I understand. Would the "correct" way to assign ledb as a wire, but then it is not compatible with the SB_IO_OD.

Is this the correct way to do it, or there is a non-sequential way to assign the led, basically not assigning in the always block.

Upvotes: 0

Views: 806

Answers (1)

Damien
Damien

Reputation: 1552

After some digging, I believe this is the correct way. It also uses much less logic cells

Working code on IceCube2, simple LED blinker:

module top (output LED_R, output LED_G, output LED_B);

wire [2:0] leds;
reg [2:0] cnt;

SB_IO_OD #(             // open drain IP instance
.PIN_TYPE(6'b011001)  // configure as output
) pin_out_driver (
.PACKAGEPIN(LED_B), // connect to this pin
.DOUT0(leds[0])           // output the state of "led"
);

SB_IO_OD #(             // open drain IP instance
.PIN_TYPE(6'b011001)  // configure as output
) pin_out_driver2 (
.PACKAGEPIN(LED_G), // connect to this pin
.DOUT0(leds[1])           // output the state of "led"
);

SB_IO_OD #(             // open drain IP instance
.PIN_TYPE(6'b011001)  // configure as output
) pin_out_driver3 (
.PACKAGEPIN(LED_R), // connect to this pin
.DOUT0(leds[2])           // output the state of "led"
);

wire sysclk;

SB_HFOSC #(.CLKHF_DIV("0b00")) osc (
.CLKHFEN(1'b1),
.CLKHFPU(1'b1),
.CLKHF(sysclk) 
) /* synthesis ROUTE_THROUGH_FABRIC = 0 */;

wire clkout;
clockdivider #(.bits(28)) div(
.clkin(sysclk),
.clkout(clkout),
.div(28'd48000000)
);

assign leds  = {~cnt[2:0]};

always @(posedge clkout)
begin
    cnt <= cnt + 1;
end

endmodule

Upvotes: 0

Related Questions