BSP包中有两个CAP相关的例程,两个例程的区别为获取的图像数据的存储格式不同,planar例程是先存储所有像素点的Y,再存U,再存V。packed例程是每个像素的YUV连续存储。
处理器为NUC980DR61Y,封装为64pin,只有CAP0接口,所以Sensor接在处理器的CAP0接口:
硬件连接如下:
CMOS的所需的24MHz工作时钟由处理器PC.3输出。
1、添加void CAP0_IRQHandler(void)函数
- /*------------------------------------------------------------------------------------------*/
- /* CAP_IRQHandler */
- /*------------------------------------------------------------------------------------------*/
- void CAP0_IRQHandler(void)
- {
- uint32_t u32CapInt;
- u32CapInt = CAP0->INT;
- if( (u32CapInt & (CAP_INT_VIEN_Msk | CAP_INT_VINTF_Msk )) == (CAP_INT_VIEN_Msk | CAP_INT_VINTF_Msk))
- {
- CAP_InterruptHandler();
- CAP0->INT |= CAP_INT_VINTF_Msk; /* Clear Frame end interrupt */
- u32EscapeFrame = u32EscapeFrame+1;
- }
-
- if((u32CapInt & (CAP_INT_ADDRMIEN_Msk|CAP_INT_ADDRMINTF_Msk)) == (CAP_INT_ADDRMIEN_Msk|CAP_INT_ADDRMINTF_Msk))
- {
- CAP0->INT |= CAP_INT_ADDRMINTF_Msk; /* Clear Address match interrupt */
- }
-
- if ((u32CapInt & (CAP_INT_MEIEN_Msk|CAP_INT_MEINTF_Msk)) == (CAP_INT_MEIEN_Msk|CAP_INT_MEINTF_Msk))
- {
- CAP0->INT |= CAP_INT_MEINTF_Msk; /* Clear Memory error interrupt */
- }
-
- if ((u32CapInt & (CAP_INT_MDIEN_Msk|CAP_INT_MDINTF_Msk)) == (CAP_INT_MDIEN_Msk|CAP_INT_MDINTF_Msk))
- {
- CAP0->INT |= CAP_INT_MDINTF_Msk; /* Clear Motion Detection interrupt */
- }
- CAP0->CTL = CAP0->CTL | CAP_CTL_UPDATE;
- }
2、注册IRQ_CAP0中断
- sysInstallISR(IRQ_LEVEL_1, IRQ_CAP0, (PVOID)CAP0_IRQHandler);
- sysSetLocalInterrupt(ENABLE_IRQ);
- sysEnableInterrupt(IRQ_CAP0);
3、使能时钟
- /* Init Engine clock and Sensor clock */
- CAP_SetFreq(CAP0,48000000,24000000);
CMOS的时钟结构如上图所示,例程中的配置SENSORx_S是选择的XTALIN12M,如果需要设置SENx_CLK为24MHz,那么需要XTALIN12M为48MHz才行,如果XTALIN12M为12MHz,那么经过分频之后SENx_CLK为6MHz。一般APLLFout、UPLLFout为300MHz,将SENSORx_SDIV配置为2,三分频后ACLKout或UCLKout为100MHz,再将SENSORx_N配置为3,四分频后SENx_CLK为25MHz,测试时发现SENSORx_S选择ULCKout才行,选ACLKout会有问题。
4、将void PacketFormatDownScale(uint32_t SensorId)函数中关于CAP1的配置改为CAP0
- void PacketFormatDownScale(uint32_t SensorId)
- {
- uint32_t u32Frame;
-
- /* Enable External CAP Interrupt */
- CAP_EnableInt(CAP0,CAP_INT_VIEN_Msk);
-
- /* Set Vsync polarity, Hsync polarity, pixel clock polarity, Sensor Format and Order */
- if(SensorId==SENSOR_GC0308)
- CAP_Open(CAP0,GC0308SensorPolarity | GC0308DataFormatAndOrder, CAP_CTL_PKTEN );
- else
- CAP_Open(CAP0,NT99XXXSensorPolarity | NT99XXXDataFormatAndOrder, CAP_CTL_PKTEN );
-
- /* Set Cropping Window Vertical/Horizontal Starting Address and Cropping Window Size */
- CAP_SetCroppingWindow(CAP0,0,0,SENSOR_IN_HEIGHT,SENSOR_IN_WIDTH);
-
- /* Set System Memory Packet Base Address Register */
- CAP_SetPacketBuf(CAP0,(uint32_t)u8FrameBuffer);
-
- /* Set Packet Scaling Vertical/Horizontal Factor Register */
- CAP_SetPacketScaling(CAP0,SYSTEM_HEIGHT,SENSOR_IN_HEIGHT,SYSTEM_WIDTH,SENSOR_IN_WIDTH);
-
- /* Set Packet Frame Output Pixel Stride Width */
- CAP_SetPacketStride(CAP0,SYSTEM_WIDTH);
-
- /* Start Image Capture Interface */
- CAP_Start(CAP0);
-
- u32Frame=u32FramePass;
- while(1)
- {
- if(u32Frame!=u32FramePass)
- {
- u32Frame=u32FramePass;
- printf("Get frame %3d\n",u32Frame);
- }
- }
-
- }
5、添加Sensor
例程中包含了三款Sensor的初始化代码,而我们项目中用到的sensor型号没在例程中,所以需要编写Sensor的初始化代码。
修改XXX_SnrReset()函数:
- static void XXX_SnrReset(void)
- {
- /* PB4 reset: H->L->H */
- outpw(REG_SYS_GPB_MFPL,(inpw(REG_SYS_GPB_MFPL) & ~0x000F0000));
-
- GPIO_SetMode(PB,1<<4,GPIO_MODE_OUTPUT);
- PB4=1;
- Delay(100);
- PB4=0;
- Delay(100);
- PB4=1;
- }
例程中所用RESET管脚为PE10,改为PB4。关于GPIO相关的寄存器,参看文档
修改XXX_SnrPowerDown()函数:
- static void XXX_SnrPowerDown(BOOL bIsEnable)
- {
- /* PB6 power down, HIGH for power down */
- outpw( REG_SYS_GPB_MFPL,(inpw(REG_SYS_GPB_MFPL) & ~0x0F000000));
- GPIO_SetMode(PB,1<<6,GPIO_MODE_OUTPUT);
- PB6=0;
- if(bIsEnable)
- PB6=1;
- else
- PB6=0;
- }
例程中所用power down管脚为PC0,改为PB6。高电平进入power down模式。
修改I2C SCL和SDA管脚,SCL改为PA1,SDA改为PA0:
SWI2C_Open(eDRVGPIO_GPIOA,eDRVGPIO_PIN1,eDRVGPIO_GPIOA,eDRVGPIO_PIN0,Delay);
例程中i2c驱动为gpio模拟,并且SWI2C_ReadByte(,)函数中关于ACK和NO_ACK的时序不符规范要求,修改之后如下:
- //-------------------------------
- //master read bytes data from slave device
- uint32_t
- SWI2C_ReadByte(
- uint8_t u8AckType,
- uint8_t u8Length
- )
- {
- uint32_t u32Data=0;
- uint8_t u8DataCount;
-
- _SWI2C_SDA_SETIN(s_sChannel.u32SDAPortIndex, s_sChannel.u32SDAPinMask);
- // Read data from slave device and the most signification bit(MSB) first
- for ( u8DataCount=0; u8DataCount<u8Length; u8DataCount++ )
- {
- u32Data = u32Data<<1;
- _SWI2C_Delay(3);
- _SWI2C_SCK_SETHIGH(s_sChannel.u32SCKPortIndex, s_sChannel.u32SCKPinMask);
- if (_SWI2C_SDA_GETVALUE(s_sChannel.u32SDAPortIndex, s_sChannel.u32SDAPinMask)==s_sChannel.u32SDAPinMask)
- u32Data = u32Data|0x01;
- _SWI2C_Delay(2);
- _SWI2C_SCK_SETLOW(s_sChannel.u32SCKPortIndex, s_sChannel.u32SCKPinMask);
- _SWI2C_Delay(2);
- }
-
- _SWI2C_SDA_SETOUT(s_sChannel.u32SDAPortIndex, s_sChannel.u32SDAPinMask);
-
- // No write Ack
- if ( u8AckType == DrvI2C_Ack_No )
- {
- _SWI2C_SDA_SETHIGH(s_sChannel.u32SDAPortIndex, s_sChannel.u32SDAPinMask);
- _SWI2C_Delay(3);
- _SWI2C_SCK_SETHIGH(s_sChannel.u32SCKPortIndex, s_sChannel.u32SCKPinMask);
- _SWI2C_Delay(2);
- _SWI2C_SCK_SETLOW(s_sChannel.u32SCKPortIndex, s_sChannel.u32SCKPinMask);
- _SWI2C_Delay(2);
- return u32Data;
- }
-
- // Have a Ack
- // write a ACK bit to slave device
- _SWI2C_SDA_SETLOW(s_sChannel.u32SDAPortIndex, s_sChannel.u32SDAPinMask);
- _SWI2C_Delay(3);
- _SWI2C_SCK_SETHIGH(s_sChannel.u32SCKPortIndex, s_sChannel.u32SCKPinMask);
- _SWI2C_Delay(2);
- _SWI2C_SCK_SETLOW(s_sChannel.u32SCKPortIndex, s_sChannel.u32SCKPinMask);
- _SWI2C_Delay(2);
-
- return u32Data;
- }
6、根据Sensor的手册修改g_XXX_VGA_RegValue[]寄存器列表。
7、运行日志
- This sample code demonstrate CAP packet down scale function
- ======================================================
- CAP library demo code
- [1] NT99141 VGA
- [2] NT99050 VGA
- [3] GC0308 VGA
- [4] XXX VGA
- ======================================================
- Sensor Chip_Version = 0x1324(0x1324)
- Get frame 1
- Get frame 2
- Get frame 3
- Get frame 4
由于u8FrameBuffer的内容会被不断覆盖,如果想要将数据缓存以待处理,那么可再定义一个相同尺寸的u8ImageBuffer,在CAP_InterruptHandler()函数中将u8FrameBuffer的内容拷贝到u8ImageBuffer,并通过一个标志防止u8ImageBuffer中的数据未处理时被覆盖,待数据处理后将标志置0。CAP_InterruptHandler()修改如下:
- void CAP_InterruptHandler(void)
- {
- u32FramePass++;
-
- if( ImageCpyFlag == 0 )
- {
- memcpy(u8ImageBuffer, u8FrameBuffer, SYSTEM_WIDTH*SYSTEM_HEIGHT * 2 );
- ImageCpyFlag = 1;
- }
- }