Camera driver learning

Publisher:psi33Latest update time:2024-07-10 Source: elecfansKeywords:s3c2440  ov9650 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

driversmediavideos3c2440camif.c

driversmediavideos3c2440_ov9650.c

driversmediavideosccb.c

Hardware Hookup

I2C Bus Connection

clip_image002 clip_image004

I2CSCL ——GPE14

I2CSDA——GPE15

Sccb.h

#define SIO_C S3C2410_GPE14

#define SIO_D S3C2410_GPE15

#define State(x) s3c2410_gpio_getpin(x)

#define High(x) do{s3c2410_gpio_setpin(x,1); smp_mb();}while(0)

#define Low(x) do{s3c2410_gpio_setpin(x,0); smp_mb();}while(0)

#define WAIT_STABLE() do{udelay(10);}while(0)

#define WAIT_CYCLE() do{udelay(90);}while(0)

#define CFG_READ(x) do{s3c2410_gpio_cfgpin(x,S3C2410_GPIO_INPUT);smp_mb();}while(0)

#define CFG_WRITE(x) do{s3c2410_gpio_cfgpin(x,S3C2410_GPIO_OUTPUT);smp_mb();}while(0)

void sccb_write(u8 IdAddr, u8 SubAddr, u8 data);

u8 sccb_read(u8 IdAddr, u8 SubAddr);

CFG_WRITE(x) sets the GPIO to output

CFG_READ(x) sets the GPIO to input

High(x) Set GPIO to high level

Low(x) Set GPIO to low level

Sccb.c

clip_image006

Pull both SCL and Data high to reach the default initialization state level.

int sccb_init(void)

{

CFG_WRITE(SIO_C);

CFG_WRITE(SIO_D);

High(SIO_C);

High(SIO_D);

WAIT_STABLE();

return 0;

}

As can be seen from the figure above, when CLK is high, DATA is pulled low, which is START

static void __inline__ sccb_start(void)

{

CFG_WRITE(SIO_D);

Low(SIO_D);

WAIT_STABLE();

}

Use a semaphore

static DECLARE_MUTEX(bus_lock);

void sccb_write(u8 IdAddr, u8 SubAddr, u8 data)

{

down(&bus_lock);

sccb_start();

sccb_write_byte(IdAddr);

sccb_write_byte(SubAddr);

sccb_write_byte(data);

sccb_stop();

up (&bus_lock);

}

First, the semaphore value is reduced to indicate that it is in use. If the semaphore is not greater than 0 at this time, it means that the bus is in use. The driver will wait here until the semaphore is greater than 0, then it is reduced by 1. At this time, the bus is unavailable to the outside world. Finally, the semaphore is increased by 1 to indicate that the bus is available.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Camera interface initialization:

/*

* camif_init()

*/

static int __init camif_init(void)

