Interfacing Davis240 with an FPGA

Event Data Structure

Davis240 event camera has a convenient USB connector that can be used to read the event stream of the camera. However, the use of multiple cameras on the on-board computer of the small UAVs will incur significant CPU load and require the design of the special USB driver. Use of FPGA can reduce CPU load and allow to process all the cameras and sensors in parallel. FPGA will receive data from the event camera and save it to the DDR memory without CPU participating. The data will be organized as shown below.

In this document, the event camera interfacing with the FPGA will be explained.

Signal Description

To interface DAVIS camera with the FPGA the user will need to use 4 signals. The signals are described in the table below.

Request (REQ)InputActive low. When the signal is asserted, the data is valid.
Select (AER_bus [9])InputSignal to distinguish X Address from Y Address. 
When “Select = 0” -> “Data = Y Address”.
When “Select = 1” -> “Data = X Address + Polarity”.
Data (AER_bus [8:0])Input9 Bit Data Bus.
Y Address (8 bits) -> Data [7:0]; 0 to 179
X Address (8 bits) -> Data [8:1]; 0 to 239
Polarity (1 Bit) -> Data [0];
Acknowledge (ACK)OutputActive Low. Assert, when Data read is complete.

Example from User Side

This example shows how does a single Y Address, X Address and Polarity receive looks like.It is suggested to use a double flip-flop synchronizer for Request, Select and Data signals. 50ns delay should be introduced before reading Y address.

Event Read Timing Diagram
  1. Wait to REQ to be asserted
  2. Read Y Address
  3. Confirm read by asserting ACK
  4. Wait for REQ to deassert & deassert ACK
  5. Wait to REQ to be asserted
  6. Read X Address and Polarity
  7. Confirm read by asserting ACK
  8. Wait for REQ to deassert & deassert ACK
  9. … go back to Step 1

Camera Connection

The camera can be connected to the FPGA board with a PCB connector. Possible design is shown below.

PCB Connector Front / Back View

In this design, the following 2 components can be used: 

  1. FLE-120-01-G-DV (required to connect PCB to the camera)
  2. SSW-108-01-S-D (standard 2.54mm female or male connector)

Comment: as this PCB was designed to be used with ULTRA96 board. Additional components required to perform voltage level translating from 1.8V to 3.3V
Event camera pinout is shown on the left. 

  • nREQ is active low;
  • nACK is active low;
  • In DAVIS 240C only (AER_7 & AER_6 are swapped):
    • pin 27 is AER_7;
    • pin 28 is AER_6;
  • Use as short wires/tracks as possible;
  • I/O are 3.3V.

Comment: Altium PCB files are available on request.

Sample Verilog Code

This sample code reads events (Y and X address consequently) and timestamps them with us clock. The flag is raised after both new Y&X addresses were received. The waveform from the test bench is shown below. AER_bus was simulated with a binary counter (ACK signal was used as a clock for the counter).

DAVIS240C Behavioral Simulation (AER_Y is LSB & AER_X is MSB)
module davis_240(
input wire clk,
input wire[8:0]AER_bus, //data bus
input wire REQ, //request signal
input wire SEL, // select signal
input wire [31:0] time_stamp, //us counter
output wire ACK, //acknowledge signal
output reg [31:0]data_out, //output data in a format Y_addr,polarity,X_addr
output reg [31:0]data_out_time //output timestap for each event
wire [7:0]AER_Y;
wire [8:0]AER_X;
reg ack = 1;
reg [8:0]X_addr_p = 0;
reg [7:0]Y_addr = 0;
reg [31:0]counter = 0; //counter for delay before reading Y addr
reg [31:0]counter1 = 0; //counter for delay before reading X addr

reg [31:0]time_r = 0; // time redister for saving timestamp 
reg x_done = 0; // confirms that X was read 
reg y_done = 0; // confirms that Y was read 
reg y_flag = 0;
reg all_done = 0; // confirms that both X&Y were read

assign ACK = ack;
// Y addr
assign AER_Y[0] = AER_bus[0];
assign AER_Y[1] = AER_bus[1];
assign AER_Y[2] = AER_bus[2];
assign AER_Y[3] = AER_bus[3];
assign AER_Y[4] = AER_bus[4];
assign AER_Y[5] = AER_bus[5];
assign AER_Y[6] = AER_bus[6];
assign AER_Y[7] = AER_bus[7];
// X addr
assign AER_X[0] = AER_bus[0]; // polarity 
assign AER_X[1] = AER_bus[1];
assign AER_X[2] = AER_bus[2];
assign AER_X[3] = AER_bus[3];
assign AER_X[4] = AER_bus[4];
assign AER_X[5] = AER_bus[5];
assign AER_X[6] = AER_bus[6];
assign AER_X[7] = AER_bus[7];
assign AER_X[8] = AER_bus[8];

//Synchronise  SEL
reg temp_sel = 0;  always @(posedge clk) begin temp_sel <= SEL; end
reg SEL_synq = 0;  always @(posedge clk) begin SEL_synq <= temp_sel; end
//Synchronise REQ
reg temp = 0;  always @(posedge clk) begin temp <= REQ; end
reg REQ_synq = 0;  always @(posedge clk) begin REQ_synq <= temp; end

always @(posedge clk)
    // GET Y
    if ((REQ_synq == 0)&&(SEL_synq == 0)) begin
        if (counter == 50) begin //delay 50 ns
            counter <= 0;
            ack <= 0;
            y_done <= 1;
            Y_addr <= AER_Y;
            time_r <= time_stamp;
        end else begin counter <= counter +1; end
    // GET X
    end else if ((REQ_synq == 0)&&(SEL_synq == 1)) begin
        if (counter1 == 10) begin //delay 10 ns
            counter1 <=0;
            ack <= 0;
            x_done <= 1;
            X_addr_p <= AER_X;
         end else begin counter1 <= counter1 + 1; end
    end else if (REQ_synq == 1) begin
        y_done <= 0;
        x_done <= 0;
        ack <=1;
    end else begin end
// D-latch used to extend y_done
always @(posedge clk) 
    if (all_done == 1)
        y_flag <= 0;
    else begin
        if (y_done == 1) begin
        y_flag <= y_done;
//raise flag when both X&Y were received
always @(posedge clk)
    if ((x_done == 1) &&(y_flag)) begin
        all_done = 1;
    end else begin
        all_done = 0;
//X&Y addr are sent to output when all_done flag is raised
always @(posedge all_done) 
    data_out[7:0] <= Y_addr;
    data_out[16:8] <= X_addr_p;
    data_out[31:17] <= 0;
    data_out_time[31:0] <= time_r;