ARM嵌入式之lcd驱动程序之显示图片

发布者:钱老李最新更新时间:2018-04-13 来源: eefocus关键字:ARM  lcd驱动  显示图片 手机看文章 扫描二维码
随时随地手机看文章

内核版本: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  lcd驱动  显示图片 引用地址:ARM嵌入式之lcd驱动程序之显示图片

上一篇:ARM嵌入式应用调试之输入模拟器之编写测试模拟功能
下一篇:ARM筆記:应用调试之自制系统调用、编写进程查看器(二)

推荐阅读最新更新时间:2024-03-16 15:59

德州仪器升级版Stellaris EVALBOT增强机器人开发
面向 TI Stellaris ARM® Cortex™-M3 微控制器的新型迷你机器人评估平台提供了更多的工具及软件选项以简化实验和开发工作 日前,德州仪器 (TI) 宣布推出其最新款 Stellaris 微控制器 (MCU) 机器人评估平台 (EVALBOT),从而使开发人员拥有了更多的软件和工具开发选项。这款隶属于 TI 嵌入式处理产品组合的新型迷你机器人平台为开发人员提供了从众多软件工具链进行选择的灵活性,这样他们就能够在其偏爱的开发环境中全面使用 Stellaris Cortex-M3 MCU 的功能。该升级版 Stellaris EVALBOT 还预先装入了 StellarisWare® 应用程序,而且该套件
[单片机]
德州仪器升级版Stellaris EVALBOT增强机器人开发
传奇芯片架构师Jim Keller离职后,AMD取消了K12 ARM CPU项目
据外媒WccfTech消息,传奇芯片架构师JimKeller在一次会议上表示,在他离开前雇主AMD后,他的K12ARMCPU项目被“愚蠢地取消”了。 据报道,“计算的未来”会议由印度科学研究所计算机科学与自动化系举办,在会议上,JimKeller简要概述了他之前从事的各种项目以及芯片设计的基础知识。    JimKeller表示,当他在AMD时,他从事Zen1的开发工作,并制定了Zen2和Zen3的计划。    如上图所示,AMD曾在PPT上宣布过K12ARMCPU 项目,该系列处理器原定于2017年上市,针对密集服务器、嵌入式细分市场。据JimKeller透露,K12ARMCPU项目实际上是在他离开AMD公司后被某些产品
[家用电子]
传奇芯片架构师Jim Keller离职后,AMD取消了K12 <font color='red'>ARM</font> CPU项目
通过framebuffer显示png图片
一、前言   png图片是无损压缩格式,它有一个比较重要的特点是可以让特定区域透明。要显示png图片需要调用png库留出的函数接口,png库留出的函数接口很多,但是帮助手册里没有详细的说明各个函数的用法,网上也没找到太多资料,因此在这里只介绍一种能用的方法。有些函数用法在代码注释里写着。 二、代码 1 /** 2 * filename: png.c 3 * author: Suzkfly 4 * date: 2021-08-14 5 * platform: S3C2416或Ubuntu 6 * 需要提前准备好lv.png这张图片,编译时要加-lpng参数,并且程序运行平台需要有png的库 7 */ 8 #inc
[单片机]
通过framebuffer<font color='red'>显示</font>png<font color='red'>图片</font>
使用 IAR for ARM 的一些心得
1. 工程中 ARM芯片选型 2. Include 目录配置 3. 配置程序在 Flash / RAM中运行 4. 配置 J-Linker仿真器 5. 修改 IAR 显示 修改左侧 Project 显示字体 修改编辑文档字体 6. IAR6.2以后的版本编译IAR6.2以前的版本会出现如下错误: view plain copy Error : declaration is incompatible with __nounwind __interwork __softfp unsigned long __REV16(unsigned long) (declare
[单片机]
使用 IAR for <font color='red'>ARM</font> 的一些心得
arm启动代码详细分析
arm启动代码详细分析 所谓启动代码,就是处理器在启动的时候执行的一段代码,主要任务是初始化处理器模式,设置堆栈,初始化变量等等.由于以上的操作均与处理器体系结构和系统配置密切相关,所以一般由汇编来编写.   具体到S64,启动代码分成两部分,一是与ARM7TDMI内核相关的部分,包括处理器各异常向量的配置,各处理器模式的堆栈设置,如有必要,复制向量到RAM,以便remap之后处理器正确处理异常,初始化数据(包括RW与ZI),最后跳转到Main.二是与处理器外部设备相关的部分,这和厂商的联系比较大.虽然都采用了ARM7TDMI的内核,但是不同的厂家整合了不同的片上外设,需要不同的初始化,其中比较重要的是初始化WDT,初始化各子
[单片机]
ARM笔记: 内存驱动实验
1.1.8 内存驱动实验 设置该工程加载时运行时地址为0x30000000,如图2-55所示: 图2-55设置加载时运行时地址 init.s:本程序文件主要实现了,关闭看门狗,初始化内存,拷贝ROM数据到内存中,然后跳往内存中执行xmain函数,从xmain函数返回之后,将全部led点亮,进入死循环。 ; ; 内存初始化实验 ; AREA Init, CODE, READONLY ENTRY start ; close watchdog ldr r0, = 0x53000000 ; 将看门狗控制寄存器地址放入r0 mov r1, #0 str r1,
[单片机]
基于ARM9TDMI的简易直流电子负载设计
0 引言 现实生活中负载的形式较为复杂,多为一些动态负载,如:负载消耗的功率是时间的函数;或者负载工作在恒定电流、恒定电阻;负载为瞬时短路负载;以及在仪表测试时,如果想对其输出特性进行可靠、全面且比较简单、快捷的测试等。传统负载不能模拟这些复杂的负载形式,关键在于不能完成自动测试,因此,要实现这些功能离不开电子负载。 目前的电子直流负载由于电路设计和电器元件选择的不完善,导致其不能在较大电流和较高电压下稳定、快速、精确的完成测量任务。本系统采用32位的ARM9TDMI为主控芯片,同时借助外部16位A/D转换芯片ADSlll5的辅助电路,能够保存更多的采样数据,从而减小了采样信号的失真度,实现了稳定快速的实时测量。对硬件电路的设计,
[单片机]
基于<font color='red'>ARM</font>9TDMI的简易直流电子负载设计
三星ARM处理器S3C4510B的HDLC通道使用及编程
摘要 三星16/32位ARM处理器S3C4510B是目前在国内应用非常广泛的一种性价比很高的ARM处理器,本文在介绍S3C4510B中HDLC通道结构特点的基础上,详细说明了4510中HDLC通道在DMA收发方式下的工作过程,使用方法和编程中的一些注意事项。 1:S3C4510B简介 S3C4510B(以下简称4510)是韩国三星公司开发的一款基于ARM7TDMI架构的16/32位高性能微处理器。具用丰富的外围接口,如以太网,HDLC等,可灵活配置,适用于多种应用。4510具有以下性能特点: ◆ 8K字节的内部CACHE,也可用作内部SRAM ◆ 两线IIC接口,作为IIC主器件使用 ◆ 以太网控制
[嵌入式]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved