MP157 linux ov5640 Driver

dev

struct ov5640_dev {
	struct i2c_client *i2c_client;//需要iic 操作
	struct v4l2_subdev sd;//v4l2 接口
	struct media_pad pad;//需要一个pad?
	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
	struct clk *xclk; /* system clock to OV5640 */
	u32 xclk_freq;

	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];// 电源控制
	struct gpio_desc *reset_gpio;
	struct gpio_desc *pwdn_gpio;
	bool   upside_down;// 上下翻转

	/* lock to protect all members below */
	struct mutex lock; //一把锁  

	int power_count;//上电状态 update the power state.

	struct v4l2_mbus_framefmt fmt;//media bus fmt
	bool pending_fmt_change; //停下来改

	const struct ov5640_mode_info *current_mode;//current
	const struct ov5640_mode_info *last_mode;//last
	enum ov5640_frame_rate current_fr;//fps
	struct v4l2_fract frame_interval;//

	struct ov5640_ctrls ctrls;//对焦 曝光 白平衡 。。。

	u32 prev_sysclk, prev_hts;//?
	//line_length = Hsync = Dummy Pixel = HTotal = HTS = H_Size + H_Blank 
	//会占用曝光时间,即可以通过调节H_Blank, 调节行长
	u32 ae_low, ae_high, ae_target; //ae 自爆

	bool pending_mode_change;
	bool streaming;// streaming enable
};

probe

static int ov5640_probe(struct i2c_client *client)
{
	struct device *dev = &client->dev;
	struct fwnode_handle *endpoint;
	struct ov5640_dev *sensor;//  senseor 5640
	struct v4l2_mbus_framefmt *fmt;
	u32 rotation;
	int ret;

	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
	if (!sensor)
		return -ENOMEM;

	sensor->i2c_client = client;// iic5

	/*
	 * default init sequence initialize sensor to
	 * YUV422 UYVY VGA@30fps
	 */
	fmt = &sensor->fmt;//指向它 修改它
	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
	fmt->colorspace = V4L2_COLORSPACE_SRGB;
	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
	fmt->width = 640;
	fmt->height = 480;
	fmt->field = V4L2_FIELD_NONE;
	
	sensor->frame_interval.numerator = 1;//分子分母计算帧率
	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];//30
	sensor->current_fr = OV5640_30_FPS;
	sensor->current_mode =
		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
	sensor->last_mode = sensor->current_mode;//640 480 vga default

	sensor->ae_target = 52;//曝光度  计算

	/* optional indication of physical rotation of sensor */
	ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
				       &rotation);// 180 or 0
	if (!ret) {
		switch (rotation) {
		case 180:
			sensor->upside_down = true;
			/* fall through */
		case 0:
			break;
		default:
			dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
				 rotation);
		}
	}

	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
						  NULL);//get 拿过来
	if (!endpoint) {
		dev_err(dev, "endpoint node not found\n");
		return -EINVAL;
	}

	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
	fwnode_handle_put(endpoint);//put 释放  
	if (ret) {
		dev_err(dev, "Could not parse endpoint\n");
		return ret;
	}

	/* get system clock (xclk) */
	sensor->xclk = devm_clk_get(dev, "xclk");
	if (IS_ERR(sensor->xclk)) {
		dev_err(dev, "failed to get xclk\n");
		return PTR_ERR(sensor->xclk);
	}

	sensor->xclk_freq = clk_get_rate(sensor->xclk);//24 000 000
	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
	    sensor->xclk_freq > OV5640_XCLK_MAX) {
		dev_err(dev, "xclk frequency out of range: %d Hz\n",
			sensor->xclk_freq);
		return -EINVAL;
	}

	/* request optional power down pin */
	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
						    GPIOD_OUT_HIGH);
	if (IS_ERR(sensor->pwdn_gpio))
		return PTR_ERR(sensor->pwdn_gpio);

	/* request optional reset pin */
	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
						     GPIOD_OUT_HIGH);
	if (IS_ERR(sensor->reset_gpio))
		return PTR_ERR(sensor->reset_gpio);

	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);//init subdev

	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
			    V4L2_SUBDEV_FL_HAS_EVENTS;
	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
	if (ret)
		return ret;

	ret = ov5640_get_regulators(sensor);
	if (ret)
		return ret;

	mutex_init(&sensor->lock);//mutex init

	ret = ov5640_check_chip_id(sensor);//chack id
	if (ret)
		goto entity_cleanup;

	ret = ov5640_init_controls(sensor);//ctrl init
	if (ret)
		goto entity_cleanup;

	ret = v4l2_async_register_subdev_sensor_common(&sensor->sd);//reg sd
	if (ret)
		goto free_ctrls;

	return 0;

free_ctrls:
	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
entity_cleanup:
	mutex_destroy(&sensor->lock);
	media_entity_cleanup(&sensor->sd.entity);
	return ret;
}

chip id

