前言
OK536N-C终于到我手上了,因为我的主要领域是做嵌入式音视频。例如相机类产品,录像类产品,直播类产品都是我所涉及到的。本片文章一起来开箱见证下OK536N-C有哪些魅力,在音视频领域如何,据说很强。
对于一个嵌入式领域的开发者来说,强不代表一切,还要关注软硬件的资料是否全,各种文档是否详细,技术售后支持是否到位。等一系列因素,如果有一个不太好,就会在整体开发过程中耽搁大事。
对于学生而言,更是如此,没有详细的资料,怎么能够快速开发出来作品,拿什么去打比赛!
我个人PC就是Ubuntu,一起看看在Ubuntu下能否一路畅通的玩耍。
truedei@truedei-code:truedei$ uname -a
Linux truedei-code 6.11.0-25-generic #25~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Apr 15 17:20:50 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
truedei@truedei-code:truedei$
一、开箱(bu)美照
因为事先去了解过某宝上OK536N-C的套餐,其中就有LVDS 10存屏幕和MIPI 7寸屏幕。10寸的大屏幕, 谁看谁心动呀,特意借到了一个10寸的LVDS的屏幕。
上电后:
这是我改了fbinit_test代码之后的效果:
二、研究如何启动
一开始不要着急插电源开机,先看手册。
手册是真的太详细了,而且手册是在线的,不用翻来翻去打开一个一个的pdf了,太赞了。之前开发全志的芯片,看手册全是一个一个的加密的pdf,很不爽。飞凌的团队把文档做的很细,并且几乎都在线文档化了。而且还是语雀来写的,我真是太高兴了,我是比较喜欢写博客的,平时记录一些东西,也都是在语雀上,使用语雀已经至少6年了,算是重度患者。
找到DC12V电源插口,找到开关,找到串口位置基本上就搞定了,如果有屏幕的话,再找到你对应屏幕的接线位置。
说到屏幕,做的很细心,可以看到,基本上闭眼就可以安装:(给你贴着怎么安装,我就直接安装的,很顺利!)
按照要求接好线
都接好线就可以准备开机了。
三、Ubuntu下连接串口到OK536N-C
因为的我的PC是Ubuntu系统的,所以没有Windows这么多的GUI图形工具可以用.OK536N-C的手册里也并没有提到PC机器是Ubuntu时怎么搭建环境,这个很遗憾.
首先确定USB-A----USB-C的线插到电脑上之后的串口是什么:
插上前执行一次lsusb:
truedei@truedei-code:truedei$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 046d:c548 Logitech, Inc. Logi Bolt Receiver
Bus 001 Device 003: ID 0b05:1939 ASUSTek Computer, Inc. AURA LED Controller
Bus 001 Device 004: ID 05e3:0610 Genesys Logic, Inc. Hub
Bus 001 Device 006: ID 3554:fa09 Compx 2.4G Wireless Receiver
Bus 001 Device 007: ID 8087:0029 Intel Corp. AX200 Bluetooth
Bus 001 Device 008: ID 04e2:1414 Exar Corp. XR21V1414 4-channel UART
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 002: ID 1d6b:0102 Linux Foundation EEM Gadget
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
truedei@truedei-code:truedei$
truedei@truedei-code:truedei$
拔掉后执行一次:
truedei@truedei-code:truedei$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 046d:c548 Logitech, Inc. Logi Bolt Receiver
Bus 001 Device 003: ID 0b05:1939 ASUSTek Computer, Inc. AURA LED Controller
Bus 001 Device 004: ID 05e3:0610 Genesys Logic, Inc. Hub
Bus 001 Device 006: ID 3554:fa09 Compx 2.4G Wireless Receiver
Bus 001 Device 007: ID 8087:0029 Intel Corp. AX200 Bluetooth
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 002: ID 1d6b:0102 Linux Foundation EEM Gadget
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
truedei@truedei-code:truedei$
经过对比即可看出:"XR21V1414 4-channel UART"就是我们想找的.
Bus 001 Device 008: ID 04e2:1414 Exar Corp. XR21V1414 4-channel UART
其实如果先看过文档的话也可以参考:
查看是否生成了/dev/ttyUSB*
truedei@truedei-code:truedei$ ls /dev/ttyUSB*
/dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2 /dev/ttyUSB3
truedei@truedei-code:truedei$
接下来我们要用到一些ubuntu下的串口工具,例如putty
如果你没有putty的话,可以安装下:
sudo apt install putty
启动putty时记得使用sudo,否则操作串口可能没有权限:
sudo putty
使用ttyUSB0,波特率115200进入:
一路回车,出现OK536 Login就是串口连接成功了:
账号:root
密码:无,直接回车
成功后的界面:
四、使用ssh远程
首先连上网,不喜欢wifi的话,就用有线,接上LAN后,在串口里执行udhcpc,就会获取到ip:
然后就可以使用ssh远程了:(没有密码)
truedei@truedei-code:truedei$ ssh root@192.168.2.105
root@OK536:~#
root@OK536:~#
我个人调试比较喜欢用scp命令,能使用ssh,基本上就能使用scp。
可以看到/mnt/UDISK有14G的存储空间:
root@OK536:~# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 991M 385M 591M 40% /
tmpfs 962M 300K 961M 1% /tmp
tmpfs 962M 460K 961M 1% /run
devtmpfs 959M 0 959M 0% /dev
/dev/mmcblk0p1 128M 5.3M 123M 5% /run/media/mmcblk0p1
/dev/by-name/UDISK 14G 107M 14G 1% /mnt/UDISK
root@OK536:~#
之后可以把测试的程序和相关的东西都远程拷贝到/mnt/UDISK即可。
例如:编译了fdinit程序,然后远程拷贝到设备里:
truedei@truedei-code:fbinit_test$ make -j10
-e
cp -f fbinit /media/truedei/soft/Ok536N-C/OKT536-linux-sdk/buildroot/package/auto/sdk_demo/bin
make finish!!!
truedei@truedei-code:fbinit_test$
truedei@truedei-code:fbinit_test$
truedei@truedei-code:fbinit_test$ scp ./fbinit root@192.168.2.105:/mnt/UDISK/
fbinit 100% 23KB 10.1MB/s 00:00
truedei@truedei-code:fbinit_test$
然后设备里就有了:
root@OK536:~# ls -l /mnt/UDISK/fbinit
-rwxrwx--- 1 root disk 23376 May 18 17:26 /mnt/UDISK/fbinit
root@OK536:~#
然后就可以运行了:
root@OK536:~# /mnt/UDISK/fbinit
fbinit test version:V2.0.20220506
================Usage================
/fbinit means:clean /dev/fb0
/fbinit 0 means:clean /dev/fb0
/fbinit 1 means:clean /dev/fb1
/fbinit 2 means:clean /dev/fb2
================usage================
cleanning /dev/fb0 ...
这是我改了fbinit_test代码之后的效果,没改的话,只是清空fb:
修改后的代码:
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/videodev2.h>
int main(int argc, char *argv[])
{
printf("fbinit test version:%s\n", MODULE_VERSION);
char dev_name[20];
memset(dev_name, 0, sizeof(dev_name));
if (argc == 1) {
printf("================Usage================\n");
printf("/fbinit means:clean /dev/fb0\n");
printf("/fbinit 0 means:clean /dev/fb0\n");
printf("/fbinit 1 means:clean /dev/fb1\n");
printf("/fbinit 2 means:clean /dev/fb2\n");
printf("================usage================\n");
sprintf(dev_name, "/dev/fb0");
} else if (argc == 2) {
sprintf(dev_name, "/dev/fb%d", atoi(argv[1]));
}
printf("cleanning %s ...\n", dev_name);
int fd;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo finfo;
// 打开帧缓冲设备
if ((fd = open(dev_name, O_RDWR)) == -1) {
printf("open file %s fail. \n", dev_name);
return 0;
}
// 获取固定屏幕信息
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) {
printf("get fixed screen information failure\n");
close(fd);
return -1;
}
int screensize = finfo.smem_len;
// 获取可变屏幕信息
if (ioctl(fd, FBIOGET_VSCREENINFO, &var) == -1) {
printf("get variable screen information failure\n");
close(fd);
return -1;
}
// 将帧缓冲区映射到用户空间
char *frameBuffer = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (frameBuffer == MAP_FAILED) {
printf("mmap framebuffer failed\n");
close(fd);
return -1;
}
// 动态生成彩条图像(简单动画:每次运行条纹颜色偏移)
int width = var.xres;
int height = var.yres;
int bpp = var.bits_per_pixel / 8;
int offset = time(NULL) % width; // 随时间变化的偏移
float PI = 3.14159265358979323846;
int fl_num = 100;
int t = 0;
while (1) {
t++;
float time = t * 0.05f;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// 多重正弦波叠加,制造动态波浪感
float fx = (float)x / width;
float fy = (float)y / height;
float wave = sinf(2 * PI * fx * 2 + time) +
0.5f * sinf(2 * PI * fx * 4 + time * 1.5f) +
0.25f * sinf(2 * PI * fx * 8 + time * 2.5f);
// 波浪影响亮度
float center = height / 2.0f + wave * 50.0f;
float dist = fabsf(y - center);
// 距离中心波浪越近越亮
float brightness = expf(-dist * 0.03f);
// 色彩渐变(可根据需要修改)
unsigned char r = (unsigned char)(brightness * 80 + fx * 175);
unsigned char g = (unsigned char)(brightness * 180 + fy * 75);
unsigned char b = (unsigned char)(brightness * 255);
int pos = (y * finfo.line_length) + (x * bpp);
if (bpp == 4) {
frameBuffer[pos + 0] = b;
frameBuffer[pos + 1] = g;
frameBuffer[pos + 2] = r;
frameBuffer[pos + 3] = 0xFF;
} else if (bpp == 3) {
frameBuffer[pos + 0] = b;
frameBuffer[pos + 1] = g;
frameBuffer[pos + 2] = r;
} else if (bpp == 2) {
unsigned short pixel = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
*((unsigned short *)(frameBuffer + pos)) = pixel;
}
}
}
// usleep(30 * 1000);
}
// 解除映射
munmap(frameBuffer, screensize);
close(fd);
printf("clean %s finish\n", dev_name);
}
文档很详细,很快就能搭建好开发环境,并且修改自己想要的代码,然后编译出来自己的程序进行调试。