STM32F4_V1.25.0韌體庫應用於STM32F407ZGT6(二)- 除錯攝像頭OV3640的IIC通路

可可西里_X_back發表於2020-12-18

1、軟體、硬體

接著上一篇部落格的工程基礎
STM32F4_V1.25.0韌體庫應用於STM32F407ZGT6(一)

2、硬體連線

嘮叨幾句,購買了一個在卡片電腦上專用的攝像頭模組,排針和我的板子camara卡槽匹配不上,只能飛線。長下面這個樣子,CAMERA是卡槽介面,背面有個CAMERB是插針
在這裡插入圖片描述

商家只管賣,連個原理圖都沒有,板子上引腳名稱也沒有,詢問商家的回覆是這攝像頭為某某板子專用,他們也沒有原理圖。網上查了那些板子camera介面的原理圖,才知道攝像頭上的三角符號一端要板子上三角符號對應。好吧,原理圖上也沒有標註三角符號那一端是地線還是排線頂端。

好不容易找到在Android系統上使用過該模組的人,給出的說明書如下。

2.1、CAMERA介面圖

下圖EINT19其實就是PWDN引腳

在這裡插入圖片描述
對應模組來看,CAMERA介面應該是下面這樣的,和上圖左右對應匹配

在這裡插入圖片描述

2.2、CAMERB介面圖

在這裡插入圖片描述
看模組背面的CAMERB介面,實際上插針對應左右兩邊和上圖相反。只要保證CAMERA介面認識正確,用萬用表探CAMERA和CAMERB即可找到引腳。

為啥這麼設計呢?帶著疑問,我去看板子的硬體,也是這樣的,板子上卡槽是按原理圖的左右順序預留的,那麼插針只有左右順序對調才能匹配板子。或者板子做預留的卡槽和攝像頭插針左右相反,總之這是需要留意的點。

用公對公的杜邦線一個一個和板子引腳連線,這裡先測試IIC通路,把5V、3.3V、GND、RST、PWDN、I2C_SCL、I2C_SDA對應連線到板子上。

板子camera介面原理圖如下:
在這裡插入圖片描述

3、程式碼實現

OV3640的IIC裝置地址是0x78,寫資料時是0x78,讀資料時是0x79。STM32的i2c驅動對於裝置地址是直接傳入0x78,根據讀寫再與或讀寫位(無需左移)。

從標準IIC波形上看攝像頭的資料,裝置地址的高7位是0X3C,那種需要左移或上讀寫位的驅動,傳入的是0X3C,左移或上讀寫位即為0x78(寫)、0x79(讀)。

在這裡插入圖片描述

3.1、i2c.h檔案

#ifndef __BSP_I2C_H__
#define __BSP_I2C_H__

/****************************** Includes *****************************/
#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"
#include "bsp_debug_usart.h"

/****************************** Defines *******************************/

#define OV3640_DEVICE_ADDRESS     0x78      	//0x78 & 1 = 0x78 寫
                                            	//0x78 | 1 = 0x79 讀

/*引腳定義*/ 
#define SENSORS_I2C_SCL_GPIO_PORT         		GPIOB
#define SENSORS_I2C_SCL_GPIO_CLK_ENABLE()    	__GPIOB_CLK_ENABLE()
#define SENSORS_I2C_SCL_GPIO_PIN         		GPIO_PIN_8
 
#define SENSORS_I2C_SDA_GPIO_PORT         		GPIOB
#define SENSORS_I2C_SDA_GPIO_CLK_ENABLE()   	__GPIOB_CLK_ENABLE()
#define SENSORS_I2C_SDA_GPIO_PIN          		GPIO_PIN_9

#define SENSORS_I2C_AF                    		GPIO_AF4_I2C1

#define SENSORS_I2C              		  		I2C1
#define SENSORS_I2C_RCC_CLK_ENABLE()     		__HAL_RCC_I2C1_CLK_ENABLE()

