JZ2440字符的点阵显示

应用程序

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
static const unsigned char fontdata_8x16[FONTDATAMAX] = {
/* 65 0x41 'A' */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x10, /* 00010000 */
0x38, /* 00111000 */
0x6c, /* 01101100 */
0xc6, /* 11000110 */
0xc6, /* 11000110 */
0xfe, /* 11111110 */
0xc6, /* 11000110 */
0xc6, /* 11000110 */
0xc6, /* 11000110 */
0xc6, /* 11000110 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
}
#define FONTDATAMAX 4096
//全部设置为全局变量
int fd_fb;
struct fb_var_screeninfo var;	/* Current var */
struct fb_fix_screeninfo fix;	/* Current fix */
int screen_size;//屏幕大小
unsigned char *fbmem;
unsigned int line_width;//每行有多少个字节
unsigned int pixel_width;//每个像素有几个字节
int fd_hzk16;
struct stat hzk_stat;
unsigned char *hzkmem;
/* color : 0x00RRGGBB */
void lcd_put_pixel(int x, int y, unsigned int color)
{
unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width;//fbmem为映射到LCD显示屏上的内存,y表示第几行这就是他的位置
unsigned short *pen_16;
unsigned int *pen_32;
unsigned int red, green, blue;
pen_16 = (unsigned short *)pen_8;
pen_32 = (unsigned int *)pen_8;
//现在开始描点
switch (var.bits_per_pixel)
{
case 8://每个像素用8位的时候
{
*pen_8 = color;
break;
}
case 16://每个像素用16位的时候
{
/* 565 */
red = (color >> 16) & 0xff;//color : 0x00RRGGBB
green = (color >> 8) & 0xff;
blue = (color >> 0) & 0xff;
//红颜色只需要5位,绿颜色只需要高6位,blue只需要保留它的高5位,这样就得到一个5-6-5
color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
*pen_16 = color;
break;
}
case 32://每个像素用32位的时候
{
*pen_32 = color;
break;
}
default:
{
printf("can't surport %dbpp\n", var.bits_per_pixel);
break;
}
}
}
void lcd_put_ascii(int x, int y, unsigned char c)
{
unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];//这个c是ascii码,每个码占据16字节
int i, b;
unsigned char byte;
for (i = 0; i < 16; i++)
{
byte = dots[i];
for (b = 7; b >= 0; b--)//由于是8*16,取出每一行
{
if (byte & (1<<b))
{
/* show */
lcd_put_pixel(x+7-b, y+i, 0xffffff); /* 白 FONTDATAMAX */
}
else
{
/* hide */
lcd_put_pixel(x+7-b, y+i, 0); /* 黑 */
}
}
}
}
//显示汉字要用到汉字库 汉字使用两个字符来描述,从网上搜索汉字库
void lcd_put_chinese(int x, int y, unsigned char *str)
{
unsigned int area = str[0] - 0xA1;//区,是第一个字符
unsigned int where = str[1] - 0xA1;//位,是第二个字符
unsigned char *dots = hzkmem + (area * 94 + where)*32;//点阵从哪里开始的,每个区域中有94个字符,每个字符占据32字节,算出总大小,然后在进行映射,算出地址
unsigned char byte;
int i, j, b;
for (i = 0; i < 16; i++)
for (j = 0; j < 2; j++)
{
byte = dots[i*2 + j];
for (b = 7; b >=0; b--)//一个一个像素来描
{
if (byte & (1<<b))//如果有位置就要显示,不然就要进行关闭
{
/* show */
lcd_put_pixel(x+j*8+7-b, y+i, 0xffffff); /* 白 */
}
else
{
/* hide */
lcd_put_pixel(x+j*8+7-b, y+i, 0); /* 黑 */
}
}
}
}
int main(int argc, char **argv)
{
unsigned char str[] = "中间";
fd_fb = open("/dev/fb0", O_RDWR);//打开设备节点
if (fd_fb < 0)
{
printf("can't open /dev/fb0\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))//获得可变的屏幕信息FBIOGET_VSCREENINFO,传给var
{
printf("can't get var\n");//如果不能获得则返回错误
return -1;
}
if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))//获得固定的屏幕信息FBIOGET_VSCREENINFO,传给fix
{
printf("can't get fix\n");
return -1;
}
line_width = var.xres * var.bits_per_pixel / 8;//每行像素个数*每个像素占据的位数/8=占据的字节数
pixel_width = var.bits_per_pixel / 8;//每个像素占据多少位/8=占据的字节数
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;//x轴的像素*y轴的像素*每个像素占的位,再除以8得到字节
fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);//直接进行内存映射,NULL表示有系统自己分配地址,属性可读可写,返回值代表成功与失败,
//第一个参数为NULL表示让系统自己给我们分配,第二个参数是大小,就是屏幕的大小,第三个参数是属性
if (fbmem == (unsigned char *)-1)//如果不成功的,返回-1
{
printf("can't mmap\n");
return -1;
}
fd_hzk16 = open("HZK16", O_RDONLY);//打开汉子库,把汉字库当做一个内存来用,只需要读,当前路径下的汉字库
if (fd_hzk16 < 0)
{
printf("can't open HZK16\n");
return -1;
}
if(fstat(fd_hzk16, &hzk_stat))//统计信息,要知道汉字库有多大,这个函数可以知道汉字库有多大,以后可以像访问一个数组那样访问他了
{
printf("can't get fstat\n");//如果不成功就返回
return -1;
}
hzkmem = (unsigned char *)mmap(NULL , hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);//把汉字库映射成内存使用,hzk_stat.st_size是汉字库的大小,PROT_READ只需要读
if (hzkmem == (unsigned char *)-1)//如果失败就返回
{
printf("can't mmap for hzk16\n");
return -1;
}
/* 清屏: 全部设为黑色 */
memset(fbmem, 0, screen_size);//就是自黑,清屏函数,全部设为黑色
lcd_put_ascii(var.xres/2, var.yres/2, 'A');//在屏幕的中间显示一个字母
printf("chinese code: %02x %02x\n", str[0], str[1]);
lcd_put_chinese(var.xres/2 + 8, var.yres/2, str);//显示一个字母宽是8,所以加上8
return 0;
}

驱动程序

#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>
//#include <asm/arch/regs-lcd.h>
//#include <asm/arch/regs-gpio.h>
//#include <asm/arch/fb.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 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];
/* 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 = 240*320*16/8;
s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS;
s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR; /* TFT */
s3c_lcd->fix.line_length = 240*2;
/* 2.2 设置可变的参数 */
s3c_lcd->var.xres = 240;
s3c_lcd->var.yres = 320;
s3c_lcd->var.xres_virtual = 240;
s3c_lcd->var.yres_virtual = 320;
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 = 240*324*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 = (3<<24) | (319<<14) | (1<<6) | (0<<0);
/* 水平方向的时间参数
* 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 = (16<<19) | (239<<8) | (10<<0);
/* 水平方向的同步信号
* bit[7:0]	: HSPW, HSYNC信号的脉冲宽度, LCD手册T7=5, 所以HSPW=5-1=4
*/
lcd_regs->lcdcon4 = 4;
#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 = (240*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");

测试方法

1、 首先把进行编译,然后拷贝到nfs目录下

arm-linux-gcc -o show_font show_font.c
cp show_font /work/nfs_root/fs_mini_new
cp HZK16 /work/nfs_root/fs_mini_new

2、 使用新内核进行启动、配置、修改内核支持把lcd.c编译进去

cp /work/drivers_and_test_new/10th_lcd/lcd.c drivers/video/
修改drivers/video/Makefile
#obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
obj-$(CONFIG_FB_S3C2410) += lcd.

3、 运行应用程序

./show_font

4、注意事项

文件一定要保存成ANSI编码,不能用UTF-8编码,不然会显示乱码。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值