i.MX6UL CSI: No data in RXFIFO

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i.MX6UL CSI: No data in RXFIFO

Jump to solution
1,172 Views
MindBender
Contributor II

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.

 

 

Full frameFull frame

2nd image line2nd image line

First pixels on 2nd image lineFirst pixels on 2nd image line

Labels (2)
0 Kudos
1 Solution
1,094 Views
MindBender
Contributor II

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.

View solution in original post

0 Kudos
2 Replies
1,095 Views
MindBender
Contributor II

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.

0 Kudos
1,089 Views
joanxie
NXP TechSupport
NXP TechSupport

thanks for your sharing

0 Kudos