#define SENSORS_I2C_FORCE_RESET()      			__HAL_RCC_I2C1_FORCE_RESET()
#define SENSORS_I2C_RELEASE_RESET()    			__HAL_RCC_I2C1_RELEASE_RESET()
									 
void I2CMaster_Init(void);										 
uint8_t OV3640_WriteReg(uint16_t Addr, uint8_t Data);
uint8_t OV3640_ReadReg(uint16_t Addr);

#endif // __BSP_I2C_H__

3.2、i2c.c檔案

OV3640的暫存器地址是16位,所以直接呼叫 HAL_I2C_Mem_Write、HAL_I2C_Mem_Read函式操作暫存器,第4個引數傳入I2C_MEMADD_SIZE_16BIT即可。

#include "bsp_i2c.h"
#include <stdio.h>

I2C_HandleTypeDef I2C_Handle;
					
/*******************************  Function ************************************/

void I2CMaster_Init(void) 
{
	GPIO_InitTypeDef GPIO_InitStructure;

	/* 使能I2Cx時鐘 */
	SENSORS_I2C_RCC_CLK_ENABLE();

	/* 使能I2C GPIO 時鐘 */
	SENSORS_I2C_SCL_GPIO_CLK_ENABLE();
	SENSORS_I2C_SDA_GPIO_CLK_ENABLE();

	/* 配置I2Cx引腳: SCL ----------------------------------------*/
	GPIO_InitStructure.Pin =  SENSORS_I2C_SCL_GPIO_PIN; 
	GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
	GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
	GPIO_InitStructure.Pull = GPIO_NOPULL;
	GPIO_InitStructure.Alternate = SENSORS_I2C_AF; 
	HAL_GPIO_Init(SENSORS_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);

	/* 配置I2Cx引腳: SDA ----------------------------------------*/
	GPIO_InitStructure.Pin = SENSORS_I2C_SDA_GPIO_PIN;  
	HAL_GPIO_Init(SENSORS_I2C_SDA_GPIO_PORT, &GPIO_InitStructure); 
	
	if(HAL_I2C_GetState(&I2C_Handle) == HAL_I2C_STATE_RESET)
	{	
		/* 強制復位I2C外設時鐘 */  
		SENSORS_I2C_FORCE_RESET(); 

		/* 釋放I2C外設時鐘復位 */   
		SENSORS_I2C_RELEASE_RESET(); 
		
        /* I2C 配置 */
		I2C_Handle.Instance = SENSORS_I2C;
        I2C_Handle.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
    	I2C_Handle.Init.ClockSpeed      = 40000;    //40K,低速率
    	I2C_Handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    	I2C_Handle.Init.DutyCycle       = I2C_DUTYCYCLE_2;
    	I2C_Handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    	I2C_Handle.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;
    	I2C_Handle.Init.OwnAddress1     = 0xFE ;
    	I2C_Handle.Init.OwnAddress2     = 0; 
   
		/* 初始化I2C */
		HAL_I2C_Init(&I2C_Handle);	
	}
}

/**
  * @brief  Manages error callback by re-initializing I2C.
  * @param  Addr: I2C Address
  * @retval None
  */
static void I2Cx_Error(void)
{
	/* 恢復I2C暫存器為預設值 */
	HAL_I2C_DeInit(&I2C_Handle); 
	/* 重新初始化I2C外設 */
	I2CMaster_Init();
}

/**
  * @brief  寫一位元組資料到OV3640暫存器
  * @param  Addr: OV3640 的暫存器地址
  * @param  Data: 要寫入的資料
  * @retval 返回0表示寫入正常,0xFF表示錯誤
  */
uint8_t OV3640_WriteReg(uint16_t Addr, uint8_t Data)
{
  HAL_StatusTypeDef status = HAL_OK;
  
  status = HAL_I2C_Mem_Write(&I2C_Handle, OV3640_DEVICE_ADDRESS, (uint16_t)Addr, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&Data, 1, 1000);
  
  /* Check the communication status */
  if(status != HAL_OK)
  {
    /* Re-Initiaize the I2C Bus */
    printf("ERR write status[%d]\r\n",status);
    I2Cx_Error();
  }
  
  return status;
}

