upduino blinky (testbench not working)
This commit is contained in:
20
blinky/Makefile
Normal file
20
blinky/Makefile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
all: sim synth
|
||||||
|
|
||||||
|
sim: blinky_tb.vcd
|
||||||
|
|
||||||
|
synth: blinky.bin
|
||||||
|
|
||||||
|
blinky_tb.vcd: blinky.v sim.v blinky_tb.v
|
||||||
|
iverilog -o blinky_tb.out blinky.v blinky_tb.v sim.v
|
||||||
|
./blinky_tb.out
|
||||||
|
gtkwave blinky_tb.vcd & # blinky_tb.gtkw &
|
||||||
|
|
||||||
|
blinky.bin: blinky.v upduino.pcf
|
||||||
|
yosys -p "synth_ice40 -top blinky -json blinky.json" blinky.v
|
||||||
|
nextpnr-ice40 --up5k --json blinky.json --pcf upduino.pcf --asc blinky.txt
|
||||||
|
icepack blinky.txt blinky.bin
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.bin *.txt *.blif *.out *.vcd *~ *.json
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
34
blinky/blinky.v
Normal file
34
blinky/blinky.v
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// cribbed from https://blog.idorobots.org/entries/upduino-fpga-tutorial.html
|
||||||
|
|
||||||
|
module blinky (output wire led_blue,
|
||||||
|
output wire led_green,
|
||||||
|
output wire led_red);
|
||||||
|
|
||||||
|
wire clk;
|
||||||
|
SB_HFOSC inthosc(
|
||||||
|
.CLKHFPU(1'b1), // power up
|
||||||
|
.CLKHFEN(1'b1), // enable
|
||||||
|
.CLKHF(clk)); // drive the clk signal
|
||||||
|
|
||||||
|
localparam N=23;
|
||||||
|
reg [N:0] counter;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
counter <= counter+1;
|
||||||
|
|
||||||
|
SB_RGBA_DRV rgb (
|
||||||
|
.RGBLEDEN (1'b1),
|
||||||
|
.RGB0PWM (counter[N]),
|
||||||
|
.RGB1PWM (counter[N-1]),
|
||||||
|
.RGB2PWM (counter[N-2]),
|
||||||
|
.CURREN (1'b1),
|
||||||
|
.RGB0 (led_blue),
|
||||||
|
.RGB1 (led_green),
|
||||||
|
.RGB2 (led_red)
|
||||||
|
);
|
||||||
|
defparam rgb.CURRENT_MODE = "0b1";
|
||||||
|
defparam rgb.RGB0_CURRENT = "0b000001";
|
||||||
|
defparam rgb.RGB1_CURRENT = "0b000001";
|
||||||
|
defparam rgb.RGB2_CURRENT = "0b000001";
|
||||||
|
|
||||||
|
endmodule
|
||||||
35
blinky/blinky_tb.v
Normal file
35
blinky/blinky_tb.v
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
`timescale 10ns/1ns
|
||||||
|
|
||||||
|
module blinky_tb;
|
||||||
|
|
||||||
|
reg clk;
|
||||||
|
wire led_blue;
|
||||||
|
wire led_green;
|
||||||
|
wire led_red;
|
||||||
|
|
||||||
|
blinky dut (
|
||||||
|
.led_blue (led_blue),
|
||||||
|
.led_green (led_green),
|
||||||
|
.led_red (led_red)
|
||||||
|
);
|
||||||
|
|
||||||
|
initial clk=0;
|
||||||
|
always #2 clk=~clk;
|
||||||
|
|
||||||
|
//-- Begin test
|
||||||
|
initial begin
|
||||||
|
|
||||||
|
//-- Set the dumpfile
|
||||||
|
$dumpfile("blinky_tb.vcd");
|
||||||
|
|
||||||
|
//-- Dump everything into the dumpfile
|
||||||
|
$dumpvars(0, blinky_tb);
|
||||||
|
|
||||||
|
//-- End after 10 time units
|
||||||
|
# 100000 $finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
23
blinky/sim.v
Normal file
23
blinky/sim.v
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
module SB_HFOSC(
|
||||||
|
input CLKHFPU,
|
||||||
|
input CLKHFEN,
|
||||||
|
output CLKHF
|
||||||
|
);
|
||||||
|
parameter CLKHF_DIV = "0b00";
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module SB_RGBA_DRV (
|
||||||
|
input RGBLEDEN,
|
||||||
|
input RGB0PWM,
|
||||||
|
input RGB1PWM,
|
||||||
|
input RGB2PWM,
|
||||||
|
input CURREN,
|
||||||
|
output RGB0,
|
||||||
|
output RGB1,
|
||||||
|
output RGB2
|
||||||
|
);
|
||||||
|
parameter CURRENT_MODE="0b1";
|
||||||
|
parameter RGB0_CURRENT="0b000001";
|
||||||
|
parameter RGB1_CURRENT="0b000001";
|
||||||
|
parameter RGB2_CURRENT="0b000001";
|
||||||
|
endmodule
|
||||||
30
blinky/tb_blinky.v
Normal file
30
blinky/tb_blinky.v
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
`timescale 1ns/10ps //Adjust to suit
|
||||||
|
|
||||||
|
module tb_blinky;
|
||||||
|
|
||||||
|
wire wire led_blue ;
|
||||||
|
wire wire led_green ;
|
||||||
|
|
||||||
|
blinky uut (
|
||||||
|
.wire led_blue ( wire led_blue ),
|
||||||
|
.wire led_green ( wire led_green )
|
||||||
|
);
|
||||||
|
|
||||||
|
parameter PERIOD = 10; //adjust for your timescale
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$dumpfile("tb_output.vcd");
|
||||||
|
$dumpvars(2, tb_blinky);
|
||||||
|
clk = 1'b0;
|
||||||
|
#(PERIOD/2);
|
||||||
|
forever
|
||||||
|
#(PERIOD/2) clk = ~clk;
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
rst=1'b0;
|
||||||
|
#(PERIOD*2) rst=~rst;
|
||||||
|
#PERIOD rst=~rst;
|
||||||
|
end
|
||||||
|
`include "user.tb_blinky.v"
|
||||||
|
endmodule
|
||||||
235
blinky/tbgen.py
Normal file
235
blinky/tbgen.py
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
#! /usr/bin/python
|
||||||
|
|
||||||
|
# THE BEER-WARE LICENSE" (Revision 42):
|
||||||
|
# <xfguo@xfguo.org> wrote this file. As long as you retain this notice you
|
||||||
|
# can do whatever you want with this stuff. If we meet some day, and you think
|
||||||
|
# this stuff is worth it, you can buy me a beer in return Xiongfei(Alex) Guo.
|
||||||
|
|
||||||
|
# some minor additions by Al Williams 2018-9-11
|
||||||
|
|
||||||
|
'''
|
||||||
|
Created on 2010-4-23
|
||||||
|
|
||||||
|
@author: Alex Guo
|
||||||
|
'''
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
class TestbenchGenerator(object):
|
||||||
|
'''
|
||||||
|
verilog test bench auto generation
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self, vfile_name = None, ofile_name = None):
|
||||||
|
self.vfile_name = vfile_name
|
||||||
|
self.vfile = None
|
||||||
|
self.ofile_name = ofile_name
|
||||||
|
if(ofile_name == None):
|
||||||
|
self.ofile = sys.stdout
|
||||||
|
self.vcont = ""
|
||||||
|
self.mod_name = ""
|
||||||
|
self.pin_list = []
|
||||||
|
self.clock_name = 'clk'
|
||||||
|
self.reset_name = 'rst'
|
||||||
|
|
||||||
|
if vfile_name == None:
|
||||||
|
sys.stderr.write("ERROR: You did not provide an input file name.\n")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
self.open()
|
||||||
|
self.parser()
|
||||||
|
self.open_outputfile()
|
||||||
|
|
||||||
|
def open(self, vfile_name = None):
|
||||||
|
if vfile_name != None:
|
||||||
|
self.vfile_name = vfile_name
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.vfile = open(self.vfile_name, 'r')
|
||||||
|
self.vcont = self.vfile.read()
|
||||||
|
except Exception as e:
|
||||||
|
print("ERROR: Input file error.\n ERROR: %s" % e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def open_outputfile(self, ofile_name = None):
|
||||||
|
try:
|
||||||
|
if(ofile_name == None):
|
||||||
|
if(self.ofile_name == None):
|
||||||
|
ofname = "tb_%s.v" % self.mod_name
|
||||||
|
self.ofile = open(ofname, 'w')
|
||||||
|
print("You did not specify an output file name, using '%s'." % ofname)
|
||||||
|
else:
|
||||||
|
self.ofile = open(self.ofile_name, 'w')
|
||||||
|
print("Output file is '%s'." % self.ofile_name)
|
||||||
|
else:
|
||||||
|
self.ofile = open(ofile_name, 'w')
|
||||||
|
print("Output file is '%s'." % ofile_name)
|
||||||
|
except Exception as e:
|
||||||
|
print("ERROR: Output file error. \n ERROR: %s" % e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def clean_other(self, cont):
|
||||||
|
## clean '// ...'
|
||||||
|
cont = re.sub(r"//[^\n^\r]*", '\n', cont)
|
||||||
|
## clean '/* ... */'
|
||||||
|
cont = re.sub(r"/\*.*\*/", '', cont)
|
||||||
|
## clean '`define ..., etc.'
|
||||||
|
#cont = re.sub(r"[^\n^\r]+`[^\n^\r]*", '\n', cont)
|
||||||
|
## clean tables
|
||||||
|
cont = re.sub(r' +', ' ', cont)
|
||||||
|
## clean '\n' * '\r'
|
||||||
|
#cont = re.sub(r'[\n\r]+', '', cont)
|
||||||
|
return cont
|
||||||
|
|
||||||
|
def parser(self):
|
||||||
|
print("Parsing...")
|
||||||
|
# print vf_cont
|
||||||
|
mod_pattern = r"module[\s]+(\S*)[\s]*\([^\)]*\)[\s\S]*"
|
||||||
|
|
||||||
|
module_result = re.findall(mod_pattern, self.clean_other(self.vcont))
|
||||||
|
#print module_result
|
||||||
|
self.mod_name = module_result[0]
|
||||||
|
|
||||||
|
self.parser_inoutput()
|
||||||
|
self.find_clk_rst()
|
||||||
|
|
||||||
|
|
||||||
|
def parser_inoutput(self):
|
||||||
|
pin_list = self.clean_other(self.vcont)
|
||||||
|
|
||||||
|
comp_pin_list_pre = []
|
||||||
|
for i in re.findall(r'(input|output|inout)[\s]+([^;,\)]+)[\s]*[;,]', pin_list):
|
||||||
|
comp_pin_list_pre.append((i[0], re.sub(r"^reg[\s]*", "", i[1])))
|
||||||
|
|
||||||
|
comp_pin_list = []
|
||||||
|
type_name = ['reg', 'wire', 'wire', "ERROR"]
|
||||||
|
for i in comp_pin_list_pre:
|
||||||
|
x = re.split(r']', i[1])
|
||||||
|
type = 0;
|
||||||
|
if i[0] == 'input':
|
||||||
|
type = 0
|
||||||
|
elif i[0] == 'output':
|
||||||
|
type = 1
|
||||||
|
elif i[0] == 'inout':
|
||||||
|
type = 2
|
||||||
|
else:
|
||||||
|
type = 3
|
||||||
|
|
||||||
|
if len(x) == 2:
|
||||||
|
x[1] = re.sub('[\s]*', '', x[1])
|
||||||
|
comp_pin_list.append((i[0], x[1], x[0] + ']', type_name[type]))
|
||||||
|
else:
|
||||||
|
comp_pin_list.append((i[0], x[0], '', type_name[type]))
|
||||||
|
|
||||||
|
self.pin_list = comp_pin_list
|
||||||
|
# for i in self.pin_list: print i
|
||||||
|
|
||||||
|
def print_dut(self):
|
||||||
|
max_len = 0
|
||||||
|
for cpin_name in self.pin_list:
|
||||||
|
pin_name = cpin_name[1]
|
||||||
|
if len(pin_name) > max_len:
|
||||||
|
max_len = len(pin_name)
|
||||||
|
|
||||||
|
|
||||||
|
self.printo( "%s uut (\n" % self.mod_name )
|
||||||
|
|
||||||
|
align_cont = self.align_print(list(map(lambda x:("", "." + x[1], "(", x[1], '),'), self.pin_list)), 4)
|
||||||
|
align_cont = align_cont[:-2] + "\n"
|
||||||
|
self.printo( align_cont )
|
||||||
|
|
||||||
|
self.printo( ");\n" )
|
||||||
|
|
||||||
|
def print_wires(self):
|
||||||
|
self.printo(self.align_print(list(map(lambda x:(x[3], x[2], x[1], ';'), self.pin_list)), 4))
|
||||||
|
self.printo("\n")
|
||||||
|
|
||||||
|
def print_clock_gen(self,period,dfile,depth,resetpol):
|
||||||
|
fsdb = " $dumpfile(\"%s\");\n $dumpvars(%d, tb_%s);\n" % (dfile, depth, self.mod_name)
|
||||||
|
|
||||||
|
clock_gen_text = "\nparameter PERIOD = %d; //adjust for your timescale\n\ninitial begin\n%s CLK = 1'b0;\n #(PERIOD/2);\n forever\n #(PERIOD/2) CLK = ~CLK;\nend\n" % (period, fsdb)
|
||||||
|
self.printo(re.sub('CLK', self.clock_name, clock_gen_text))
|
||||||
|
if self.reset_name!="":
|
||||||
|
clock_gen_text = "\ninitial begin\n RST=1'b%d;\n #(PERIOD*2) RST=~RST;\n #PERIOD RST=~RST;\n end\n" % resetpol
|
||||||
|
self.printo(re.sub('RST',self.reset_name, clock_gen_text))
|
||||||
|
|
||||||
|
def find_clk_rst(self):
|
||||||
|
for pin in self.pin_list:
|
||||||
|
if re.match(r'[\S]*(clk|clock)[\S]*', pin[1]):
|
||||||
|
self.clock_name = pin[1]
|
||||||
|
print("Clock signal detected: '%s'." % pin[1])
|
||||||
|
break
|
||||||
|
|
||||||
|
for pin in self.pin_list:
|
||||||
|
if re.match(r'rst|reset', pin[1]):
|
||||||
|
self.reset_name = pin[1]
|
||||||
|
print("Reset signal detected: '%s'." % pin[1])
|
||||||
|
break
|
||||||
|
|
||||||
|
# Original code -- no longer used
|
||||||
|
def print_module_head_orig(self):
|
||||||
|
self.printo("`include \"timescale.v\"\nmodule tb_%s;\n\n" % self.mod_name)
|
||||||
|
|
||||||
|
def print_module_head(self,timescale):
|
||||||
|
self.printo("`timescale %s //Adjust to suit\n\nmodule tb_%s;\n\n" % (timescale,self.mod_name))
|
||||||
|
|
||||||
|
def print_module_end(self,iname):
|
||||||
|
if iname is None:
|
||||||
|
iname='user.tb_%s.v' % self.mod_name
|
||||||
|
self.printo("`include \"%s\"\nendmodule\n" % iname)
|
||||||
|
|
||||||
|
def printo(self, cont):
|
||||||
|
self.ofile.write(cont)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self.vfile != None:
|
||||||
|
self.vfile.close()
|
||||||
|
print("Output complete.\n\n")
|
||||||
|
|
||||||
|
def align_print(self, content, indent):
|
||||||
|
""" Align pretty print."""
|
||||||
|
|
||||||
|
row_len = len(content)
|
||||||
|
col_len = len(content[0])
|
||||||
|
align_cont = [""] * row_len
|
||||||
|
for i in range(col_len):
|
||||||
|
col = list(map(lambda x:x[i], content))
|
||||||
|
max_len = max(list(map(len, col)))
|
||||||
|
for i in range(row_len):
|
||||||
|
l = len(col[i])
|
||||||
|
align_cont[i] += "%s%s" % (col[i], (indent + max_len - l) * ' ')
|
||||||
|
|
||||||
|
# remove space in line end
|
||||||
|
align_cont = list(map(lambda s:re.sub('[ ]*$', '', s), align_cont))
|
||||||
|
return "\n".join(align_cont) + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print('''***************** tbgen - Auto generate a testbench. *****************
|
||||||
|
Author: Xiongfei(Alex) Guo <xfguo@credosemi.com>
|
||||||
|
License: Beerware
|
||||||
|
''')
|
||||||
|
ofile_name = None
|
||||||
|
|
||||||
|
aparse = argparse.ArgumentParser(description='Automatically generate Verilog testbench')
|
||||||
|
aparse.add_argument('input_file', help='input Verilog file')
|
||||||
|
aparse.add_argument('output_file', help='output Verilog testbench', nargs='?', default=None)
|
||||||
|
aparse.add_argument('-p','--period', type=int, help='set period in clock ticks (default=10)', default=10)
|
||||||
|
aparse.add_argument('-t','--timescale',help='set timescale (default=1ns/10ps)', default='1ns/10ps')
|
||||||
|
aparse.add_argument('-d','--dumpfile',help='set dumpfile (default=tb_output.vcd)', default='tb_output.vcd')
|
||||||
|
aparse.add_argument('-l','--level', type=int, help='set dump depth level (usually 0,1, or 2; default=2)', default=2)
|
||||||
|
aparse.add_argument('-r','--resetneg', help='set reset to negative (default positive)', action='store_const', const=1, default=0)
|
||||||
|
aparse.add_argument('-i','--include', help='sets user include file name (default=user.tb_<name>.v)', default=None)
|
||||||
|
args = aparse.parse_args()
|
||||||
|
|
||||||
|
tbg = TestbenchGenerator(args.input_file, args.output_file)
|
||||||
|
|
||||||
|
|
||||||
|
tbg.print_module_head(args.timescale)
|
||||||
|
tbg.print_wires()
|
||||||
|
tbg.print_dut()
|
||||||
|
tbg.print_clock_gen(args.period,args.dumpfile,args.level,args.resetneg)
|
||||||
|
tbg.print_module_end(args.include)
|
||||||
|
tbg.close()
|
||||||
63
blinky/upduino.pcf
Normal file
63
blinky/upduino.pcf
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# The LED pins are on dedicated pins and cannot be modified!
|
||||||
|
# Note that they are negative logic (write a 0 to turn on).
|
||||||
|
# These are also brought out to the left side of the board.
|
||||||
|
# Cut the board trace on jumper R28 to disable the onboard 3 color LED.
|
||||||
|
set_io -nowarn led_green 39
|
||||||
|
set_io -nowarn led_red 41
|
||||||
|
set_io -nowarn led_blue 40
|
||||||
|
|
||||||
|
# FTDI chip interface
|
||||||
|
set_io -nowarn serial_txd 14 # FPGA transmit to USB
|
||||||
|
set_io -nowarn serial_rxd 15 # FPGA receive from USB
|
||||||
|
set_io -nowarn spi_cs 16 # Connected to SPI flash, drive high unless using SPI flash!
|
||||||
|
|
||||||
|
# If using the FTDI MPSSE engine, the following signals apply
|
||||||
|
set_io -nowarn spi_sck 15 # Shared with the flash
|
||||||
|
set_io -nowarn spi_ssn 16 # Connected to SPI flash, drive high unless using SPI flash!
|
||||||
|
set_io -nowarn spi_mosi 17 # Shared with the flash
|
||||||
|
set_io -nowarn spi_miso 14 # Shared with the flash
|
||||||
|
|
||||||
|
# Normal GPIO pins, left side
|
||||||
|
set_io -nowarn gpio_23 23
|
||||||
|
set_io -nowarn gpio_25 25
|
||||||
|
set_io -nowarn gpio_26 26
|
||||||
|
set_io -nowarn gpio_27 27
|
||||||
|
set_io -nowarn gpio_32 32
|
||||||
|
set_io -nowarn gpio_35 35
|
||||||
|
set_io -nowarn gpio_31 31
|
||||||
|
set_io -nowarn gpio_37 37
|
||||||
|
set_io -nowarn gpio_34 34
|
||||||
|
set_io -nowarn gpio_43 43
|
||||||
|
set_io -nowarn gpio_36 36
|
||||||
|
set_io -nowarn gpio_42 42
|
||||||
|
set_io -nowarn gpio_38 38
|
||||||
|
set_io -nowarn gpio_28 28
|
||||||
|
|
||||||
|
# Normal GPIO pins, right side
|
||||||
|
|
||||||
|
# Following pins are added on the v3.0 of the board.
|
||||||
|
# SPI pins are brought out to the right side of the board
|
||||||
|
|
||||||
|
# Note: On board 12MHz clock can be brought to IOB_25B_G3 (pin 20) which is a global
|
||||||
|
# clock input. Short across R16 (labelled OSC on the board) to enable 12MHz clock to
|
||||||
|
# pin 20.
|
||||||
|
set_io -nowarn gpio_20 20
|
||||||
|
set_io -nowarn gpio_10 10
|
||||||
|
|
||||||
|
# Following are also found on v2.x of the UPduino
|
||||||
|
set_io -nowarn gpio_12 12
|
||||||
|
set_io -nowarn gpio_21 21
|
||||||
|
set_io -nowarn gpio_13 13
|
||||||
|
set_io -nowarn gpio_19 19
|
||||||
|
set_io -nowarn gpio_18 18
|
||||||
|
set_io -nowarn gpio_11 11
|
||||||
|
set_io -nowarn gpio_9 9
|
||||||
|
set_io -nowarn gpio_6 6
|
||||||
|
set_io -nowarn gpio_44 44
|
||||||
|
set_io -nowarn gpio_4 4
|
||||||
|
set_io -nowarn gpio_3 3
|
||||||
|
set_io -nowarn gpio_48 48
|
||||||
|
set_io -nowarn gpio_45 45
|
||||||
|
set_io -nowarn gpio_47 47
|
||||||
|
set_io -nowarn gpio_46 46
|
||||||
|
set_io -nowarn gpio_2 2
|
||||||
4
upduino/apio.ini
Normal file
4
upduino/apio.ini
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[env]
|
||||||
|
board = upduino31
|
||||||
|
top-module = main
|
||||||
|
|
||||||
53
upduino/leds.v
Normal file
53
upduino/leds.v
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// More info about the primitve led control block SB_RGBA_DRV:
|
||||||
|
// https://github.com/tinyvision-ai-inc/UPduino-v3.0/blob/master/RTL/blink_led/rgb_blink.v
|
||||||
|
// https://blog.idorobots.org/entries/upduino-fpga-tutorial.html
|
||||||
|
|
||||||
|
module leds (
|
||||||
|
input clk,
|
||||||
|
input red_en,
|
||||||
|
input green_en,
|
||||||
|
input blue_en,
|
||||||
|
output wire [2:0] leds_out // [0]=red, [1]=green, [2]=blue
|
||||||
|
);
|
||||||
|
|
||||||
|
// Intensity multiplier for all three channels.
|
||||||
|
localparam integer IntensityAll = 2;
|
||||||
|
|
||||||
|
// Intensity controls in the range [0, 512].
|
||||||
|
localparam integer IntensityRed = 4 * IntensityAll;
|
||||||
|
localparam integer IntensityGreen = 2 * IntensityAll;
|
||||||
|
localparam integer IntensityBlue = 24 * IntensityAll;
|
||||||
|
|
||||||
|
// Frequency divider generate the PWM counter.
|
||||||
|
reg [15:0] divider;
|
||||||
|
|
||||||
|
// 9 bits PWM counter.
|
||||||
|
wire [ 8:0] pwm_counter = divider[15:7];
|
||||||
|
|
||||||
|
wire pwm_red = pwm_counter < IntensityRed;
|
||||||
|
wire pwm_green = pwm_counter < IntensityGreen;
|
||||||
|
wire pwm_blue = pwm_counter < IntensityBlue;
|
||||||
|
|
||||||
|
// Behavior.
|
||||||
|
always @(posedge clk) begin
|
||||||
|
divider <= divider + 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
// Instantiate the RGB current source primitive.
|
||||||
|
SB_RGBA_DRV #(
|
||||||
|
.CURRENT_MODE("0b1"), // "0b0" -> full current, "0b1" -> half current.
|
||||||
|
.RGB0_CURRENT("0b000001"),
|
||||||
|
.RGB1_CURRENT("0b000001"),
|
||||||
|
.RGB2_CURRENT("0b000001")
|
||||||
|
) RGB_DRIVER (
|
||||||
|
.RGBLEDEN(1'b1),
|
||||||
|
.RGB0PWM (green_en && pwm_green), // Green led input.
|
||||||
|
.RGB1PWM (blue_en & pwm_blue), // Blue led input.
|
||||||
|
.RGB2PWM (red_en & pwm_red), // Red led input.
|
||||||
|
.CURREN (1'b1),
|
||||||
|
.RGB0 (leds_out[1]), // Current regulated output to green led.
|
||||||
|
.RGB1 (leds_out[2]), // Current regulated output to blue led.
|
||||||
|
.RGB2 (leds_out[0]) // Current regulated output to red led.
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
||||||
8
upduino/main.pcf
Normal file
8
upduino/main.pcf
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Mapping of the design signals to FPGA pins.
|
||||||
|
|
||||||
|
# The full Upduino3 PCF file is availble at:
|
||||||
|
# https://github.com/tinyvision-ai-inc/UPduino-v3.0/tree/master/RTL/common
|
||||||
|
|
||||||
|
set_io leds_out[0] 41 # Red.
|
||||||
|
set_io leds_out[1] 39 # Green.
|
||||||
|
set_io leds_out[2] 40 # Blue.
|
||||||
30
upduino/main.v
Normal file
30
upduino/main.v
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Generates a RGB blinking pattern. Uses the internal oscilator.
|
||||||
|
module main (
|
||||||
|
// [0]=red, [1]=green, [2]=blue. See pin definitions in main.pcf
|
||||||
|
output [2:0] leds_out
|
||||||
|
);
|
||||||
|
|
||||||
|
wire clk;
|
||||||
|
|
||||||
|
oscilator oscilator (.clk(clk));
|
||||||
|
|
||||||
|
// Frequency divider to generate the RGB patterns.
|
||||||
|
reg [25:0] divider;
|
||||||
|
wire red_en = divider[25] & divider[24];
|
||||||
|
wire green_en = divider[25] & ~divider[24];
|
||||||
|
wire blue_en = ~divider[25] & divider[24];
|
||||||
|
|
||||||
|
leds leds (
|
||||||
|
.clk(clk),
|
||||||
|
.red_en(red_en),
|
||||||
|
.green_en(green_en),
|
||||||
|
.blue_en(blue_en),
|
||||||
|
.leds_out(leds_out)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Behavior.
|
||||||
|
always @(posedge clk) begin
|
||||||
|
divider <= divider + 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
14
upduino/oscilator.v
Normal file
14
upduino/oscilator.v
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Instanciates the internal high speed oscilator. This is needed
|
||||||
|
// only if the external Upduino oscilator is not connected to the FPGA.
|
||||||
|
|
||||||
|
module oscilator (
|
||||||
|
output clk
|
||||||
|
);
|
||||||
|
|
||||||
|
SB_HFOSC interal_osc (
|
||||||
|
.CLKHFPU(1'b1),
|
||||||
|
.CLKHFEN(1'b1),
|
||||||
|
.CLKHF (clk)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
||||||
Reference in New Issue
Block a user