<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                以前沒有寫Lcd驅動程序,現在開始做項目了,才發現Lcd驅動程序必須認真學習。還是老規矩先上代碼。 內核版本:linux-3.4.2 ? ? ? ? ? ? ? ? ? lcd:4.3 lcd.c文件如下: ~~~ #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/dma-mapping.h> #include <linux/interrupt.h> #include <linux/workqueue.h> #include <linux/wait.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/div64.h> #include <asm/mach/map.h> static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red, ? ? unsigned int green, unsigned int blue, ? ? unsigned int transp, struct fb_info *info); struct lcd_regs { unsigned longlcdcon1; unsigned longlcdcon2; unsigned longlcdcon3; unsigned longlcdcon4; unsigned longlcdcon5; ? ? unsigned longlcdsaddr1; ? ? unsigned longlcdsaddr2; ? ? unsigned longlcdsaddr3; ? ? unsigned longredlut; ? ? unsigned longgreenlut; ? ? unsigned longbluelut; ? ? unsigned longreserved[9]; ? ? unsigned longdithmode; ? ? unsigned longtpal; ? ? unsigned longlcdintpnd; ? ? unsigned longlcdsrcpnd; ? ? unsigned longlcdintmsk; ? ? unsigned longlpcsel; }; static struct fb_ops s3c_lcdfb_ops = { .owner= THIS_MODULE, .fb_setcolreg= s3c_lcdfb_setcolreg, .fb_fillrect= cfb_fillrect, ? ? ? ? ? /* 這三個函數是在內核自帶的,動態加載時候,需要把這個三個編譯成模塊當吧驅動程序編譯進內核時候,就不用去管著三個函數 */ .fb_copyarea= cfb_copyarea, .fb_imageblit= cfb_imageblit, }; static struct fb_info *s3c_lcd; static volatile unsigned long *gpbcon; static volatile unsigned long *gpbdat; static volatile unsigned long *gpccon; static volatile unsigned long *gpdcon; static volatile unsigned long *gpgcon; static volatile struct lcd_regs* lcd_regs; static u32 pseudo_palette[16]; /* from pxafb.c */ static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) { chan &= 0xffff; chan >>= 16 - bf->length; return chan << bf->offset; } static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red, ? ? unsigned int green, unsigned int blue, ? ? unsigned int transp, struct fb_info *info) { unsigned int val; if (regno > 16) return 1; /* 用red,green,blue三原色構造出val */ val ?= chan_to_field(red,&info->var.red); val |= chan_to_field(green, &info->var.green); val |= chan_to_field(blue,&info->var.blue); //((u32 *)(info->pseudo_palette))[regno] = val; pseudo_palette[regno] = val; return 0; } static int lcd_init(void) { /* 1. 分配一個fb_info */ s3c_lcd = framebuffer_alloc(0, NULL); /* 2. 設置 */ /* 2.1 設置固定的參數 */ strcpy(s3c_lcd->fix.id, "mylcd"); s3c_lcd->fix.smem_len = 480*272*16/8; s3c_lcd->fix.type ? ? = FB_TYPE_PACKED_PIXELS; s3c_lcd->fix.visual ? = FB_VISUAL_TRUECOLOR; /* TFT */ s3c_lcd->fix.line_length = 480*2; /* 2.2 設置可變的參數 */ s3c_lcd->var.xres ? ? ? ? ? = 480; s3c_lcd->var.yres ? ? ? ? ? = 272; s3c_lcd->var.xres_virtual ? = 480; s3c_lcd->var.yres_virtual ? = 272; s3c_lcd->var.bits_per_pixel = 16; /* RGB:565 */ s3c_lcd->var.red.offset ? ? = 11; s3c_lcd->var.red.length ? ? = 5; s3c_lcd->var.green.offset ? = 5; s3c_lcd->var.green.length ? = 6; s3c_lcd->var.blue.offset ? ?= 0; s3c_lcd->var.blue.length ? ?= 5; s3c_lcd->var.activate ? ? ? = FB_ACTIVATE_NOW; /* 2.3 設置操作函數 */ s3c_lcd->fbops ? ? ? ? ? ? ?= &s3c_lcdfb_ops; /* 2.4 其他的設置 */ s3c_lcd->pseudo_palette = pseudo_palette; //s3c_lcd->screen_base ?= ; ?/* 顯存的虛擬地址 */? s3c_lcd->screen_size ? = 480*272*16/8; /* 3. 硬件相關的操作 */ /* 3.1 配置GPIO用于LCD */ gpbcon = ioremap(0x56000010, 8); gpbdat = gpbcon+1; gpccon = ioremap(0x56000020, 4); gpdcon = ioremap(0x56000030, 4); gpgcon = ioremap(0x56000060, 4); ? ? *gpccon ?= 0xaaaaaaaa; ? /* GPIO管腳用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND */ *gpdcon ?= 0xaaaaaaaa; ? /* GPIO管腳用于VD[23:8] */ *gpbcon &= ~(3); ?/* GPB0設置為輸出引腳 */ *gpbcon |= 1; *gpbdat &= ~1; ? ? /* 輸出低電平 */ *gpgcon |= (3<<8); /* GPG4用作LCD_PWREN */ /* 3.2 根據LCD手冊設置LCD控制器, 比如VCLK的頻率等 */ lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs)); /* bit[17:8]: VCLK = HCLK / [(CLKVAL+1) x 2], LCD手冊P14 * ? ? ? ? ? ?10MHz(100ns) = 100MHz / [(CLKVAL+1) x 2] * ? ? ? ? ? ?CLKVAL = 4 * bit[6:5]: 0b11, TFT LCD * bit[4:1]: 0b1100, 16 bpp for TFT * bit[0] ?: 0 = Disable the video output and the LCD control signal. */ lcd_regs->lcdcon1 ?= (4<<8) | (3<<5) | (0x0c<<1); #if 1 /* 垂直方向的時間參數 * bit[31:24]: VBPD, VSYNC之后再過多長時間才能發出第1行數據 * ? ? ? ? ? ? LCD手冊 T0-T2-T1=4 * ? ? ? ? ? ? VBPD=3 * bit[23:14]: 多少行, 320, 所以LINEVAL=320-1=319 * bit[13:6] : VFPD, 發出最后一行數據之后,再過多長時間才發出VSYNC * ? ? ? ? ? ? LCD手冊T2-T5=322-320=2, 所以VFPD=2-1=1 * bit[5:0] ?: VSPW, VSYNC信號的脈沖寬度, LCD手冊T1=1, 所以VSPW=1-1=0 */ lcd_regs->lcdcon2 ?= (1<<24) | (271<<14) | (1<<6) | (9); /* 水平方向的時間參數 * bit[25:19]: HBPD, VSYNC之后再過多長時間才能發出第1行數據 * ? ? ? ? ? ? LCD手冊 T6-T7-T8=17 * ? ? ? ? ? ? HBPD=16 * bit[18:8]: 多少列, 240, 所以HOZVAL=240-1=239 * bit[7:0] : HFPD, 發出最后一行里最后一個象素數據之后,再過多長時間才發出HSYNC * ? ? ? ? ? ? LCD手冊T8-T11=251-240=11, 所以HFPD=11-1=10 */ lcd_regs->lcdcon3 = (1<<19) | (479<<8) | (1); /* 水平方向的同步信號 * bit[7:0]: HSPW, HSYNC信號的脈沖寬度, LCD手冊T7=5, 所以HSPW=5-1=4 */ lcd_regs->lcdcon4 = 40; #else lcd_regs->lcdcon2 =S3C2410_LCDCON2_VBPD(5) | \ S3C2410_LCDCON2_LINEVAL(319) | \ S3C2410_LCDCON2_VFPD(3) | \ S3C2410_LCDCON2_VSPW(1); lcd_regs->lcdcon3 =S3C2410_LCDCON3_HBPD(10) | \ S3C2410_LCDCON3_HOZVAL(239) | \ S3C2410_LCDCON3_HFPD(1); lcd_regs->lcdcon4 =S3C2410_LCDCON4_MVAL(13) | \ S3C2410_LCDCON4_HSPW(0); #endif /* 信號的極性? * bit[11]: 1=565 format * bit[10]: 0 = The video data is fetched at VCLK falling edge * bit[9] : 1 = HSYNC信號要反轉,即低電平有效? * bit[8] : 1 = VSYNC信號要反轉,即低電平有效? * bit[6] : 0 = VDEN不用反轉 * bit[3] : 0 = PWREN輸出0 * bit[1] : 0 = BSWP * bit[0] : 1 = HWSWP 2440手冊P413 */ lcd_regs->lcdcon5 = (1<<11) | (0<<10) | (1<<9) | (1<<8) | (1<<0); /* 3.3 分配顯存(framebuffer), 并把地址告訴LCD控制器 */ s3c_lcd->screen_base = dma_alloc_writecombine(NULL, s3c_lcd->fix.smem_len, &s3c_lcd->fix.smem_start, GFP_KERNEL); lcd_regs->lcdsaddr1 ?= (s3c_lcd->fix.smem_start >> 1) & ~(3<<30); lcd_regs->lcdsaddr2 ?= ((s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len) >> 1) & 0x1fffff; lcd_regs->lcdsaddr3 ?= (480*16/16); ?/* 一行的長度(單位: 2字節) */ //s3c_lcd->fix.smem_start = xxx; ?/* 顯存的物理地址 */ /* 啟動LCD */ lcd_regs->lcdcon1 |= (1<<0); /* 使能LCD控制器 */ lcd_regs->lcdcon5 |= (1<<3); /* 使能LCD本身 */ *gpbdat |= 1; ? ? /* 輸出高電平, 使能背光 */ /* 4. 注冊 */ register_framebuffer(s3c_lcd); return 0; } static void lcd_exit(void) { unregister_framebuffer(s3c_lcd); lcd_regs->lcdcon1 &= ~(1<<0); /* 關閉LCD本身 */ *gpbdat &= ~1; ? ? /* 關閉背光 */ dma_free_writecombine(NULL, s3c_lcd->fix.smem_len, s3c_lcd->screen_base, s3c_lcd->fix.smem_start); iounmap(lcd_regs); iounmap(gpbcon); iounmap(gpccon); iounmap(gpdcon); iounmap(gpgcon); framebuffer_release(s3c_lcd); } module_init(lcd_init); module_exit(lcd_exit); MODULE_LICENSE("GPL"); ~~~ 測試程序怎么編寫就看你的應用程序了,但是框架是不變的如下:下面是在Lcd上顯示一幅圖片,用到了libjpeg庫,這個地方可以不用關注,主要是看看應用程序怎么調用驅動程序的,我總結有如下當函數: ~~~ static int FBDeviceInit(void) ? ?/* FB初始化函數 */ static int FBShowPixel(int iX, int iY, unsigned int dwColor) ?/* 填充像素,具體怎么填充看如下代碼中 */ static int FBCleanScreen(unsigned int dwBackColor) ? ? ?/* 清屏函數,把顯示屏初始化為黑色 */ ~~~ ~~~ #include <stdio.h> #include "jpeglib.h" #include <setjmp.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <linux/fb.h> #include <string.h> #include <stdlib.h> #define FB_DEVICE_NAME "/dev/fb0" #define DBG_PRINTF printf static int g_fd; static struct fb_var_screeninfo g_tFBVar; static struct fb_fix_screeninfo g_tFBFix; static unsigned char *g_pucFBMem; static unsigned int g_dwScreenSize; static unsigned int g_dwLineWidth; static unsigned int g_dwPixelWidth; static int FBDeviceInit(void) { int ret; g_fd = open(FB_DEVICE_NAME, O_RDWR); ? /* 打開lcd驅動設備節點 */ if (0 > g_fd) { DBG_PRINTF("can't open %s\n", FB_DEVICE_NAME); } ret = ioctl(g_fd, FBIOGET_VSCREENINFO, &g_tFBVar); ? /* 獲取lcd可變參數 */ if (ret < 0) { DBG_PRINTF("can't get fb's var\n"); return -1; } ret = ioctl(g_fd, FBIOGET_FSCREENINFO, &g_tFBFix); ??/* 獲取lcd固定參數 */ if (ret < 0) { DBG_PRINTF("can't get fb's fix\n"); return -1; } g_dwScreenSize = g_tFBVar.xres * g_tFBVar.yres * g_tFBVar.bits_per_pixel / 8; ?/* 計算lcd屏幕大小 */ g_pucFBMem = (unsigned char *)mmap(NULL , g_dwScreenSize, PROT_READ | PROT_WRITE, MAP_SHARED, g_fd, 0); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* 把顯存映射成內存一樣,方便我們直接操作 */ if (0 > g_pucFBMem) { DBG_PRINTF("can't mmap\n"); return -1; } g_dwLineWidth ?= g_tFBVar.xres * g_tFBVar.bits_per_pixel / 8; g_dwPixelWidth = g_tFBVar.bits_per_pixel / 8; return 0; } static int FBShowPixel(int iX, int iY, unsigned int dwColor) ?/* 填充像素,dwcolor就是我們要在一個像素顯示的顏色 */ { unsigned char *pucFB; unsigned short *pwFB16bpp; unsigned int *pdwFB32bpp; unsigned short wColor16bpp; /* 565 */ int iRed; int iGreen; int iBlue; if ((iX >= g_tFBVar.xres) || (iY >= g_tFBVar.yres)) { DBG_PRINTF("out of region\n"); return -1; } pucFB ? ? ?= g_pucFBMem + g_dwLineWidth * iY + g_dwPixelWidth * iX; pwFB16bpp ?= (unsigned short *)pucFB; pdwFB32bpp = (unsigned int *)pucFB; switch (g_tFBVar.bits_per_pixel) { case 8: { *pucFB = (unsigned char)dwColor; break; } case 16: { iRed ? = (dwColor >> (16+3)) & 0x1f; iGreen = (dwColor >> (8+2)) & 0x3f; iBlue ?= (dwColor >> 3) & 0x1f; wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue; *pwFB16bpp= wColor16bpp; break; } case 32: { *pdwFB32bpp = dwColor; break; } default : { DBG_PRINTF("can't support %d bpp\n", g_tFBVar.bits_per_pixel); return -1; } } return 0; } static int FBCleanScreen(unsigned int dwBackColor) { unsigned char *pucFB; unsigned short *pwFB16bpp; unsigned int *pdwFB32bpp; unsigned short wColor16bpp; /* 565 */ int iRed; int iGreen; int iBlue; int i = 0; pucFB ? ? ?= g_pucFBMem; pwFB16bpp ?= (unsigned short *)pucFB; pdwFB32bpp = (unsigned int *)pucFB; switch (g_tFBVar.bits_per_pixel) { case 8: { memset(g_pucFBMem, dwBackColor, g_dwScreenSize); break; } case 16: { iRed ? = (dwBackColor >> (16+3)) & 0x1f; iGreen = (dwBackColor >> (8+2)) & 0x3f; iBlue ?= (dwBackColor >> 3) & 0x1f; wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue; while (i < g_dwScreenSize) { *pwFB16bpp= wColor16bpp; pwFB16bpp++; i += 2; } break; } case 32: { while (i < g_dwScreenSize) { *pdwFB32bpp= dwBackColor; pdwFB32bpp++; i += 4; } break; } default : { DBG_PRINTF("can't support %d bpp\n", g_tFBVar.bits_per_pixel); return -1; } } return 0; } static int FBShowLine(int iXStart, int iXEnd, int iY, unsigned char *pucRGBArray) { int i = iXStart * 3; int iX; unsigned int dwColor; if (iY >= g_tFBVar.yres) return -1; if (iXStart >= g_tFBVar.xres) return -1; if (iXEnd >= g_tFBVar.xres) { iXEnd = g_tFBVar.xres; } for (iX = iXStart; iX < iXEnd; iX++) { /* 0xRRGGBB */ dwColor = (pucRGBArray[i]<<16) + (pucRGBArray[i+1]<<8) + (pucRGBArray[i+2]<<0); i += 3; FBShowPixel(iX, iY, dwColor); } return 0; } ~~~ ~~~ /* Allocate and initialize a JPEG decompression object ? ?// 分配和初始化一個decompression結構體 Specify the source of the compressed data (eg, a file) // 指定源文件 Call jpeg_read_header() to obtain image info? // 用jpeg_read_header獲得jpg信息 Set parameters for decompression? // 設置解壓參數,比如放大、縮小 jpeg_start_decompress(...); ? // 啟動解壓:jpeg_start_decompress while (scan lines remain to be read) jpeg_read_scanlines(...);? // 循環調用jpeg_read_scanlines jpeg_finish_decompress(...);? // jpeg_finish_decompress Release the JPEG decompression object? // 釋放decompression結構體 */ /* Uage: jpg2rgb <jpg_file> ?*/ int main(int argc, char **argv) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; FILE * infile; int row_stride; unsigned char *buffer; if (argc != 2) { printf("Usage: \n"); printf("%s <jpg_file>\n", argv[0]); return -1; } if (FBDeviceInit()) { return -1; } FBCleanScreen(0); /* 一下部分是把圖片解壓出來,取出各個像素值放在一個緩沖區中,我們只需要把這些像素填進lcd當中去就行 */ // 分配和初始化一個decompression結構體 cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); // 指定源文件 if ((infile = fopen(argv[1], "rb")) == NULL) { fprintf(stderr, "can't open %s\n", argv[1]); return -1; } jpeg_stdio_src(&cinfo, infile); // 用jpeg_read_header獲得jpg信息 jpeg_read_header(&cinfo, TRUE); /* 源信息 */ printf("image_width = %d\n", cinfo.image_width); printf("image_height = %d\n", cinfo.image_height); printf("num_components = %d\n", cinfo.num_components); // 設置解壓參數,比如放大、縮小 printf("enter scale M/N:\n"); scanf("%d/%d", &cinfo.scale_num, &cinfo.scale_denom); printf("scale to : %d/%d\n", cinfo.scale_num, cinfo.scale_denom); // 啟動解壓:jpeg_start_decompress jpeg_start_decompress(&cinfo); /* 輸出的圖象的信息 */ printf("output_width = %d\n", cinfo.output_width); printf("output_height = %d\n", cinfo.output_height); printf("output_components = %d\n", cinfo.output_components); // 一行的數據長度 row_stride = cinfo.output_width * cinfo.output_components; buffer = malloc(row_stride); // 循環調用jpeg_read_scanlines來一行一行地獲得解壓的數據 while (cinfo.output_scanline < cinfo.output_height)? { (void) jpeg_read_scanlines(&cinfo, &buffer, 1); // 寫到LCD去 FBShowLine(0, cinfo.output_width, cinfo.output_scanline, buffer); } free(buffer); jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return 0; } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看