Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions hdl/pattern/moving_pix.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
`timescale 1ns / 1ps
`include "common/evt_counter.sv"
`default_nettype none // prevents system from inferring an undeclared logic (good practice)


module moving_pix #(
parameter int CLOCK_SPEED = 100_000_000, // 100MHz
parameter int NUM_LEDS = 20, // !!! ASSUMES STRAND DRIVER HAS MORE LEDS (next_led_request >= NUM_LEDS)
parameter int FRAMES_PER_LED = 100,
parameter int COLOR_WIDTH = 8,
parameter int GREEN_VAL = 8'hFF,
parameter int RED_VAL = 8'hFF,
parameter int BLUE_VAL = 8'hFF,
localparam int LED_COUNTER_WIDTH = $clog2(NUM_LEDS),
localparam int FRAME_COUNTER_WIDTH = $clog2(FRAMES_PER_LED)
)
(
input wire rst_in, // active high
input wire clk_in, // 100MHz
input wire [LED_COUNTER_WIDTH-1:0] next_led_request,
input wire request_valid,
output logic [COLOR_WIDTH-1:0] green_out,
output logic [COLOR_WIDTH-1:0] red_out,
output logic [COLOR_WIDTH-1:0] blue_out,
output logic color_ready
);

logic [LED_COUNTER_WIDTH-1:0] current_pixel_idx;
logic [LED_COUNTER_WIDTH-1:0] last_pixel_request;
logic [FRAME_COUNTER_WIDTH-1:0] num_strand_frames;
logic cur_pix_displayed;
assign cur_pix_displayed = ((last_pixel_request != next_led_request) && (last_pixel_request == current_pixel_idx));
logic displayed_prev_led;

always_ff @(posedge clk_in) begin
if (rst_in) begin
// Reset all states
current_pixel_idx <= 0;
last_pixel_request <= next_led_request;
num_strand_frames <= 0;
green_out <= 8'h00;
red_out <= 8'h00;
blue_out <= 8'h00;
color_ready <= 0;
displayed_prev_led <= 0;
end else begin
// Update num_strand_frames too keep track of how many frames we display current_pixel_idx
last_pixel_request <= next_led_request;
if (cur_pix_displayed) begin
if (num_strand_frames == FRAMES_PER_LED - 1) begin
// Increment current pixel index to display
current_pixel_idx <= (current_pixel_idx == NUM_LEDS - 1) ? 0 : current_pixel_idx + 1;
displayed_prev_led <= 1;
end else begin
displayed_prev_led <= 0;
end
// handle looping and skipping next led on last frame of current led
num_strand_frames <= (displayed_prev_led) ? 0 : (num_strand_frames == FRAMES_PER_LED - 1) ? 0 : num_strand_frames + 1;
end

// Respond to requests
if (next_led_request == current_pixel_idx && !displayed_prev_led) begin
green_out <= GREEN_VAL;
red_out <= RED_VAL;
blue_out <= BLUE_VAL;
color_ready <= 1;
end else begin
green_out <= 8'h00;
red_out <= 8'h0A;
blue_out <= 8'h00;
color_ready <= 1;
end
end
end

endmodule
`default_nettype wire
24 changes: 20 additions & 4 deletions hdl/top_level.sv
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
`timescale 1ns / 1ps // (comment to prevent autoformatting)
`include "driver/led_driver.sv"
`include "pattern/pat_gradient.sv"
`include "pattern/moving_pix.sv"
`include "clk/cw_hdmi_clk_wiz.v"
`include "clk/cw_fast_clk_wiz.v"
`include "cam/camera_reader.sv"
Expand All @@ -17,10 +18,11 @@
`default_nettype none

