I. Introduction
The content of s3c2440 lcd driver analysis includes the principle of LCD image display, the operation of s3c2440 LCD controller, the example of LCD driver using platform bus-device-driver model, the setting of LCD related parameters, fb character device driver example, framebuffer registration and management, and the complete process analysis of an LCD display.
2. LCD principle and hardware analysis
2.1 LCD Principle Analysis
SDRAM: A continuous memory is applied in SDRAM as the storage of LCD display data, called framebuffer.
LCD controller: The LCD controller is connected to the LCD screen through hardware circuits. LCD
screen: As a peripheral, it is connected to the MCU (pins are configured as LCD pins) through hardware circuits.
When an image is displayed on an LCD screen, it can be seen that the LCD controller first takes out a frame of image data from the video memory and then inputs it to the LCD screen. For a 480*272 screen, a frame displayed has 480*272 pixels, 272 rows, and 480 columns. For each row of pixels, the LCD controller has a VCLK signal control. With each VCLK, the displayed pixel moves one pixel to the right. When it moves to the last pixel in this row, the LCD controller has an HSYNC signal to control the pixel to jump to the first pixel of the next row for display. For a frame of image (also called a field), that is, when the pixel moves to the last position of the last row and is displayed, the LCD controller has a VSYNC signal to control the pixel to move back to the first pixel of the first row to display the next frame of image.
2.2 Hardware Circuit
2.2.1 LCD backlight circuit
To turn on the LCD display, you need to enable KEYBOARD (generally EN means high level is valid, and a horizontal line above EN means low level is valid) to turn on the backlight.
2.2.2 LCD screen
VLINE: HSYNC signal output pin (operated by LCD controller)
VFRAME: VSYNC signal output pin (operated by LCD controller)
VCLK: VCLK signal output pin (operated by LCD controller)
VD3~VD7: B data output pins in RGB (565)
VD10~VD15: G data output pins in RGB (565)
VD19~VD23: R data output pins in RGB (565) TS*: for ts touch screen connection
2.2.3 S3c2440 master control
Involving GPG, GPD, GPC pins.
VM: LCD controller enable pin (configured by the register of the LCD controller). To turn on the LCD display, you need to configure the corresponding bit of the relevant register to enable. LCD_PWREN: LCD power enable pin (configured by the register of the LCD controller). To turn on the LCD display, you need to configure the corresponding bit of the relevant register to enable.
3. LCD Application Platform Bus-Device-Driver Model
3.1 Loading and registering lcd devices
MACHINE_START(S3C2440, "SMDK2440")
/* Maintainer: Ben Dooks
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
Expand the above macro
static const struct machine_desc __mach_desc_SMDK2440
__attribute_used__
__attribute__((__section__(".arch.info.init"))) = {
.nr = MACH_TYPE_SMDK2410, /* architecture number */
.name = "SMDK2440", /* architecture name */
/* Maintainer: Jonas Dietsche */
.phys_io = S3C2410_PA_UART, /* start of physical io */
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100, /* tagged list */
.map_io = smdk2440_map_io, /* IO mapping function */
.init_irq = s3c24xx_init_irq,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
}
MACHINE_START mainly defines the type of "struct machine_desc", which is placed in section (".arch.info.init"), and is the initialization data. It will be discarded after the kernel starts. Each member function is called at different times:
1. init_machine is called by customize_machine in arch/arm/kernel/setup.c. It is placed in the arch_initcall() section and will be called automatically in sequence.
2. init_irq is called in start_kernel() -> init_IRQ() -> init_arch_irq().
3. map_io is called in setup_arch() -> paging_init() -> devicemaps_init(). Other functions are mainly used in setup_arch().
When the system is initialized, smdk2440_machine_init is called
static void __init smdk2440_machine_init(void)
{
// Set the LCD parameters here, separate from the driver. In this way, when you want to modify the LCD, you don't need to change the driver layer program, you only need to modify the device layer parameters, which is convenient for transplantation.
s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg);
// Register the devices in the smdk2440_devices array to the platform bus
platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
smdk_machine_init();
}
// smdk2440_devices array
static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
&s3c2440_device_sdi,
};
// lcd device
struct platform_device s3c_device_lcd = {
.name = "s3c2410-lcd",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_lcd_resource),
.resource = s3c_lcd_resource,
.dev = {
.dma_mask = &s3c_device_lcd_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
// Set the LCD device parameters smdk2440_lcd_cfg. The meaning of each parameter will be explained later during probe analysis.
/* 480x272 */
static struct s3c2410fb_mach_info smdk2440_lcd_cfg __initdata = {
.right = {
.lcdcon1 = S3C2410_LCDCON1_TFT16BPP |
S3C2410_LCDCON1_TFT |
S3C2410_LCDCON1_CLKVAL(0x04),
.lcdcon2 = S3C2410_LCDCON2_VBPD(1) |
S3C2410_LCDCON2_LINEVAL(271) |
S3C2410_LCDCON2_VFPD(1) |
S3C2410_LCDCON2_VSPW(9),
.lcdcon3 = S3C2410_LCDCON3_HBPD(1) |
S3C2410_LCDCON3_HOZVAL(479) |
S3C2410_LCDCON3_HFPD(1),
.lcdcon4 = S3C2410_LCDCON4_HSPW(40),
.lcdcon5 = S3C2410_LCDCON5_FRM565 |
S3C2410_LCDCON5_INVVLINE |
S3C2410_LCDCON5_INVVFRAME |
S3C2410_LCDCON5_PWREN |
S3C2410_LCDCON5_HWSWP,
},
.gpccon = 0xaaaaaaaa,
.gpccon_mask = 0xffffffff,
.gpcup = 0xffffffff,
.gpcup_mask = 0xffffffff,
.gpdcon = 0xaaaaaaaa,
.gpdcon_mask = 0xffffffff,
.gpdup = 0xffffffff,
.gpdup_mask = 0xffffffff,
.fixed_syncs = 1,
.type = S3C2410_LCDCON1_TFT,
.width = 480,
.height = 272,
.xres = {
.min = 480,
.max = 480,
.defval = 480,
},
.yres = {
.max = 272,
.min = 272,
.defval = 272,
},
.bpp = {
.min = 16,
.max = 16,
.defval = 16,
},
};
Call platform_device_register to register the platform device
int platform_add_devices(struct platform_device **devs, int num)
{
int i, ret = 0;
for (i = 0; i < num; i++) {
ret = platform_device_register(devs[i]);
if (ret) {
while (--i >= 0)
platform_device_unregister(devs[i]);
break;
}
}
return ret;
}
3.2 Loading and registering the lcd driver
3.2.1 Compile into kernel and load driver
Compile kernel settings, make menuconfig
-> Device Drivers
-> Graphics support
<*> Support for frame buffer devices
linux-2.6.22.6/.config
CONFIG_FB_S3C2410=y
linux-2.6.22.6/drivers/video/Makefile
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
Then make uImage, compile the s3c2410fb driver into the kernel, and it will be loaded when the system starts, that is, the driver's s3c2410fb_init function will be called.
int __devinit s3c2410fb_init(void)
{
// Register to the platform bus driver
return platform_driver_register(&s3c2410fb_driver);
}
3.3 LCD device and driver matching
platform_driver_register->
driver_register->
bus_add_driver->
driver_attach->
bus_for_each_dev->
__driver_attach
__driver_attach(kernel 2.6.22)
static int __driver_attach(struct device * dev, void * data)
{
struct device_driver * drv = data;
/*
* Lock device and try to bind to it. We drop the error
* here and always return 0, because we need to keep trying
* to bind to devices and some drivers will return an error
* simply if it didn't support the device.
*
* driver_probe_device() will spit a warning if there
* is an error.
*/
if (dev->parent) /* Needed for USB */
down(&dev->parent->sem);
down(&dev->sem);
if (!dev->driver)
driver_probe_device(drv, dev); //Call the probe function of the driver layer program
up(&dev->sem);
if (dev->parent)
up(&dev->parent->sem);
return 0;
}
__driver_attach(kernel 3.4)
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
/*
* Lock device and try to bind to it. We drop the error
* here and always return 0, because we need to keep trying
* to bind to devices and some drivers will return an error
* simply if it didn't support the device.
*
* driver_probe_device() will spit a warning if there
* is an error.
*/
// Match driver and device
if (!driver_match_device(drv, dev))
return 0;
if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
if (!dev->driver)
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);
return 0;
}
driver_probe_device calls the probe of the driver layer
Previous article:《Linux driver: s3c2440 lcd driver analysis -- final chapter》
Next article:《Linux driver: s3c2410/s3c2440 ts driver analysis -- final chapter》
- Popular Resources
- Popular amplifiers
- Naxin Micro and Xinxian jointly launched the NS800RT series of real-time control MCUs
- How to learn embedded systems based on ARM platform
- Summary of jffs2_scan_eraseblock issues
- Application of SPCOMM Control in Serial Communication of Delphi7.0
- Using TComm component to realize serial communication in Delphi environment
- Bar chart code for embedded development practices
- Embedded Development Learning (10)
- Embedded Development Learning (8)
- Embedded Development Learning (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Intel promotes AI with multi-dimensional efforts in technology, application, and ecology
- ChinaJoy Qualcomm Snapdragon Theme Pavilion takes you to experience the new changes in digital entertainment in the 5G era
- Infineon's latest generation IGBT technology platform enables precise control of speed and position
- Two test methods for LED lighting life
- Don't Let Lightning Induced Surges Scare You
- Application of brushless motor controller ML4425/4426
- Easy identification of LED power supply quality
- World's first integrated photovoltaic solar system completed in Israel
- Sliding window mean filter for avr microcontroller AD conversion
- What does call mean in the detailed explanation of ABB robot programming instructions?
- Infineon Technologies Launches ModusToolbox™ Motor Kit to Simplify Motor Control Development
- Infineon Technologies Launches ModusToolbox™ Motor Kit to Simplify Motor Control Development
- STMicroelectronics IO-Link Actuator Board Brings Turnkey Reference Design to Industrial Monitoring and Equipment Manufacturers
- Melexis uses coreless technology to reduce the size of current sensing devices
- Melexis uses coreless technology to reduce the size of current sensing devices
- Vicor high-performance power modules enable the development of low-altitude avionics and EVTOL
- Chuangshi Technology's first appearance at electronica 2024: accelerating the overseas expansion of domestic distributors
- Chuangshi Technology's first appearance at electronica 2024: accelerating the overseas expansion of domestic distributors
- "Cross-chip" quantum entanglement helps build more powerful quantum computing capabilities
- Ultrasound patch can continuously and noninvasively monitor blood pressure
- How to access the external network through the router when STM32 is plugged into the network cable?
- Shocked! Douban is abuzz with discussion! Many mobile phone cameras have been burned! Don't shoot like this
- X-NUCLEO-IKS01A3 sensor test based on STM32F401RE development board VI LSM6DSO pedometer test
- Introduction to the basic knowledge of mounting on FPC
- Do you really know what "I love you" means?
- Cypress launches clock chip and self-programming kit
- Can't enter the main function
- Definition and classification of sensors
- Talk about the current mainstream microcontrollers, what are their advantages and disadvantages
- Competition in mobile operating systems intensifies