导航

    全志在线开发者论坛

    • 注册
    • 登录
    • 搜索
    • 版块
    • 话题
    • 在线文档
    • 社区主页
    1. 主页
    2. TrueDei
    3. 最佳
    • 资料
    • 关注 0
    • 粉丝 0
    • 我的积分 305
    • 主题 4
    • 帖子 4
    • 最佳 2
    • 群组 0

    TrueDei 发布的最佳帖子

    • OK536N-C+UVC摄像头+10寸LVDS屏幕实现实时采集绘制(纯软方案)

      突如其来想法

      恰好看到OK536N-C的手册支持UVC,手里恰好有一个UVC摄像头,也恰好有一个LVDS的屏幕,也恰好产生了一个好奇的想法:

      是否可以实时采集UVC摄像头的数据然后通过LVDS屏幕绘制出来?

      如果可以实现的话,还可以继续延伸,例如:增加AI的一些应用,通过LVDS实时显示出来。

      先来看下效果

      a66ff11b-6349-4d97-a98e-e249435ca9f9-image.png

      为好奇买单

      为了能快速为我的好奇买单,按照初步调试一个板子的经验,肯定先翻看官方的doc手册,是否支持UVC(USB Video Class).

      第一步:确定是否支持:

      在Tina_Linux_USB_开发指南.pdf中有说明,是支持UVC的:

      Device Drivers ‑‑‑>
      <*> Multimedia support ‑‑‑>
      [*] Media USB Adapters ‑‑‑>
      <*> USB Video Class (UVC)
      [*] UVC input events device support
      

      第二步:查找是否有案例

      因为OK536N-C是基于全志T536的,所以飞凌+强强联手,案例也会弥补一些全志官方空缺的demo.

      现在看下飞凌的demo:在forlinx目录下

      飞凌的团队确实缺少了这个我这个好奇想法的功能demo的支持。

      017ba906-d68d-4855-b652-10fbd77d6a81-image.png

      再来看下全志官方的demo:

      有2个demo比较好奇,一个是fbinit_test和usbcam_test

      97e8e9b7-98c0-4eae-a25b-f1d3a78f2f34-image.png

      fbinit_test的功能描述:

      此demo用于清除当前显示的fb的数据,让显示屏上处于干净的状态,方便测试应用送显。

      usbcam_test的功能描述:

      此demo用于验证usb camera功能是否正常。

      没错,这两个就是我们实现的基石,就是快速开发的地基。

      现在目标找到了!!!

      开始买单

      了解清楚你UVC摄像头和LVDS屏幕的参数。

      例如我的UVC摄像头支持YUYV(YUYV 4:2:2)/H264/H265/MJPG(Motion-JPEG):

      而且每个格式下还支持不同的分辨率和帧率。

      camName=HD Camera,devName=Input 1,camPath=/dev/video1
      fmt index=0,description=YUYV 4:2:2,pixelformat=YUYV,v_fmt_type=0
      framsize.discrete.height=720,framsize.discrete.width=1280,framsize.frameRates.size()=2,frameRates=,10,5
      framsize.discrete.height=576,framsize.discrete.width=1024,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=600,framsize.discrete.width=800,framsize.frameRates.size()=2,frameRates=,10,5
      framsize.discrete.height=448,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=480,framsize.discrete.width=640,framsize.frameRates.size()=5,frameRates=,25,20,15,10,5
      framsize.discrete.height=360,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=270,framsize.discrete.width=480,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=180,framsize.discrete.width=320,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      fmt index=1,description=Motion-JPEG,pixelformat=MJPG,v_fmt_type=1
      framsize.discrete.height=1080,framsize.discrete.width=1920,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=896,framsize.discrete.width=1600,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=720,framsize.discrete.width=1280,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=576,framsize.discrete.width=1024,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=540,framsize.discrete.width=960,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=600,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=448,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=576,framsize.discrete.width=720,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=480,framsize.discrete.width=720,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=480,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=360,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=270,framsize.discrete.width=480,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=288,framsize.discrete.width=352,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=240,framsize.discrete.width=320,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      fmt index=2,description=H.264,pixelformat=H264,v_fmt_type=2
      framsize.discrete.height=1080,framsize.discrete.width=1920,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=896,framsize.discrete.width=1600,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=720,framsize.discrete.width=1280,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=576,framsize.discrete.width=1024,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=540,framsize.discrete.width=960,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=600,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=448,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=576,framsize.discrete.width=720,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=480,framsize.discrete.width=720,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=480,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=360,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=270,framsize.discrete.width=480,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=288,framsize.discrete.width=352,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=240,framsize.discrete.width=320,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      fmt index=3,description=35363248-0000-0010-8000-00aa003,pixelformat=,v_fmt_type=2
      framsize.discrete.height=1080,framsize.discrete.width=1920,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=896,framsize.discrete.width=1600,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=720,framsize.discrete.width=1280,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=576,framsize.discrete.width=1024,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=540,framsize.discrete.width=960,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=600,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=448,framsize.discrete.width=800,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=576,framsize.discrete.width=720,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=480,framsize.discrete.width=720,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=480,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=360,framsize.discrete.width=640,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=270,framsize.discrete.width=480,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=288,framsize.discrete.width=352,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      framsize.discrete.height=240,framsize.discrete.width=320,framsize.frameRates.size()=6,frameRates=,30,25,20,15,10,5
      ============================================================
      
      

      LVDS屏幕:

      1、支持RGB888的1280*800的分辨率;

      有了这些参数,就可以很清楚的知道下一步要干什么。

      1、选择采集的格式,因为转RGB,使用YUV是比较合适的,纯软件也简单一些。

      所以我们选择采集YUV,才从YUV中选择一个何时的分辨率,我们选择1280*720的,因为这个最接近LVDS屏幕的最大分辨率:

      fmt index=0,description=YUYV 4:2:2,pixelformat=YUYV,v_fmt_type=0
      framsize.discrete.height=720,framsize.discrete.width=1280,framsize.frameRates.size()=2,frameRates=,10,5
      

      实现功能

      1、获取UVC相机的各种参数

      这里用到了我的一个开源项目中的一个代码。

      https://github.com/truedei/UPlayer

      https://github.com/truedei/UPlayer/blob/main/src/core/utils/v4l2utils.h

      https://github.com/truedei/UPlayer/blob/main/src/core/utils/v4l2utils.cpp

      直接复制出来小改后使用即可.

      e3e18578-15b7-4357-bf26-1eb74fc79954-image.png

      然后就可以得到UVC的各种参数:

      #include "v4l2utils.h"
      
      int main(int argc, char *argv[]) {
      
        // 查询所有拥有video能力的USB设备
        {
          vector<Camera> cms = GetAllVideoDevices();
          for(auto c: cms)
          {
              cout << "camName=" << c.camName.c_str()
              << ",devName=" << c.devName.c_str()
              << ",camPath=" << c.camPath.c_str() << endl;
      
              auto vfmts = c.vfmts;
              for(auto fmt: vfmts)
              {
                  cout << "fmt index=" << fmt.index
                      << ",description=" << fmt.description.c_str()
                      << ",pixelformat=" << fmt.pixelformat
                      << ",v_fmt_type=" << fmt.v_fmt_type
                      << endl;
                  auto frmsizes = fmt.frmsizes;
                  for(auto fs: frmsizes)
                  {
                      cout << "framsize.discrete.height="  << fs.height
                          << ",framsize.discrete.width="  << fs.width ;
      
                      auto frmsizes = fs.frameRates;
                      cout << ",framsize.frameRates.size()="  << frmsizes.size()
                      <<",frameRates=";
                      for(auto fr: frmsizes)
                      {
                          cout << ","  << fr;
                      }
                      cout << endl;
                  }
              }
              cout << "============================================================" << endl;
          }
        }
      
          ....
          ....
          ....
      }
      

      main函数分为4大部分:

      1、查询UVC的参数,选择合适的参数进行初始化;

      2、初始化LVDS屏幕fd描述符,以及获取参数;

      3、获取数据&数据转换&渲染数据;

      4、释放数据;

      68a93175-d31c-43ea-a393-60cf4e7ed886-image.png

      比较核心的是转换&绘制图像数据:

      这里我还做了特殊处理,上下对齐黑边,因为分辨率不一致,不好看

      179ae148-d4ea-48f2-9756-29ac7a46305c-image.png

      未使用硬件加速处理的时间:

      read_frame time cost 0.145181(s)
      read_frame time cost 0.111765(s)
      read_frame time cost 0.111757(s)
      

      效果还是可以的,后期再用硬件加速看看效果。

      代码已放在github:

      https://github.com/truedei/OK536N-C-LVDS-UVC

      发布在 飞凌嵌入式专区
      TrueDei
      TrueDei
    • OK536N-C开箱以及在Linux下如何管理开发板

      前言

      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的屏幕。

      8455b13f-79d4-4fa3-bda4-77910cdc3ddd-image.png

      上电后:
      0256ab3b-5563-4c3a-8306-3c533238e21f-image.png

      这是我改了fbinit_test代码之后的效果:

      二、研究如何启动

      一开始不要着急插电源开机,先看手册。

      手册是真的太详细了,而且手册是在线的,不用翻来翻去打开一个一个的pdf了,太赞了。之前开发全志的芯片,看手册全是一个一个的加密的pdf,很不爽。飞凌的团队把文档做的很细,并且几乎都在线文档化了。而且还是语雀来写的,我真是太高兴了,我是比较喜欢写博客的,平时记录一些东西,也都是在语雀上,使用语雀已经至少6年了,算是重度患者。

      2b3d2610-2f35-4fd5-98cd-636b8c0ce1cd-image.png

      找到DC12V电源插口,找到开关,找到串口位置基本上就搞定了,如果有屏幕的话,再找到你对应屏幕的接线位置。

      说到屏幕,做的很细心,可以看到,基本上闭眼就可以安装:(给你贴着怎么安装,我就直接安装的,很顺利!)

      9149daee-5433-4355-a08c-1f42d75dba65-image.png

      按照要求接好线

      ba2d41d7-0410-41a0-b304-b47d129f8474-image.png

      都接好线就可以准备开机了。

      三、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
      

      其实如果先看过文档的话也可以参考:

      4967a5f2-2db7-431a-82ad-b431c3469d25-image.png

      查看是否生成了/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进入:
      a0ddf3d6-1f41-48e4-84be-8b3e2090f455-image.png

      一路回车,出现OK536 Login就是串口连接成功了:

      c8191089-a25e-44cd-be59-7460ca214a2f-image.png

      账号:root
      密码:无,直接回车

      成功后的界面:

      dea368b7-d8d4-43c6-a104-66abace14b33-image.png

      四、使用ssh远程

      首先连上网,不喜欢wifi的话,就用有线,接上LAN后,在串口里执行udhcpc,就会获取到ip:
      ce23e02e-4795-4803-86b5-c28c362796b1-image.png

      然后就可以使用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);
      }
      

      文档很详细,很快就能搭建好开发环境,并且修改自己想要的代码,然后编译出来自己的程序进行调试。

      发布在 飞凌嵌入式专区
      TrueDei
      TrueDei
    • 1 / 1