Przeglądaj źródła

projects/rgb_panel: Add support for the single-PMOD option

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Sylvain Munaut 5 lat temu
rodzic
commit
f649acd303

+ 2 - 2
projects/rgb_panel/Makefile

@@ -14,11 +14,11 @@ PROJ_TOP_SRC := rtl/top.v
 PROJ_TOP_MOD := top
 
 # Target config
-BOARD ?= icebreaker
+BOARD ?= icebreaker-double
 DEVICE = up5k
 PACKAGE = sg48
 
-NEXTPNR_ARGS = --freq 35
+NEXTPNR_ARGS = --pre-pack data/clocks.py
 
 # Include default rules
 include ../../build/project-rules.mk

+ 16 - 0
projects/rgb_panel/README.md

@@ -96,3 +96,19 @@ Obviously the number for the `crop` filter need to be adjusted for your source
 material to get a square image that selects the best region to show. Also, you
 can do use unix FIFOs to directly pipe content from `ffmpeg` to the `stream.py`
 application without the need for intermediate files.
+
+
+Single PMOD support
+-------------------
+
+By default the code is built to have a [double-width PMOD](https://github.com/icebreaker-fpga/icebreaker-pmod/tree/master/led-panel)
+connected on the PMOD1A and PMOD1B port.
+
+There is an alternate [single-width PMOD](https://github.com/icebreaker-fpga/icebreaker-pmod/tree/master/led-panel-single)
+that uses a bit of external logic to reduce the number of IO lines used (so you
+have more free PMODs slots). To build the project with this option, use
+`make BOARD=icebreaker-single`.
+
+The `pcf` is by default configured to have this PMOD on slot P1A, but you can
+edit `icebreaker-single.pcf` to change the pin assignements if it's plugged
+somewhere else.

+ 2 - 0
projects/rgb_panel/data/clocks.py

@@ -0,0 +1,2 @@
+ctx.addClock("clk", 30)
+ctx.addClock("clk_2x", 60)

+ 1 - 1
projects/rgb_panel/data/top-icebreaker.pcf

@@ -1,4 +1,4 @@
-# RGB panel pmod
+# RGB panel dual pmod
  # Data for panels with Red on pin 1/5 and Blue on pin 3/7
 set_io -nowarn hub75_data[5] 3  # A7 - Red   1
 set_io -nowarn hub75_data[4] 48 # A8 - Green 1

+ 40 - 0
projects/rgb_panel/data/top-icebreaker-single.pcf

@@ -0,0 +1,40 @@
+# RBG panel single-pmod (on P1A)
+
+ # Data for panels with Red on pin 1/5 and Blue on pin 3/7
+#set_io -nowarn hub75_data[2] 2		# P1A2 Red
+#set_io -nowarn hub75_data[1] 3		# P1A7 Green
+#set_io -nowarn hub75_data[0] 4		# P1A1 Blue
+
+ # Data for panels with Red on pin 3/7 and Blue on pin 1/5
+set_io -nowarn hub75_data[2] 4		# P1A1 Red
+set_io -nowarn hub75_data[1] 3		# P1A7 Green
+set_io -nowarn hub75_data[0] 2		# P1A2 Blue
+
+ # Row address
+set_io -nowarn hub75_addr_inc 47	# P1A3
+set_io -nowarn hub75_addr_rst 48	# P1A8
+
+ # Control
+set_io -nowarn hub75_clk 46		# P1A9
+set_io -nowarn hub75_le 44		# P1A10
+set_io -nowarn hub75_blank 45		# P1A4
+
+# SPI Flash
+set_io -nowarn flash_mosi 14
+set_io -nowarn flash_miso 17
+set_io -nowarn flash_cs_n 16
+set_io -nowarn flash_clk 15
+
+# SPI Slave
+set_io -nowarn slave_mosi 14
+set_io -nowarn slave_miso 17
+set_io -nowarn slave_cs_n 11
+set_io -nowarn slave_clk 15
+
+# PMOD2 buttons
+set_io -nowarn pmod_btn[0] 20
+set_io -nowarn pmod_btn[1] 19
+set_io -nowarn pmod_btn[2] 18
+
+# Clock
+set_io -nowarn clk_12m 35

+ 21 - 9
projects/rgb_panel/rtl/sysmgr.v

@@ -37,6 +37,7 @@ module sysmgr (
 	input  wire clk_in,
 	input  wire rst_in,
 	output wire clk_out,
+	output wire clk_2x_out,
 	output wire rst_out
 );
 
@@ -45,33 +46,43 @@ module sysmgr (
 	wire pll_reset_n;
 
 	wire clk_i;
+	wire clk_2x_i;
 	wire rst_i;
 	reg [3:0] rst_cnt;
 
 	// PLL instance
 `ifdef SIM
-	assign clk_i = clk_in;
+	reg clk_div = 1'b0;
+	always @(posedge clk_in)
+		clk_div <= ~clk_div;
+
+	assign clk_i = clk_div;
+	assign clk_2x_i = clk_in;
 	assign pll_lock = pll_reset_n;
 `else
-	SB_PLL40_PAD #(
+	SB_PLL40_2F_PAD #(
 		.DIVR(4'b0000),
 `ifdef PANEL_FAST
-		.DIVF(7'b1001111),
+		.DIVF(7'b1001111),	// 60 MHz output
 `else
-		.DIVF(7'b0111111),
+		.DIVF(7'b1000001),	// 49.5 MHz output
 `endif
-		.DIVQ(3'b101),
+		.DIVQ(3'b100),
 		.FILTER_RANGE(3'b001),
 		.FEEDBACK_PATH("SIMPLE"),
 		.DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"),
 		.FDA_FEEDBACK(4'b0000),
 		.SHIFTREG_DIV_MODE(2'b00),
-		.PLLOUT_SELECT("GENCLK"),
-		.ENABLE_ICEGATE(1'b0)
+		.PLLOUT_SELECT_PORTA("GENCLK"),
+		.PLLOUT_SELECT_PORTB("GENCLK_HALF"),
+		.ENABLE_ICEGATE_PORTA(1'b0),
+		.ENABLE_ICEGATE_PORTB(1'b0)
 	) pll_I (
 		.PACKAGEPIN(clk_in),
-		.PLLOUTCORE(),
-		.PLLOUTGLOBAL(clk_i),
+		.PLLOUTCOREA(),
+		.PLLOUTGLOBALA(clk_2x_i),
+		.PLLOUTCOREB(),
+		.PLLOUTGLOBALB(clk_i),
 		.EXTFEEDBACK(1'b0),
 		.DYNAMICDELAY(8'h00),
 		.RESETB(pll_reset_n),
@@ -85,6 +96,7 @@ module sysmgr (
 `endif
 
 	assign clk_out = clk_i;
+	assign clk_2x_out = clk_2x_i;
 
 	// PLL reset generation
 	assign pll_reset_n = ~rst_in;

+ 22 - 1
projects/rgb_panel/rtl/top.v

@@ -39,8 +39,14 @@
 
 module top (
 	// RGB panel PMOD
+`ifdef BOARD_ICEBREAKER_SINGLE
+	output wire hub75_addr_inc,
+	output wire hub75_addr_rst,
+	output wire [2:0] hub75_data,
+`else
 	output wire [4:0] hub75_addr,
 	output wire [5:0] hub75_data,
+`endif
 	output wire hub75_clk,
 	output wire hub75_le,
 	output wire hub75_blank,
@@ -91,6 +97,7 @@ module top (
 `endif
 
 	wire clk;
+	wire clk_2x;
 	wire rst;
 
 	// Frame buffer write port
@@ -120,9 +127,21 @@ module top (
 		.N_COLS(N_COLS),
 		.N_CHANS(N_CHANS),
 		.N_PLANES(N_PLANES),
-		.BITDEPTH(BITDEPTH)
+		.BITDEPTH(BITDEPTH),
+`ifdef BOARD_ICEBREAKER_SINGLE
+		.PHY_DDR(2),	// DDR data with early edge
+		.PHY_AIR(3),	// Enabled and invert INC
+		.SCAN_MODE("LINEAR")
+`else
+		.SCAN_MODE("ZIGZAG")
+`endif
 	) hub75_I (
+`ifdef BOARD_ICEBREAKER_SINGLE
+		.hub75_addr_inc(hub75_addr_inc),
+		.hub75_addr_rst(hub75_addr_rst),
+`else
 		.hub75_addr(hub75_addr),
+`endif
 		.hub75_data(hub75_data),
 		.hub75_clk(hub75_clk),
 		.hub75_le(hub75_le),
@@ -143,6 +162,7 @@ module top (
 		.cfg_post_latch_len(8'h80),
 		.cfg_bcm_bit_len(8'h06),
 		.clk(clk),
+		.clk_2x(clk_2x),
 		.rst(rst)
 	);
 
@@ -321,6 +341,7 @@ module top (
 		.clk_in(clk_12m),
 		.rst_in(1'b0),
 		.clk_out(clk),
+		.clk_2x_out(clk_2x),
 		.rst_out(rst)
 	);
 `endif