/**
  * @brief  從OV3640暫存器中讀取一個位元組的資料
  * @param  Addr: 暫存器地址ַ
  * @retval 返回讀取得的資料
  */
uint8_t OV3640_ReadReg(uint16_t Addr)
{
  uint8_t Data = 0;

  HAL_StatusTypeDef status = HAL_OK;

  status = HAL_I2C_Mem_Read(&I2C_Handle, OV3640_DEVICE_ADDRESS, (uint16_t)Addr, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&Data, 1, 1000);

  /* Check the communication status */
  if(status != HAL_OK)
  {
    /* I2C error occurred */
    printf("ERR read status[%d]\r\n",status);
    I2Cx_Error();
  }
  
  /* return the read data */
  return Data;
}

3.3、ov3640.h檔案

定義了攝像頭所需的所有引腳

#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"

// VSYNC 
#define DCMI_VSYNC_GPIO_PORT        	    GPIOB
#define DCMI_VSYNC_GPIO_CLK_ENABLE()      	__HAL_RCC_GPIOB_CLK_ENABLE()
#define DCMI_VSYNC_GPIO_PIN         	    GPIO_PIN_7
#define DCMI_VSYNC_AF			            GPIO_AF13_DCMI

// HSYNC
#define DCMI_HSYNC_GPIO_PORT        	    GPIOA
#define DCMI_HSYNC_GPIO_CLK_ENABLE()     	__HAL_RCC_GPIOA_CLK_ENABLE()
#define DCMI_HSYNC_GPIO_PIN         	    GPIO_PIN_4
#define DCMI_HSYNC_AF			            GPIO_AF13_DCMI

// PIXCLK
#define DCMI_PIXCLK_GPIO_PORT        	    GPIOA
#define DCMI_PIXCLK_GPIO_CLK_ENABLE()     	__HAL_RCC_GPIOA_CLK_ENABLE()
#define DCMI_PIXCLK_GPIO_PIN         	    GPIO_PIN_6
#define DCMI_PIXCLK_AF			            GPIO_AF13_DCMI

// PWDN
#define DCMI_PWDN_GPIO_PORT        	      	GPIOC
#define DCMI_PWDN_GPIO_CLK_ENABLE()       	__HAL_RCC_GPIOC_CLK_ENABLE()
#define DCMI_PWDN_GPIO_PIN         	      	GPIO_PIN_0

// RST
#define DCMI_RST_GPIO_PORT        	      	GPIOF
#define DCMI_RST_GPIO_CLK_ENABLE()        	__HAL_RCC_GPIOF_CLK_ENABLE()
#define DCMI_RST_GPIO_PIN       	        GPIO_PIN_10

// D0-D7
#define DCMI_D0_GPIO_PORT        	      	GPIOC
#define DCMI_D0_GPIO_CLK_ENABLE()      		__HAL_RCC_GPIOC_CLK_ENABLE()
#define DCMI_D0_GPIO_PIN                	GPIO_PIN_6
#define DCMI_D0_AF			                GPIO_AF13_DCMI

#define DCMI_D1_GPIO_PORT      	        	GPIOC
#define DCMI_D1_GPIO_CLK_ENABLE()      		__HAL_RCC_GPIOC_CLK_ENABLE()
#define DCMI_D1_GPIO_PIN         	      	GPIO_PIN_7
#define DCMI_D1_AF			                GPIO_AF13_DCMI

#define DCMI_D2_GPIO_PORT               	GPIOC
#define DCMI_D2_GPIO_CLK_ENABLE()      		__HAL_RCC_GPIOC_CLK_ENABLE()
#define DCMI_D2_GPIO_PIN         	      	GPIO_PIN_8
#define DCMI_D2_AF			                GPIO_AF13_DCMI

