Implementation principle of LCD driver in Embedded System
From: http://www.laogu.com/wz_18338.htm
Source: Today's electronics
Author: Yang xianqiang, Sichuan University, Tian Yuanfu
Details:
This article describes how to implement Modular programming of the LCD driver and how to load the driver into the system kernel statically Based on Samsung's arm9-series embedded processor S3C2410.
This article describes how to develop Embedded LCD drivers on the Linux platform based on the LCD interface of Samsung's kernel chip S3C2410.
The hardware in this article uses the Samsung S3C2410 chip Development Board, the software uses the Linux 2.4.19 platform, the compiler is the arm-Linux-GCC cross compiler, using a 640 × 480 resolution TFT color LCD, by Rewriting and debugging the Linux driver, the driver and display of the screen are successfully realized.
Concept of embedded driver
The device driver is the interface between the operating system kernel and the hardware of the machine. The device driver shields the hardware details from the application. In this way, the hardware device is just a device file, applications can operate on hardware devices like normal files. The device driver is a part of the kernel. It provides the following functions: Initialize and release the device, transfer data from the kernel to the hardware, and read data from the hardware; read the data that the application sends to the device file, send back the data requested by the application, and detect and process device errors.
Linux classifies devices into two basic categories: character devices and Block devices. The main difference between a character device and a block device is that when a read/write request is sent to a character device, the actual hardware I/O usually follows. Character devices perform sequential read/write operations in a single byte, without using the buffer technology. Block devices store and read/write data blocks of a fixed size, such as hard disks and floppy disks, A system memory is used as the buffer. To improve efficiency, the system provides a caching mechanism for block device read/write. The implementation is much more complex than that of character devices due to issues such as buffer management, scheduling, and synchronization. LCD is accessed and managed by character devices. Linux regards the display driver as a character device and sends the data to be displayed in one byte to the LCD driver.
Linux device management is closely integrated with the file system. Various devices are stored in the/dev directory as files, which are called device files. Applications can open, close, and read/write these device files to complete operations on the device, just like operating a common data file. To manage these devices, the system numbers the devices. Each device number is divided into the primary device number and secondary device number. The primary device number is used to distinguish different types of devices, while the secondary device number is used to distinguish multiple devices of the same type. For common devices, Linux has a conventional number, for example, the master device Number of the hard disk is 3. Linux provides a unified operation function interface for all device files by using the data structure struct file_operations. This data structure includes the pointers of many operation functions, such as open (), close (), read (), and write (). However, due to the many types of peripherals, the operation methods are different. The members in the struct file_operations struct are a series of interface functions, such as the read/write function for read/write and IOCTL for control. To open a file, call the open operation in file_operations. Different types of files have different file_operations member functions, such as common disk data files and interface functions to complete disk data block read/write operations. For various device files, then, I/O functions in the respective drivers are called to perform operations on specific devices. In this way, applications do not have to consider devices or common files. They can be processed as files with clear and unified I/O interfaces. Therefore, file_operations is an I/O interface at the file level.
LCD Controller
The function of the LCD controller is to display the driving signal and then drive the LCD. You only need to read and write a series of registers to complete the configuration and display driver. In the process of driving the LCD design, the first step is to configure the LCD controller, and the most important step in the configuration of the LCD controller is the designation of the frame buffer. The content to be displayed is read from the buffer and displayed on the screen. The size of the frame buffer is determined by the screen resolution and the number of colors displayed. The implementation of driving frame buffering is the focus of the entire driving development process. The LCD controller in S3C2410 supports two types of Liquid Crystal: STN and TFT. The LCD Controller supports four-digit dual-scan, four-digit single-scan, and eight-digit single-scan display modes for an stn LCD Panel. It supports four-level and 16-level gray-level monochrome display modes, supports 256-color and 4096-color display, and supports LCD with multiple resolutions, such as 640x480, 320x240, and 160x160. In the 256-color display mode, the maximum value is 4096x1024, 2048x2048, and 1024x4096. The tft LCD Panel supports 1-2-4-8bpp (bits per pixel) color palette display mode and 16 BPP non-color palette display.
The frame buffer is a driver interface that appears in Linux 2.2.xx and later kernel versions. This interface will show that the device is abstracted as the frame buffer device zone. The frame buffer Provides abstract processing for image hardware devices. It represents some video hardware devices that allow application software to access image hardware devices through a clearly defined interface. In this way, the software does not need to know anything that involves underlying hardware drivers (such as hardware registers ). It allows upper-layer applications to directly read and write the display buffer and perform I/O Control in graphic mode. You can use a dedicated device node to access this device, such as/dev/FB *. You can think of it as an image showing the memory. After you map it to the process address space, you can perform read/write operations, and the read/write operations can be reflected in the LCD.
The device file corresponding to the frame buffer device is/dev/FB *. If the system has multiple video cards, Linux also supports multiple frame buffering devices, up to 32, that is,/dev/fb0 ~ /Dev/fb31. /Dev/FB points to the current frame buffer device. Generally, the default frame buffer device is/dev/fb0.
The frame buffer device is also a character device, using the "file layer-driver layer" interface method. The following data structure is defined at the file layer.
Static struct file_operations fb_fops = {
Ower: this_module,
Read: fb_read,/* read operation */
Write: fb_write,/* write operation */
Ioct1: fb_ioct1,/* I/O operations */
MMAP: fb_mmap,/* ing operation */
Open: fb_open,/* open operation */
Release: fb_release,/* close operation */
}
Its member functions are defined in Linux/driver/Video/fbmem. C. The functions perform operations on specific hardware, set registers, and map display buffering. The main struct is as follows.
● Struct fb_fix_screeninfo: records the unchangeable information of the frame buffer device and the specified display mode. It contains the physical address and length of the screen buffer.
● Struct fb_var_screeninfo: records the modifiable information of the frame buffer device and the specified display mode. It includes the resolution of the display screen, the number of bits per pixel, and some time series variables. The variable xres defines the number of workers for a row on the screen, yres defines the number of workers for a column on the screen, and bits_per_pixel defines how many bits are used for each pixel.
● Struct fb_info: Linux is the driver layer interface defined by the frame buffer device. It not only contains underlying functions, but also records device status data. Each frame buffer device corresponds to an fb_info structure. The member variable modename is the device name, fontname is the display font, and fbops is the pointer to the underlying function.
LCD driver development
1. Compile the initialization Function
The initialization function first initializes the LCD controller, sets the display mode and number of colors by writing registers, and then allocates the LCD display buffer. In Linux, you can use the kmalloc () function to allocate continuous space. Buffer size: Number of dot matrix lines X number of dot matrix columns X indicates the number of bits/8 in one pixel. The buffer is usually allocated in a large volume of off-chip SDRAM, and the starting address is stored in the LCD control register. The LCD display method used in this article is 640x480, 16-bit color, the display buffer to be allocated is 640x480x2 = 600kb. Finally, initialize an fb_info structure, fill in the member variables, and call register_framebuffer (& fb_info) to register fb_info into the kernel.
2. Compile member functions
Compile the member functions corresponding to the function pointer fb_ops in the fb_info structure. For simple implementation of the embedded system, you only need the following three functions.
Struct fb_ops {
......
INT (* fb_get_fix) (struct fb_fix_screeninfo * Fix, int con, struct fb_info * info );
INT (* fb_get_var) (struct fb_var_screeninfo * var, int con, struct fb_info * info );
INT (* fb_set_var) (struct fb_var_screeninfo * var, int con, struct fb_info * info );
......
}
Struct fb_ops is defined in include/Linux/FB. h. These functions are used to set/obtain the member variables in the fb_info structure. When the application performs the ioctl operation on the device files, it will call them. For fb_get_fix (), the application imports the fb_fix_screeninfo structure and assigns values to its member variables in the function, mainly smem_start (buffer start address) and smem_len (buffer length ), finally, it is returned to the application. The input parameter of the fb_set_var () function is fb_var_screeninfo. The function must assign values to xres, yres, and bits_per_pixel.
For/dev/FB, you can perform the following operations on the display device.
● Read/write/dev/FB: it is equivalent to the read/write screen buffer.
● Map operation: since Linux is working in protection mode, each application has its own virtual address space, so it cannot directly access the physical buffer address in the application. Therefore, Linux provides the MMAP function in the file_operations structure for file operations, which can map the file content to the user space. For frame buffer devices, you can map the physical address of the screen buffer to a virtual address in the user space, then, the user can access the screen buffer by reading and writing the virtual address, and draw a picture on the screen.
● I/O Control: For frame buffering devices, IOCTL operations on device files can be performed to read/set display device and screen parameters, such as resolution, number of display colors, and screen size. IOCTL operations are performed by the underlying driver. In the application, the general steps for operating/dev/FB are as follows: Open the/dev/FB device file; Use ioctrl to obtain the parameters of the current display screen, for example, the screen resolution and the number of bits per pixel can be calculated based on the screen parameters. The screen buffer can be mapped to the user space. After the ing, the screen buffer can be read and written directly, drawing and image display.
LCD modular drive
When compiling a modular driver for the LCD of S3C2410, you must first remove the LCD Driver from the kernel. Here we need to make some changes. The system call is added to the following files and should be removed:/root/usr/src/ARM/Linux/kernel/sys. c;/root/usr/src/ARM/Linux/include/unistd under arm-arm. H and LCD. h;/root/usr/src/ARM/Linux/ARCH/ARM/kernel. s.
Write a modular driver with the following key functions.
● LCD _kernel_init (void) // executed when the module is loaded
● LCD _kernel_exit (void) // executed when the module is removed from the kernel space
● LCD _kernel1_ioctl (struct * inode, struct * file, unsigned int cmd, unsigned longarg) // other functions
Whenever a device driver is assembled, the system automatically calls the initialization module LCD _kernel_init (void ).
Another function that must be provided is LCD _kernel_exit (void). It is called when the module is detached and is responsible for the work of the device driver.
Run the insmod LCD. O command to add the LCD driver to the kernel. Run the rmmod LCD command to delete the LCD Driver from the kernel.
Statically loaded LCD Driver
Compile the LCD Driver LCD. c. Put it in the arm/Linux/Drivers/Char directory and modify ARM/Linux/Drivers/Char/config. in file, add a line: bool ''LCD driver support'' config _ LCD; modify the ARM/Linux/Drivers/Char/MAKEFILE file, and add a line: obj-$ (config_ LCD) + = LCD. o.
In this way, when making xconfig, you will choose whether to compile the LCD driver into the kernel. The same method can be used on other devices.
First, my board uses the ch7005 to convert the LCD signal to VGA. The 2.4 kernel provides a driver, and the display effect is small. People on the Internet said that as long as the LCD is driven up, it can be displayed, and someone like me, it is displayed successfully.
Now my porting process is as follows: ARCH/ARM/mach-s3c2410/mach-smdk2410.c
Static struct s3c2410fb_mach_info smdk2410_ LCD _platdata = {
. Fixed_syncs = 0,
. Width = 640,
. Size = 480,
. Xres = {
. Defval = 640,
. Min = 640,
. Max = 640,
},
. Yres = {
. Defval = 480,
. Min = 480,
. Max = 480,
},
. Bpp = {
. Defval = 16,
. Min = 16,
. Max = 16,
},
. Regs = {
. Lcdcon1 = s3c2410_lcdcon0000tft16bpp | s3c2410_lcdcon0000tft | s3c2410_lcdcon0000clkval (1 ),
. Lcdcon2 = s3c2410_lcdcon2_vbpd (25) | s3c2410_lcdcon2_vfpd (5) | s3c2410_lcdcon2_vspw (1 ),
. Lcdcon3 = s3c2410_lcdcon3_hbpd (67) | s3c2410_lcdcon3_hfpd (40 ),
. Lcdcon4 = s3c2410_lcdcon4_hspw (31) | s3c2410_lcdcon4_mval (13),. lcdcon5 = large | small | s3c2410_lcdcon5_pwren | small | s3c2410_lcdcon5_invvframe,
},
. Gpcup = 0 xffffffff,
. Gpcup_mask = 0 xffffffff,. gpccon = 0 xaaaaaaaa,
. Gpccon_mask = 0 xffffffff,. gpdup = 0 xffffffff,
. Gpdup_mask = 0 xffffffff,. gpdcon = 0 xaaaaaaaa,
//. Gpdcon_mask = 0 xffffffff,
. Gpdcon_mask = 0,. lpcsel = 0x00,
}; Added to the smdk2410_map_io Function
Set_s3c2410fb_info (& smdk2410_ LCD _platdata); the first time after startup
Parameters:
Setenv bootargs console = ttysac0 root =/dev/nfs nfsroot = 59.69.74.87:/public/myroot_nfs IP = fingerprint: 59.69.74.87: 59.69.74.1: 255.0.0.0: Authorization: eth0: Off
After startup
Console: switching to color frame buffer device 80x30
Fb0: s3c2410fb Frame Buffer Device
Fb1: Virtual Frame Buffer Device, using 1024 K of video memory does not move. After restart
The second time: VGA is displayed with flashing color lines, but the effect is not good.
Initializing cryptographic API
Console: switching to color frame buffer device 80x30
Fb0: s3c2410fb Frame Buffer Device
Fb1: Virtual Frame Buffer Device, using 1024 K of video memory
S3C2410 RTC, (c) 2004 simtec electronicsramdisk driver initialized: 16 RAM disks of 8192 K size 1024 blocksize
Loop: loaded (max 8 devices)
NBD: Registered device at major 43
Usbcore: registered new driver UB
Cirrus Logic cs8900a driver for Linux (modified for smdk2410)
Eth0: cs8900a rev E at 0xe0000300 IRQ = 52, no EEPROM, ADDR: 08: 0: 3E: 26: 0a: 5b
Nftl DRIVER: nftlcore. C $ revision: 1.97 $, nftlmount. C $ revision: 1.40 $
Usbmon: debugfs is not available
....
[Root @ hjembed/] # ll/dev/FB/
CrW-RW-1 Root 29, 0 Jan 1 00:00 0
CrW-RW-1 Root 29, 1 Jan 1 00:00 1 [root @ hjembed/] # Cat/proc/interrupts
Cpu0
30: 68164 S3C2410 timer tick
32: 0 s3c2410-lcd
42: 0 ohci_hcd: usb1
52: 15333 eth0
S3c2410-uart 70: 49
71: 116 s3c2410-uart
Err: 0
[Root @ hjembed/] # During the porting process, the register settings are completely set in 2.4, and some suspect that gpcup = 0 xffffffff,
. Gpcup_mask = 0 xffffffff,. gpccon = 0 xaaaaaaaa,
. Gpccon_mask = 0 xffffffff,. gpdup = 0 xffffffff,
. Gpdup_mask = 0 xffffffff,. gpdcon = 0 xaaaaaaaa,
//. Gpdcon_mask = 0 xffffffff,
. Gpdcon_mask = 0,. lpcsel = 0x00. the settings of these parameters have been found for a long time. I haven't introduced them yet. I don't know where to start with the code. Also, I saw kmust senior http://www.hhcn.com/cgi-bin/topic.cgi in the Forum? Forum = 3 & topic = 553 & show = 25
The initialization of gpioc and gpiod added to the void _ init smdk_machine_init (void) function of the arch/ARM/mach-s3c2410/common-smdk.c file is as follows:
S3c2410_gpio_cfgpin (s3c2410_gpc0, s3c2410_gpc0_lend );
S3c2410_gpio_cfgpin (s3c2410_gpc1, s3c2410_gpc1_vclk );
... I looked at the hardware schematic and didn't see gpioc. gpiod is related to LCD. Maybe I missed it, or maybe the Board supplier didn't figure it out. I tried it on QT two days ago. I didn't do it. I tried it occasionally today. I got so excited two times that I think it was my fault. Then I turned off the power, restart, and the result is not displayed again. Try again the 2.4 kernel,
There are no little penguins, or the colored stripes flash. I did several more experiments and found a rule;
First use uboot to download Vivi, switch to Vivi, download the 2.4 kernel, start, and display the little penguin,
Then, download uboot in Vivi, download the 2.6 kernel, and start it. Now, if you press the reset key, download the 2.6 kernel again and start it.
However, if you press the power key and turn it on again, no matter whether you download the 2.6 kernel or the 2.4 kernel, the startup will not show the penguin, but the flashing color stripes. As a result, Vivi must initialize something. Help me analyze and analyze it! Fortunately, the VIVI source code provided contains the VGA. c file. After you open it, you can read and write 24c08, and Google it,
It turned out to be a serial EEPROM, but there was no such device in the Board schematic. What should I do now? Little penguins under 2.6, the display effect is good, the flash is not strong under 2.4.
--------------------------------------------------------------------------------
My analysis should be correct. Now I use Vivi to guide the 2.6 kernel, and the little penguin is displayed normally!
It seems that it was a preliminary test of chemical engineering. Fortunately, there is now an interface that shows you how to modify uboot.
References: http://www.helloeda.com/Article/deembed/200612/55.html
LCD Driver transplant notes |
|
Author: Tag Source: csdn clicks:
37652 updated on: 2006-12-9 |
LCD driver to kernel 2.6.11 Transplantation Summary Hardware environment: SBC-2410X Development Board (CPU: S3C2410X) Kernel version: 2.6.11.1 Running Environment: debian2.6.8 Cross-compilation environment: gcc-3.3.4-glibc-2.3.3 Note: The driver is transplanted Based on the s3c2400 framebuffer. 1. Download the Linux kernel source code from the Internet to the local machine and decompress it: # Tar jxf linux-2.6.11.1.tar.bz2 2. Open the MAKEFILE file in the top-level directory of the kernel. The content to be modified in this file includes the following two aspects. (1) Specify the target platform. Before transplantation: Arch? = $ (Subarch) After transplantation: Arch: = arm (2) Specify the cross compiler. Before transplantation: Cross_compile? = After transplantation: Cross_compile: =/opt/crosstool/arm-s3c2410-linux-gnu/gcc-3.3.4-glibc-2.3.3/bin/arm-s3c2410-linux-gnu- Note: assume that the compiler is placed in the local directory. 3. Add and modify the driver source code, which involves the following aspects. (1) Place the LCD drivers s3c2400fb. C and s3c2400fb. H on the Development Board to the drivers/Video/directory, and change the name to s3c2410fb. c/s3c2400fb. h. # Cp s3c2400fb. C. Drivers/Video/s3c2410fb. c (2. add sbc_gpio_con_set (), aggregate (), sbc_gpio_function_set () declaration and implementation code in the C driver to replace write_gpio_bit () and set_gpio_ctrl () functions in the 2.4.18 code, in 2.4.18, both functions use pointers to set the CPU registers, and _ raw_writel () is used in the 2.6.11 driver () to encapsulate the register settings. In the driver porting process, because it is based on the s3c2400 driver, the main modification is to modify the corresponding register settings according to the hardware of the Development Board used. The main modifications are: The s3c2410fb_mach_info structure. The results mainly define some information about the display, such as the clock and size, and modify the register settings in the c2400fb_activate_var function, this function involves the settings of the S3C2410 LCD controller. The registers must be set based on the screen (TFT/cstn) used. The functions of s3c2400fb_set_controller_regs and s3c2400fb_ LCD _init are modified, this function involves the physical connection between the CPU and the LCD. You need to set various cpio registers based on the connection between the LCD and the CPU. Note: For specific modifications, see the driver. (3) Modify ARCH/ARM/mach-s3c2410/S3C2410. C, in the s3c2410_iodesc structure Add: iodesc_ent (LCD) Note: The preceding statement is used to map the physical address of the cpu LCD register to the virtual address. The above structure also defines the range occupied by the virtual address, and specify the domain (attribute) to which the range points ). (4) modify the kconfig file in the drivers/video directory and add the following content at the end: Config fb_s3c2410 Tristate "S3C2410 LCD support" Depends on FB & arm & arch_s3c2410 Help This is a framebuffer device for the S3C2410 LCD controller. If you plan to use the LCD display with your S3C2410 system, say y here. (5) modify the makefile in the drivers/video directory and add the following content at the end: OBJ-$ (config_fb_s3c2410) + = s3c2410fb. O cfbfillrect. O cfbcopyarea. O cfbimgblt. o 4. Configure and compile the kernel. In the kernel top-level directory, type: # Make smdk2410_defconfig Because kernel 2.6 supports S3C2410 by default, there is a default Kernel configuration file. It only includes a simple configuration. Manual configuration is required to compile the LCD driver into the kernel. # Make menuconfig Graphics support ---> [*] Support for frame buffer devices [*] S3C2410 LCD support (based on s3c2400) Add the LCD driver you just added to the kernel statically. Finally, compile the kernel. # Make Then download the image to the Development Board. A penguin icon is displayed in the upper left corner of the LCD display. View the device file. [Root @ fa/] # ls-Al/dev/FB/0 It can be seen that the LCD has been successfully driven. To test the driver, you can use your own (see the attachment test. c) to display lines of any color on the display screen. Problem Analysis During the LCD Driver porting process, problems mainly occur due to incorrect register settings. After replacing the driver with functions and rewriting some functions, compile the driver into the kernel. The kernel can correctly compile the connection and generate an image file, download the image file to the development board. You can see a device file registered by the system under the drivers/video directory, however, after the system is started, the penguin icon cannot be seen and tested with a test program. The LCD screen cannot display any colored lines. After checking the source code for multiple times, we can find that the 8 registers of the CPU related LCD and the settings of the GPC and GPD registers are incorrect. After correctly setting these registers, you can see the penguin icon after the system starts. Because the background of the screen is blue, the color of the icon is incorrectly displayed, but you can use the test program you wrote to draw the lines of the set color, the screen can always be correctly displayed, so the color problem of the screen has not been solved yet. |