module top_level #(
parameter int NUM_LEDS = 10,
parameter int NUM_LEDS = 50,
parameter int COLOR_WIDTH = 8,
localparam int CounterWidth = $clog2(NUM_LEDS)
) (

input wire clk_100mhz,
output logic [15:0] led,
// camera bus
Expand Down Expand Up @@ -53,17 +55,31 @@ module top_level #(
logic [CounterWidth-1:0] next_led_request;

// instantiate pattern modules
pat_gradient #(
// pat_gradient #(
// .NUM_LEDS(NUM_LEDS),
// .COLOR_WIDTH(COLOR_WIDTH)
// ) pat_gradient_inst (
// .rst_in(sys_rst_led),
// .clk_in(clk_100_passthrough),
// .next_led_request(next_led_request),
// .red_out(next_red),
// .green_out(next_green),
// .blue_out(next_blue),
// .color_valid(color_valid)
// );
// instantiate moving_pix module
moving_pix #(
.NUM_LEDS(NUM_LEDS),
.COLOR_WIDTH(COLOR_WIDTH)
) pat_gradient_inst (
.rst_in(sys_rst_led),
.clk_in(clk_100_passthrough),
.next_led_request(next_led_request),
.red_out(next_red),
.request_valid(1),
.green_out(next_green),
.red_out(next_red),
.blue_out(next_blue),
.color_valid(color_valid)
.color_ready(color_valid)
);

// instantiate led_driver module
Expand Down
86 changes: 86 additions & 0 deletions sim/test_moving_pix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import os
import sys
from pathlib import Path
import typing
from collections import deque

import cocotb
from cocotb.clock import Clock
from cocotb.runner import get_runner
from cocotb.triggers import ClockCycles, FallingEdge, RisingEdge

NUM_LEDS = 5
NUM_FRAMES_PER_LED = 4


@cocotb.test()
async def test_a(dut):
"""Test for driving first pixel a correct color"""
dut._log.info("Starting...")
cocotb.start_soon(Clock(dut.clk_in, 10, units="ns").start())

await ClockCycles(dut.clk_in, 2) # check the pre-reset behavior

# Reset
dut.rst_in.value = 1
await ClockCycles(dut.clk_in, 3)
await FallingEdge(dut.clk_in)
dut.rst_in.value = 0
dut.next_led_request.value = 0

# Start Driving
for pix in range(NUM_LEDS):
for frame in range(NUM_FRAMES_PER_LED):
for request in range(NUM_LEDS):
# Iterate through the strand
await RisingEdge(dut.clk_in)
dut.next_led_request.value = request
await FallingEdge(dut.clk_in)
await ClockCycles(dut.clk_in, 120)
dut._log.info(f"Checking pixel {pix} frame {frame}")
dut._log.info(f"g: {dut.green_out.value}, r: {dut.red_out.value}, b: {dut.blue_out.value}")
if pix == request:
assert dut.green_out.value == 0xFF
assert dut.red_out.value == 0xFF
assert dut.blue_out.value == 0xFF
else:
assert dut.green_out.value == 0
assert dut.red_out.value == 0
assert dut.blue_out.value == 0


def is_runner():
"""Moving pixel tester"""
hdl_toplevel_lang = os.getenv("HDL_TOPLEVEL_LANG", "verilog")
sim = os.getenv("SIM", "icarus")
proj_path = Path(__file__).resolve().parent.parent
sys.path.append(str(proj_path / "sim" / "model"))
sources = [proj_path / "hdl" / "pattern" / "moving_pix.sv"]
build_test_args = ["-Wall"]
parameters = {
"NUM_LEDS": NUM_LEDS,
"FRAMES_PER_LED": NUM_FRAMES_PER_LED,
}
sys.path.append(str(proj_path / "sim"))
runner = get_runner(sim)
runner.build(
sources=sources,
hdl_toplevel="moving_pix",
includes=[proj_path / "hdl"],
always=True,
build_args=build_test_args,
parameters=parameters,
timescale=("1ns", "1ps"),
waves=True,
)
run_test_args = []
runner.test(
hdl_toplevel="moving_pix",
test_module="test_moving_pix",
test_args=run_test_args,
waves=True,
)


if __name__ == "__main__":
is_runner()