內核版本:linux-3.4.2 lcd:4.3
上代碼之前我得講解一些基本的知識點,LCD驅動我們只需要寫硬件這一塊的代碼就可以了,下面有三個函數內核已經幫我們寫好了,我們只需要調用就可以了,這幾個函數實現了內核層和應用成數據的傳遞,有興趣的朋友去分析一下源碼,我里驅動寫好了我們可以選擇動態加載驅動或者直接靜態編譯進內核,這個的區別在前文中我講解的非常清楚了,希望朋友一定要去看一下,Linux驅動靜態編譯和動態編譯方法詳解
這個代碼相對有點復雜,朋友們一定要仔細分析。驅動程序如下:
lcd.c文件如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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 long lcdcon1;
unsigned long lcdcon2;
unsigned long lcdcon3;
unsigned long lcdcon4;
unsigned long lcdcon5;
unsigned long lcdsaddr1;
unsigned long lcdsaddr2;
unsigned long lcdsaddr3;
unsigned long redlut;
unsigned long greenlut;
unsigned long bluelut;
unsigned long reserved[9];
unsigned long dithmode;
unsigned long tpal;
unsigned long lcdintpnd;
unsigned long lcdsrcpnd;
unsigned long lcdintmsk;
unsigned long lpcsel;
};
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];
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;
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)
{
s3c_lcd = framebuffer_alloc(0, NULL);
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;
s3c_lcd->fix.line_length = 480*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;
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;
s3c_lcd->fbops = &s3c_lcdfb_ops;
s3c_lcd->pseudo_palette = pseudo_palette;
//s3c_lcd->screen_base = ;
s3c_lcd->screen_size = 480*272*16/8;
gpbcon = ioremap(0x56000010, 8);
gpbdat = gpbcon+1;
gpccon = ioremap(0x56000020, 4);
gpdcon = ioremap(0x56000030, 4);
gpgcon = ioremap(0x56000060, 4);
*gpccon = 0xaaaaaaaa;
*gpdcon = 0xaaaaaaaa;
*gpbcon &= ~(3);
*gpbcon |= 1;
*gpbdat &= ~1;
*gpgcon |= (3<<8);
lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs));
lcd_regs->lcdcon1 = (4<<8) | (3<<5) | (0x0c<<1);
#if 1
lcd_regs->lcdcon2 = (1<<24) | (271<<14) | (1<<6) | (9);
lcd_regs->lcdcon3 = (1<<19) | (479<<8) | (1);
lcd_regs->lcdcon4 = 40;
#else
lcd_regs->lcdcon2 = S3C2410_LCDCON2_VBPD(5) | \
S3C2410_LCDCON2_LINeval_r(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
lcd_regs->lcdcon5 = (1<<11) | (0<<10) | (1<<9) | (1<<8) | (1<<0);
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);
//s3c_lcd->fix.smem_start = xxx;
lcd_regs->lcdcon1 |= (1<<0);
lcd_regs->lcdcon5 |= (1<<3);
*gpbdat |= 1;
register_framebuffer(s3c_lcd);
return 0;
}
static void lcd_exit(void)
{
unregister_framebuffer(s3c_lcd);
lcd_regs->lcdcon1 &= ~(1<<0);
*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)
static int FBShowPixel(int iX, int iY, unsigned int dwColor)
static int FBCleanScreen(unsigned int dwBackColor)
#include
#include "jpeglib.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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);
if (0 > g_fd)
{
DBG_PRINTF("can't open %s\n", FB_DEVICE_NAME);
}
ret = ioctl(g_fd, FBIOGET_VSCREENINFO, &g_tFBVar);
if (ret < 0)
{
DBG_PRINTF("can't get fb's var\n");
return -1;
}
ret = ioctl(g_fd, FBIOGET_FSCREENINFO, &g_tFBFix);
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;
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)
{
unsigned char *pucFB;
unsigned short *pwFB16bpp;
unsigned int *pdwFB32bpp;
unsigned short wColor16bpp;
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;
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++)
{
dwColor = (pucRGBArray[i]<<16) + (pucRGBArray[i+1]<<8) + (pucRGBArray[i+2]<<0);
i += 3;
FBShowPixel(iX, iY, dwColor);
}
return 0;
}
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 \n", argv[0]);
return -1;
}
if (FBDeviceInit())
{
return -1;
}
FBCleanScreen(0);
// 分配和初始化一個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;
}
上一篇:ARM嵌入式應用調試之輸入模擬器之編寫測試模擬功能
下一篇:ARM筆記:應用調試之自制系統調用、編寫進程查看器(二)
推薦閱讀
史海拾趣
DDD公司成立于1964年,當時正值電子行業的蓬勃發展期。創始人看到了延遲線技術在計算機和電信領域中的巨大潛力,決定投身其中。然而,初期的市場并不如預期般順利,公司面臨著資金短缺、技術難題和市場競爭等多重壓力。但DDD公司的創始人憑借對技術的熱情和堅定的信念,帶領團隊不斷研發新產品,優化生產工藝,逐漸在市場中樹立了自己的品牌形象。
在保持核心技術優勢的同時,意瑞半導體還不斷擴大其產品線,涉足更多的領域,如物聯網等。公司致力于提供從芯片設計到系統集成的一攬子解決方案,以滿足不同客戶的需求。此外,公司還積極申請專利和集成電路布圖設計專有權,累計申請近20項專利發明和39項集成電路布圖設計專有權,進一步鞏固了其在行業中的技術領先地位。
E-tec Interconnect Ltd成立于XX世紀初,起初是一家專注于電子連接器設計與制造的小型公司。在創始團隊的帶領下,E-tec注重基礎技術的積累,投入大量資源進行研發和創新。他們成功開發了一系列高精度、高可靠性的連接器產品,為公司的后續發展奠定了堅實的基礎。
EXCELSEMI公司自創立之初,就致力于半導體技術的研發與創新。在早期,公司研發團隊成功攻克了高性能半導體材料的生產技術難題,這一技術突破為公司后續的產品開發奠定了堅實基礎。隨著技術的不斷進步,EXCELSEMI在半導體芯片設計、制造和封裝等領域都取得了顯著成果,逐漸在市場中嶄露頭角。
在作硬件之前,需要看的資料有: 1.芯片數據手冊,描述該器件的引腳信號、片上資源、電氣指標和機械特性(如封裝等),在做硬件前必看(TMS320F281x數據手冊SPRS174J) 2.某一系列DSP的CPU和指令集用戶指南,描述該系列DSP的CPU結構、內部寄存器 ...… 查看全部問答∨ |
|
哎,買了個太陽能小夜燈,被騙了。想自己改進一下,請假一下電路如何改進 買了個太陽能小夜燈,說白天太陽底下充電一個白天,能亮一個晚上。可它是當快沒電了的時候,一閃一閃的。正常亮也就亮兩個小時,然后就是一閃一閃的亮。晚上一閃一閃的晃的睡不著。 我想改進一下,當它快沒電的時候不讓它亮了。… 查看全部問答∨ |
為什么可以把系統從掛起狀態的設備不能通過DevicePowerNotify申請進入D3狀態呢? 小弟看了windows mobile 5.0的文檔,但是看得一頭霧水,請各位大哥大姐指教,本人不勝感激!以下是mobile的部分文檔: Devices that can wake the s ...… 查看全部問答∨ |
看上去是個運動水壺,其實他是一個LED露營燈, 如果你旅行時有重要的私人用品,還可以將他們都裝進去,防水防潮。這款名叫LightCap 300 LED戶外燈,LED燈藏在瓶蓋里面,瓶蓋的外面是貼有整塊太陽能板,不管你在哪只要野外晴天就能充電,夜晚就能持 ...… 查看全部問答∨ |
最近再做一個FPGA通過并口與PC機進行通信的實驗:數據從FPGA傳向PC機。給FPGA下載代碼后,PC機接收不到數據,當打開示波器的一瞬間或者用示波器的探頭地接觸電路板的地時,PC機可以接收到數據! 我在網上看了一些資料,發現可能是“浮地”的問題, ...… 查看全部問答∨ |
光盤是《51單片機C語言開發詳解》一書的配套光盤,內含書中各章節摘抄內容做得PPT和書中的源代碼。PPT寫得簡介易懂,非常值得一讀。我很想買到這本書,無奈書已停版,各大書店都買不到。… 查看全部問答∨ |
|
搭建開發環境 1> 安裝開發環境 CubeSuitePlus_Package_V20200 2> 將r7f0c809_dif壓縮文件中的文件夾Device_Custom拷貝到安裝環境的根目錄下 3> 更新仿真器硬件文件 1、插上仿真器,安裝驅動程序, ...… 查看全部問答∨ |