For security purposes, we are implementing our own camera driver in Op-Tee.
The sensor is connected to the CSI properly. My predecessor had this hardware working under Linux, using a hacked up Linux driver, but unfortunately his work got lost.
The sensor is configured with the same parameters as my predecessor did and it outputs 480 lines with 1280 pixels each. These lines are supposed to be alternating lines of BGBGBGBG and GRGRGRGR pixels, 8-bits each, on D2...D9. See attached oscillograms.
Question 1: Is the CSI aware of image geometry, treating different colored pixels differently, other than for statistic purposes?
The CSI peripheral is configured initialized as follows. First clocks are enabled like this:
static int csi_clocks(unsigned char enable)
{
vaddr_t ccm_base = core_mmu_get_va(CCM_BASE, MEM_AREA_IO_SEC);
uint32_t reg;
if (!ccm_base) {
EMSG("No CCM_BASE mapping");
return -1;
}
/* Enable csi_mclk during all modes, except STOP mode (CCM.CCGR3.CG15) */
/* TODO: CCM.CCGR3.CG15 is reserved in the user manual */
reg = io_read32(ccm_base + CCM_CCGR3);
if (enable)
reg |= CCM_CCGRx__CG(15, 0x3);
else
reg &= ~CCM_CCGRx__CG(15, 0x3);
io_write32(ccm_base + CCM_CCGR2, reg);
if (enable) {
/* Derive csi_mclk from osc_clk, 1:1 for 24MHz */
reg = io_read32(ccm_base + CCM_CSCDR3);
reg &= ~(CSI_PODF__MASK |
CSI_CLK_SEL__MASK);
reg |= CSI_PODF__DIV_BY_1 |
CSI_CLK_SEL__OSC_CLK;
io_write32(ccm_base + CCM_CSCDR3, reg);
}
/* Enable CSI peripheral clock during all modes, except STOP mode (CCM.CCGR2.CG1) */
reg = io_read32(ccm_base + CCM_CCGR2);
if (enable)
reg |= CCM_CCGRx__CG(1, 0x3);
else
reg &= ~CCM_CCGRx__CG(1, 0x3);
io_write32(ccm_base + CCM_CCGR2, reg);
return 0;
}
Next, the peripheral is reset like this, much like the Linux driver does:
#define CSICR1_RESET_VAL 0x40000800
#define CSICR2_RESET_VAL 0x00000000
#define CSICR3_RESET_VAL 0x00000000
static void csi_hw_reset(void)
{
io_write32(csi.base + CSI_CSICR3,
io_read32(csi.base + CSI_CSICR3) | CSI_CSICR3__FRMCNT_RST);
io_write32(csi.base + CSI_CSICR1, CSICR1_RESET_VAL);
io_write32(csi.base + CSI_CSICR2, CSICR2_RESET_VAL);
io_write32(csi.base + CSI_CSICR3, CSICR3_RESET_VAL);
}
Then it is initialized like this:
#define CAPT_WIDTH 1280
#define CAPT_HEIGHT 480
static void csi_init_interface(void)
{
uint32_t cr;
uint32_t imag_para;
cr = CSI_CSICR1__EXT_VSYNC |
CSI_CSICR1__RXFF_INTEN |
CSI_CSICR1__SOF_POL | /* SOF interrupt is generated on SOF rising edge */
CSI_CSICR1__HSYNC_POL | /* HSYNC is active high */
CSI_CSICR1__CLR_RXFIFO |
CSI_CSICR1__GCLK_MODE | /* Gated clock mode: pixel clock signal is valid only when HSYNC is active */
CSI_CSICR1__REDGE | /* Pixel data is latched at the rising edge of CSI_PIXCLK */
CSI_CSICR1__FCC; /* Synchronous FIFO clear is selected */
io_write32(csi.base + CSI_CSICR1, cr);
imag_para = CSI_CSIIMAG_PARA__IMAGE_WIDTH(CAPT_WIDTH) |
CSI_CSIIMAG_PARA__IMAGE_HEIGHT(CAPT_HEIGHT);
io_write32(csi.base + CSI_CSIIMAG_PARA, imag_para);
cr = CSI_CSICR3__DMA_REFLASH_RFF;
io_write32(csi.base + CSI_CSICR3, cr);
}
Finally, it is enabled, like this:
static void csi_enable(unsigned char enable)
{
uint32_t cr18;
cr18 = io_read32(csi.base + CSI_CSICR18);
if (enable)
cr18 |= CSI_CSICR18__CSI_ENABLE;
else
cr18 &= ~CSI_CSICR18__CSI_ENABLE;
io_write32(csi.base + CSI_CSICR18, cr18);
}
I figured I'd start with small results, like receiving image data from the RXFIFO, but unfortunately it stays empty. No telling bits in CSI_CSISR are getting activated either.
What does work, is CSI.CSICR3.FRMCNT. This register field increases with 30 every second, as expected for a 30fps signal. So it clearly is receiving the camera signal.
Question 2: Why is no data being received?
Full CSI register contents are listed below:
# /unit_tests/memtool CSI.
SOC: i.MX6UL
CSI Addr:0x21c4000
CSI.CSICR1 Addr:0x021C4000 Value:0x40060812 - This register controls the sensor interface timing and interrupt generation.
CSI.CSICR1.PIXEL_BIT(0..0) :0x0
Pixel Bit.
CSI.CSICR1.REDGE(1..1) :0x1
Valid Pixel Clock Edge Select.
CSI.CSICR1.INV_PCLK(2..2) :0x0
Invert Pixel Clock Input.
CSI.CSICR1.INV_DATA(3..3) :0x0
Invert Data Input.
CSI.CSICR1.GCLK_MODE(4..4) :0x1
Gated Clock Mode Enable.
CSI.CSICR1.CLR_RXFIFO(5..5) :0x0
Asynchronous RXFIFO Clear.
CSI.CSICR1.CLR_STATFIFO(6..6) :0x0
Asynchronous STATFIFO Clear.
CSI.CSICR1.PACK_DIR(7..7) :0x0
Data Packing Direction.
CSI.CSICR1.FCC(8..8) :0x0
FIFO Clear Control.
CSI.CSICR1.CCIR_EN(10..10) :0x0
CCIR656 Interface Enable.
CSI.CSICR1.HSYNC_POL(11..11) :0x1
HSYNC Polarity Select.
CSI.CSICR1.SOF_INTEN(16..16) :0x0
Start Of Frame (SOF) Interrupt Enable.
CSI.CSICR1.SOF_POL(17..17) :0x1
SOF Interrupt Polarity.
CSI.CSICR1.RXFF_INTEN(18..18) :0x1
RxFIFO Full Interrupt Enable.
CSI.CSICR1.FB1_DMA_DONE_INTEN(19..19) :0x0
Frame Buffer1 DMA Transfer Done Interrupt Enable.
CSI.CSICR1.FB2_DMA_DONE_INTEN(20..20) :0x0
Frame Buffer2 DMA Transfer Done Interrupt Enable.
CSI.CSICR1.STATFF_INTEN(21..21) :0x0
STATFIFO Full Interrupt Enable.
CSI.CSICR1.SFF_DMA_DONE_INTEN(22..22) :0x0
STATFIFO DMA Transfer Done Interrupt Enable.
CSI.CSICR1.RF_OR_INTEN(24..24) :0x0
RxFIFO Overrun Interrupt Enable.
CSI.CSICR1.SF_OR_INTEN(25..25) :0x0
STAT FIFO Overrun Interrupt Enable.
CSI.CSICR1.COF_INT_EN(26..26) :0x0
Change Of Image Field (COF) Interrupt Enable.
CSI.CSICR1.VIDEO_MODE(27..27) :0x0
Video mode select.
CSI.CSICR1.PRP_IF_EN(28..28) :0x0
CSI-PrP Interface Enable.
CSI.CSICR1.EOF_INT_EN(29..29) :0x0
End-of-Frame Interrupt Enable.
CSI.CSICR1.EXT_VSYNC(30..30) :0x1
External VSYNC Enable.
CSI.CSICR1.SWAP16_EN(31..31) :0x0
SWAP 16-Bit Enable.
CSI.CSICR2 Addr:0x021C4004 Value:0x00000000 - This register provides the statistic block with data about which live view resolution is being used, and the starting sensor pixel of the Bayer pattern.
CSI.CSICR2.HSC(0..7) :0x0
Horizontal Skip Count.
CSI.CSICR2.VSC(8..15) :0x0
Vertical Skip Count.
CSI.CSICR2.LVRM(16..18) :0x0
Live View Resolution Mode.
CSI.CSICR2.BTS(19..20) :0x0
Bayer Tile Start.
CSI.CSICR2.SCE(23..23) :0x0
Skip Count Enable.
CSI.CSICR2.AFS(24..25) :0x0
Auto Focus Spread.
CSI.CSICR2.DRM(26..26) :0x0
Double Resolution Mode.
CSI.CSICR2.DMA_BURST_TYPE_SFF(28..29) :0x0
Burst Type of DMA Transfer from STATFIFO.
CSI.CSICR2.DMA_BURST_TYPE_RFF(30..31) :0x0
Burst Type of DMA Transfer from RxFIFO.
CSI.CSICR3 Addr:0x021C4008 Value:0x2D7F0000 - This read/write register acts as an extension of the functionality of the CSI Control register 1, adding additional control and features.
CSI.CSICR3.ECC_AUTO_EN(0..0) :0x0
Automatic Error Correction Enable.
CSI.CSICR3.ECC_INT_EN(1..1) :0x0
Error Detection Interrupt Enable.
CSI.CSICR3.ZERO_PACK_EN(2..2) :0x0
Dummy Zero Packing Enable.
CSI.CSICR3.TWO_8BIT_SENSOR(3..3) :0x0
Two 8-bit Sensor Mode.
CSI.CSICR3.RXFF_LEVEL(4..6) :0x0
RxFIFO Full Level.
CSI.CSICR3.HRESP_ERR_EN(7..7) :0x0
Hresponse Error Enable.
CSI.CSICR3.STATFF_LEVEL(8..10) :0x0
STATFIFO Full Level.
CSI.CSICR3.DMA_REQ_EN_SFF(11..11) :0x0
DMA Request Enable for STATFIFO.
CSI.CSICR3.DMA_REQ_EN_RFF(12..12) :0x0
DMA Request Enable for RxFIFO.
CSI.CSICR3.DMA_REFLASH_SFF(13..13) :0x0
Reflash DMA Controller for STATFIFO.
CSI.CSICR3.DMA_REFLASH_RFF(14..14) :0x0
Reflash DMA Controller for RxFIFO.
CSI.CSICR3.FRMCNT_RST(15..15) :0x0
Frame Count Reset.
CSI.CSICR3.FRMCNT(16..31) :0x2d7f
Frame Counter.
CSI.CSISTATFIFO Addr:0x021C400C Value:0x00000000 - The StatFIFO is a read-only register containing statistic data from the sensor.
CSI.CSISTATFIFO.STAT(0..31) :0x0
Static data from sensor
CSI.CSIRFIFO Addr:0x021C4010 Value:0x00000000 - This read-only register contains received image data.
CSI.CSIRFIFO.IMAGE(0..31) :0x0
Received image data
CSI.CSIRXCNT Addr:0x021C4014 Value:0x00009600 - This register works for EOF interrupt generation.
CSI.CSIRXCNT.RXCNT(0..21) :0x9600
RxFIFO Count.
CSI.CSISR Addr:0x021C4018 Value:0x80014000 - This read/write register shows sensor interface status, and which kind of interrupt is being generated.
CSI.CSISR.DRDY(0..0) :0x0
RXFIFO Data Ready.
CSI.CSISR.ECC_INT(1..1) :0x0
CCIR Error Interrupt.
CSI.CSISR.HRESP_ERR_INT(7..7) :0x0
Hresponse Error Interrupt Status.
CSI.CSISR.COF_INT(13..13) :0x0
Change Of Field Interrupt Status.
CSI.CSISR.F1_INT(14..14) :0x1
CCIR Field 1 Interrupt Status.
CSI.CSISR.F2_INT(15..15) :0x0
CCIR Field 2 Interrupt Status.
CSI.CSISR.SOF_INT(16..16) :0x1
Start of Frame Interrupt Status.
CSI.CSISR.EOF_INT(17..17) :0x0
End of Frame (EOF) Interrupt Status.
CSI.CSISR.RXFF_INT(18..18) :0x0
RXFIFO Full Interrupt Status.
CSI.CSISR.DMA_TSF_DONE_FB1(19..19) :0x0
DMA Transfer Done in Frame Buffer1.
CSI.CSISR.DMA_TSF_DONE_FB2(20..20) :0x0
DMA Transfer Done in Frame Buffer2.
CSI.CSISR.STATFF_INT(21..21) :0x0
STATFIFO Full Interrupt Status.
CSI.CSISR.DMA_TSF_DONE_SFF(22..22) :0x0
DMA Transfer Done from StatFIFO.
CSI.CSISR.RF_OR_INT(24..24) :0x0
RxFIFO Overrun Interrupt Status.
CSI.CSISR.SF_OR_INT(25..25) :0x0
STATFIFO Overrun Interrupt Status.
CSI.CSISR.DMA_FIELD1_DONE(26..26) :0x0
When DMA field 0 is complete, this bit will be set to 1(clear by writing 1).
CSI.CSISR.DMA_FIELD0_DONE(27..27) :0x0
When DMA field 0 is complete, this bit will be set to 1(clear by writing 1).
CSI.CSISR.BASEADDR_CHHANGE_ERROR(28..28) :0x0
When using base address switching enable, this bit will be 1 when switching occur before DMA complete.
CSI.CSIDMASA_STATFIFO Addr:0x021C4020 Value:0x00000000 - This register provides the start address for the embedded DMA controller of STATFIFO.
CSI.CSIDMASA_STATFIFO.DMA_START_ADDR_SFF(2..31) :0x0
DMA Start Address for STATFIFO.
CSI.CSIDMATS_STATFIFO Addr:0x021C4024 Value:0x00000000 - This register provides the total transfer size for the embedded DMA controller of STATFIFO.
CSI.CSIDMATS_STATFIFO.DMA_TSF_SIZE_SFF(0..31) :0x0
DMA Transfer Size for STATFIFO.
CSI.CSIDMASA_FB1 Addr:0x021C4028 Value:0x8E196000 - This register provides the start address in the frame buffer1 for the embedded DMA controller of RxFIFO.
CSI.CSIDMASA_FB1.DMA_START_ADDR_FB1(2..31) :0x23865800
DMA Start Address in Frame Buffer1.
CSI.CSIDMASA_FB2 Addr:0x021C402C Value:0x8E22C000 - This register provides the start address in the frame buffer2 for the embedded DMA controller of RxFIFO.
CSI.CSIDMASA_FB2.DMA_START_ADDR_FB2(2..31) :0x2388b000
DMA Start Address in Frame Buffer2.
CSI.CSIFBUF_PARA Addr:0x021C4030 Value:0x00000000 - This register provides the stride of the frame buffer to show how many words to skip before starting to write the next row of the image.
CSI.CSIFBUF_PARA.FBUF_STRIDE(0..15) :0x0
Frame Buffer Parameter.
CSI.CSIFBUF_PARA.DEINTERLACE_STRIDE(16..31) :0x0
DEINTERLACE_STRIDE is only used in the deinterlace mode.
CSI.CSIIMAG_PARA Addr:0x021C4034 Value:0x028000F0 - This register provides the width and the height of the image from the sensor.
CSI.CSIIMAG_PARA.IMAGE_HEIGHT(0..15) :0xf0
Image Height.
CSI.CSIIMAG_PARA.IMAGE_WIDTH(16..31) :0x280
Image Width.
CSI.CSICR18 Addr:0x021C4048 Value:0x8002D000 - This read/write register acts as an extension of the functionality of the CSI Control register 1
CSI.CSICR18.NTSC_EN(0..0) :0x0
This bit is used to select NTSC/PAL mode When input is TVDECODER or standard CCIR656 video.
CSI.CSICR18.DEINTERLACE_EN(2..2) :0x0
This bit is used to select the output method When input is standard CCIR656 video.
CSI.CSICR18.PARALLEL24_EN(3..3) :0x0
When input is parallel rgb888/yuv444 24bit, this bit can be enabled.
CSI.CSICR18.BASEADDR_SWITCH_EN(4..4) :0x0
When this bit is enabled, CSI DMA will switch the base address according to BASEADDR_SWITCH_SEL rather than atomically by DMA completed.
CSI.CSICR18.BASEADDR_SWITCH_SEL(5..5) :0x0
CSI 2 base addresses switching method.
CSI.CSICR18.FIELD0_DONE_IE(6..6) :0x0
In interlace mode, fileld 0 means interrupt enabled.
CSI.CSICR18.DMA_FIELD1_DONE_IE(7..7) :0x0
When in interlace mode, field 1 done interrupt enable.
CSI.CSICR18.LAST_DMA_REQ_SEL(8..8) :0x0
Choosing the last DMA request condition.
CSI.CSICR18.BASEADDR_CHANGE_ERROR_IE(9..9) :0x0
Base address change error interrupt enable signal.
CSI.CSICR18.RGB888A_FORMAT_SEL(10..10) :0x0
Output is 32-bit format.
CSI.CSICR18.AHB_HPROT(12..15) :0xd
Hprot value in AHB bus protocol.
CSI.CSICR18.CSI_LCDIF_BUFFER_LINES(16..17) :0x2
The number of lines are used in handshake mode with LCDIF.
CSI.CSICR18.MASK_OPTION(18..19) :0x0
These bits used to choose the method to mask the CSI input.
CSI.CSICR18.CSI_ENABLE(31..31) :0x1
CSI global enable signal.
Solved! Go to Solution.
We have found the cause of the problem. We were unaware that besides Pad and Mux settings, some pins also have a SELECT_INPUT register, with a DAISY field, that needs to be configured properly to get the right signals from the right pads.
The default DAISY settings for CSI_HSYNC_SELECT_INPUT and CSI_VSYNC_SELECT_INPUT are both 0, respectively CSI_HSYNC_ALT0 (Selecting Pad: CSI_HSYNC for Mode: ALT0) and CSI_VSYNC_ALT0 (Selecting Pad: CSI_VSYNC for Mode: ALT0), so these signals were received.
But for CSI_PIXCLK_SELECT_INPUT the default 0 value selects GPIO1_IO07_ALT3 (Selecting Pad: GPIO1_IO07 for Mode: ALT3). It needs to be set to 1 for CSI_PIXCLK_ALT0 (Selecting Pad: CSI_PIXCLK for Mode: ALT0) for PIXCLK to be received.
Receiving no PIXCLK on the CSI peripheral perfectly explains why we did see CSI.CSICR3.FRMCNT increment at the expected rate, but no data in the RxFIFO. Setting the correct SELECT_INPUT.DAISY values for these signals and the CSI DATA signals did make the CSI peripheral produce data.
I find it a bit unfortunate (avoiding the word sloppy here) that the Reference Manuel makes no reference from SW_PAD_CTL registers to the appropriate SELECT_INPUT if applicable, and vice versa, because this is a real caveat. This has cost us - and probably many others - lots of time, which could have been prevented with a few small annotations.
We have found the cause of the problem. We were unaware that besides Pad and Mux settings, some pins also have a SELECT_INPUT register, with a DAISY field, that needs to be configured properly to get the right signals from the right pads.
The default DAISY settings for CSI_HSYNC_SELECT_INPUT and CSI_VSYNC_SELECT_INPUT are both 0, respectively CSI_HSYNC_ALT0 (Selecting Pad: CSI_HSYNC for Mode: ALT0) and CSI_VSYNC_ALT0 (Selecting Pad: CSI_VSYNC for Mode: ALT0), so these signals were received.
But for CSI_PIXCLK_SELECT_INPUT the default 0 value selects GPIO1_IO07_ALT3 (Selecting Pad: GPIO1_IO07 for Mode: ALT3). It needs to be set to 1 for CSI_PIXCLK_ALT0 (Selecting Pad: CSI_PIXCLK for Mode: ALT0) for PIXCLK to be received.
Receiving no PIXCLK on the CSI peripheral perfectly explains why we did see CSI.CSICR3.FRMCNT increment at the expected rate, but no data in the RxFIFO. Setting the correct SELECT_INPUT.DAISY values for these signals and the CSI DATA signals did make the CSI peripheral produce data.
I find it a bit unfortunate (avoiding the word sloppy here) that the Reference Manuel makes no reference from SW_PAD_CTL registers to the appropriate SELECT_INPUT if applicable, and vice versa, because this is a real caveat. This has cost us - and probably many others - lots of time, which could have been prevented with a few small annotations.
thanks for your sharing