Note: this post is still a work in progress.
- add an AXI IIC block to the design and run automation
- run synthesis and generate the bitstream
Image Sensor Bringup
As a sanity check that the image sensor is working, let’s integrate an AXI i2c peripheral and make sure we can snag the camera sensor ID values. We will write some firmware to run on the PS (Zynq speak for the ARM cores). Here are the general steps to follow:
- Make a new block design with the Zynq PS included.
- Add an AXI IIC (Xilinx for I2C) block and run automation.
- create a quick block to generate an
xclksignal for the image sensor. I just divided my main clock by 4 to hit 12.5 MHz.
- I tweaked the IO pins of the I2C block to use some pins on my board that are unencumbered by pullup resistors. The ArduCam module and the Cora board that I’m using both try to be helpful by including the I2C pullup resistors, but I don’t want any pull issues so I will rely on just the ones on the camera module.
- Ensure the I2C block is seen by the Zynq. You may need to go into the Zynq block and enable it after it’s added to the block diagram.
- Generate bitstream and export hardware to SDK.
I created a new board support package. Assuming the block design is set up correctly, the BSP will include the Xilinx IIC (I2C) driver code. Then it’s time to look at the example code provided by the I2C driver to get the basic usage pattern down.
Examples are located in
TODO FILE PATH for me.
A Few Gotchas
It took a little while to get the sensor talking. Here were some of the things I overlooked.
The camera sensor needs
xclkto begin replying over I2C. This became obvious after looking at the camera module pinout and wondering what
The device IDs in the OV2640 datasheet are in hex! And they include the read/write bit. The read/write bit part was obvious in that two addresses were given, the radix was not obvious. It seems that Omnivision uses hex by default in their datasheets, without a
0xprefix or an
hto be seen.
I only uncovered this after blasting requests to all possible I2C addresses and using a logic analyzer to find the
Note that the Xilinx I2C drivers will add a read/write bit accordingly, so only supply the 7-bit address and make sure the radix is correct. For my
OV2640, this is
Despite what the datasheet says, the OV2640 seems to have 2 options for the product ID -
0x41. I get
0x41is in the datasheet. Given that I can read/write other registers and the ArduCam driver also lists these, it’s clearly not a problem.
Slave addr = 60 write 61 read
COM10  will set the positive edge of pclk as the active edge
Register Set 1
Register FF controls which register page is accessable. When register FF is 0x00, the addresses do this: Reg F7 = slave ID MCU in the camera has BIST.
Register Set 2
When register FF equals 0x01 0A = product ID number (PIDH) 0B = product ID number (PIDL)
Set device addr = 60 write Write 01 to FF Read (61) from 0x0A Read (61) from 0x0B
Designing the Camera Interface Core
There are several clocks in this design.
- clk - the main system clock
- xclk - generated by the FPGA from the main clock, fed to the image sensor
- vclk - output from the camera, this is what the video stream is synchronized to
Therefore, we have some clock domain crossing to handle. First, we need to transition from the vclk domain into the clk domain. This occurs when we load in a pixel from the camera (synchronized to vclk), and need to handle it within the FPGA (the exent of the ‘handling’ changes).
How can we handle this? Let’s look at some examples.