/**************************************************************************** * Copyright: (C)2014 Î人ÁèÔÆÇ¶ÈëʽʵÑéÊÒ www.emblinux.com * Author: GuoWenxue QQ: 281143292 * Description: ·Ü¶·STM32v5¿ª·¢°åOV7670µÄ¼Ä´æÆ÷±í£¬Ö¡Í¬²½ÖжÏÅäÖ㬠* ÒÔ¼°ÉãÏñÍ·OV7670+FIFOµÄÒý½Å³õʼ»¯£º * * ChangeLog: * °æ±¾ºÅ ÈÕÆÚ ×÷Õß ËµÃ÷ * V1.0.0 2014.08.25 GuoWenxue ·¢²¼¸Ã°æ±¾ ****************************************************************************/ /* CF7670C-V3ÉãÏñÍ·Ä£¿éPin¹Ü½ÅºÍSTM32v5 Á¬½Ó±í: *| ²Î¿¼ºÍ<·Ü¶·STM32¿ª·¢°åV5Ô­Àíͼ.pdf> *+---------------------------------------+------------------------------+ *| CF7670C-V3ÉãÏñÍ·Ä£¿éÒý½Å¼°ËµÃ÷ | STM32¶ËÒý½ÅÁ¬½Ó¼°ËµÃ÷ | *+---------------------------------------+------------------------------+ *| Pin1-VCC(3.3V,·½º¸Å̱ê¼ÇµÄΪµÚÒ»½Å) | 3.3V | *| Pin2-GND | GND | *| Pin3-SCL(SCCB_SCL²»´øÉÏÀ­µç×è) | PE2 | *| Pin4-SDA(SCCB_SDA ´ø4.7KÉÏÀ­µç×è) | PE3 | *| Pin5-VSYNC(OV7670 ֡ͬ²½ÐźÅ) | PE4 | *| Pin6-HREF(OV7670 ÐÐͬ²½ÐźÅ) | NC | *| Pin7-WEN(FIFO(AL422)дÔÊÐí,¸ßµçƽÓÐЧ | PE5 | *| Pin8-XCLK(NC/RE# ¿Õ½Å) | NC | *| Pin9-RRST(FIFO¶ÁµØÖ·¸´Î» | PE6 | *| Pin10-OE#(FIFOÊý¾ÝÊä³öʹÄÜ,µÍµçƽÓÐЧ | GND | *| Pin11-RCK#(FIFO¶ÁÊý¾ÝʱÖÓ | PD12 | *| Pin12-GND | GND | *| | | *| Pin13-D0 FIFOÊý¾Ý¿ÚÊä³öBIT0 | PC0 | *| Pin14-D1 FIFOÊý¾Ý¿ÚÊä³öBIT1 | PC1 | *| Pin15-D2 FIFOÊý¾Ý¿ÚÊä³öBIT2 | PC2 | *| Pin16-D3 FIFOÊý¾Ý¿ÚÊä³öBIT3 | PC3 | *| Pin17-D4 FIFOÊý¾Ý¿ÚÊä³öBIT4 | PC4 | *| Pin18-D5 FIFOÊý¾Ý¿ÚÊä³öBIT5 | PC5 | *| Pin19-D6 FIFOÊý¾Ý¿ÚÊä³öBIT6 | PC6 | *| Pin20-D7 FIFOÊý¾Ý¿ÚÊä³öBIT7 | PC7 | *+------------------+-----------------+---------------------------------+ */ #include "stm32f10x.h" #include "stm32f10x_exti.h" #include "misc.h" #include "ov7670_reg.h" #include "stm32v5_ov7670.h" #include "stm32v5_sccb.h" #include "stm32v5_systick.h" #include "lcd_r61509v.h" /* g_OV7670_VSYNCÓÃÀ´±êʾһ֡µÄ¿ªÊ¼ºÍ½áÊø: * OV7670µÄÊý¾ÝÒÔVGAʱÐòÊä³ö,ÔÚ¸ÃʱÐòÖÐVSYNCµÄϽµÑرíʾһ֡µÄÊý¾Ý¿ªÊ¼,¶øÉÏÉýÑØ±íʾһ֡µÄÊý¾Ý½áÊø. * ËùÒÔÎÒÃǽ«VSYNC¹Ü½ÅPE4ÅäÖóÉEXTI4ÉÏÉýÑØ´¥·¢Ä£Ê½.ÔÚEXTI4µÄÖжϴ¦Àí³ÌÐòEXTI4_IRQHandler()ÖÐ,µÚÒ»´Î * ½øÈëÖжϵÄʱºò,˵Ã÷ÉÏÒ»Ö¡Êý¾ÝÒѾ­½áÊø(ÕâÒ²Òâζ×ÅÕâÒ»Ö¡Êý¾ÝµÄ¿ªÊ¼),ÎÒÃÇ¿ªÊ¼Ê¹ÄÜÉãÏñÍ·Êý¾ÝдÈëFIFO * ²¢¸üÐÂg_OV7670_VSYNCµÄ״ֵ̬Ϊ1;µ±µÚ¶þ´Î½øÈëÖжϵÄʱºò,˵Ã÷ÕâÒ»Ö¡Êý¾ÝµÄ´«ÊäÒѾ­½áÊø,ÎÒÃǾͽûÖ¹ * ÉãÏñÍ·Êý¾ÝдÈëFIFO²¢¸üÐÂg_OV7670_VSYNCµÄ״ֵ̬Ϊ2; * ÔÚÓ¦ÓóÌÐòÖÐ,ÒªÅжÏg_OV7670_VSYNCµÄÖµÊÇ·ñΪ2,Èç¹ûΪ2Ôò¿ÉÒÔ´ÓFIFOÖжÁÈ¡Êý¾Ý,¶ÁÍêºó¸üÐÂÆä״ֵ̬Ϊ0. */ uint8_t g_OV7670_VSYNC = 0; static cam_fifo_pin_t cam_fifo_pins[CAM_FIFO_PIN_MAX] = { {CAM_FIFO_PIN_RRST, GPIOE, GPIO_Pin_6}, /* OV7670 FIFO¶ÁµØÖ·¸´Î», PE6*/ {CAM_FIFO_PIN_RCLK, GPIOD, GPIO_Pin_12}, /* OV7670 FIFO¶ÁʱÖÓ, PD12 */ {CAM_FIFO_PIN_WE, GPIOE, GPIO_Pin_5}, /* OV7670 FIFOдÔÊÐí, PE5 */ }; void set_ov7670_fifo_pin(int which, int level) { if(which<0 || which> CAM_FIFO_PIN_MAX ) return; if(LEVEL_LOW == level) GPIO_ResetBits(cam_fifo_pins[which].group, cam_fifo_pins[which].pin); else GPIO_SetBits(cam_fifo_pins[which].group, cam_fifo_pins[which].pin); } void ov7670_fifo_read_prepare(void) { set_ov7670_fifo_pin(CAM_FIFO_PIN_RRST, LEVEL_LOW); set_ov7670_fifo_pin(CAM_FIFO_PIN_RCLK, LEVEL_LOW); set_ov7670_fifo_pin(CAM_FIFO_PIN_RCLK, LEVEL_HIGH); set_ov7670_fifo_pin(CAM_FIFO_PIN_RRST, LEVEL_HIGH); set_ov7670_fifo_pin(CAM_FIFO_PIN_RCLK, LEVEL_LOW); set_ov7670_fifo_pin(CAM_FIFO_PIN_RCLK, LEVEL_HIGH); } /*³õʼ»¯ÉãÏñÍ·Ä£¿éʹÓõÄFIFO(AL422)Ïà¹ØÒý½Å */ void init_ov7670_fifo_pin(void) { GPIO_InitTypeDef GPIO_InitStructure; /* FIFO_RCLK : PD12 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOD, &GPIO_InitStructure); /* FIFO_VSYNC : PE4 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOE, &GPIO_InitStructure); /* FIFO_WEN:PE5 FIFO_RRST:PE6 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOE, &GPIO_InitStructure); /* FIFO D[0-7] */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); /* PE0-VS-XRST, must set to GPIO output mode here */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOE, &GPIO_InitStructure); } /* ½«VSYNCÁ¬½ÓµÄPE4¹Ü½Å³õʼ»¯ÎªÍⲿÖжÏEXTI4ģʽ£¬²¢ÉèÖÃΪϽµÑØ´¥·¢: * STM32ÉÏËùÓеÄGPIO¶¼ÒýÈëµ½EXTIÍⲿÖжÏÏßÉÏ£¬Ê¹µÃËùÓеÄGPIO¶¼ÄÜ×÷ΪÍⲿÖÐ¶ÏµÄ * ÊäÈëÔ´.ÆäÖÐPA0~PG0Á¬µ½EXTI0ÉÏ... PA4~PG4Á¬µ½EXT4ÉÏ...PA15~PG15Á¬µ½EXTI15ÉÏ * ͨһʱ¿ÌEXTIxÖ»ÄÜÏìÓ¦Ò»¸ö¶Ë¿ÚµÄʼþ´¥·¢,µ«¿ÉÒÔ·Öʱ¸´Óá£Ëü¿ÉÒÔÅäÖÃΪÉÏÉýÑØ, * ϽµÑØ»òË«±ßÑØ´¥·¢¡£ */ void init_ov7670_vsync(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; /* ³õʼ»¯PE4¿ÚΪGPIOÊäÈëģʽ */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOE, &GPIO_InitStructure); /* ½«PE4(VSYNC)¹Òµ½³õʼ»¯ÎªEXTI4ģʽ,²¢Ê¹ÓÃÉÏÉýÑØ´¥·¢: * OV7670ʹÓÃVGAʱÐò´«ÊäÊý¾Ý,VSYNCµÄϽµÑرíʾһ֡Êý¾Ý * (¼´Ò»¸±Í¼Ïñ)µÄ´«Ê俪ʼ,VSYNNµÄÉÏÉýÑØ±íʾһ֡Êý¾ÝµÄ´«Êä½áÊø */ GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4); EXTI_InitStructure.EXTI_Line = EXTI_Line4; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //ÖжÏģʽ EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //ÉÏÉýÑØ´¥·¢ EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); /* ·ÖÅäVSYNCÖжÏÓÅÏȼ¶ */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn ; //ÍⲿÖжÏ4 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //ÇÀÕ¼ÓÅÏȼ¶ 0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //×ÓÓÅÏȼ¶0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //ʹÄÜ NVIC_Init(&NVIC_InitStructure); } void EXTI4_IRQHandler(void) { if( RESET != EXTI_GetITStatus(EXTI_Line4) ) { /*µÚÒ»´ÎVSYNCµÄϽµÑص½À´,˵Ã÷ÕâʱºòÉÏÒ»Ö¡Êý¾ÝÒѾ­½áÊø, Ò²¾ÍÊÇÕâÒ»Ö¡Êý¾Ý¿ªÊ¼.Õâʱ¿ªÊ¼ÈÃÉãÏñÍ·µÄÊý¾Ýдµ½FIFOÖÐÈ¥*/ if( 0==g_OV7670_VSYNC ) { FIFO_WE_H(); /* À­¸ßʹFIFOдʹÄÜ */ g_OV7670_VSYNC = 1; FIFO_WE_H(); /* À­¸ßʹFIFOдʹÄÜ */ } /*µÚ¶þ´ÎVSYNCµÄϽµÑص½À´,˵Ã÷ÕâÒ»Ö¡µÄÊý¾Ý´«ÊäÒѾ­½áÊø,´ËʱFIFO ÀïÃæ¾ÍÒѾ­»º³åºÃOV7670д½øÀ´µÄÍêÕûµÄRGB565 320*240µÄͼÏóÊý¾Ý, ÏÖÔھͽûÖ¹ÉãÏñÍ·µÄÊý¾ÝдÈëµ½FIFOÖÐÈ¥,²¢¸üÐÂg_OV7670_VSYNC*/ else if( 1==g_OV7670_VSYNC ) { FIFO_WE_L(); /* À­µÍʹFIFOдֹͣ */ g_OV7670_VSYNC = 2; } /*ÔÚÓ¦ÓóÌÐòÖÐÑ­»·¼ì²â±êÖ¾±äÁ¿,g_OV7670_VSYNC=2ʱ¾Í¿ÉÒÔ¶ÁFIFOÖеÄÊý¾Ý, ¶ÁÈ¡ÍêFIFOÖеÄÊý¾Ýºó,Ó¦¸ÃÁ¢¿Ì½«g_OV7670_VSYNCÉèÖÃΪ0 */ EXTI_ClearITPendingBit(EXTI_Line4); } } int ov_write_regs(const ov_regval_t *pReglist ) { const ov_regval_t *pNext = pReglist ; while ( !((pNext->reg == OV_REG_TERM) && (pNext->val == OV_VAL_TERM)) ) { if(pNext->reg == 0xFE) { msleep(5); } else { if( !I2C_WriteByte(pNext->reg, pNext->val, OV7670_ADDR) ) { return 1; } } pNext++ ; } return 0; } /* ³õʼ»¯OV7670ÄÚ²¿¸÷¸ö¼Ä´æÆ÷ */ int init_ov7670_reg(int output_fmt) { uint8_t ID_code = 0; /*³õʼ»¯PE2/PE3Á½¸ö¹Ü½Å,ËûÃÇÓÃÀ´GPIOÄ£ÄâI2C×ÜÏß*/ init_sccb_gpio(); /* ͨ¹ýдOV7670µÄCOM7¼Ä´æÆ÷µÄbit[7]À´ÖØÆôËü */ if( !I2C_WriteByte(OV7670_REG_COM7, 1<<7, OV7670_ADDR) ) { return 1 ; } msleep(15); /* ´Ó¼Ä´æÆ÷ÖжÁ³ö²úÆ·ID²¢ÅжÏÊÇ·ñÊÇOV7670µÄID */ if( !I2C_ReadByte(&ID_code, 1, OV7670_REG_VERID, OV7670_ADDR) ) { return 2; } if(ID_code != OV7670_VERID) { return 3; } /* ³õʼ»¯OV7670µÄÆäËû¼Ä´æÆ÷ */ ov_write_regs(ov7670_default_regs); switch(output_fmt) { case FMT_QVGA_YUV422: ov_write_regs(ov7670_fmt_qvga_yuv422); break; case FMT_QVGA_RGB565: ov_write_regs(ov7670_fmt_qvga_rgb565); break; case FMT_QVGA_RGB444: ov_write_regs(ov7670_fmt_qvga_rgb444); break; case FMT_QVGA_RAWRGB: ov_write_regs(ov7670_fmt_qvga_raw); break; } return 0; } int OV7670_Initialize(int output_fmt) { init_ov7670_fifo_pin(); /* ±ØÐëÔÚÕ⸴λһÏÂLCD */ LCD_RST_SET(0); msleep(200); LCD_RST_SET(1); while( 0!=init_ov7670_reg(output_fmt) ) ; /* Èç¹û¼Ä´æÆ÷³õʼ»¯Ê§°ÜÔò»áËÀÔÚÕâÀï */ init_ov7670_vsync(); msleep(50); return 0; }