DVP Receiver

Fall 2023

The questions below are due on Tuesday December 31, 2024; 11:59:00 PM.
 
You are not logged in.

Please Log In for full access to the web site.
Note that this link will take you to an external site (https://shimmer.mit.edu) to authenticate, and then you will be redirected back to this page.

This exercise will have you build a module that reconstructs video frame data as it's presented by the camera we'll be connecting to our boards.

The protocol the cameras use to provide us data is called "Digital Video Port" (DVP) by the camera's datasheet. This isn't really a fully specified protocol, but it's described in full by the datasheet. Rather than serializing data bits to be sent over one wire, DVP sends a full byte (8 bits) of data over parallel wires to be received simultaneously, synchronized by a clock wire (PCLK) and with metadata HSYNC and VSYNC wires to align the data received. We'll worry about the specifics of reading from these wires and turning bytes into pixel data in the next exercise, but for now we'll assume some level of pre-processing and focus on recovering the coordinates of pixels received from the camera, to let us reconstruct a full camera view.

Just like the HDMI signal we built [last week], DVP sends the pixels of a full frame serially by an established raster pattern, reading through the frame pixels like text on a page: from left to right across each row, then moving to the next row from top to bottom across the screen. The end of each row and the end of each frame is signaled by the HSYNC signal and the VSYNC signal (both active low*) respectively. Pixel data is real, valid data when both HSYNC and VSYNC are high. When HSYNC is pulled low for a blanking period, this indicates that a row is complete and after the blanking period ends (when HSYNC goes back high) the next row will begin to be transmitted, starting from the left edge. When VSYNC is pulled low for a blanking period, this indicates the frame is complete and the next frame will begin, starting with the pixel in the top-left corner.

Now that we are not generating blanking periods and instead receiving them, we no longer care (nor do we know with certainty) how long of blanking periods the camera will give us, just that there will be blanking inbetween each row indicated by HSYNC and between each frame indicated by VSYNC. Notably, there is no "front porch" or "back porch" blanking section; all data received when HSYNC and VSYNC are not pulled low is valid pixel data.

We will again consider the frame that we are reconstructing in terms of hcount and vcount pixel coordinates. hcount has a value of 0 in the top row, and increases for each row further down in the frame image; vccount has a value of 0 in the left-most column, and increases for pixels further to the right.

In order to determine the coordinates of the pixels received from a camera, you'll build a dvp_receiver module, which takes in the data for a pixel and transmits that same pixel data alongside its coordinate position. If the pixel data passed in is in a blanking region, this module will not return valid pixel data. The (pre-processed) camera signals you'll be working with are:

  • valid_in: a single-cycle high valid signal indicating the presence of new data that should be operated on; most, if not all, of what your module does should happen when this is high. Note that this is an indication of a valid read of data from the wires, regardless of whether it falls in a blanking region.
  • pixel_in: The (16-bit) pixel data from the camera
  • hsync_in: The HSYNC bit sent alongside this pixel from the camera, low when in the row-blanking region
  • vsync_in: The VSYNC bit sent alongside this pixel from the camera, low when in the frame-blanking region

Based on these signals, you'll generate the following set of output signals:

  • valid_out: a single-cycle high valid signal, indicating the presence of real pixel data (non-blanking)
  • pixel_out: The (unmodified) pixel data passed into this module
  • hcount_out: The row (y-axis) coordinate of the pixel being transmitted
  • vcount_out: The column (x-axis) coordinate of the pixel

The generation of coordinate values should complete within one cycle, so if valid pixel data appears on the input wires at cycle n, that data should be present on the output wires at cycle n+1.

A starting skeleton of the module is shown below. Fill in logic to determine hcount and vcount values for the pixels it receives.

module dvp_receiver
(
 input wire clk_in,
 input wire rst_in,

 input wire valid_in,
 input wire [15:0] pixel_in,
 input wire hsync_in,
 input wire vsync_in,

 output logic valid_out,
 output logic [15:0] pixel_out,
 output logic [12:0] hcount_out,
 output logic [11:0] vcount_out
);

  // your code here

endmodule

It may be helpful to draw out a state machine that depends on changes to vsync and hsync values and determines how counters for hcount and vcount should progress. It's important to remember that, since we don't know the length of blanking regions, this logic should react to rising and falling edges of these signals.

It should be noted that, while for this lab we will only ever be using a 240x320 pixel frame from the camera, this module should be able to handle any image frame size that doesn't overflow the hcount and vcount bit sizes.

*note: some parts of this protocol can be changed depending on the settings of the camera, including whether the HSYNC and VSYNC wires are active high or active low. We'll learn more later about the process of assigning camera settings like these

** this is not a signal that comes from the camera, but rather comes from our pre-processing.