{

Configure the GPIO interface function of CAMIF

/* set gpio-j to camera mode. */

s3c2410_gpio_cfgpin(S3C2440_GPJ0, S3C2440_GPJ0_CAMDATA0);

s3c2410_gpio_cfgpin(S3C2440_GPJ1, S3C2440_GPJ1_CAMDATA1);

s3c2410_gpio_cfgpin(S3C2440_GPJ2, S3C2440_GPJ2_CAMDATA2);

s3c2410_gpio_cfgpin(S3C2440_GPJ3, S3C2440_GPJ3_CAMDATA3);

s3c2410_gpio_cfgpin(S3C2440_GPJ4, S3C2440_GPJ4_CAMDATA4);

s3c2410_gpio_cfgpin(S3C2440_GPJ5, S3C2440_GPJ5_CAMDATA5);

s3c2410_gpio_cfgpin(S3C2440_GPJ6, S3C2440_GPJ6_CAMDATA6);

s3c2410_gpio_cfgpin(S3C2440_GPJ7, S3C2440_GPJ7_CAMDATA7);

s3c2410_gpio_cfgpin(S3C2440_GPJ8, S3C2440_GPJ8_CAMPCLK);

s3c2410_gpio_cfgpin(S3C2440_GPJ9, S3C2440_GPJ9_CAMVSYNC);

s3c2410_gpio_cfgpin(S3C2440_GPJ10, S3C2440_GPJ10_CAMHREF);

s3c2410_gpio_cfgpin(S3C2440_GPJ11, S3C2440_GPJ11_CAMCLKOUT);

s3c2410_gpio_cfgpin(S3C2440_GPJ12, S3C2440_GPJ12_CAMRESET);

Apply for the CAMIF register area. Since the OS manages it in a unified way, you need to make sure that the register area has not been acquired by other processes, so you need to apply for it.

/* init camera's virtual memory. */

if (!request_mem_region((unsigned long)S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF, CARD_NAME))

{

right = -EBUSY;

goto error1;

}

Applying for the register area is equivalent to making the physical address available, and then mapping the physical address to the virtual address.

/* remap the virtual memory. */

camif_base_addr = (unsigned long)ioremap_nocache((unsigned long)S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF);

if (camif_base_addr == (unsigned long)NULL)

{

right = -EBUSY;

goto error2;

}

Get the CAMIF clock, use 24M

/* init camera clock. */

pdev->clk = clk_get(NULL, "camif");

if (IS_ERR(pdev->clk))

{

right = -ENOENT;

goto error3;

}

clk_enable(pdev->clk);

camif_upll_clk = clk_get(NULL, "camif-upll");

clk_set_rate(camif_upll_clk, 24000000);

mdelay(100);

Initialize the status of CAMIF

/* init camif state and its lock. */

pdev->state = CAMIF_STATE_FREE;

CAMIF DEV's status:

/* for s3c2440camif_dev->state field. */

enum

{

CAMIF_STATE_FREE = 0, // not openned

CAMIF_STATE_READY = 1, // openned, but standby

CAMIF_STATE_PREVIEWING = 2, // in previewing

CAMIF_STATE_CODECING = 3 // in capturing

};

Register Miscellaneous Devices:

/* register to videodev layer. */

if (misc_register(&misc) < 0)

{

right = -EBUSY;

goto error4;

}

printk(KERN_ALERT"s3c2440 camif init donen");

Initialize the SCCB interface, Serial Camera Control Bus, which is actually an I2C interface

sccb_init();

Hardware reset CAMIF

hw_reset_camif();

In fact, it is a software reset. Configure the software reset of the CIGCTRL register

/* software reset camera interface. */

static void __inline__ hw_reset_camif(void)

{

u32 cigctrl;

cigctrl = (1<<30)|(1<<29);

iowrite32(cigctrl, S3C244X_CIGCTRL);

mdelay(10);

cigctrl = (1<<29);

iowrite32(cigctrl, S3C244X_CIGCTRL);

mdelay(10);

}

clip_image008

Check if OV9650 exists. GPG4 is connected to LCD_PWR. I don’t know why?

has_ov9650 = s3c2440_ov9650_init() >= 0;

s3c2410_gpio_setpin(S3C2410_GPG4, 1);

clip_image010

Initialization of OV9650:

int s3c2440_ov9650_init(void)

{

printk(KERN_ALERT"Loading OV9650 driver.........n");

/* power on. */

ov9650_poweron();

mdelay(100);

/* check device. */

if (ov9650_check() == 0 && ov9650_check() == 0)

{

printk(KERN_ERR"No OV9650 found!!!n");

return -ENODEV;

}

show_ov9650_product_id();

ov9650_init_regs();

printk("ov9650 init done!n");

return 0;

}

OV9650 is powered on. GPG12 is set as output. Although the interrupt pin is used here, it seems that there is no interrupt. This is a power control pin, PWDN, 0: power on, 1: power down

static void __inline__ ov9650_poweron(void)

{

s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_OUTP);

s3c2410_gpio_setpin(S3C2410_GPG12, 0);

mdelay(20);

}

clip_image012

clip_image014

OV9650 detection, read OV9650 Manu ID

static int __inline__ ov9650_check(void)

