/****************************************************************************
|
* Copyright: (C)2014 Î人ÁèÔÆÇ¶ÈëʽʵÑéÊÒ www.emblinux.com
|
* Author: GuoWenxue<guowenxue@gmail.com> QQ: 281143292
|
* Description: ·Ü¶·STM32v5¿ª·¢°åOV7670µÄ¼Ä´æÆ÷±í£¬Ö¡Í¬²½ÖжÏÅäÖã¬
|
* ÒÔ¼°ÉãÏñÍ·OV7670+FIFOµÄÒý½Å³õʼ»¯£º
|
*
|
* ChangeLog:
|
* °æ±¾ºÅ ÈÕÆÚ ×÷Õß ËµÃ÷
|
* V1.0.0 2014.08.25 GuoWenxue ·¢²¼¸Ã°æ±¾
|
****************************************************************************/
|
|
/* CF7670C-V3ÉãÏñÍ·Ä£¿éPin¹Ü½ÅºÍSTM32v5 Á¬½Ó±í:
|
*| ²Î¿¼<CF7670C-V3 ¼òҪ˵Ã÷.pdf>ºÍ<·Ü¶·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);
|
}
|
}
|
|
|
static __inline int ov_read_reg(u16 reg, u8 *val)
|
{
|
if( !I2C_ReadByte(val, 1, reg, OV7670_ADDR) )
|
return -1;
|
|
return 0;
|
}
|
|
static __inline int ov_write_reg(u16 reg, u8 val)
|
{
|
return !I2C_WriteByte(reg, val, OV7670_ADDR);
|
}
|
|
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( ov_write_reg(pNext->reg, pNext->val) )
|
{
|
return 1;
|
}
|
}
|
pNext++ ;
|
}
|
return 0;
|
}
|
|
/* ³õʼ»¯OV7670ÄÚ²¿¸÷¸ö¼Ä´æÆ÷ */
|
int init_ov7670_reg(int output_fmt)
|
{
|
u8 ID_code = 0;
|
|
/*³õʼ»¯PE2/PE3Á½¸ö¹Ü½Å,ËûÃÇÓÃÀ´GPIOÄ£ÄâI2C×ÜÏß*/
|
init_sccb_gpio();
|
|
/* ͨ¹ýдOV7670µÄCOM7¼Ä´æÆ÷µÄbit[7]À´ÖØÆôËü */
|
if( ov_write_reg(OV7670_REG_COM7, 1<<7) )
|
{
|
return 1 ;
|
}
|
msleep(15);
|
|
/* ´Ó¼Ä´æÆ÷ÖжÁ³ö²úÆ·ID²¢ÅжÏÊÇ·ñÊÇOV7670µÄID */
|
if( ov_read_reg(OV7670_REG_VERID, &ID_code) )
|
{
|
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;
|
}
|
|
/* ²Î¿¼ ov7670·Ö±æÂÊÉèÖÃ.pdf */
|
void ov7670_config_window_size(u16 startx, u16 starty, u16 width, u16 height)
|
{
|
u16 endx = (startx+width*2)/784;
|
u16 endy = (starty+height*2);
|
|
u8 x_reg, y_reg, v;
|
|
ov_read_reg(REG_HREF, &x_reg );
|
x_reg &= 0xC0;
|
|
ov_read_reg(REG_VREF, &y_reg );
|
y_reg &= 0xF0;
|
|
//ÉèÖÃ HREF
|
v = x_reg|((endx&0x7)<<3)|(startx&0x7);
|
ov_write_reg(REG_HREF, v );
|
|
v = (startx&0x7F8)>>3;
|
ov_write_reg(REG_HSTART, v );
|
|
v = (endx&0x7F8)>>3;
|
ov_write_reg(REG_HSTOP, v );
|
|
//ÉèÖÃ VREF
|
v = y_reg|((endy&0x3)<<2)|(starty&0x3);
|
ov_write_reg(REG_VREF, v );
|
|
v = (starty&0x3FC)>>2;
|
ov_write_reg(REG_VSTART, v );
|
|
v = (endy&0x3FC)>>2;
|
ov_write_reg(REG_VSTOP, v );
|
}
|
|
|