#define DCMI_D3_GPIO_PORT        	      	GPIOC
#define DCMI_D3_GPIO_CLK_ENABLE()      		__HAL_RCC_GPIOC_CLK_ENABLE()
#define DCMI_D3_GPIO_PIN       	        	GPIO_PIN_9
#define DCMI_D3_AF			                GPIO_AF13_DCMI

#define DCMI_D4_GPIO_PORT        	      	GPIOE
#define DCMI_D4_GPIO_CLK_ENABLE()      		__HAL_RCC_GPIOE_CLK_ENABLE()
#define DCMI_D4_GPIO_PIN         	      	GPIO_PIN_4
#define DCMI_D4_AF			                GPIO_AF13_DCMI

#define DCMI_D5_GPIO_PORT               	GPIOB
#define DCMI_D5_GPIO_CLK_ENABLE()      		__HAL_RCC_GPIOB_CLK_ENABLE()
#define DCMI_D5_GPIO_PIN         	      	GPIO_PIN_6
#define DCMI_D5_AF			                GPIO_AF13_DCMI

#define DCMI_D6_GPIO_PORT        	      	GPIOE
#define DCMI_D6_GPIO_CLK_ENABLE()      		__HAL_RCC_GPIOE_CLK_ENABLE()
#define DCMI_D6_GPIO_PIN       	        	GPIO_PIN_5
#define DCMI_D6_AF			                GPIO_AF13_DCMI

#define DCMI_D7_GPIO_PORT      	        	GPIOE
#define DCMI_D7_GPIO_CLK_ENABLE()      		__HAL_RCC_GPIOE_CLK_ENABLE()
#define DCMI_D7_GPIO_PIN                	GPIO_PIN_6
#define DCMI_D7_AF			                GPIO_AF13_DCMI

#define OV3640_PIDH                         0x300A  //產品ID高8位
#define OV3640_PIDL                         0x300B  //產品ID低8位

//產品ID結構體
typedef struct
{
  uint8_t PIDH;
  uint8_t PIDL;
}OV3640_IDTypeDef;

3.4、ov3640.c檔案

初始化控制攝像頭使用的GPIO

/**
  * @brief  初始化控制攝像頭使用的GPIO
  * @param  None
  * @retval None
  */
