1 资料下载
https://download.100ask.net/boards/Allwinner/T113/index.html
2 软件安装
资料下载完毕后,根据说明,安装vmware,安装win驱动
3 配置开发环境
为了方便,建议将sdk文件上传到目录 /home/book/
安装必要的工具包,如果出现问题 Could not get lock /var/lib/dpkg/lock-frontend ,可执行以下指令
sudo rm /var/lib/apt/lists/lock
sudo rm /var/cache/apt/archives/lock
sudo rm /var/lib/dpkg/lock*
sudo dpkg --configure -a
sudo apt update
按照以下顺序执行指令
sudo apt-get install -y sed make binutils build-essential gcc g++ bash patch gzip bzip2 perl tar cpio unzip rsync file bc wget python cvs git mercurial rsync subversion android-tools-mkbootimg vim libssl-dev android-tools-fastboot
cat tina-d1-h.tar.bz2.* | tar -jxv
sudo apt-get install build-essential subversion git libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip lib32z1 lib32z1-dev lib32stdc++6 libstdc++6 libc6:i386 libstdc++6:i386 lib32ncurses5 lib32z1 -y
系统推荐的
git clone https://gitee.com/weidongshan/100ASK_T113-Pro_TinaSDK.git
cd 100ASK_T113-Pro_TinaSDK
git submodule update --init
cp ./* -rfvd ../tina-d1-h
以下指令作用是编译镜像,建议执行一次(,编译过程中,如果中途出现选项,直接按enter)
cd ~/tina-d1-h
source build/envsetup.sh
lunch 4
make && pack
4 usb摄像头lcd显示源码
可根据需要自行进行多线程改编
源代码 camera_usb_yuyv_lcd.c
点击查看代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <asm/types.h>
#include <linux/videodev2.h>
#include <linux/fb.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <math.h>
#include <wchar.h>
#include <time.h>
#include <stdbool.h>
#define CAM_WIDTH 640
#define CAM_HEIGHT 480
// #define CAM_WIDTH 1280
// #define CAM_HEIGHT 720
#define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 600
static char dev_video[64];
static char *dev_fb0;
static char *yuv_buffer;
static char *rgb_buffer;
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
#define YUVToRGB(Y) \
((u16)((((u8)(Y) >> 3) << 11) | (((u8)(Y) >> 2) << 5) | ((u8)(Y) >> 3)))
struct v4l2_buffer video_buffer;
/*全局变量*/
int lcd_fd;
int video_fd;
static unsigned char *lcd_mem_p = NULL; //保存LCD屏映射到进程空间的首地址
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
char *video_buff_buff[4]; /*保存摄像头缓冲区的地址*/
int video_height = 0;
int video_width = 0;
unsigned char *lcd_display_buff; //LCD显存空间
unsigned char *lcd_display_buff2; //LCD显存空间
static void errno_exit(const char *s)
{
fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
exit(EXIT_FAILURE);
}
static int xioctl(int fh, int request, void *arg)
{
int r;
do {
r = ioctl(fh, request, arg);
} while (-1 == r && EINTR == errno);
return r;
}
static int video_init(void)
{
struct v4l2_capability cap;
ioctl(video_fd, VIDIOC_QUERYCAP, &cap);
struct v4l2_fmtdesc dis_fmtdesc;
dis_fmtdesc.index = 0;
dis_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("-----------------------支持格式---------------------\n");
while (ioctl(video_fd, VIDIOC_ENUM_FMT, &dis_fmtdesc) != -1) {
printf("\t%d.%s\n", dis_fmtdesc.index + 1,
dis_fmtdesc.description);
dis_fmtdesc.index++;
}
struct v4l2_format video_format;
video_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
video_format.fmt.pix.width = CAM_WIDTH;
video_format.fmt.pix.height = CAM_HEIGHT;
video_format.fmt.pix.pixelformat =
V4L2_PIX_FMT_YUYV; //使用JPEG格式帧,用于静态图像采集
ioctl(video_fd, VIDIOC_S_FMT, &video_format);
printf("当前摄像头支持的分辨率:%dx%d\n", video_format.fmt.pix.width,
video_format.fmt.pix.height);
if (video_format.fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV) {
printf("当前摄像头不支持YUYV格式输出.\n");
video_height = video_format.fmt.pix.height;
video_width = video_format.fmt.pix.width;
//return -3;
} else {
video_height = video_format.fmt.pix.height;
video_width = video_format.fmt.pix.width;
printf("当前摄像头支持YUYV格式输出.width %d height %d\n",
video_height, video_height);
}
/*3. 申请缓冲区*/
struct v4l2_requestbuffers video_requestbuffers;
memset(&video_requestbuffers, 0, sizeof(struct v4l2_requestbuffers));
video_requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
video_requestbuffers.count = 4;
video_requestbuffers.memory = V4L2_MEMORY_MMAP;
if (ioctl(video_fd, VIDIOC_REQBUFS, &video_requestbuffers))
return -4;
printf("成功申请的缓冲区数量:%d\n", video_requestbuffers.count);
/*4. 得到每个缓冲区的地址: 将申请的缓冲区映射到进程空间*/
struct v4l2_buffer video_buffer;
memset(&video_buffer, 0, sizeof(struct v4l2_buffer));
int i;
for (i = 0; i < video_requestbuffers.count; i++) {
video_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
video_buffer.index = i;
video_buffer.memory = V4L2_MEMORY_MMAP;
if (ioctl(video_fd, VIDIOC_QUERYBUF, &video_buffer))
return -5;
/*映射缓冲区的地址到进程空间*/
video_buff_buff[i] =
mmap(NULL, video_buffer.length, PROT_READ | PROT_WRITE,
MAP_SHARED, video_fd, video_buffer.m.offset);
printf("第%d个缓冲区地址:%#X\n", i, video_buff_buff[i]);
}
/*5. 将缓冲区放入到采集队列*/
memset(&video_buffer, 0, sizeof(struct v4l2_buffer));
for (i = 0; i < video_requestbuffers.count; i++) {
video_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
video_buffer.index = i;
video_buffer.memory = V4L2_MEMORY_MMAP;
if (ioctl(video_fd, VIDIOC_QBUF, &video_buffer)) {
printf("VIDIOC_QBUF error\n");
return -6;
}
}
printf("启动摄像头采集\n");
/*6. 启动摄像头采集*/
int opt_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(video_fd, VIDIOC_STREAMON, &opt_type)) {
printf("VIDIOC_STREAMON error\n");
return -7;
}
return 0;
}
int lcd_init(void)
{
/*2. 获取可变参数*/
if (ioctl(lcd_fd, FBIOGET_VSCREENINFO, &vinfo))
return -2;
printf("屏幕X:%d 屏幕Y:%d 像素位数:%d\n", vinfo.xres, vinfo.yres,
vinfo.bits_per_pixel);
//分配显存空间,完成图像显示
lcd_display_buff =
malloc(vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8);
/*3. 获取固定参数*/
if (ioctl(lcd_fd, FBIOGET_FSCREENINFO, &finfo))
return -3;
printf("smem_len=%d Byte,line_length=%d Byte\n", finfo.smem_len,
finfo.line_length);
/*4. 映射LCD屏物理地址到进程空间*/
lcd_mem_p = (unsigned char *)mmap(0, finfo.smem_len,
PROT_READ | PROT_WRITE, MAP_SHARED,
lcd_fd, 0); //从文件的那个地方开始映射
memset(lcd_mem_p, 0xFFFFFF, finfo.smem_len);
printf("映射LCD屏物理地址到进程空间\n");
return 0;
}
static void close_device(void)
{
if (-1 == close(video_fd))
errno_exit("close");
video_fd = -1;
if (-1 == close(lcd_fd))
errno_exit("close");
lcd_fd = -1;
}
static void open_device(void)
{
video_fd = open(dev_video, O_RDWR /* required */ | O_NONBLOCK, 0);
if (-1 == video_fd) {
fprintf(stderr, "Cannot open '%s': %d, %s\n", dev_video, errno,
strerror(errno));
exit(EXIT_FAILURE);
}
lcd_fd = open(dev_fb0, O_RDWR, 0);
if (-1 == lcd_fd) {
fprintf(stderr, "Cannot open '%s': %d, %s\n", dev_fb0, errno,
strerror(errno));
exit(EXIT_FAILURE);
}
}
/*
将YUV格式数据转为RGB
*/
void yuv_to_rgb(unsigned char *yuv_buffer, unsigned char *rgb_buffer,
int iWidth, int iHeight)
{
int x;
int z = 0;
unsigned char *ptr = rgb_buffer;
unsigned char *yuyv = yuv_buffer;
for (x = 0; x < iWidth * iHeight; x++) {
int r, g, b;
int y, u, v;
if (!z)
y = yuyv[0] << 8;
else
y = yuyv[2] << 8;
u = yuyv[1] - 128;
v = yuyv[3] - 128;
r = (y + (359 * v)) >> 8;
g = (y - (88 * u) - (183 * v)) >> 8;
b = (y + (454 * u)) >> 8;
*(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b); // b color
*(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g); // g color
*(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r); // r color
*(ptr++) = 0xff; // a color
if (z++) {
z = 0;
yuyv += 4;
}
}
}
void rgb24_to_rgb565(char *rgb24, char *rgb16)
{
int i = 0, j = 0;
for (i = 0; i < 240 * 240 * 3; i += 3) {
rgb16[j] = rgb24[i] >> 3; // B
rgb16[j] |= ((rgb24[i + 1] & 0x1C) << 3); // G
rgb16[j + 1] = rgb24[i + 2] & 0xF8; // R
rgb16[j + 1] |= (rgb24[i + 1] >> 5); // G
j += 2;
}
}
static void lcd_image(unsigned int start_x, unsigned int end_x,
unsigned int start_y, unsigned int end_y,
unsigned char* color)
{
unsigned long i;
unsigned int j;
/* 填充颜色 */
i = start_y * vinfo.xres; //定位到起点行首
for ( ; start_y <= end_y; start_y++, i+=(vinfo.xres*4))
{
for (j = start_x; j <= end_x*4; j++)
{
lcd_mem_p[i + j] = *color++;
}
*color--;
}
}
int stopflag=0;
#include <fcntl.h> // for open
#include <stdio.h>
#include <unistd.h> // for close
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
//在 ctrl+c 后,主循环中的while(1)在此期间不会退出 exit(0)时,主循环在while(1)之后的程序也不会被执行
// int stopflag=0;
void sigintHandler(int signum) {
//退出
if(stopflag>0){return ;}
stopflag=1;
usleep(1000*200);//等待退出
printf("waitfor normal exit!!!\n");
exit(0);
}
int main(int argc, char **argv)
{
// 注册SIGINT信号处理函数
signal(SIGINT, sigintHandler);
if(argc==2){
strcpy(dev_video,argv[1]);
}
else{
strcpy(dev_video,"/dev/video0");
}
dev_fb0 = "/dev/fb0";
printf("camera:%s\n",dev_video);
printf("fb:%s\n",dev_fb0);
open_device();
video_init();
lcd_init();
/*3. 读取摄像头的数据*/
struct pollfd video_fds;
video_fds.events = POLLIN;
video_fds.fd = video_fd;
memset(&video_buffer, 0, sizeof(struct v4l2_buffer));
rgb_buffer = malloc(CAM_WIDTH * CAM_HEIGHT * 4);
yuv_buffer = malloc(CAM_WIDTH * CAM_HEIGHT * 4);
unsigned char *rgb_p;
int w, h, i, j;
unsigned char r, g, b;
unsigned int c;
int flag_loss = 0;
while (!stopflag) {// stopflag
/*等待摄像头采集数据*/
poll(&video_fds, 1, -1);
/*得到缓冲区的编号*/
video_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
video_buffer.memory = V4L2_MEMORY_MMAP;
ioctl(video_fd, VIDIOC_DQBUF, &video_buffer);
// 数据丢帧显示
if(flag_loss%3==0){
yuv_to_rgb(video_buff_buff[video_buffer.index], yuv_buffer, video_height, video_width);
// 数据检测
// 数据显示
lcd_image(0, CAM_WIDTH, 0, CAM_HEIGHT, yuv_buffer);
}
flag_loss+=1;
/*将缓冲区放入采集队列*/
ioctl(video_fd, VIDIOC_QBUF, &video_buffer);
//printf("将缓冲区放入采集队列\n");
}
/*4. 关闭视频设备*/
close_device();
printf("normal exit!!!\n");
return 0;
}
对应makefile文件
点击查看代码
PRO_DIR ?= ${shell pwd}
export ARCH=arm
export CROSS_COMPILE=/home/book/tina-d1-h/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/bin/arm-openwrt-linux-muslgnueabi-
export STAGING_DIR=/home/book/tina-d1-h/out/t113-100ask/staging_dir
CC := $(CROSS_COMPILE)gcc
# 外部头文件目录 库文件,库目录
CFLAGS += -I/home/book/tina-d1-h/out/t113-100ask/staging_dir/target/usr/include/allwinner
CFLAGS += -I/home/book/tina-d1-h/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/include
LDFLAGS += -L/home/book/tina-d1-h/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/lib/
CFLAGS += -I./include
CFLAGS += -I/home/book/tina-d1-h/out/t113-100ask/compile_dir/target/libuapi/ipkg-install/usr/include
LDFLAGS += -L/home/book/tina-d1-h/out/t113-100ask/staging_dir/target/usr/lib
LDFLAGS += -L./lib -lpthread -ldface -ldl -lMNN
# 使用gcc编译c++
CFLAGS += -lstdc++ -mfloat-abi=hard
CFLAGS += -DDEBUG -g # -lbacktrace
usb_lcd:
$(CC) -o 12_safe_lcd camera_usb_yuyv_lcd.c
adb push ./12_safe_lcd /mnt/UDISK
# /mnt/UDISK/12_safe_lcd
5 数据下发
此处采用adb进行文件下发(在makefile中已经包含了下发指令)
关于adb设置有一下几个注意点
如果忘记了,或者不弹窗了,点击虚拟机左下角,点击链接就可以了,
测试指令 adb devices 正常情况如下
异常情况如下, adb devices 指令找不到设备,解决方案参考
https://blog.csdn.net/linpeach/article/details/109027746
常用指令
ls /etc/udev/rules.d/
echo SUBSYSTEM=="usb",ATTRS{idVendor}=="18d1",ATTRS{idProduct}=="d002",MODE="0666",GROUP="plugdev",SYMLINK+="android",SYMLINK+="android_adb" > /etc/udev/rules.d/90-android.rules
sudo udevadm control --reload-rules
sudo service udev restart
sudo udevadm trigger
adb kill-server
adb start-server
参考 https://www.cnblogs.com/feiquan/p/12806081.html
传文件
adb pull <手机路径> <本机路径> 从手机中拉取信息到本地电脑上
adb push <本机路径> <手机路径> 从本地电脑推送信息到手机上
adb pull /root/test.txt ./
adb push ./test.txt /root/
6 程序运行如下
执行指令 /mnt/UDISK/12_safe_lcd
默认使用 /dev/video0
显示效果如下
7 其他常用指令
时间校准
date -s 2024-04-18
date -s 16:47:00
开发板加入临时运行库目录
export LD_LIBRARY_PATH=/mnt/UDISK/lib:$LD_LIBRARY_PATH
标签:usb,buffer,int,lcd,video,T113,百问,fd,include
From: https://www.cnblogs.com/RYSBlog/p/18208571