R16开发板tina系统LCD调试
Posted __2017__
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了R16开发板tina系统LCD调试相关的知识,希望对你有一定的参考价值。
http://blog.csdn.net/u013686019/article/details/78934023
一、环境准备
1、开发板简介
一款名为PARROT的板子,长相如下:
LCD的基本参数:1280*800,LVDS接口,具体参数参见:
tina/target/allwinner/astar-parrot/configs/sys_config.fex
2、Tina SDK V2.1代码下载
$ curl https://raw.githubusercontent.com/tinalinux/repo/stable/repo > ~/bin/repo
$ chmod +x ~/bin/repo
$ export PATH=$PATH:~/bin/
$ mkdir tina && cd tina
$ repo init -u https://github.com/tinalinux/manifest -b r16-v2.1.y -m r16/v2.1.y.xml
$ repo sync
3、编译环境
主机:
$ uname -ra
Linux 4.10.0-42-generic #46~16.04.1-Ubuntu SMP Mon Dec 4 15:57:59 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
make版本:
$ make -v
GNU Make 4.1
make downgrading:
make_3.81-8.2_amd64.deb
gcc版本:
$ gcc -v
gcc version 4.8.5
注:gcc版本太高出现“error: environment variable SOURCE_DATE_EPOCH must expand to a non-negative integer less than or equal to 253402300799”的错误
4、编译
准备环境变量:
$ . build/envsetup.sh
$ lunch astar_parrot-tina
生成kernel的config文件(否则编译出错):
$ make kernel_menuconfig
直接"Exit"即可,在./lichee/linux-3.4/目录下生成.config文件
编译、打包:
$ make -jN
$ pack -d
$ ./build.sh -p sun8iw5p1
编译uboot过程中提示缺少libcrypto.a\\libssl.a,解决方式:
$ cd lichee/brandy/extern-libs/
$ tar -jxvf openssl-secure-system.tar.bz2
$ cd openssl-1.0.1g-for-secure-system/openssl-1.0.1g
$ vi Makefile
修改Makefile中目标“build_libs”下的路径信息至正确的路径下,如SDK编译环境下的“~/tina/lichee/brandy/gcc-linaro/lib/gcc/arm-linux-gnueabi/4.6.3/”目录:
之后编译该库文件:
$make build_libs –j8
编译成功后,重新编译u-boot可以通过,并生成u-boot-sun8iw5p1.bin文件。
二、LCD测试
系统启动过程中uboot logo:
系统启动完成进入Linux系统,通过操作Framebuffer读写LCD数据。
Tina自带Framebuffer测试代码位于:package/utils/fbtest/
以下测试代码参考自“基于嵌入式Linux的LCD液晶点阵显示的基本实现”,未做优化。
1、测试demo主函数
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <linux/fb.h>
#include "font_8x16.h" // 该文件来自Linux的drivers/video/console/font_8x16.c文件
#define SCREEN_WIDTH (1280)
#define SCREEN_HEIGHT (800)
#define ASCII_WIDTH (8) /* font 8x16 */
#define ASCII_HEIGHT (16) /* font 8x16 */
// B G R A
#define WHITE (0xffffffff)
#define RED (0x0000ff00)
#define GREEN (0x00ff0000)
#define BLUE (0xff000000)
#define BLACK (0x00000000)
#define FBDEV "/dev/fb0"
int main(int argc, char **argv)
int ret;
ret = fb_init();
assert(ret == 0);
ret = font_init();
assert(ret == 0);
clear_screen(WHITE);
sleep(1);
disp_char(100, 50, '9'); // 1、测试单个字符显示
disp_string(100, 100, "abcdefghijklmnopqrstuvwxyz1234567890"); // 2、测试字符串
disp_string(1000, 200, "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"); // 3、测试换行
sleep(1); // 在编辑中文时,一定要注意编辑器使用的字符集
disp_single_hzk16(100, 300, "我"); // 4、测试单个汉字,"我", 在HZK16字库中偏移:136928
disp_hzk16(100, 400, "拦路雨偏似雪花,富士山"); // 5、测试汉字字串
disp_mix(100, 500, "Eason: 拦路雨偏似雪花,富士山"); // 6、测试中英混合
disp_bmp(1000, 600, BMP_PATH); // 7、测试图片
deinit();
return 0;
显示:
2、全局变量
int fd_fb; // FB设备的fd
struct fb_var_screeninfo var; // 定义LCD的可变参数
struct fb_fix_screeninfo fix; // 定义LCD的固定参数
int screen_size; // 表示整个屏幕所占显存的大小
int line_width; // 表示屏幕每一行所占显存的大小
int pixel_width; // 表示每个像素点所占显存的大小
char *fbmem; // 表示显存的起始地址
int fd_hzk16; // HZK16汉字库的文件句柄
struct stat hzk16_stat; // 描述HZK16这个文件的状态信息
char *hzk16mem; // HZK16这个汉字库映射到内存的起始地址
3、framebuffer初始化
static int fb_init()
int ret = -1;
fd_fb = open(FBDEV, O_RDWR);
if (fd_fb < 0)
return -1;
ret = ioctl(fd_fb, FBIOGET_VSCREENINFO, &var);
if(ret == -1)
printf("can't ioctl for /dev/fb0!\\n");
return -1;
ret = ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix);
if(ret == -1)
printf("can't ioctl for /dev/fb0!\\n");
return -1;
/* 获取液晶显存,每一行显存, */
pixel_width = var.bits_per_pixel / 8; // 每一个像素显存的大小,bytes
screen_size = var.xres * var.yres * pixel_width; // 整个LCD显存的大小,bytes
line_width = var.xres * pixel_width; // 每一行显存的大小,bytes
printf("LCD res: %d x %d\\n", var.xres, var.yres);
printf(" pixel_width: %d\\n", pixel_width);
printf(" screen_size: %d\\n", screen_size);
printf(" line_width: %d\\n", line_width);
/* 将LCD显存映射到用户空间 */
fbmem = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if(fbmem == (char *)-1)
printf("mmap for /dev/fb0 error!\\n");
return -1;
return 0;
4、HZK16字库初始化
static int font_init()
int ret = -1;
fd_hzk16 = open("/usr/sbin/HZK16", O_RDONLY);
if (fd_hzk16 < 0) return -1;
ret = fstat(fd_hzk16, &hzk16_stat);
if (ret < 0) return -1;
hzk16mem = mmap(NULL, hzk16_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);
if(hzk16mem == (char *)-1)
printf("mmap for HZK16 error!\\n");
return -1;
return 0;
5、清屏
static void clear_screen(int color)
memset(fbmem, color, screen_size);
6、资源回收
static void deinit()
munmap(fbmem, screen_size);
close(fd_fb);
munmap(hzk16mem, hzk16_stat.st_size);
close(fd_hzk16);
7、显示单个像素
static void disp_pixel(int x, int y, int color)
__u8 *pen8 = fbmem + y * line_width + x * pixel_width;
//__u16 *pen16 = (__u16 *) pen8;
__u32 *pen32 = (__u32 *) pen8;
switch (var.bits_per_pixel)
case 32:
*pen32 = color;
break;
default:
printf("Unsupported bits_per_pixel!\\n");
printf("bits_per_pixel must be 32 bits!\\n");
break;
8、字符显示
字符fontdata_8x16[]数组来自Linux的drivers/video/console/font_8x16.c文件
static void disp_char(int x, int y, char c)
unsigned char *buffer = (unsigned char *)&fontdata_8x16[c * 16];
unsigned char data;
int i, j;
/* 循环操作将整个字符写入到显存指定位置中,达到在指定位置显示字�?*/
for(i = 0; i < 16; i++)
data = buffer[i];
for(j = 0; j < 8; j++)
if(data & 0x80)
disp_pixel(x + j, y + i, WHITE); /*白色*/
else
disp_pixel(x + j, y + i, BLACK); /*黑色*/
data = data << 1;
static void disp_string(int x, int y, const char *str)
assert(str);
//assert(x < (SCREEN_WIDTH - 8));
//assert(y < (SCREEN_HEIGHT - 16));
while (*str)
disp_char(x, y, *str);
str ++;
x += 8;
if (x > (SCREEN_WIDTH - ASCII_WIDTH))
x = 0;
y += ASCII_HEIGHT;
if (y > (SCREEN_HEIGHT - ASCII_HEIGHT))
y = 0;
9、汉字显示
字库下载地址:http://pan.baidu.com/share/link?shareid=2514580636&uk=320828865
注:在编辑中文时,一定要注意编辑器使用的字符集!如果和字库的不一致,将一直是乱码。
经测,使用VS2008编辑的中文可以正常显示。
static void disp_single_hzk16(int x, int y, char *str)
int area = str[0] - 0xa1 ;
int where = str[1] - 0xa1;
int offset = (area * 94 + where) * 32;
__u8 *buffer = (__u8 *) (hzk16mem + offset);
__u16 data;
int i, j;
for (i = 0; i < 16; i ++)
data = (buffer[i * 2] << 8) | buffer[2 * i + 1];
for (j = 0; j < 16; j ++)
if (data & 0x8000)
disp_pixel(x + j, y + i, WHITE); /*白色*/
else
disp_pixel(x + j, y + i, BLACK); /*黑色*/
data <<= 1;
static void disp_hzk16(int x, int y, char *str)
assert(str);
//assert(x < (SCREEN_WIDTH - 16));
//assert(y < (SCREEN_HEIGHT - 16));
while (*str)
disp_single_hzk16(x, y, str);
str += 2;
x += 16;
if (x > (SCREEN_WIDTH - 16))
x = 0;
y += 16;
if (y > (SCREEN_HEIGHT - 16))
y = 0;
static void disp_mix(int x, int y, char *str)
assert(str);
while (*str)
if (*str & 0x80) // chinese
disp_single_hzk16(x, y, str);
str += 2;
x += 16;
if (x > (SCREEN_WIDTH - 16))
x = 0;
y += 16;
else
disp_char(x, y, *str);
str += 1;
x += 8;
if (x > (SCREEN_WIDTH - ASCII_WIDTH))
x = 0;
y += ASCII_HEIGHT;
if (y > (SCREEN_HEIGHT - ASCII_HEIGHT))
y = 0;
10、汉字显示原理
以上原文。
HZK16字库是符合GB2312标准的16×16点阵字库,HZK16的GB2312-80支持的汉字有6763个,符号682个。其中一级汉字有 3755个,按声序排列,二级汉字有3008个,按偏旁部首排列。
我们在一些应用场合根本用不到这么多汉字字模,所以在应用时就可以只提取部分字体作为己用。
HZK16字库里的16×16汉字一共需要256个点来显示,也就是说需要32个字节才能达到显示一个普通汉字的目的。
我们知道一个GB2312汉字是由两个字节编码的,范围为0xA1A1~0xFEFE。A1-A9为符号区,B0-F7为汉字区。每一个区有94个字符(注意:这只是编码的许可范围,不一定都有字型对应,比如符号区就有很多编码空白区域)。
下面以汉字"我"为例,介绍如何在HZK16文件中找到它对应的32个字节的字模数据。前面说到一个汉字占两个字节,这两个中前一个字节为该汉字的区号,后一个字节为该字的位号。其中,每个区记录94个汉字,位号为该字在该区中的位置。所以要找到"我"在hzk16库中的位置就必须得到它的区码和位码。
区码:汉字的第一个字节-0xA0 (因为汉字编码是从0xA0区开始的, 所以文件最前面就是从0xA0区开始, 要算出相对区码)
位码:汉字的第二个字节-0xA0
这样我们就可以得到汉字在HZK16中的绝对偏移位置:
offset=(94*(区码-1)+(位码-1))*32
注解:
- 区码减1是因为数组是以0为开始而区号位号是以1为开始的
- (94*(区号-1)+位号-1)是一个汉字字模占用的字节数
- 最后乘以32是因为汉字库文应从该位置起的32字节信息记录该字的字模信息(前面提到一个汉字要有32个字节显示)
我画的图示:
11、显示图片
#define BMP_PATH "/usr/sbin/ram.bmp"
#define BMP_WIDTH (128)
#define BMP_HEIGHT (128)
#define BMP_INDEX (BMP_HEIGHT-1)
#define BMP_SIZE (BMP_WIDTH*BMP_HEIGHT*3+54) // bmp header 54 bytes
int disp_bmp(int x, int y, const char *path)
int sx, sy, location;
const int bytes_per_pixel = pixel_width;
const int screensize = screen_size;
char *map_mem = fbmem;
const int start_location = x * bytes_per_pixel + y * line_width;
FILE *file_fd = fopen(path, "r");
char buffer[BMP_SIZE];
int readCnt = fread(buffer, sizeof(buffer), 1, file_fd);
fclose(file_fd);
for(sx = 0; sx < BMP_WIDTH; sx ++)
for(sy = 0; sy < BMP_HEIGHT; sy++)
location = start_location + sx * bytes_per_pixel + sy * line_width;
// 矫正BMP显示和LCD显示的上下反 BMP_INDEX-y
*(map_mem + location + 0) = buffer[54+(BMP_WIDTH*(BMP_INDEX-sy)+sx)*3+0];// 蓝色的色深
*(map_mem + location + 1) = buffer[54+(BMP_WIDTH*(BMP_INDEX-sy)+sx)*3+1];// 绿色的色深
*(map_mem + location + 2) = buffer[54+(BMP_WIDTH*(BMP_INDEX-sy)+sx)*3+2];// 红色的色深
//*(map_mem + location + 3) = 0;// 是否透明
return 0;
以上是关于R16开发板tina系统LCD调试的主要内容,如果未能解决你的问题,请参考以下文章
全志 Tina Linux LCD显示屏调试指南 支持MIPI DSI RGB LVDS I8080 SPI等接口,开发板支持百问网T113 D1-H哪吒 DongshanPI-D1s V853
全志 Tina Linux LCD显示屏调试指南 支持MIPI DSI RGB LVDS I8080 SPI等接口,开发板支持百问网T113 D1-H哪吒 DongshanPI-D1s V853
全志 Tina Linux 系统软件 开发指南 sdk源码编译操作 深入理解Tina-sdk编译框架 支持百问网T113 D1-H哪吒 DongshanPI-D1s V853-Pro等开发板
全志 Tina Linux 系统软件 开发指南 sdk源码编译操作 深入理解Tina-sdk编译框架 支持百问网T113 D1-H哪吒 DongshanPI-D1s V853-Pro等开发板
全志 Tina Linux 系统软件 开发指南 sdk源码编译操作 深入理解Tina-sdk编译框架 支持百问网T113 D1-H哪吒 DongshanPI-D1s V853-Pro等开发板