driversmediavideos3c2440camif.c
driversmediavideos3c2440_ov9650.c
driversmediavideosccb.c
Hardware Hookup
I2C Bus Connection
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
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);
}
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);
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);
}
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)
Previous article:u-boot-2011.06 transplant
Next article:FreeRTOS task source code analysis and the relationship between program stack and task stack
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- CGD and Qorvo to jointly revolutionize motor control solutions
- CGD and Qorvo to jointly revolutionize motor control solutions
- Keysight Technologies FieldFox handheld analyzer with VDI spread spectrum module to achieve millimeter wave analysis function
- Infineon's PASCO2V15 XENSIV PAS CO2 5V Sensor Now Available at Mouser for Accurate CO2 Level Measurement
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- A new chapter in Great Wall Motors R&D: solid-state battery technology leads the future
- Naxin Micro provides full-scenario GaN driver IC solutions
- Interpreting Huawei’s new solid-state battery patent, will it challenge CATL in 2030?
- Are pure electric/plug-in hybrid vehicles going crazy? A Chinese company has launched the world's first -40℃ dischargeable hybrid battery that is not afraid of cold
- Advances in radar technology and the development of in-cockpit sensing technology
- Is it so difficult to post a message?
- [RVB2601 Creative Application Development] Ultrasonic pressure-sensitive buttons based on RISC-V processor
- First of all, the 9 boards sent by National Technology have arrived. It's so fast.
- There is no year-end bonus this year.
- Pingtou Ge RRVB2601 Review: Unboxing, Hardware Analysis and Environment Setup
- Play Basic with micro:bit
- PIC32MX250F128B please help?
- What is the use of a diode in parallel with a pull-up resistor?
- Regarding the improvement suggestions after studying "PCB layout and thermal design system of high-density power system", please use the website as "Editor"...