Skip to content

Commit

Permalink
Initial structure with gateware directory to store cores sources.
Browse files Browse the repository at this point in the history
Example SpinalHDL core handling ov7670 registered inputs
Example litex firmware to access ov7670 control bus
  • Loading branch information
dlobato committed Oct 17, 2022
1 parent ec22d55 commit 749447b
Show file tree
Hide file tree
Showing 105 changed files with 2,301 additions and 1 deletion.
1 change: 1 addition & 0 deletions .bsp/sbt.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name":"sbt","version":"1.6.0","bspVersion":"2.0.0-M5","languages":["scala"],"argv":["/usr/lib/jvm/java-11-openjdk-amd64/bin/java","-Xms100m","-Xmx100m","-classpath","/home/dlobato/.local/share/JetBrains/IdeaIC2022.2/Scala/launcher/sbt-launch.jar","-Dsbt.script=/usr/bin/sbt","xsbt.boot.Boot","-bsp"]}
28 changes: 27 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,32 @@
debug.log

.vscode
.idea
obj_dir
*.fst
imgui.ini
imgui.ini

build

*.d
*.o
*.bin
*.elf
*.map

*.egg-info/

# sbt specific
.cache/
.history/
.lib/
dist/*
target
lib_managed/
src_managed/
project/boot/
project/plugins/project/

simWorkspace/
tmp/
null
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
19 changes: 19 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
ThisBuild / version := "1.0"
ThisBuild / scalaVersion := "2.12.16"
ThisBuild / organization := "org.jderobot"

val spinalVersion = "1.7.3"
val spinalCore = "com.github.spinalhdl" %% "spinalhdl-core" % spinalVersion
val spinalLib = "com.github.spinalhdl" %% "spinalhdl-lib" % spinalVersion
val spinalIdslPlugin = compilerPlugin("com.github.spinalhdl" %% "spinalhdl-idsl-plugin" % spinalVersion)
val scalatest = "org.scalatest" %% "scalatest-funsuite" % "3.2.14" % "test"

lazy val mylib = (project in file("."))
.settings(
name := "fpga-robotics",
Compile / scalaSource := baseDirectory.value / "gateware" / "main" / "scala",
Test / scalaSource := baseDirectory.value / "gateware" / "test" / "scala",
libraryDependencies ++= Seq(spinalCore, spinalLib, spinalIdslPlugin)
)

fork := true
Binary file added doc/OV7670_2006.pdf
Binary file not shown.
Binary file added doc/schematics_v308.pdf
Binary file not shown.
73 changes: 73 additions & 0 deletions gateware/main/scala/fpga_robotics/video/input/OV7670.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package fpga_robotics.video.input

import spinal.core._
import spinal.lib.graphic.Rgb
import spinal.lib.{Flow, _}

case class OV7670CAMIF() extends Bundle with IMasterSlave {
val pclk = Bool()
val vsync = Bool()
val href = Bool()
val data = Bits(8 bits)

override def asMaster(): Unit = {
out(pclk)
out(vsync)
out(href)
out(data)
}

def slaveResync(): OV7670CAMIF = {
val ret = cloneOf(this)
ret := BufferCC(this)
ret
}

def toFlow(): Flow[OV7670CAMIF] = {
val f = Flow(OV7670CAMIF())
f.valid := pclk.rise()
f.pclk := pclk
f.vsync := vsync
f.href := href
f.data := data
f
}

def toFlowInSync(): Flow[OV7670CAMIF] = {
val f = Flow(OV7670CAMIF())
val inSync = RegNextWhen(True, vsync.rise(), False)
f.valid := pclk.rise() & (inSync | vsync.rise())
f.pclk := pclk
f.vsync := vsync
f.href := href
f.data := data
f
}
}

case class OV7670() extends Component {
val io = new Bundle {
val camif: OV7670CAMIF = slave(OV7670CAMIF())
val frame_count = out UInt(32 bits)
}

val camif = io.camif.slaveResync()

val counter = Counter(32 bits)
when(camif.toFlowInSync().fire) {
when(camif.vsync.rise()) {
counter.increment()
}
}

io.frame_count := counter
}

object OV7670 {
def main(args: Array[String]): Unit = {
val outRtlDir = if (!args.isEmpty) args(0) else "gateware/main/verilog/video/input"
SpinalConfig(
targetDirectory = outRtlDir,
).generateVerilog(OV7670())
}
}
File renamed without changes.
File renamed without changes.
144 changes: 144 additions & 0 deletions gateware/main/verilog/video/input/OV7670.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Generator : SpinalHDL v1.7.3 git head : aeaeece704fe43c766e0d36a93f2ecbb8a9f2003
// Component : OV7670
// Git hash : ec22d55dd561d6161102dac82b90d4fa1fa8591f

`timescale 1ns/1ps

module OV7670 (
input io_camif_pclk,
input io_camif_vsync,
input io_camif_href,
input [7:0] io_camif_data,
output [31:0] io_frame_count,
input clk,
input reset
);

wire io_camif_buffercc_io_dataOut_pclk;
wire io_camif_buffercc_io_dataOut_vsync;
wire io_camif_buffercc_io_dataOut_href;
wire [7:0] io_camif_buffercc_io_dataOut_data;
wire [31:0] _zz_counter_valueNext;
wire [0:0] _zz_counter_valueNext_1;
wire camif_pclk;
wire camif_vsync;
wire camif_href;
wire [7:0] camif_data;
reg counter_willIncrement;
wire counter_willClear;
reg [31:0] counter_valueNext;
reg [31:0] counter_value;
wire counter_willOverflowIfInc;
wire counter_willOverflow;
reg camif_vsync_regNext;
wire when_OV7670_l38;
reg _zz_1;
reg camif_pclk_regNext;
reg camif_vsync_regNext_1;
reg camif_vsync_regNext_2;
wire when_OV7670_l58;

assign _zz_counter_valueNext_1 = counter_willIncrement;
assign _zz_counter_valueNext = {31'd0, _zz_counter_valueNext_1};
BufferCC io_camif_buffercc (
.io_dataIn_pclk (io_camif_pclk ), //i
.io_dataIn_vsync (io_camif_vsync ), //i
.io_dataIn_href (io_camif_href ), //i
.io_dataIn_data (io_camif_data[7:0] ), //i
.io_dataOut_pclk (io_camif_buffercc_io_dataOut_pclk ), //o
.io_dataOut_vsync (io_camif_buffercc_io_dataOut_vsync ), //o
.io_dataOut_href (io_camif_buffercc_io_dataOut_href ), //o
.io_dataOut_data (io_camif_buffercc_io_dataOut_data[7:0]), //o
.clk (clk ), //i
.reset (reset ) //i
);
assign camif_pclk = io_camif_buffercc_io_dataOut_pclk;
assign camif_vsync = io_camif_buffercc_io_dataOut_vsync;
assign camif_href = io_camif_buffercc_io_dataOut_href;
assign camif_data = io_camif_buffercc_io_dataOut_data;
always @(*) begin
counter_willIncrement = 1'b0;
if(((camif_pclk && (! camif_pclk_regNext)) && (_zz_1 || (camif_vsync && (! camif_vsync_regNext_1))))) begin
if(when_OV7670_l58) begin
counter_willIncrement = 1'b1;
end
end
end

assign counter_willClear = 1'b0;
assign counter_willOverflowIfInc = (counter_value == 32'hffffffff);
assign counter_willOverflow = (counter_willOverflowIfInc && counter_willIncrement);
always @(*) begin
counter_valueNext = (counter_value + _zz_counter_valueNext);
if(counter_willClear) begin
counter_valueNext = 32'h0;
end
end

assign when_OV7670_l38 = (camif_vsync && (! camif_vsync_regNext));
assign when_OV7670_l58 = (camif_vsync && (! camif_vsync_regNext_2));
assign io_frame_count = counter_value;
always @(posedge clk or posedge reset) begin
if(reset) begin
counter_value <= 32'h0;
_zz_1 <= 1'b0;
end else begin
counter_value <= counter_valueNext;
if(when_OV7670_l38) begin
_zz_1 <= 1'b1;
end
end
end

always @(posedge clk) begin
camif_vsync_regNext <= camif_vsync;
camif_pclk_regNext <= camif_pclk;
camif_vsync_regNext_1 <= camif_vsync;
end

always @(posedge clk) begin
camif_vsync_regNext_2 <= camif_vsync;
end


endmodule

module BufferCC (
input io_dataIn_pclk,
input io_dataIn_vsync,
input io_dataIn_href,
input [7:0] io_dataIn_data,
output io_dataOut_pclk,
output io_dataOut_vsync,
output io_dataOut_href,
output [7:0] io_dataOut_data,
input clk,
input reset
);

(* async_reg = "true" *) reg buffers_0_pclk;
(* async_reg = "true" *) reg buffers_0_vsync;
(* async_reg = "true" *) reg buffers_0_href;
(* async_reg = "true" *) reg [7:0] buffers_0_data;
(* async_reg = "true" *) reg buffers_1_pclk;
(* async_reg = "true" *) reg buffers_1_vsync;
(* async_reg = "true" *) reg buffers_1_href;
(* async_reg = "true" *) reg [7:0] buffers_1_data;

assign io_dataOut_pclk = buffers_1_pclk;
assign io_dataOut_vsync = buffers_1_vsync;
assign io_dataOut_href = buffers_1_href;
assign io_dataOut_data = buffers_1_data;
always @(posedge clk) begin
buffers_0_pclk <= io_dataIn_pclk;
buffers_0_vsync <= io_dataIn_vsync;
buffers_0_href <= io_dataIn_href;
buffers_0_data <= io_dataIn_data;
buffers_1_pclk <= buffers_0_pclk;
buffers_1_vsync <= buffers_0_vsync;
buffers_1_href <= buffers_0_href;
buffers_1_data <= buffers_0_data;
end


endmodule
33 changes: 33 additions & 0 deletions gateware/test/scala/fpga_robotics/video/input/OV7670Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package fpga_robotics.video.input

import org.scalatest.funsuite.AnyFunSuite
import spinal.core.sim._

class OV7670Test extends AnyFunSuite {
val compiled: SimCompiled[OV7670] = SimConfig.withWave.compile(OV7670())

test("frame count") {
compiled.doSim{ dut =>
dut.clockDomain.forkStimulus(10)

dut.io.camif.pclk #= false
dut.io.camif.vsync #= false
dut.io.camif.href #= false

val pclkThread = fork {
while (true) {
dut.clockDomain.waitSampling(4)
dut.io.camif.pclk #= !dut.io.camif.pclk.toBoolean
}
}

dut.clockDomain.waitSampling(10)

for(i <- 0 until 100) {
waitUntil(dut.io.camif.pclk.toBoolean)
dut.io.camif.vsync #= !dut.io.camif.vsync.toBoolean
dut.clockDomain.waitSampling(16)
}
}
}
}
1 change: 1 addition & 0 deletions project/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version=1.6.0
Empty file added project/plugins.sbt
Empty file.
Loading

0 comments on commit 749447b

Please sign in to comment.