static int ov5640_check_chip_id(struct ov5640_dev *sensor)
{
	struct i2c_client *client = sensor->i2c_client;
	int ret = 0;
	u16 chip_id;

	ret = ov5640_set_power_on(sensor);
	if (ret)
		return ret;

	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);//read chip id
	if (ret) {
		dev_err(&client->dev, "%s: failed to read chip identifier\n",
			__func__);
		goto power_off;
	}

	if (chip_id != 0x5640) {
		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
			__func__, chip_id);
		ret = -ENXIO;
	}

power_off:
	ov5640_set_power_off(sensor);
	return ret;
}
pwr_on
static int ov5640_set_power_on(struct ov5640_dev *sensor)
{
	struct i2c_client *client = sensor->i2c_client;
	int ret;

	ret = clk_prepare_enable(sensor->xclk);
	if (ret) {
		dev_err(&client->dev, "%s: failed to enable clock\n",
			__func__);
		return ret;
	}

	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
				    sensor->supplies);
	if (ret) {
		dev_err(&client->dev, "%s: failed to enable regulators\n",
			__func__);
		goto xclk_off;
	}

	ov5640_reset(sensor);
	ov5640_power(sensor, true);

	ret = ov5640_init_slave_id(sensor);//多个slave时 改成不同0x3c的id
	if (ret)
		goto power_off;

	return 0;

power_off:
	ov5640_power(sensor, false);
	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
xclk_off:
	clk_disable_unprepare(sensor->xclk);
	return ret;
}

在这里插入图片描述

### STM32MP157OV5640摄像头模块配置及使用教程 #### 初始化DCMI外设 为了使STM32能够读取来自OV5640的数据,需要先初始化DCMI(Digital Camera Interface)。这涉及到配置DMA控制器用于高效传输图像数据至外部SRAM。具体来说,DMA2 Stream1被用来搬运由DCMI捕获的数据流,并采用了双缓冲机制以提高效率。每次当有1 KB的数据量完成转移时,会在相应的DMA中断服务程序里触发处理过程,负责把临时缓存区内的像素信息复制到最终的目标存储位置。 ```c // DCMI DMA Initialization Code Snippet HAL_DMA_Init(&amp;hdma_dcmi); __HAL_LINKDMA(hdmi, hdmarx, hdma_dcmi); static void MX_DCMI_Init(void){ __HAL_RCC_DCMI_CLK_ENABLE(); hcdmi.Instance = DCMI; hcdmi.Init.SynchroMode = DCMI_SYNCHRO_HARDWARE; hcdmi.Init.PCKPolarity = DCMI_PCKPOLARITY_FALLING; hcdmi.Init.VSPolarity = DCMI_VSPOLARITY_LOW; hcdmi.Init.HSPolarity = DCMI_HSPOLARITY_LOW; hcdmi.Init.CaptureRate = DCMI_CR_ALL_FRAME; hcdmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B; if (HAL_DCMI_Init(&amp;hcdmi) != HAL_OK){ Error_Handler(); } } ``` #### SCCB接口初始化 SCCB(Serial Camera Control Bus)是连接MCU和CMOS传感器之间的串行通信总线协议之一。对于STM32而言,这意味着要设定特定的GPIO引脚作为I²C SDA/SCL功能来实现对OV5640内部寄存器的操作。通过这些操作可以调整相机的各种参数比如分辨率、帧率以及色彩模式等特性。 ```c // I2C Configuration for SCCB Communication with OV5640 void ov5640_sccb_init(){ hi2c1.Instance = I2C1; hi2c1.Init.Timing = 0x20909CEC; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if(HAL_I2C_Init(&amp;hi2c1)!= HAL_OK){ while(1){} } // Set the camera address to be used by SCCB commands. sccb_camera_address = OV5640_SLAVE_ADDR >> 1; } int write_register(uint8_t reg_addr,uint8_t data){ uint8_t buffer[2]; buffer[0]=reg_addr; buffer[1]=data; return HAL_I2C_Master_Transmit(&amp;hi2c1,sccb_camera_address<<1,buffer,sizeof(buffer),HAL_MAX_DELAY); } ``` #### 设置OV5640输出格式 一旦硬件层面准备就绪之后,则需进一步编程控制OV5640的工作状态。例如指定其工作于JPEG压缩编码方式下并设置合适的视频解析度。这部分通常涉及一系列预定义好的命令序列发送给目标设备从而达到预期效果。 ```c // Configure OV5640 Resolution and Output Format as JPEG write_register(OV5640_REG_COM7, COM7_SRST); /* Software reset */ while(read_register(OV5640_REG_COM7)&amp;COM7_SRST){} /* Wait until reset complete */ /* Select sensor mode */ write_register(OV5640_REG_COM7, COM7_ZOOM_EN | COM7_VIDEO_MODE); /* Apply resolution settings */ apply_resolution_settings(); /* Switch output format to JPEG */ set_jpeg_output_format(); ``` 以上代码片段展示了如何基于STM32平台构建起一套完整的解决方案以便更好地利用OV5640 CMOS成像器件的功能[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值