PC host: Ubuntu 10.4 and redhat 9.0
Target board: TQ2440 development board Linux kernel: 2.6.30
Screen model: WXCAT35-TG3#001F Resolution: 320X240
This article will introduce how to port LCD devices.
Before porting, configure the kernel and compile the LCD device into the kernel.
1. Transplantation
To port the LCD settings, you only need to modify the data of the two structures located in arch/arm/mach-s3c2440/mach-smdk2440.c.
1.1 s3c2410fb_display structure
The modified content is as follows:
/* LCD driver info */
static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {
.lcdcon5 = S3C2410_LCDCON5_FRM565 |
S3C2410_LCDCON5_INVVLINE |
S3C2410_LCDCON5_INVVFRAME |
S3C2410_LCDCON5_PWREN |
S3C2410_LCDCON5_HWSWP,
.type = S3C2410_LCDCON1_TFT,
.width = 320, // 240,
.height = 240, // 320,
.pixclock = 156250,//166667, /* HCLK 60 MHz, divisor 10 */
.xres = 320, // 240,
.yres = 240, // 320,
.bpp = 16,
.left_margin = 20,
.right_margin = 38, //8,
.hsync_len = 30, //4,
.upper_margin = 15, //8,
.lower_margin = 12, //7,
.vsync_len = 3, //4,
};
How are the above parameters modified? Let's take a look.
Type indicates the display mode, here it is TFT mode.
Width and height indicate the screen resolution, my resolution is 320X240.
xres and yres are equal to width and height respectively.
bpp means the number of bits per pixel, 16 bits is used here.
The values of the six parameters left_margin, right_margin, hsync_len, upper_margin, lower_margin, and vsync_len are given in the LCD manual. The following figure shows the parameters in the LCD:
Here, I give the corresponding relationship between the above 6 parameters and the data in the LCD manual:
.left_margin = Hsync front porch = 20
.right_margin = Hsync back porch = 38
.hsync_len = Hsync pulse width = 30
.upper_margin = Vsync back porch = 15
.lower_margin = Vsync front porch = 12
.vsync_len = Vsync pulse width = 3
The value of pixclock is used to calculate CLKVAL. In the S3C2440 datasheet, the calculation formula for CLKVAL is:
CLKVAL = HCLK / VCLK / 2 -1, where VCLK is Dclk in the figure above, and its value is 6.4MHz.
/* s3c2410fb_activate_var
*
* activate (set) the controller from the given framebuffer
* information
*/
static void s3c2410fb_activate_var(struct fb_info *info)
{
struct s3c2410fb_info *fbi = info->par;
void __iomem *regs = fbi->io;
int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT; /*regs.lcdcon1 is set in s3c2410fb_check_var*/
struct fb_var_screeninfo *var = &info->var;
int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock) / 2;
dprintk("%s: var->xres = %d\n", __func__, var->xres);
dprintk("%s: var->yres = %d\n", __func__, var->yres);
dprintk("%s: var->bpp = %d\n", __func__, var->bits_per_pixel);
if (type == S3C2410_LCDCON1_TFT) {
s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs);/*Calculate the value that needs to be set to the control register based on var*/
--clkdiv;
if (clkdiv < 0)
clkdiv = 0;
} else {
s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs);
if (clkdiv < 2)
clkdiv = 2;
}
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv);/*Set CLKVAL*/
/* write new registers */
dprintk("new register set:\n");
dprintk("lcdcon[1] = 0x%08lx\n", fbi->regs.lcdcon1);
dprintk("lcdcon[2] = 0x%08lx\n", fbi->regs.lcdcon2);
dprintk("lcdcon[3] = 0x%08lx\n", fbi->regs.lcdcon3);
dprintk("lcdcon[4] = 0x%08lx\n", fbi->regs.lcdcon4);
dprintk("lcdcon[5] = 0x%08lx\n", fbi->regs.lcdcon5);
/*Fill the calculated value into the LCD controller*/
writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID,
regs + S3C2410_LCDCON1); /*LCD is still disabled*/
writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2);
writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3);
writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4);
writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5);
/* set lcd address pointers */
s3c2410fb_set_lcdaddr(info); /*Set LCD frame buffer start address*/
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID,
writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1); /*Enable LCD*/
}
static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi,
unsigned long pixclk)
{
unsigned long clk = clk_get_rate(fbi->clk); /*Get the current clock frequency (Hz)*/
unsigned long long div;
/* pixclk is in picoseconds, our clock is in Hz
*
* Hz -> picoseconds is / 10^-12
*/
div = (unsigned long long)clk * pixclk;
div >>= 12; /* div / 2^12 */
do_div(div, 625 * 625UL * 625); /* div / 5^12 */
dprintk("pixclk %ld, divisor is %ld\n", pixclk, (long)div);
return div;
}
First, pixclock is passed as a parameter to the s3c2410fb_calc_pixclk function. After the function is executed, clkdiv = clk x pixclk / 10^12 / 2.
Then, because the TFT mode is adopted, clkdiv-1. Finally, we get:
clkdiv = clk X pixclk / 10^12 / 2 - 1, where clk is HCLK, and the LCD module uses HCLK as the clock source.
For easy observation, the calculation formula in the previous datasheet is copied here: CLKVAL = HCLK / VCLK / 2 -1.
We can see that 1/VCLK = pixclk / 10^12, that is, pixclk = 10^12 / VCLK. We already know that VCLK = Dclk = 6.4MHz,
Therefore, pixclk = 156250.
In fact, there is such a passage in the kernel reference document:
The speed at which the electron beam paints the pixels is determined by the
dotclock in the graphics board. For a dotclock of eg 28.37516 MHz (millions
of cycles per second), each pixel is 35242 ps (picoseconds) long:
1/(28.37516E6 Hz) = 35.242E-9 s
That is to say, the reciprocal of VCLK multiplied by 10^12 is pixclk. The unit picoseconds stands for picoseconds, which is 10^12.
The last parameter, lcdcon5, is the configuration information of register LCDCON5.
S3C2410_LCDCON5_FRM565 means using 565 format.
S3C2410_LCDCON5_PWREN indicates that the PWREN pin output signal is enabled.
S3C2410_LCDCON5_INVVLINE and S3C2410_LCDCON5_INVVFRAME indicate inverting the VLINE/HSYNC and VFRAME/VSYNC signal lines. This can be determined by comparing the LCD manual and the S3C2440 datasheet.
S3C2410_LCDCON5_HWSWP: Since little-endian mode is used, half-word swapping needs to be set.
1.2 s3c2410fb_mach_info structure
The modified content is as follows:
static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {
.displays = &smdk2440_lcd_cfg,
.num_displays = 1,
.default_display = 0,
#if 0
/* currently setup by downloader */
.gpccon = 0xaa940659,
.gpccon_mask = 0xffffffff,
.gpcup = 0x0000ffff,
.gpcup_mask = 0xffffffff,
.gpdcon = 0xaa84aaa0,
.gpdcon_mask = 0xffffffff,
.gpdup = 0x0000faff,
.gpdup_mask = 0xffffffff,
#endif
//no
// .lpcsel = ((0xCE6) & ~7) | 1<<4,
};
The only modification made is to disable lpsel, because if you are not using a Samsung LPC3600/LCC3600 LCD, you must disable LPC3600/LCC3600 mode (write 0 to TCONSEL).
num_displays indicates how many LCD devices there are.
default_display indicates which LCD device this is.
2. Testing
After modifying the above two data structures, compile the kernel directly and then download it to the development board.
You can execute the command fbset, the output is as follows:
mode "320x240-58"
# D: 6.400 MHz, H: 15.686 kHz, V: 58.097 Hz
geometry 320 240 320 240 16
timings 156250 20 38 15 12 30 3
accel false
rgba 5/11,6/5,5/0,0/0
endmode
The values above are the parameters we set.
In addition, testing can be performed using the following test procedures:
#include
#include
#include
#include
#include
//#include
int main()
{
int fd, retval, i;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
unsigned short *memstart;
fd = open("/dev/fb0", O_RDWR);
if(fd < 0){
printf("open /dev/fb0 failed\n");
return -1;
}
retval = ioctl(fd, FBIOGET_FSCREENINFO, &fix);
if(retval < 0){
printf("ioctl failed\n");
return -1;
}
printf("seme len= %d\n", fix.smem_len);
memstart = mmap(NULL, 240*320*2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (memstart == MAP_FAILED){
printf("mmap wrong\n");
}
for(; ;){
sleep(1);
for(i = 0; i < (153600>>1); i++)
*(memstart + i) = 0xf800;
sleep(1);
for(i = 0; i < (153600>>1); i++)
*(memstart + i) = 0x0c00;
}
}
The test program is from the Internet, I just modified it slightly.
Previous article:S3C2440 Linux driver transplantation——SPI
Next article:S3C2440 Linux driver transplantation - button
Recommended ReadingLatest update time:2024-11-16 13:28
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- MSP430 capture device is simple and practical
- Colorful wallet programmed with CircuitPython
- The storage and downloading of time values sent by customers require sum verification or CRC verification
- EPWM CMPA register configuration problem
- Allegro's latest solution for 48v system
- EEWORLD University Hall----Live Replay: Microchip Security Series 12 - PolarFire? SoC FPGA Secure Boot
- "Praise my country": Let's gather together and talk about the useful domestic microcontrollers
- Ling Embedded Talent Recruitment is in full swing! Don’t run~ It’s you~
- A correct schematic does not necessarily produce a correct PCB design
- "Operational Amplifier Parameter Analysis and LTspice Application Simulation" 5, Chapter 3, 4, 5 Sample Reading