{

u32 one;

mid = sccb_read(OV9650_SCCB_ADDR, 0x1c)<<8;

mid |= sccb_read(OV9650_SCCB_ADDR, 0x1d);

printk("SCCB address 0x%02X, manufacture ID 0x%04X, expect 0x%04Xn", OV9650_SCCB_ADDR, mid, OV9650_MANUFACT_ID);

return (mid==OV9650_MANUFACT_ID)?1:0;

}

#define OV9650_SCCB_ADDR 0x60

#define OV9650_MANUFACT_ID 0x7FA2

#define OV9650_PRODUCT_ID 0x9650

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Camera interface open:

/*

* camif_open()

*/

static int camif_open(struct inode *inode, struct file *file)

{

First, determine whether OV9650 camera is a static variable at the beginning of the file.

struct s3c2440camif_dev *pdev;

struct s3c2440camif_fh *fh;

int ret;

if (!has_ov9650) {

return -ENODEV;

}

pdev = &camera;

Allocate memory for the file handle

fh = kzalloc(sizeof(*fh),GFP_KERNEL); // alloc memory for filehandle

Set the device status to open and standby and initialize the CAMIF configuration.

pdev->state = CAMIF_STATE_READY;

init_camif_config(fh);

Configure CAMIF and finally update the configuration

/* config camif when master-open camera.*/

static void init_camif_config(struct s3c2440camif_fh * fh)

{

struct s3c2440camif_dev * pdev;

pdev = fh->dev;

pdev->input = 0; // FIXME, the default input image format, see inputs[] for detail.

/* the source image size (input from external camera). */

pdev->srcHsize = 1280; // FIXME, the OV9650's horizontal output pixels.

pdev->srcVsize = 1024; // FIXME, the OV9650's verical output pixels.

/* the windowed image size. */

pdev->wndHsize = 1280;

pdev->wndVsize = 1024;

/* codec-path target(output) image size. */

pdev->coTargetHsize = pdev->wndHsize;

pdev->coTargetVsize = pdev->wndVsize;

/* preview-path target(preview) image size. */

pdev->preTargetHsize = 640;

pdev->preTargetVsize = 512;

update_camif_config(fh, CAMIF_CMD_STOP);

}

Since the device status is CAMIF_STATE_READY, update the register directly.

/* update camera interface with the new config. */

static void update_camif_config (struct s3c2440camif_fh * fh, u32 cmdcode)

{

struct s3c2440camif_dev * pdev;

pdev = fh->dev;

switch (pdev->state)

{

case CAMIF_STATE_READY:

update_camif_regs(fh->dev); // config the regs directly.

break;

case CAMIF_STATE_PREVIEWING:

/* camif is previewing image. */

disable_irq(IRQ_S3C2440_CAM_P); // disable cam-preview irq.

/* source image format. */

if (cmdcode & CAMIF_CMD_SFMT)

{

// ignore it, nothing to do now.

}

/* target image format. */

if (cmdcode & CAMIF_CMD_TFMT)

{

/* change target image format only. */

pdev->cmdcode |= CAMIF_CMD_TFMT;

}

I don't know why we have to wait for VSYNC to be L and then configure the registers.

/* update camif registers, called only when camif ready, or ISR. */

static void __inline__ update_camif_regs(struct s3c2440camif_dev * pdev)

{

if (!in_irq())

{

while(1) // wait until VSYNC is 'L'

{

barrier();

if ((ioread32(S3C244X_CICOSTATUS)&(1<<28)) == 0)

break;

}

}

/* WARNING: don't change the statement sort below!!! */

update_source_fmt_regs(pdev);

update_target_wnd_regs(pdev);

update_target_fmt_regs(pdev);

update_target_zoom_regs(pdev);

}

Initialize DMA memory of CAMIF.

ret = init_image_buffer(); // init image buffer.

Here memory is allocated for DMA, allocated by page, and knowledge of memory management needs to be learned?

/* init image buffer (only when the camif is first open). */

static int __inline__ init_image_buffer(void)

[1] [2]
Keywords:s3c2440  ov9650 Reference address:Camera driver learning

Previous article:u-boot-2011.06 transplant
Next article:FreeRTOS task source code analysis and the relationship between program stack and task stack

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号