void OV3640_HW_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    /***DCMI引腳配置***/
    /* 使能DCMI時鐘 */

    DCMI_RST_GPIO_CLK_ENABLE();
    DCMI_PWDN_GPIO_CLK_ENABLE();
    DCMI_VSYNC_GPIO_CLK_ENABLE();
    DCMI_HSYNC_GPIO_CLK_ENABLE();
    DCMI_PIXCLK_GPIO_CLK_ENABLE();

    DCMI_D0_GPIO_CLK_ENABLE();
    DCMI_D1_GPIO_CLK_ENABLE();
    DCMI_D2_GPIO_CLK_ENABLE();
    DCMI_D3_GPIO_CLK_ENABLE();    
    DCMI_D4_GPIO_CLK_ENABLE();
    DCMI_D5_GPIO_CLK_ENABLE();
    DCMI_D6_GPIO_CLK_ENABLE();
    DCMI_D7_GPIO_CLK_ENABLE();
   
    /*控制/同步訊號線*/
    GPIO_InitStructure.Pin = DCMI_VSYNC_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.Pull = GPIO_PULLUP ;
    GPIO_InitStructure.Alternate = DCMI_VSYNC_AF;
    HAL_GPIO_Init(DCMI_VSYNC_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = DCMI_HSYNC_GPIO_PIN;
    GPIO_InitStructure.Alternate = DCMI_HSYNC_AF;
    HAL_GPIO_Init(DCMI_HSYNC_GPIO_PORT, &GPIO_InitStructure);
 
    GPIO_InitStructure.Pin = DCMI_PIXCLK_GPIO_PIN;
    GPIO_InitStructure.Alternate = DCMI_PIXCLK_AF;
    HAL_GPIO_Init(DCMI_PIXCLK_GPIO_PORT, &GPIO_InitStructure);
    
    /*資料訊號*/
    GPIO_InitStructure.Pin = DCMI_D0_GPIO_PIN;
    GPIO_InitStructure.Alternate = DCMI_D0_AF;
    HAL_GPIO_Init(DCMI_D0_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = DCMI_D1_GPIO_PIN;
    GPIO_InitStructure.Alternate = DCMI_D1_AF;
    HAL_GPIO_Init(DCMI_D1_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = DCMI_D2_GPIO_PIN;
    GPIO_InitStructure.Alternate = DCMI_D2_AF;
    HAL_GPIO_Init(DCMI_D2_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = DCMI_D3_GPIO_PIN;
    GPIO_InitStructure.Alternate = DCMI_D3_AF;
    HAL_GPIO_Init(DCMI_D3_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = DCMI_D4_GPIO_PIN;
    GPIO_InitStructure.Alternate = DCMI_D4_AF;
    HAL_GPIO_Init(DCMI_D4_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = DCMI_D5_GPIO_PIN;
    GPIO_InitStructure.Alternate = DCMI_D5_AF;
    HAL_GPIO_Init(DCMI_D5_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = DCMI_D6_GPIO_PIN;
    GPIO_InitStructure.Alternate = DCMI_D6_AF;
    HAL_GPIO_Init(DCMI_D6_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = DCMI_D7_GPIO_PIN;
    GPIO_InitStructure.Alternate = DCMI_D7_AF;
    HAL_GPIO_Init(DCMI_D7_GPIO_PORT, &GPIO_InitStructure);


    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.Pull = GPIO_PULLUP ;
    GPIO_InitStructure.Pin = DCMI_PWDN_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;    
    HAL_GPIO_Init(DCMI_PWDN_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = DCMI_RST_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init(DCMI_RST_GPIO_PORT, &GPIO_InitStructure);
    
    /*PWDN引腳,高電平關閉電源,低電平供電,GPIO_PIN_RESET是0*/
    HAL_GPIO_WritePin(DCMI_PWDN_GPIO_PORT,DCMI_PWDN_GPIO_PIN,GPIO_PIN_RESET);
}

/**
  * @brief  讀取攝像頭的ID
  * @param  OV3640ID:儲存ID的結構體
  * @retval None
  */
void OV3640_ReadID(OV3640_IDTypeDef *OV3640ID)
{
  /*讀取寄存晶片ID*/
  OV3640ID->PIDH = OV3640_ReadReg(OV3640_PIDH);
  OV3640ID->PIDL = OV3640_ReadReg(OV3640_PIDL);
}


3.5、main函式

int main(void)
{

  HAL_Init();
  /* Configure the system clock to 168 MHz */
  SystemClock_Config();
  DEBUG_USART_Config();
  HAL_Delay(1000);
  //camera	ID 結構體初始化
  OV3640_IDTypeDef OV3640_Camera_ID;
  //I2C初始化
  I2CMaster_Init();   
  //攝像頭硬體初始化
  OV3640_HW_Init();
  HAL_Delay(100);

  //讀取攝像頭ID
  OV3640_ReadID(&OV3640_Camera_ID);
  printf("ID = %x%x\r\n",OV3640_Camera_ID.PIDH ,OV3640_Camera_ID.PIDL);
  
  if(OV3640_Camera_ID.PIDH  == 0x36)
  {
      printf("Right\r\n");
      while(1);
  }
  else
  {
      printf("ERR\r\n");
      while(1);  
  }
}

4、除錯通路

4.1、抓取IIC波形失敗

用邏輯分析儀抓取波形,發現在裝置地址0x78後,收到攝像頭回復的NACK,隨後跟著Stop。懷疑是IIC驅動不對,因為有的OV攝像頭預設回覆的是NACK,而STM32F4的V1.25.0驅動在收到NACK後會報錯退出。OV家的攝像頭,使用SCCB協議,類似IIC,但和IIC還是有點區別,對第9位不關心。

查閱資料,這篇部落格給出瞭解釋,OV3640會回覆ACK,所以不是驅動的問題。
Wince6.0 上增加ov3640攝像頭

4.2、查詢原因,解決問題

可能壓根攝像頭就沒有工作,因為程式起來後,攝像頭一點溫度都沒有,查閱資料發現別的模組外部都有一個24M的晶振,而我購買這一塊攝像頭沒有外部時鐘,草率了以為有來著,原來晶振是長那個樣子。

好吧!查閱資料,尋求幫助,瞭解到攝像頭的時鐘可以由外部晶振提供,或者由主控晶片提供,這裡使用PA8引腳(MCO1)直接將板子外部晶振的時鐘輸出給攝像頭。

我手上的板子外部晶振是25M,剛好符合攝像頭工作時鐘(6-27M)

void ov3640_input_clk()
{
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.Pin = GPIO_PIN_8;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    //時鐘源輸出到MCO1引腳(PA8),選擇HSE時鐘作為MCO1源,1分頻,那麼輸出25M時鐘給攝像頭
    HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE,RCC_MCODIV_1);
}

用示波器探測PA8引腳,可以觀察到25M穩定時鐘輸出,將PA8引腳接到攝像頭的CAMCLK腳

提供時鐘後,攝像頭髮燙了,但是IIC依然沒有資料,害怕因為短路攝像頭才發燙。

在同事幫助下,看晶片手冊文件,上電要滿足一定的時序,攝像頭才會正常工作。對於硬體小白的我來說,以為晶片只要供電就能工作,沒想到還有一定的時序要求。

(哎呦喂,一定要仔細看手冊啊!!!!!!!)

在這裡插入圖片描述
如果1.8V用於I/O電源,則首選使用內部DVDD。 如果2.8V用於I/O電源,由於內部DVDD調節器的高壓下降,存在潛在的熱問題。 因此,對於2.8V的I/O電源,OmniVision建議使用外部DVDD源。

用萬用表探測攝像頭模組的電壓,供電是5V,電源轉換後DOVDD是2.79V,DVDD是1.53V,AVDD是2.79V,這也分不清該用啥電源啊?

隨便試試哪種時序吧!

在這裡插入圖片描述
這個上電後,需要延時5ms再將PWDN腳拉低,加了延時也沒有效果,依然IIC通訊沒有成功。

看到一篇部落格,說OV5640和OV3640差不多,所以參照OV5640的初始化流程,發現OV5640的上電時序還對復位腳有操作。

檢視OV5640的datasheet,無論外部電源還是內部電源,時序都差不多,在PWDN拉低後還有拉高RESET腳才能操作IIC,且保證時鐘穩定輸入。

在這裡插入圖片描述
修改程式碼

void OV3640_HW_Init(void)
{
    /***省略程式碼部分***/

    /*POWER 低*/
    HAL_GPIO_WritePin(DCMI_PWDN_GPIO_PORT,DCMI_PWDN_GPIO_PIN,(GPIO_PinState)0);
    /*RESET 高*/
    HAL_GPIO_WritePin(DCMI_RST_GPIO_PORT,DCMI_RST_GPIO_PIN,(GPIO_PinState)1);
}

再次抓波形,成功讀取到OV3640的產品ID,我的天哪!終於可以了,忙活了幾天。

該產品ID和0V5640這些不一樣,並不是型號ID,而是0X364C
在這裡插入圖片描述

5、總結

5.1、攝像頭要麼使用外部晶振時鐘,要麼使用主控板提供時鐘,必須有時鐘才能工作。

5.2、一定要仔細看手冊,這裡寫了要把復位腳拉高後才能操作IIC,只看圖的我忽略了那句話。

在這裡插入圖片描述

5.3、遇到問題,冷靜分析。

別急,別急,別急

查硬體、查軟體、查文件

相關文章