导航

    全志在线开发者论坛

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

    q1215200171 发布的最佳帖子

    • 第二届RISC-V中国峰会议程公布

      ​3CBFA239-78E1-4e77-B16F-4D7A8BE8D8EA.png

      第二届 RISC-V中国峰会将于2022年8月24日至26日举办,持续三天,峰会将分成两个线上分会场同时进行。

      本届峰会将会包含产业界最新技术及产品发布、学术界前沿成果展示等,共收录技术报告、成果展示、短演讲80余个。

      全志科技产品研发中心总经理黄少锐也将以“RISC-V音视频计算芯片的应用与探索”为题,在8月24日周三的下午,于分会场A进行线上主题演讲,欢迎感兴趣的朋友前来交流探讨。

      hsr2.jpg

      以下为峰会的完整议程时间表:

      640.jpg640 1.jpg

      ​

      发布在 公告
      q1215200171
      budbool
    • 【全志R329】R329开发板上的周易AIPU语音识别实战(PPT+视频)

      近期,极术社区联合矽速科技组织了搭载周易AIPU处理器的R329开发板申领活动,很多工程师进行了评测,但是如何能够更有效得利用周易AIPU来进行AI应用的部署开发呢?请关注本期由矽速科技CTO吴长泽带来的公开课。

      分享内容

      全志科技在2020年发布了搭载安谋科技“周易”AIPU的AI语音专用芯片R329,它主攻智能语音市场,其高算力、低功耗的特性引起了行业内的广泛关注。 本期课程将分享在矽速科技的MaixSense R329开发板上利用“周易”AIPU快速进行实时语音识别功能的全流程实现过程,让大家了解“周易”AIPU Compass SDK的强大,同时大家可以在开发板上DIY属于自己的智能语音助理。

      以下是内容大纲

      • 矽速MaixSense R329开发板软硬件介绍

      • “周易”AIPU Compass SDK简介及使用技巧

      • R329开发板上的视觉算法部署简介

      • 端侧LVCSR(大词汇量连续语音识别)算法实现

      视频及PPT

      • 视频观看地址:https://aijishu.com/l/1110000000226394

      • PPT部分预览(文末提供下载)

      a.png
      b.png
      c.png

      Q&A精选

      如果大家有对周易 Z2 AIPU/R329的问题,欢迎在此提问 https://aijishu.com/t/aipu/questions

      嘉宾简介

      吴才泽 Caesar Wu

      d.jfif

      Sipeed 矽速科技 CTO

      Caesar 毕业于浙江大学,拥有多年嵌入式软硬件设计经验,熟悉端侧AIoT算法优化部署。他开发的矽速MAIX开源AIoT产品系列深受国内外工程师及创客欢迎,目前他组织的MaixPy开源项目在github star已超过1K 。

      本次视频分享为周易"AIPU"系列第五期,前四期请点击下方链接。

      第一期|Arm中国周易“AIPU”初探
      第二期|快速贯通全志智能语音技术,R329专用处理器大剖析
      第三期|全志Tina-Linux软件平台及R329应用开发介绍(视频+PPT)
      第四期|Arm中国周易Z2 AIPU概述(视频+PPT)

      欢迎关注周易"AIPU"专栏获取周易"AIPU"更多技术干货等。

      (文章转载自:极术社区 极术小姐姐)
      (原文链接:https://aijishu.com/a/1060000000230794 )

      发布在 A Series
      q1215200171
      budbool
    • 【FAQ】全志R系列wpa_supplicant和wpa_cli简介

      问题背景

      硬件:R系列芯片
      软件:Tina

      问题简述

      说明:该FAQ旨在记录wpa_supplicant和wpa_cli的一些基础知识,方便在Tina系统上做网络联通性的排查。

      问题分析

      wpa_supplicant是一个连接、配置WiFi的工具,它主要包含wpa_supplicant与wpa_cli两个程序。 可以通过wpa_cli来进行WiFi的配置与连接,前提要保证wpa_supplicant正常启动。
      相当于wpa_supplicant 是服务端,wpa_cli 是客户端。

      1.wpa_supplicant

      启动wpa_supplicant应用
      wpa_supplicant -i wlan0 -Dnl80211 -c/etc/wifi/wpa_supplicant.conf -O /etc/wifi/sockets -B
      wpa_supplicant -Dnl80211 -iwlan0 -c/etc/wifi/wpa_supplicant.conf -B
      wpa_supplicant -B -iwlan0 -c/etc/wifi/wpa_supplicant.conf -Dwext
      -D 驱动程序名称(可以是多个驱动程序:nl80211,wext)
      -i 接口名称
      -c 配置文件
      -B 在后台运行守护进程

      配置文件 /etc/wpa_supplicant.conf文件里,添加下面代码:
      ctrl_interface=/var/run/wpa_supplicant //
      update_config=1 // 强制更新覆盖配置 
      ctrl_interface指向的是一个目录,在这个目录中默认会生成一个文件/var/run/wpa_supplicant/wlan0,这是local socket address,相当于UNIX Domain Socket,程序和后台程序wpa_supplicant进行通信(其实是wpa_supplicant作为后台服务程序是通过本地socket和客户端进行通信的)
      update_config = 1时会在(客户端发送SAVE_CONFIG命令)更新这个配置文件。

      Tina上wpa_supplicant的启动是放在/etc/init.d/wpa_supplicant自启动脚本中的。

      2.wpa_cli

      wpa_cli 是客户端,用来进行WiFi的配置与连接。

      启动wpa_cli应用

      wpa_cli 有命令和交互的方式进行操作
      wpa_cli -i wlan0 scan   //搜索附件wifi热点
      wpa_cli -i wlan0 scan_result   //显示搜索wifi热点
      wpa_cli -i wlan0 status //当前WPA/EAPOL/EAP通讯状态
      wpa_cli -i wlan0 ping //pings wpa_supplicant
      

      添加新的连接

      wpa_cli -i wlan0 add_network //添加一个网络连接,会返回
      wpa_cli set_network ssid ‘“name”’ //ssid名称
      wpa_cli set_network psk ‘“psk”’  //密码
      wpa_cli set_network scan_ssid 1
      wpa_cli set_network priority 1 //优先级
      

      保存连接

      wpa_cli -i wlan0 save_config //信息保存到默认的配置文件中,前面提到的/etc/wpa_supplicant.conf
      

      断开连接

      wpa_cli -i wlan0 disable_network
      

      连接已有连接

      wpa_cli -i wlan0 list_network //列举保存过得连接
      wpa_cli -i wlan0 select_network //连接指定的ssid
      wpa_cli -i wlan0 enable_network //使能制定的ssid
      

      网络连接成功的配置文件示例

      ctrl_interface=/var/run/wpa_supplicant/
      ap_scan=1
      network={
      scan_ssid=1
      ssid="xxxx"
      psk="xxxx"
      bssid=
      priority=2
      }
      

      例如:

      wpa_cli -i wlan0 scan;
      wpa_cli -i wlan0 scan_result;
      wpa_cli -i wlan0 add_network;
      wpa_cli -i wlan0 set_network 0  ssid '"AW-PDC-PD2-fly2.4g"';
      wpa_cli -i wlan0 set_network 0  key_mgmt WPA-PSK;
      wpa_cli -i wlan0 set_network 0  psk '"xxxxxxxx"';
      wpa_cli -i wlan0 save_config;
      wpa_cli -i wlan0 select_network 0;
      wpa_cli -i wlan0 enable_network 0;
      wpa_cli -i wlan0 list_network;
      wpa_cli -i wlan0 status;
      

      问题记录

      • 错误1
        Successfully initialized wpa_supplicant
        ioctl[SIOCSIWENCODEEXT]: Invalid argument
        ioctl[SIOCSIWENCODEEXT]: Invalid argument

      原来在命令中sudo wpa_supplicant -B -D n180211,wext -i wlo1 -c /home/wpa_supplicant.cfg
      错把nl80211写成n180211,注意是数字1与字母l的区别。

      • 错误2
        wpa supplicant: No network configuration found for current AP
        说明配置文件写的不对,尤其从网上复制过来时常有看不见的tab字符等。
        解决办法:从Archlinux文档上复制了一份格式正确的配置,再改一改就OK了

      • 错误3
        ctrl_iface exists and seems to be in use - cannot override it
        Delete ‘/var/run/wpa_supplicant/wlo1’ manually if it is not used anymore
        Failed to initialize control interface ‘/var/run/wpa_supplicant’.
        You may have another wpa_supplicant process already running or the file was
        left by an unclean termination of wpa_supplicant in which case you will need
        to manually remove this file before starting wpa_supplicant again.
        系统已经存在打开的多个wpa_supplicant实例,执行一下sudo killall wpa_supplicant杀死所有wpa_supplicant即可。

      • 错误4
        Successfully initialized wpa_supplicant
        [ 2093.037373] ieee80211_do_open: vif_type=2, p2p=0, ch=3, addr=34:0f:51:ac:5f:97
        [ 2093.045662] [STA] !!!xradio_vif_setup: id=0, type=2, p2p=0, addr=34:0f:51:ac:5f:97
        [ 2093.055088] [AP_WRN] BSS_CHANGED_ASSOC but driver is unjoined.
        nl80211: deinit ifname=wlan0 disabled_11b_rates=0
        [ 2093.088882] [STA_WRN] !!! xradio_remove_interface: vif_id=0
        wlan0: Failed to initialize driver interface

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 大二学生DIY RISC-V开发板,获阿里批量采购订单

      DIY D1s开发板

      00后开源创客 @YuzukiTsuru 基于全志D1s芯片设计并制作了一款RISC-V开发板,目前该开发板已经获得了阿里等多家知名科技公司的批量采购订单,将会被用于嵌入式系统的研究和IoT产品的研发。

      PP.jpg

      值得一提的是,本开发板部分小件如电容电阻等是嘉立创机贴的,但D1s主控、XR829等大件物料为心灵手巧的作者本人手贴。

      大佬手贴D1s实录
      e41ce59047cff0e98da42e39b4368723_Sub_01_3.gif e41ce59047cff0e98da42e39b4368723_Sub_02.gif e41ce59047cff0e98da42e39b4368723_Sub_03_1.gif

      免费开源全部设计资料

      该开发板基于全志D1s芯片(阿里平头哥C906 RISC-V核)设计,可用于方案评估、方案预研和个人DIY,可应用于游戏机、智能商显、智能中控等产品形态。作者将开源开发板的全部设计资料。

      开发板将提供的资料有:

      • 硬件资料:原理图、PCB layout、BOM list
      • 软件资料:适配的Tina Linux SDK(全志官方客户平台可下载)、基于官方SDK修改的适配补丁、测试用的固件。
      • 技术支持:将提供力所能及的基础技术支持,请到【全志在线开发者论坛】提问,作者和社区的爱好者会回复。

      以上所有资料获取:https://bbs.aw-ol.com/topic/1257/

      986bb80f-5de9-4216-a3f0-b0a89a9e5d62-produce_danzhi.smt_snapshot.top.624896a_y77.smt2204100029-resized.png
      贴片图

      25082a47-4dbb-4801-a72b-153b352a070b-sss-resized.jpg
      实物图

      规格介绍:

      • 基于全志D1s芯片,阿里平头哥C906 RISC-V核心
      • 支持全志官方Tina Linux系统,标准linux5.4内核
      • 支持RGB显示接口;
      • 支持DSI接口;
      • 支持TP接口;
      • 支持SD卡;
      • 支持JATG/UART debug;
      • 支持USB Host/device;
      • 支持LINEIN接口,支持HPOUT接口;
      • 集成全志XR829 WiFi/BT芯片,支持a2dp与hfp

      ce12587d-da60-4c63-8200-474b772146fa-22-resized.jpg
      D1s开发板拓展应用-桌面小电脑

      00后创客大佬

      开发板作者 @YuzukiTsuru 是一位00后的大二学生,目前就国内某院校物联网专业。他高中时就搭建了自己的个人博客,上大学后开始玩嵌入式,恰逢全志在线成立并进行资料开源,就开始围绕全志芯片进行项目开发,目前已经基于全志的芯片做了十几个不同型号的开发板并开源到立创开源硬件平台等社区。

      立创开源硬件平台个人主页
      640.png

      Github个人主页
      微信图片_20220421092514.png

      全志在线个人主页:https://bbs.aw-ol.com/user/yuzukitsuru

      购买途径

      本开发板由原作者委托哇酷科技代售并开具发票,所有收益将由哇酷转交给原作者@YuzukiTsuru,有兴趣的可以扫码到淘宝店购买。
      微信图片_20220422100450.jpg

      发布在 MR Series
      q1215200171
      budbool
    • 回复: 第二届RISC-V中国峰会议程公布

      下午两点全志科技线上分享地址:
      B站:https://live.bilibili.com/10339607
      电子发烧友:https://t.elecfans.com/live/2096.html

      发布在 公告
      q1215200171
      budbool
    • 小时候画在手腕上的表,我让他真正动了起来

      小时候,我们总是充满想象力和创造力。

      在那个年龄,我们没有真正的手表,但我们总是喜欢在纸上画出自己的手表,仿佛它真的能告诉我们时间。

      ezgif.com-optimize (3).gif

      为了弥补童年的遗憾,作者找到了一个智能手表的开源项目——NWatch,并把他移植到了R128开发板上。

      640.jfif

      项目简介

      本项目基于ZakKemble的开源项目NWatch,与原作者的NWatch不一样的是,作者将其移植到DShanMCU-R128s2-DevKit开发板的同时相比于原作者添加了一些功能,比如优化屏幕刷新,使显示更流畅,以及添加蜂鸣器、旋转编码器、DHT11温湿度传感器。

      菜单滑动.gif

      赛车.gif

      硬件准备

      本项目的基础用意是提供一个综合的示例进行学习参考,所以没有将所有硬件集成到一小块开发板上,而是采用面包板来实现手表功能效果,所需要用到的硬件有以下几个:

      • DShanMCU-R128s2-DevKit开发板
      • 0.96寸OLED(SSD1306)
      • EC11旋转编码器模块
      • 红外接收模块+红外遥控器
      • 无源蜂鸣器模块
      • DHT11温湿度模块

      菜单滑动.gif

      模块 接线 对应引脚
      IIC OLED SCK PB00
      SDA PB01
      EC11 S1 PA24
      S2 PA25
      KEY PA29
      蜂鸣器 BEEP DATA PA26
      红外接收 IR DATA PA10
      DHT11 DHT11 DATA PA6

      软件系统

      手表上的所有功能都伴有动画效果。

      原作者对软件系统的代码花费了大量时间进行优化渲染,优化的内容就包括了将位图图像从闪存复制到RAM中的帧缓冲区,并通过 SPI 将帧缓冲区发送到 OLED,最终使得手表能够在几乎所有区域的显示中可以保持100+FPS。

      球转.gif

      一些主要的动画内容:
      1.进入和退出睡眠模式时的 CRT 动画(类似于某些 Android 智能手机具有的 CRT 动画)。
      2.主要时间数字切换时具有动画效果。
      3.菜单有一个向左/向右滚动的动画,选择一个选项将会有当前菜单从屏幕上掉下来的动画效果。

      640 (1).jfif

      转换时钟.gif

      二次开发

      打开以下文件进行修改:

      R128-S2-SDK/board/r128s2/pro/configs/sys_config.fex
      

      IIC引脚配置:

      [twi1]
      twi1_sck        = port:PB00<3><1><default><default>
      twi1_sda        = port:PB01<3><1><default><default>
      

      PWM配置:

      [pwm6]
      pwm_used        = 1
      pwm_positive    = port:PA26<4><0><2><default>
      

      接下来添加100ask_r128_demos,首先clone仓库或者下载仓库压缩包到本地,并将仓库目录放在sdk的这个目录下面:

      R128-S2-SDK/lichee/rtos-components/thirdparty/100ask_r128_demos
      

      赛车.gif

      打开文件进行编辑

      R128-S2-SDK/lichee/rtos-components/thirdparty/Makefile
      

      在文件的最后面或最前一行加入下面的内容:

      obj-$(CONFIG_COMPONENTS_100ASK_R128_DEMOS) += 100ask_r128_demos/
      

      打开文件进行编辑

      R128-S2-SDK/lichee/rtos-components/thirdparty/Kconfig
      

      在文件的最后或最前一行加入下面的内容:

      source components/common/thirdparty/100ask_r128_demos/Kconfig
      

      红外控制.gif

      源码获取

      基于R128-S2设计的全套开发板已上线淘宝百问网韦东山老师个人店进行售卖,包含黑色的DshanMCU-R128s2-R16N16模组和全套的DshanMCU-R128s2-DEVKIT。

      • DshanMCU-R128s2-R16N16模组:39.9元
      • DshanMCU-R128s2-DEVKIT开发板:59.9元

      “主图_01”为智能对象-1.jpg

      R128开发板购买链接:https://m.tb.cn/h.5T4uATe?tk=S079W0vCt6v

      Gitee源码获取链接:

      https://gitee.com/weidongshan/100ask_r128_demos/tree/master/nwatch
      

      GitHub源码获取链接:

      https://github.com/100askTeam/100ask_r128_demos/tree/master/nwatch
      

      如果你不想自己编译或者不需要二次开发,那么可以从下方获取固件:

      Gitee处Releases获取:

      https://gitee.com/weidongshan/100ask_r128_demos/releases/tag/v0.0.1
      

      GitHub处Releases获取:

      https://github.com/100askTeam/100ask_r128_demos/releases/tag/v0.0.1
      

      烧写固件到DShanMCU-R128s2-DevKit在新窗口打开后开机会自动启动NWatch任务,如果没有自动启动在串口终端输入命令然后按回车即可nwatch_100ask 3。

      更多关于项目的详情可以前往百问网R128综合项目开发案例界面了解。

      https://aw-r128.100ask.net/zh/rtos/demo/part2/chapter1.html

      发布在 A Series
      q1215200171
      budbool
    • 【FAQ】全志D1芯片 如何解决在创建视频解码器后,未送入视频帧数据之前,cpu被占满的问题

      1、现象
      目前D1使用vdecoder SDK,其中调用完初始化完解码器函数后,在未送入视频帧数据让该解码器工作之前,cpu会被占满;

      2、问题原因
      目前代码 vdecoder.c 中 ENABLE_SBM_FRAME_INTERFACE 默认值为1,使用帧接口,此时解码H264会使用软件搜头,CPU占用率会比较高。

      3、解决方法
      将 ENABLE_SBM_FRAME_INTERFACE 改为 0 即可,此时使用硬件搜头。

      单核且CPU频率不高的情况,建议 ENABLE_SBM_FRAME_INTERFACE 置为 0 。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 平头哥Sipeed LicheeRV 86 Panel GPIO管脚引出,RGB三色LED闪烁

      作者@zhang1gong
      原文链接:https://occ.t-head.cn/community/post/detail?spm=a2cl5.14300636.0.0.7f1f180fHnTGVq&id=4039809713964126208

      1 核心板LED点亮

      LicheeRV教程提供了核心板上的LED点亮教程。LED点亮或闪烁往往是广泛应用于自动控制的嵌入式系统运行的第一个试验程序,如同一般在桌面系统上学习编程语言运行的第一个程序:“Hello, world!”。我是第一次在Linux系统下运行点灯程序,感觉和在裸机上用c或汇编编程完全不同:基本上不用关心硬件,完全是对文件操作,充分提现了Linux系统“万物皆文件”的理念。核心板上驱动LED的GPIO口(PC1)与底板上的其他应用冲突,因此必须把核心板从底板上拆下,才能做这个点灯试验。但是,核心板上的USB口并不具备模拟串口功能,对此教程似乎并没有明确说明。几位已经做了这个试验的测试者都提到了:要用ADB。虽然大概早晚都会在我的桌面系统中装ADB以搭建交叉编译环境,我还是想先看看有没有其他办法。将核心板从底板拆下后,发现在USB口旁边有4个预留的焊盘,PCB板背面在焊盘旁边标出了“T R G 5V”,不禁使人想到:这难道是个串口?查了一下原理图,果然如此!正好我手头有不止一个串口转USB的小板(某宝上几块钱一个还包邮),为什么不用这个串口呢?忽然想到开发套件中有个小口袋装了4脚插针,应该就是干这个用的。顺利地将4脚插针焊上,但马上发现:如果将核心板插回底板,由于在串口插针下是底板上的复位按键,需要对焊上的插针修剪,否则插针的焊接端就会顶到复位按键上。焊接、修剪过程其实十分简单,但我差点儿在阴沟里翻船。经历了核心板不能工作、终于又恢复的过程(此处略去具体翻船现场和恢复过程200字),总算有惊无险!

      通过核心板上的串口,经小板转换成USB连到桌面系统的模拟终端,按照教程给出的命令行指令逐条执行,点灯过程很顺利。(教程给出的命令行指令有一处小错:“cd /sys/class/gpio/export/gpio65”)

      b1dea9f5d461d39ce4f425d371d41073.jpg

      2 引脚扩展,RGB三色LED闪烁

      底板上预留的扩展引脚区给人以无限遐想,总觉得如不把它们引出来,似乎对不起设计者的初衷。将引脚引出的主要障碍是需要把显示屏与底板分离。分离本身其实并不困难,难的是下决心去做这种带一点儿破坏性的事情(恳请厂家在出厂时就把双排插座焊上吧)。用刀片将显示屏和底板之间的连接分离,小心地在底板上焊上插座,可以方便地用杜邦线连接扩展引脚了。

      根据底板上扩展引脚的标号,对照原理图,在感觉没有被占用的引脚中选择B2、B3、B4来用,分别用来驱动三色LEB中的R、G、B。参照教程,先用

      “cat /sys/kernel/debug/pinctrl/2000000.pinctrl/pinmux-pins”

      命令查询管脚标号对应的数字编号:

      6e192a9bf3f0ba1c183a0f2445c5e25f.png

      然后参照教程写了两个脚本,并放到“/mnt/SDCARD”目录下,这样掉电文件也不会丢失:

      \

      # rgb_config.sh
      ​
      echo 34 > /sys/class/gpio/export
      echo 35 > /sys/class/gpio/export
      echo 36 > /sys/class/gpio/export
      ​
      cd /sys/class/gpio/gpio34
      echo out>direction
      cd /sys/class/gpio/gpio35
      echo out>direction
      cd /sys/class/gpio/gpio36
      echo out>direction
      

      \

      # rgb_blink.sh
      ​
      for a in $(seq 1 5)
      do
        cd /sys/class/gpio/gpio34
        echo 1 > value
        sleep 0.5
        cd /sys/class/gpio/gpio35
        echo 1 > value
        sleep 0.5
        cd /sys/class/gpio/gpio36
        echo 1 > value
        sleep 1
      ​
        cd /sys/class/gpio/gpio34
        echo 0 > value
        sleep 0.5
        cd /sys/class/gpio/gpio35
        echo 0 > value
        sleep 0.5
        cd /sys/class/gpio/gpio36
        echo 0 > value
        sleep 1
      ​
      done
      

      脚本“rgb_config.sh”用来初始化管脚,“rgb_blink.sh”控制三色LED的闪烁。

      Linux系统下万物皆文件,还要进一步好好体会。

      发布在 MR Series
      q1215200171
      budbool
    • 回复: 【素材汇总】V853素材汇总

      V851s.png v853chip.png 853立.png 851S立.png

      发布在 公告
      q1215200171
      budbool
    • 【FAQ】全志H616芯片 以太网模块初始化失败如何解决?

      1.【问题现象】

      执行ifconfig -a/ifconfig eth0/ifconfig eth0 up命令,找不到eth0设备,有如下类似打印:

      root@TinaLinux:/# ifconfig -a
      lo        Link encap:Local Loopback  
                inet addr:127.0.0.1  Mask:255.0.0.0
                inet6 addr: ::1/128 Scope:Host
                UP LOOPBACK RUNNING  MTU:65536  Metric:1
                RX packets:6480 errors:0 dropped:0 overruns:0 frame:0
                TX packets:6480 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:1 
                RX bytes:505440 (493.5 KiB)  TX bytes:505440 (493.5 KiB)
      
      root@TinaLinux:/# 
      root@TinaLinux:/# ifconfig eth0
      ifconfig: eth0: error fetching interface information: Device not found
      root@TinaLinux:/# 
      root@TinaLinux:/# ifconfig eth0 up
      ifconfig: SIOCGIFFLAGS: No such device
      

      2.【问题分析】

      以太网模块配置未生效或存在GPIO冲突

      3.【排查步骤】

      • 步骤1:抓取内核启动log,搜索"gmac"关键字段,检查gmac驱动是否probe成功;

      • 步骤2:若内核启动log显示probe失败,常见原因是GPIO资源冲突导致,有如下类似打印:

      sun50iw10p1-pinctrl pio: pin PH0 already requested by twi0; cannot claim for gmac0
      sun50iw10p1-pinctrl pio: pin-224 (gmac0) status -22
      sun50iw10p1-pinctrl pio: could not request pin 224 (PH0) from group PH0  on device pio
      sunxi-gmac gmac0: Error applying setting, reverse things back
      sunxi-gmac: probe of gmac0 failed with error -22
      
      • 步骤3:若内核启动log无gmac相关打印,则需要确认以太网配置是否生效。

      4.【解决办法】

      4.1 GPIO冲突
      (1) 首先,结合内核启动log定位与哪个模块存在GPIO冲突,有如下类似打印:

      sun50iw10p1-pinctrl pio: pin PH0 already requested by twi0; cannot claim for gmac0
      

      (2) 然后,确认该模块GPIO配置是否有误或者是否可以关闭该模块。

      4.2 以太网配置未生效
      (1) 首先,确认内核menuconfig以太网模块配置是否打开,路径及截图如下:

      menuconfig -> Device Drivers -> Network device support -> Ethernet driver support
      

      3dcc7d980e5444a7974c067edefb4933.jpg

      (2) 然后,确认board.dts/sys_config.fex中GMAC模块是否打开,board.dts配置示例如下:

      gmac0: eth@05020000{
          phy-mode = "rgmii";
          use_ephy25m = <1>;
          tx-delay = <7>;
          rx-delay = <0>;
          status = "okay";
      };
      

      注:

      • status = “okay"代表打开该模块,status = “disabled"代表关闭该模块;

      • 确保PHY与GMAC之间物理接口与软件配置相匹配,对于RGMII接口phy-mode配置为"rgmii”,RMII接口phy-mode配置为"rmii”;
        © use_ephy25m=1代表PHY使用SOC内部EPHY_25M时钟,use_ephy25m=0或者不配置该参数,代表PHY不使用SOC内部EPHY_25M时钟,
        需外挂25M晶振为PHY提供时钟;

      发布在 H/F/TV Series
      q1215200171
      budbool
    • 【FAQ】全志D1芯片 如何解决Audiocodec使用S24_LE格式进行录音,软件分析波形异常的问题?

      问题背景

      硬件:R329
      软件:Tina
      内核:Linux-4.9

      问题描述

      使用Audiocodec进行录音,格式S24_LE,录制的.wav波形在某些软件中异常

      arecord -D hw:audiocodec -f S24_LE -r 16000 -c 2 -d10 /tmp/test3_S24_LE.wav
      

      d65d357edb0842cb9d54148ed1c5e0b3.jpg
      需要放大很多倍才能看到声音波形

      3cddc50a8f214d7380305433df378993.jfif

      问题分析

      1.R329的Audiocodec用于录音的ADC只支持16bit和20bit的采样精度。采样后的数字信号会存放到RX_FIFO中,RX_FIFO的大小为256*20-bit,其他平台可以在User Manual确认支持的采样精度,从而判断是否会有这个问题产生

      4570bdb36f594591b6ec4c71310e5fe7.jfif

      2.RX_DATA是一个32位的寄存器,保存的是从RX_FIFO获取的一个channel的样本数据,当使用arecord进行录音时,RX_DATA中的值会经DMA搬至内存,最后保存到.wav中

      5c2c17d228f944fd8a4a6e8d1924e778.jfif

      其中RX_DATA有四种模式去获取RX_FIFO的数据,S24_LE和S32_LE均采用20-bit mode0

      6972b81f741b4bf9829ecb814f5dbb7a.jfif

      当设置了20bit采样精度时,对应的两种模式如下图所示:

      8b502f06666046368fafccf0d13eee46.jfif

      3.先说明一下S24_LE和S32_LE这两种格式的区别

      S24_LE指有符号整型,范围是-2^23 ~ ((2^23) - 1),有效数据在低24位
      S32_LE指有符号整型,范围是-2^31 ~ ((2^31) - 1),有效数据在高24位

      LSB                           MSB
               1st byte  2nd byte  3rd byte  4th byte   alignment
      S32_LE:   00000000  xxxxxxxx  xxxxxxxx  xxxxxxxx   32 bits
      S24_LE:   xxxxxxxx  xxxxxxxx  xxxxxxxx  00000000   32 bits
      S24_3LE:  xxxxxxxx  xxxxxxxx  xxxxxxxx             24 bits
      

      4.在驱动程序中,S24_LE和S32_LE虽然都支持,但他们两者都是使用20-bit的mode0,这导致这两种格式保存到文件中的数据排布是一致的,但生成的wav头信息中的采样位数则不一样,从下图可以看出两者的差异

      S32_LE的wav文件信息:

      b782fd998a1a42bfafb6a46a3362d79b.jfif

      若软件以S32_LE进行解析,以上红框的数据变为0x0f80f0,依然可以保留全部有效数据

      5de38b0c26a346a2bd0cc517b1cb6485.jfif

      S24_LE的wav文件信息:

      561fc954670c4a7e8f5c122acd788689.jfif

      若软件以S24_LE进行解析,以上红框的数据变为0x55f000,便会丢失一部分数据

      a185f006bee4483ebb53b3835c4053dc.jfif

      解决方案

      总结原因就是audiocodec的采样精度只支持16和20bit,因此PCM格式中S24_LE虽然也支持,但硬件的特性使驱动并不能做到很好的适配,若软件以标准S24_LE格式进行分析,则会丢失高位的有效数据,这取决于软件如何对数据进行分析,解决方法有以下三种

      • 使用audiocodec时,使用-f S32_LE,修改wav头信息中的采样位数位32,这对大部分软件都有效
      arecord -D hw:-f S32_LE -r 16000 -c 2 -d10 /tmp/test32.wav
      
      • 如果必须使用S24_LE格式进行录音,可以选择其他支持24bit采样的音频接口,如I2S等
      • 假如必须使用audiocodec声卡,S24_LE格式进行录音,可以自行调整RX_DATA寄存器的模式,结合RX_DATA寄存器中实际的有效数据分布,自己开发软件进行数据分析
        如果有分析和处理音频数据的需求,可以参考以上思路,结合RX_DATA寄存器去调整
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • LVGL日历控件和显示天气

      利用TCP封装HTTP包请求天气信息

      Linux还真是逐步熟悉中,现在才了解到Linux即没有原生的GUI,也没有应用层协议栈,所以要实现HTTP应用,必须利用TCP然后自己封装HTTP数据包。本篇即记录封装HTTP数据包,到心知天气请求天气信息的案例实现过程。

      1、心知天气API说明
      心知天气应该是当下国内使用很普遍的一个天气数据站点。相关注册和使用过程,这里就不再啰嗦了,不清楚的朋友可以自己到官网上查看(https://www.seniverse.com/)。

      本例仅测试实时天气数据获取,天气相关数据只有“状态(晴朗之类)”和“气温”,请求接口地址如下:

      https://api.seniverse.com/v3/weather/now.json?key=your_api_key&location=beijing&language=zh-Hans&unit=c

      1.png

      可以看到请求地址给的是域名,TCP连接需要直接给IP地址,所以用ping来获取其IP为“116.62.81.138”,端口自然是80。

      2.png

      得到IP地址后,先不着急编程,通过网络助手实验一把,具体过程是:选择TCP Client,连接对方IP和端口(116.62.81.138:80),然后将请求地址前加上方法字串“GET”,结尾还要有两个回车换行“\r\n\r\n”。初次测试时,忘记了回车换行符没有成功,加上后就好了。

      3.png
      4.png

      封装好的数据包是:“GET https://api.thinkpage.cn/v3/weather/now.json?key=yourkey&location=tianjin&language=en&unit=c\r\n\r\n”。

      2、JSON分析
      请求到的数据是JSON格式,贴到Json.cn(https://www.json.cn/)的在线工具里,可以更清晰的看到其结构。

      5.png

      可以看到请求实时数据(now.json),得到一个JSON对象,包含一个“results”引导的JSON数组,且数组只有一个元素,元素中又包含“location”、“now”和“last_update”三个JSON对象,内部还有键值对。

      既然是开发Linux API的C程序,当然利用cJSON库来帮助进行数据解析了。本人使用的库是从网上搜到的一个百度网盘分享。

      链接:https://pan.baidu.com/s/1DQynsdlNyIvsVXmf4W5b8Q
      提取码:ww4z

      3、请求天气案例
      具体思路就是建立TCP Client连接心知天气的Server,然后发送请求包,得到响应包,解析并打印出结果,案例比较简单做成单次的——开启即运行到底,代码如下:

      #include <stdio.h>
      #include <sys/types.h>
      #include <sys/socket.h>
      #include <string.h>
      #include <netinet/in.h>
      #include <arpa/inet.h>
      
      #include "cJSON.h"
      
      #define SERVER_IP      "116.62.81.138"
      #define SERVER_PORT    80
      #define NOW            "now.json"
      #define DAILY          "daily.json"
      #define API_KEY        "SK0LJ8FI2TP0L-IsQ"
      #define CITY           "tianjin"
      #define REQ_PACK       "GET https://api.thinkpage.cn/v3/weather/%s?key=%s&location=%s&language=en&unit=c\r\n\r\n"
      #define N              1024
      #define errlog(errmsg) do{ perror(errmsg);\
                  printf("----%s----%s----%d----\n", __FILE__, __func__, __LINE__);\
                  return -1;\
              } while(0)
      
      //struct for weather data
      typedef struct {
          char id[16];
          char name[32];
          char country[16];
          char path[64];
          char timezone[32];
          char tz_offset[16];
          char text[16];
          char code[4];
          char temp[8];
          char last_update[32];
      } weather_t;
      
      //parse function & print weather_t data function
      void aita_ParseJsonNow(char *json, weather_t *w);
      void aita_PrintWeather(weather_t *w);
      
      int main(int argc, const char *argv[]) {
          int sockfd;
          struct sockaddr_in serveraddr;
          socklen_t addrlen = sizeof(serveraddr);
          char sendbuf[N] = "";
          char recvbuf[N] = "";
          weather_t weather = {0};
      //create socket
          if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
              errlog("socket error");
          }
      //connect to server of seniverse.com
          serveraddr.sin_family = AF_INET;
          serveraddr.sin_addr.s_addr = inet_addr(SERVER_IP);
          serveraddr.sin_port = htons(SERVER_PORT);
          if((connect(sockfd, (struct sockaddr*)&serveraddr, addrlen)) < 0) {
              errlog("connect error");
          }
      //build & send request package
          sprintf(sendbuf, REQ_PACK, NOW, API_KEY, CITY);
          if(send(sockfd, sendbuf, N, 0) < 0) {
              errlog("send error");
          }
      //waiting server response
          if(recv(sockfd, recvbuf, N, 0) < 0) {
              errlog("recv error");
          }
          printf("recv: %s\n", recvbuf);
      //parse & print data
          aita_ParseJsonNow(recvbuf, &weather);
          aita_PrintWeather(&weather);
          close(sockfd);
          return 0;
      }
      
      void aita_ParseJsonNow(char *msg, weather_t *w) {
          cJSON *json, *ja, *jo, *josub, *item;
          json = cJSON_Parse(msg); //parse string to cJSON type
          if(json == NULL) {
              printf("json type cast error: %s", cJSON_GetErrorPtr());
              return;
          } else {
              printf("parse now pack\n");
              if((ja=cJSON_GetObjectItem(json, "results")) != NULL) { //get results array
                  if((jo=cJSON_GetArrayItem(ja, 0)) != NULL) {        //get array[0](the only item)
                      //get location object
                      if((josub=cJSON_GetObjectItem(jo, "location")) != NULL) {
                          if((item=cJSON_GetObjectItem(josub, "id")) != NULL) {
                              memcpy(w->id, item->valuestring, strlen(item->valuestring));
                          }
                          if((item=cJSON_GetObjectItem(josub, "name")) != NULL) {
                              memcpy(w->name, item->valuestring, strlen(item->valuestring));
                          }
                          if((item=cJSON_GetObjectItem(josub, "country")) != NULL) {
                              memcpy(w->country, item->valuestring, strlen(item->valuestring));
                          }
                          if((item=cJSON_GetObjectItem(josub, "path")) != NULL) {
                              memcpy(w->path, item->valuestring, strlen(item->valuestring));
                          }
                          if((item=cJSON_GetObjectItem(josub, "timezone")) != NULL) {
                              memcpy(w->timezone, item->valuestring, strlen(item->valuestring));
                          }
                          if((item=cJSON_GetObjectItem(josub, "timezone_offset")) != NULL) {
                              memcpy(w->tz_offset, item->valuestring, strlen(item->valuestring));
                          }
                      }
                      //get now object
                      if((josub=cJSON_GetObjectItem(jo, "now")) != NULL) {
                          if((item=cJSON_GetObjectItem(josub, "text")) != NULL) {
                              memcpy(w->text, item->valuestring, strlen(item->valuestring));
                          }
                          if((item=cJSON_GetObjectItem(josub, "code")) != NULL) {
                              memcpy(w->code, item->valuestring, strlen(item->valuestring));
                          }
                          if((item=cJSON_GetObjectItem(josub, "temperature")) != NULL) {
                              memcpy(w->temp, item->valuestring, strlen(item->valuestring));
                          }
                      }
                      //get last_update object
                      if((josub=cJSON_GetObjectItem(jo, "last_update")) != NULL) {
                          memcpy(w->last_update, josub->valuestring, strlen(josub->valuestring));                 
                      }
                  }
              }
          }
          //delete original json pack free memory
          cJSON_Delete(json);
          return;
      }
      
      void aita_PrintWeather(weather_t *w) {
          printf("id: %s\n", w->id);
          printf("name: %s\n", w->name);
          printf("country: %s\n", w->country);
          printf("path: %s\n", w->path);
          printf("timezone: %s\n", w->timezone);
          printf("timezone_offset: %s\n", w->tz_offset);
          printf("text: %s\n", w->text);
          printf("code: %s\n", w->code);
          printf("temperature: %s\n", w->temp);
          printf("last_update: %s\n", w->last_update);
      }
      

      项目路径中建立了源文件main.c,编写上述代码,并导入cJSON.c和cJSON.h,编译命令为:“riscv64-unknown-linux-gnu-gcc main.c cJSON.c -o weather -lm”。因为cJSON会用到math库,而它需要“-lm”来动态链接。

      7.png
      6.png

      lvgl显示图片和本地时间

      1、lvgl的图片显示
      lvgl框架中图片可以是一个文件也可以是一个变量(数组形式的图片码),当然文件还需要初始化lvgl对文件系统的接口,本例暂以变量形式提供。

      应用要显示图片,则需要引入一个图片控件,然后设置它的数据源——使用“lv_img_set_src()”函数。示例如下:

      lv_obj_t * icon = lv_img_create(lv_scr_act(), NULL);
      /*From variable*/
      lv_img_set_src(icon, &my_icon_dsc);
      

      上述代码中“icon”是一个lvgl对象指针,通过“lv_img_create()”实例化,则对应图片控件。设置数据源时传入参数“my_icon_dsc”是lvgl中的图片描述符数据结构“lv_img_dsc_t”——本身是一个结构体类型,其定义源码如下:

      //in “../lvgl/src/draw/lv_img_buf.h”
      typedef struct {
          uint32_t cf : 5;          /*Color format: See `lv_img_color_format_t`*/
          uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a
                                       non-printable character*/
       
          uint32_t reserved : 2; /*Reserved to be used later*/
          uint32_t w : 11; /*Width of the image map*/
          uint32_t h : 11; /*Height of the image map*/
      } lv_img_header_t;
       
      typedef struct {
          lv_img_header_t header; /**< A header describing the basics of the image*/
          uint32_t data_size;     /**< Size of the image in bytes*/
          const uint8_t * data;   /**< Pointer to the data of the image*/
      } lv_img_dsc_t;
      

      示例代码中,图片描述符变量的定义过程如下代码:

      uint8_t my_icon_data[] = {0x00, 0x01, 0x02, ...};
       
      static lv_img_dsc_t my_icon_dsc = {![8.png](/assets/uploads/files/1653270047514-8.png) 
          .header.always_zero = 0,
          .header.w = 80,
          .header.h = 60,
          .data_size = 80 * 60 * LV_COLOR_DEPTH / 8,
          .header.cf = LV_IMG_CF_TRUE_COLOR,          /*Set the color format*/
          .data = my_icon_data,
      };
      

      其中,枚举“LV_IMG_CF_TRUE_COLOR”是色彩格式定义,表示RGB格式。

      宏“LV_COLOR_DEPTH”则定义色彩深度,它位于“lv_conf.h”,用户可以自定义。本例中设置为32,即4字节的ARGB8888格式。

      2、时间获取
      86板的Tina Linux可以通过C time库轻松地获得本地时间等数据。本例使用的API有:time()、localtime()、strftime()以及time_t、struct tm。

      8.png

      9.png

      10.png

      11.png

      3、图片和时间显示案例
      本例继续使用线程管理lvgl刷新,创建1s周期的lvgl定时器,在定时器回调中获取本地时间并格式化输出。另外,系统初始时显示一个“天津”的Logo,而且初始即做一次时间获取和输出(如果不做,初始刹那label会显示默认“text”字样)。

      图片码通过软件“Img2Lcd”获取,软件配置方式如下图所示。图片生成的数组有72008个字节,被放置到头文件“aita_logo.h”。

      12.png

      /* Includes ------------------------------------------------------- */
      #include "lvgl/lvgl.h"
      #include "lv_drivers/display/fbdev.h"
      #include "lv_drivers/indev/evdev.h"
      #include <stdio.h>
      #include <string.h>
      #include <unistd.h>
      #include <pthread.h>
      #include <time.h>
      #include <sys/time.h>
      #include <sys/types.h>
      #include <sys/socket.h>
      #include <netinet/in.h>
      #include <arpa/inet.h>
      #include "aita_logo.h"
       
      /* Private macro -------------------------------------------------- */
      #define AITA_DISP_BUF_SIZE     (128 * 1024)
      #define AITA_SCREEN_WIDTH      480
      #define AITA_SCREEN_HEIGHT     480
      #define AITA_TITLE_STRING      "AITA Weather for LicheeRV with LVGL"
      #define SEND_PERIOD            1000
      #define errlog(errmsg)         do{ perror(errmsg);\
          printf("----%s----%s----%d----\n", __FILE__, __func__, __LINE__);\
          return;\
          } while(0)
       
      /* Global variables ----------------------------------------------- */
      lv_indev_t *aita_indev;   //pointer of indev
      lv_obj_t *sys_scr;        //pointer of system screen instance
      lv_obj_t *head_label;     //pointer of title label instance
      lv_obj_t *main_label;     //pointer of main label instance
      char main_label_text[32]; //main label text string for datetime
      lv_obj_t *logo_img;       //pointer of city logo image instance
      lv_timer_t *sec_timer;    //pointer of timer instance for tcp polling
      pthread_t lvgl_tid;       //lvgl thread id
      pthread_t tcprecv_tid;    //tcp receive thread id
      pthread_mutex_t lvgl_mutex;  //mutex for lvgl tick
      //image descriptor for logo_img
      //ARGB8888 image 180*100 which code array is 'tj_logo' 
      lv_img_dsc_t img_dsc_city = {
        .header.always_zero = 0,
        .header.w = 180,
        .header.h = 100,
        .data_size = 18000 * LV_COLOR_SIZE / 8,
        .header.cf = LV_IMG_CF_TRUE_COLOR,
        .data = tj_logo,
      };
       
      /* Private function prototypes ------------------------------------ */
      void aita_InitLVGL(void);
      void aita_CreateMainUI(void);
      void *thread_lvgl(void *arg);
      void sec_timer_cb(lv_timer_t *timer);
      void aita_InitTimer(void);
      void aita_GetTime(void);
       
      /* Private functions ---------------------------------------------- */
      int main(void) {
          void *retval;
       
      //by author. initialize lvgl including displaybuffer, device for disp & input
          aita_InitLVGL();
          
      //by author. initialize and register event device
      //these code must be in main(), otherwise the touch will fail.
          static lv_indev_drv_t indev_drv;
          lv_indev_drv_init(&indev_drv);
          indev_drv.type = LV_INDEV_TYPE_POINTER; //by author. choice touchpad
          indev_drv.read_cb = evdev_read;         //by author. input callback
          aita_indev = lv_indev_drv_register(&indev_drv);
       
      //by author. create the main view when the demo starts up    
          aita_CreateMainUI();
       
      //by author. create a timer
          aita_InitTimer();
       
      //by author. create mutex for lvgl
          if(pthread_mutex_init(&lvgl_mutex, NULL) != 0) {
              errlog("initialize mutex error");
          }
       
      //by author. create lvgl thread
          if(pthread_create(&lvgl_tid, NULL, thread_lvgl, (void *)0) != 0) {
              errlog("create lvgl thread error");
          }
       
      //by author. wait for thread exit, this demo should never be here.
          pthread_join(lvgl_tid, &retval);
          printf("lvgl thread exit, return value: %s\n", (char *)retval);
          pthread_mutex_destroy(&lvgl_mutex);
          return 0;
      }
       
      /*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/
      uint32_t custom_tick_get(void)
      {
          static uint64_t start_ms = 0;
          if(start_ms == 0) {
              struct timeval tv_start;
              gettimeofday(&tv_start, NULL);
              start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;
          }
       
          struct timeval tv_now;
          gettimeofday(&tv_now, NULL);
          uint64_t now_ms;
          now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;
       
          uint32_t time_ms = now_ms - start_ms;
          return time_ms;
      }
       
      void aita_InitLVGL(void) {
          /*LittlevGL init*/
          lv_init();
       
          /*Linux frame buffer device init*/
          fbdev_init(); //by author. initialize framebuffer device for display
          evdev_init(); //by author. initialize event device for touchpad
       
          /*A small buffer for LittlevGL to draw the screen's content*/
          static lv_color_t buf[AITA_DISP_BUF_SIZE];
          /*Initialize a descriptor for the buffer*/
          static lv_disp_draw_buf_t disp_buf;
          lv_disp_draw_buf_init(&disp_buf, buf, NULL, AITA_DISP_BUF_SIZE);
          /*Initialize and register a display driver*/
          static lv_disp_drv_t disp_drv;
          lv_disp_drv_init(&disp_drv);
          disp_drv.draw_buf   = &disp_buf;
          disp_drv.flush_cb   = fbdev_flush;
          disp_drv.hor_res    = 480;
          disp_drv.ver_res    = 480;
          lv_disp_drv_register(&disp_drv);
      }
       
      void aita_CreateMainUI(void) {
          //by author. create system screen which is basic graphic level
          sys_scr = lv_obj_create(lv_scr_act());
          lv_obj_set_size(sys_scr, AITA_SCREEN_WIDTH, AITA_SCREEN_HEIGHT);
          //by author. create the main title which is just a label
          head_label = lv_label_create(sys_scr);
          lv_label_set_text(head_label, AITA_TITLE_STRING);
          lv_obj_align(head_label, LV_ALIGN_TOP_MID, 0, 10);
          //by author. create the city logo image
          logo_img = lv_img_create(sys_scr);
          lv_img_set_src(logo_img, &img_dsc_city);
          lv_obj_align(logo_img, LV_ALIGN_TOP_LEFT, 10, 40);
          //by author. get local time and show string
          aita_GetTime();
          main_label = lv_label_create(sys_scr);
          lv_label_set_text(main_label, main_label_text);
          lv_obj_align(main_label, LV_ALIGN_TOP_LEFT, 200, 40);
          lv_obj_set_style_text_font(main_label, &lv_font_montserrat_20, 0);
      }
       
      //by author. lvgl core thread function
      void *thread_lvgl(void *arg) {
          while(1) {
              pthread_mutex_lock(&lvgl_mutex);
              lv_task_handler();
              pthread_mutex_unlock(&lvgl_mutex);
              usleep(5000); /* sleep for 5 ms */
          }
      }
       
      //by author. sec_timer callback which refresh date string
      void sec_timer_cb(lv_timer_t *timer) {
          aita_GetTime();
          lv_label_set_text(main_label, main_label_text);  
      }
      //by author. initialize timer for 1s timing
      void aita_InitTimer(void) {
          sec_timer = lv_timer_create(sec_timer_cb, 1000, NULL);
          lv_timer_set_repeat_count(sec_timer, -1);
      }
      //by author. get local time string
      void aita_GetTime(void) {
          time_t    tsec;
          struct tm *tlocal;
          tsec = time(NULL);
          tlocal = localtime(&tsec);
          memset(main_label_text, 0, 32);
          strftime(main_label_text, 32, "%Y-%m-%d %a %H:%M:%S", tlocal);
      }
      

      13.png

      lvgl日历控件和显示天气

      本篇结合本人前两篇的HTTP请求天气数据(通过“心知天气”网站)和lvgl显示图片及时间,在案例主界面上增加了日历显示和实时天气显示,先直接上图。

      14.png

      1、lvgl日历控件
      calendar是lvgl提供的“Extra widgets”组件之一,需要注意的是8.0版本后有几个API的传参发生了变化,本例使用8.3版本,设置日期是需要同时传递“年、月、日”三个参数。

      本例使用的API有:lv_calendar_create()、lv_canlendar_set_today_date()、lv_calendar_set_showed_date()和lv_calendar_header_arrow_create()。

      lv_calendar_create()函数用于实例化calendar控件,传参是控件的父容器指针,本例使用“lv_scr_act()”即系统屏幕。

      15.png

      lv_canlendar_set_today_date()函数用于设置当前日期,本人使用发现lvgl是附带万年历功能的,只要设置好当天的年月日,就可以自动生成正确的日历排布。函数传参分别是控件指针和年月日数据。

      关于年月日参数有两点注意事项。一是v7版本中,传参通过lv_calendar_date_t结构体,其包含年月日三个成员。二是如果使用了C time库的struct tm,注意其中年份需要加上“1900”,而月份则需要加“1”。

      16.png

      lv_calendar_set_showed_date()函数用于设置日历当前显示页,也就是设置当前月份。本人实验的效果是当天日期框会自动高亮,如果想设置多个高亮日期,可以使用函数lv_calendar_set_highlighted_dates()。

      17.png

      lv_calendar_header_arrow_create()函数用于向日历控件顶部增加“左、右箭头”两个按钮用于日历翻页(一页是一月)。此外,还有函数lv_calendar_header_dropdown_create()则是设置两个下拉列表分别用于选择年份和月份。这两个函数都只用传递日历控件指针一个参数,且是8.1版本新增API。

      2、日历和天气显示案例
      本案例的思路是:1)在应用启动时,获取当前时间(上篇中已经实现),然后将时间保存在全局量“struct tm today”中,并利用变量“today”来初始化日历控件的日期数据。2)上篇实现的时间显示案例,通过lvgl定时器,每秒获取本地数据,此处在定时器回调中再增加一个每到正分钟发送“Linux条件变量”。3)同时,应用启动时建立两个线程——lvgl线程和请求天气线程,请求天气线程等待条件变量到来,开启一次天气数据请求过程。

      本例代码结合文章上半部分已经给出的案例,这里只给出改变部分。

      /* Includes ------------------------------------------------------- */
      // 增加头文件,cJSON用于解析JSON格式的天气数据
      #include "cJSON.h"
       
      /* Private macro -------------------------------------------------- */
      // 增加请求天气数据相关的宏定义
      #define HTTP_IP                "116.62.81.138"
      #define HTTP_PORT              80
      #define NOW                    "now.json"
      #define API_KEY                "SK0LJ8FI2TP0L-IsQ"
      #define CITY                   "tianjin"
      #define REQ_PACK               "GET https://api.thinkpage.cn/v3/weather/%s?key=%s&location=%s&language=en&unit=c\r\n\r\n"
      #define N                      1024
      // struct for weather data 建立结构体存储解析后的天气数据
      typedef struct {
          char id[16];
          char name[32];
          char country[16];
          char path[64];
          char timezone[32];
          char tz_offset[16];
          char text[16];
          char code[4];
          char temp[8];
          char last_update[32];
      } weather_t;
       
      /* Global variables ----------------------------------------------- */
      // 增加显示天气的标签控件定义
      lv_obj_t *weather_label;  //pointer of weather label instance
      // 增加日历控件定义
      lv_obj_t  *calendar;      //pointer of calendar instance
      // 定义today变量存储当前日期,用于设置日历
      struct tm today;          //
      // 请求天气的线程ID
      pthread_t reqweather_tid; //request weather thread id
      // 请求天气线程等待的条件变量(min_cond)
      // Linux中需要互斥量包含条件变量的使用,所以定义cond_mutex
      pthread_mutex_t cond_mutex;  //mutex for 1-min cond
      pthread_cond_t  min_cond; //1-min cond
      /* Private functions ---------------------------------------------- */
      int main(void) {
      // other code from previous demo
      // main()函数中创建互斥量、条件变量、请求天气线程
      //by author. create mutex for 1-min cond
          if(pthread_mutex_init(&cond_mutex, NULL) != 0) {
              errlog("initialize cond mutex error");
          }
       
      //by author. create condition for 1-min
          if(pthread_cond_init(&min_cond, NULL) != 0) {
              errlog("initialize 1 minute condition error");
          }
       
      //by author. create request weather thread
          if(pthread_create(&reqweather_tid, NULL, thread_reqweather, (void *)0) != 0) {
              errlog("create request weather thread error");
          }
       
      //by author. wait for thread exit, this demo should never be here.
          pthread_join(lvgl_tid, &retval);
          printf("lvgl thread exit, return value: %s\n", (char *)retval);
          pthread_join(reqweather_tid, &retval);
          printf("request weather thread exit, return value: %s\n", (char *)retval);
          pthread_mutex_destroy(&lvgl_mutex);
          pthread_mutex_destroy(&cond_mutex);
          pthread_cond_destroy(&min_cond);
          return 0;
      }
       
      void aita_CreateMainUI(void) {
      // other code from previous demo
      // aita_CreateMainUI()被main()函数调用,初始化主界面。
          //by author. create the weather label
          weather_label = lv_label_create(sys_scr);
          lv_label_set_text(weather_label, "         ");
          lv_obj_align(weather_label, LV_ALIGN_TOP_LEFT, 200, 120);
          //by author. create the calendar
          calendar = lv_calendar_create(sys_scr);
          lv_obj_set_size(calendar, 235, 235);
          lv_obj_align(calendar, LV_ALIGN_BOTTOM_LEFT, 10, -50);
          lv_calendar_set_today_date(calendar, today.tm_year+1900, today.tm_mon+1, today.tm_mday);
          lv_calendar_set_showed_date(calendar, today.tm_year+1900, today.tm_mon+1);
          lv_calendar_header_arrow_create(calendar);
      }
       
      // 增加正分钟发送条件变量
      void sec_timer_cb(lv_timer_t *timer) {
          aita_GetTime();
          lv_label_set_text(main_label, main_label_text);
          if(today.tm_sec == 0) {
              //by author. send condition signal per whole minute
              pthread_cond_signal(&min_cond);
          }
      }
      // 增加对today的赋值
      void aita_GetTime(void) {
          time_t    tsec;
          struct tm *tlocal;
          tsec = time(NULL);
          tlocal = localtime(&tsec);
          today = *tlocal;
          memset(main_label_text, 0, 32);
          strftime(main_label_text, 32, "%Y-%m-%d %a %H:%M:%S", tlocal);
      }
       
      // 请求天气线程业务逻辑
      void *thread_reqweather(void *arg) {
          int sockfd;
          struct sockaddr_in serveraddr;
          socklen_t addrlen = sizeof(serveraddr);
          char sendbuf[N] = "";
          char recvbuf[N] = "";
          weather_t weather = {0};
          char w_string[64] = "";
       
          while(1) {
              pthread_mutex_lock(&cond_mutex);
              pthread_cond_wait(&min_cond, &cond_mutex);
              pthread_mutex_unlock(&cond_mutex);     
          //create socket
              if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
                  errlog("socket error");
              }
          //connect to server of seniverse.com
              serveraddr.sin_family = AF_INET;
              serveraddr.sin_addr.s_addr = inet_addr(HTTP_IP);
              serveraddr.sin_port = htons(HTTP_PORT);
              if((connect(sockfd, (struct sockaddr*)&serveraddr, addrlen)) < 0) {
                  errlog("connect error");
              }
          //build & send request package
              memset(sendbuf, 0, N);
              sprintf(sendbuf, REQ_PACK, NOW, API_KEY, CITY);
              if(send(sockfd, sendbuf, N, 0) < 0) {
                  errlog("send error");
              }
          //waiting server response
              if(recv(sockfd, recvbuf, N, 0) < 0) {
                  errlog("recv error");
              }
              printf("recv: %s\n", recvbuf);
          //parse & print data,下面两个函数来自于“十三”案例
              aita_ParseJsonNow(recvbuf, &weather);
              aita_PrintWeather(&weather);
              close(sockfd);
              memset(recvbuf, 0, N);
          //show weather string
              memset(w_string, 0, 64);
              sprintf(w_string, "weather:%s temperatur:%s", weather.text, weather.temp);
              pthread_mutex_lock(&lvgl_mutex);
              lv_label_set_text(weather_label, w_string);
              pthread_mutex_unlock(&lvgl_mutex);       
          }
      }
      

      另外,本例在lvgl工程中增加了cJSON.c和cJSON.h文件,Makefile也做出了调整,具体如下所示。

      18.png

      原文链接:https://occ.t-head.cn/community/post/detail?spm=a2cl5.25411629.0.0.6597180fVP7giT&id=4039525135236603904
      作者 @ firr

      发布在 MR Series
      q1215200171
      budbool
    • 到立创开源平台DIY 赢取万元奖金

      • 星火计划报名页面:

      https://oshwhub.com/activities/spark2023/fp#P1

      • 全志H616电脑DIY报名页面:

      https://oshwhub.com/activities/spark2023/fp/detail?demand_uuid=6bdf5f66bf064607b3fb371299c9bd22

      什么是「星火计划」?

      嘉立创旗下的开源硬件平台,特推【星火计划】活动,给想干一个大项目的电子人提供弹药,也提供展示的平台。

      微信图片_20230428112617.png

      星火计划,是立创开源硬件平台面向全球电子爱好者发出的硬件开源助力活动。专门陪跑那种比较费钱的开源设计!

      星火计划项目在2022年正式开启,每年举办一次,每次举办一年。

      目前,星火计划分为两个赛道,分别是自由赛道和外包赛道。

      自由赛道项目不限主题,不限参与人群,只要你有想法都可以来报名,该赛道下单个项目最高可提供一万元的耗材经费支持!

      微信图片_20230428112624.png

      外包赛道为星火计划二期的全新赛道,有不同类型的外包项目需求,每个外包项目均提供定额项目奖金,外包项目仅对接一人,成功结项百分百获奖!

      微信图片_20230428112626.png

      外包计划

      纠结症患者在参赛时一般会想:我要做什么项目?我能做什么项目?我的项目要实现什么功能才能脱颖而出?做好了能不能评上奖?.......

      这也是嘉立创通过对2022期参赛者的调研发现的普遍问题,大家把前因后果全都考虑了一遍才发现自己还是连一点项目头绪都没有,但又不想错过这个千载难逢的好机会!毕竟,这种史诗级羊毛不薅?这说不过去!

      基于此类“通病”,星火计划外包赛道就为专门治愈这类“纠结症患者”而生!不同应用领域的需求让你应接不暇,总有一个适合你!

      微信图片_20230428091708.png

      一套流程行云流水,每个外包项目均提供定额的项目奖金,且只对接一位参赛者,成功结项将百分百获奖!

      贡献创意

      如果 这里面没有你想要参加的项目,你也可以“贡献创意”,把你觉得还不错的项目创意提给我们,为星火计划推波助澜,成就更多开源好项目。

      【贡献创意】的需求一经采纳,贡献者奖100元无门槛元器件券,无上限!

      微信图片_20230428092126.png

      活动奖励

      微信图片_20230428112634.png

      活动流程

      微信图片_20230428112637.png

      Vlog记录奖励

      微信图片_20230428092231.png

      全志方案赛道

      在外包赛道中有全志H616电脑的悬赏项目,当然,有更好想法的开发者也可以选择自由赛道,无限发挥自己的脑洞,你的每一个创意都可以在星火计划中获得全力的支持。

      微信图片_20230428112639.png

      微信图片_20230428112642.jpg

      H616电脑设计需求

      外设接口
      1、HDMI接口1(4k显示);
      2、USB2.0
      3
      3、USB2.0_OTG1;
      4、3.5mm音频接口
      1;
      5、USB-Type-C供电*1;
      6、TF卡槽;

      内置:
      1、板载WiFi、蓝牙5.0;
      2、运行存储:2GB;
      3、内存:32GB;
      4、电池充放电电路;
      5、10.1寸触摸屏;

      设计说明
      1、使用嘉立创EDA设计;
      2、整体项目需设计合适的3D外壳,材料不限(公版模型也可以);
      3、外壳模型必须有着对应的接口说明;
      4、支持加载Android镜像载入;

      验收说明
      1、电路部分需完全使用嘉立创EDA专业版进行设计,设计前需与工作人员确认方案的可行性后再进行;
      2、原理图电路正确,PCB布局走线要求整理美观,无明显缺陷,设计合理,整体外形协调美观;
      3、要求录制完整的演示视频,提供项目硬件、软件源文件、器件清单,填写完善开源项目描述。
      4、中标后即可进行设计,设计过程中所需耗材与器件需自行准备,项目完成后发放奖金,规定时间内未完成将重新启动项目招标,原项目作废,且不报销已购买物料。
      5、嘉立创EDA拥有完整的项目解释权,但会保留作者的著作权。

      发布在 公告
      q1215200171
      budbool
    • BliKVM v4,基于芒果派H616的KVM解决方案,开箱、连接,使用手把手演示视频

      BLIKVM 是一款开源 KVM over IP 软件,可帮助您远程管理服务器或工作站,无论目标系统的健康状况如何,目前可与 Raspberry Pi CM4 硬件、Raspberry Pi HAT 或 PCIe 板配合使用。

      还有一种更紧凑、可能更便宜的型号正在开发中,该型号会适配Mango Pi 的最小模组mCore-H616。

      Allwinner-H616-KVM-over-IP.jpg BLIKVM-H616-system.jpg

      发布在 H/F/TV Series
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 汇编代码调试技巧

      1.问题背景
      问题平台:XR806 + RTOS

      2.问题描述
      XR806(M33内核)适配新的RTOS时,沿用M4F的启动代码后出现了系统奔溃,但是expection显示的PC地址和LR地址都被修改,无法准确判断哪条语句导致的错误。

      3.问题分析

      • 通过log定位到是启动代码出现了问题。
      • arm汇编中,可利用b .进入死循环。
      • 在汇编中可以利用以下代码打印log:
      //.c文件中插入
      void AsmPrint(void)
      {
          printf("var = %#x\n",PrintMagic);
      }
      #汇编代码中插入以下代码查看R0的值
          LDR R8,=PrintMagic
          str R0,[R8]
          LDR R8,=AsmPrint
          bx R8
      
      • 最后发现汇编代码正常,但在运行第一个任务时系统奔溃。原因为M33内核新增了PSPlimit功能,任务栈超过了设定值时会直接触发usage Fault。同时RTOS在系统启动前修改了PC地址和LR地址,导致exception中无法正确显示PC地址和LR地址。

      4.解决方法
      使用__set_PSPLIM可以设置PSPlimit地址,在不确定PSP限制时,可以__set_PSPLIM(0)取消这个功能,MSP也是相同道理。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 回复: 【送开发板啦】百问科技基于全志D1-H定制的开发板——东山哪吒STU第一堂系统开发直播课堂

      手把手带你玩转东山哪吒STU系列开发板——硬件简述部分
      https://www.bilibili.com/video/BV1cB4y1v71Z?p=2&spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=b0f9a9d0a52bf431a0252a7090b3639e

      发布在 MR Series
      q1215200171
      budbool
    • 回复: 花费400元,DIY了一台A133平板电脑

      @lovehex99 @jordonwu 帮各位大佬问过作者本人了,没有套件卖😁

      发布在 爱搞机专区
      q1215200171
      budbool
    • 回复: 【素材汇总】R128素材汇总

      最新的R128开发板

      R128z.png R128mm.png

      发布在 公告
      q1215200171
      budbool
    • 【FAQ】全志R系列在Tina下如何确认方案的optee版本信息

      问题背景
      Tina环境下当前支持两个版本的optee,一个是2.5.0,一个是3.7.0。

      由于Tina下平台众多,客户不是很清楚哪些平台支持哪个版本的optee。

      问题分析
      optee版本主要涉及三个部分optee-client,optee-os-dev-kit,optee.bin。由于2.5与3.7版本跨度太大,所以这三者必须版本匹配,系统才能正常工作,Tina release版本SDK是通过make menuconfig中的OPTEE_VERSION_2_5与OPTEE_VERSION_3_7来统一配置版本信息。

      可以参考《TinaLinux_安全使用指南》第1.2章节的适用范围来,确认平台的optee版本,旧芯片支持2.5版本,新芯片使用3.7版本。这里汇总如下:

      optee-2.5.0: R18、MR133、R311、R328…

      optee-3.7.0: R329、MR813、R818、R528…

      理论上来说,所有平台都可以支持optee的3.7.0版本。有些客户希望对旧芯片,如R328,升级到3.7.0,此时,系统中就会存在两个版本optee,如果没有统一管理,就容易造成混乱。

      问题解决

      optee-client
      查看tina/package/security/optee-client*/Makefile中的PKG_VERSION来确认版本信息。

      PKG_VERSION:=2.5.0
      

      optee-os-dev-kit
      查看tina/package/security/optee-os-dev-kit/dev_kit/arm-plat-xxx/export-

      ta_arm32/host_include/conf.mk中的CFG_OPTEE_REVISION_MAJOR与CFG_OPTEE_REVISION_MINOR
      
      CFG_OPTEE_REVISION_MAJOR=2
      CFG_OPTEE_REVISION_MINOR=5
      

      optee.bin
      optee.bin头部包含版本信息,可以通过hexdump进行查看。

      $ hexdump -C optee_xxx.bin -n 64
      00000000 fd 03 00 ea 6f 70 74 65 65 00 00 00 00 00 00 00 |....optee.......|
      00000010 00 00 00 00 00 00 00 00 00 00 00 00 33 2e 37 00 |............3.7.|
      
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • Ubuntu官方发布适配全志D1-H哪吒开发板的镜像

      Ubuntu发行商Canonical近日官方发布了适配全志D1-H哪吒开发板的Ubuntu镜像,旨在为开发者提供稳定的底层框架,让开发者可以专注于核心应用程序的开发。

      官方原文:https://canonical.com/blog/canonical-enables-ubuntu-on-allwinners-nezha-risc-v-boards

      开发者可以直接到Ubuntu官方网站获取镜像文件及安装指南。

      下载链接:https://ubuntu.com/download/risc-v

      微信图片_20220823085813.jpg

      微信图片_20220823090612.png

      此次发布的镜像是Ubuntu Severt 22.04.1版本,该版本的移植适配工作由 Canonical、阿里平头哥以及全志共同完成。

      微信图片_20220823090615.jpg
      D1-H哪吒运行Ubuntu Server

      Ubuntu是最受欢迎的开源操作系统之一,其稳定且可靠的特性吸引大部分开发者选用其作为开发时的首选OS。RISC-V架构在近些年的时间里飞速发展,从低端微控制器到高端服务器级处理器皆可发现用RISC-V架构进行部署的应用。开源软件搭配上开源硬件,让免费且可扩展软硬件的自由度迈上新的台阶。

      D1-H哪吒开发板距发布至今已有超过一年的时间,全志以“开放BSP,融入OS”为核心,建立起了丰富的Linux开发生态,目前开发板已经成功适配了全志自研Tina Linux、Ubuntu、RT-Thread Smart、Debian、Fedora......等数款系统,全志也将携手各厂商、社区、工程师、开源创客等业内伙伴,在开源软硬件适配方向持续深耕,完善开发生态,为开发者提供多元化的选择。

      发布在 MR Series
      q1215200171
      budbool
    • 将开发板设计拆解为10个部分,教你DIY一块F1C200S Linux开发板

      本项目是基于全志F1C200S设计的开源屏幕开发板,设计的目标是提供一个低成本、超迷你且适合Linux开发的平台,特别是针对屏幕接口的支持。

      6CBDD02B-E413-43bc-9E4B-4ED9D59D5D89.png

      项目简介

      开发板板载16M nor flash,主控芯片采用F1C200S,内置64M DRAM。同时附带USB Host接口以及USB type-c口,以及CH340串口转USB芯片,用于开发调试使用。

      BSg0uNlFhrgra5PaDGQ5ixUliEZ9eMlfngXx7wVG.png

      硬件设计

      由于芯片功能繁多,开发板设计也相对复杂,为了教会大家自己DIY开发板,作者将开发板设计的硬件部分按功能拆分为了10个不同的知识点,来对开发板整体设计进行全面介绍和详细讲解电路原理。

      全志F1C200S主控

      全志F1C200s是一款高度集成、低功耗的移动应用处理器,支持高清视频解码,包括H.264、H.263、MPEG 1/2/4等格式,同时还具备音频编解码器和I2S/PCM接口,适用于多媒体音视频设备。

      芯片基于ARM 9架构,并SiP了DDR,这样的配置使其外围电路在设计时会非常简单,非常适合作为入门级的Linux开发板。该部分原理图如下图所示:

      微信图片_20240102141158.png

      • SVREF用于给DRAM提供参考电压,该部分所需电压为VCC_DRAM/2
      • 2VCC_DRAM为DRAM供电,电压为2.5V
      • VCC_IO为GPIO供电,电压为3.3V
      • VCC_CORE为核心供电,电压为1.2V
      • AVCC为模拟供电,该部分非常重要,不接会导致USB Host无法枚举设备,同时需要注意该引脚供电范围为2.5V-3.1V,不可以使用3.3V供电,会导致内部电路损坏。
      • X1为24M晶振,为芯片提供时钟信号,采用22pF负载电容。

      SDMMC接口

      SDMMC接口用于接入Micro SD卡,系统启动时,可以从SD卡中加载U-Boot,内核,RootFS,实现Linux启动。

      微信图片_20240102141209.png

      如上图所示,相关线路说明如下所示:

      • CLK: SDMMC时钟,每个时钟周期传输一个命令或数据位。频率可在0至25MHz之间变化。SD卡总线管理器可以自由产生0至25MHz的频率,没有任何限制
      • CMD: 命令传输线,命令通过该CMD线串行传输
      • D0~D3: 数据通过这些数据线传传输
      • 按照SDMMC规范,SDMMC线路还需要增加10K上拉电阻,如果没有可以会影响数据传输,本原理图中R7-R11即上拉电阻。同时,为了保证电源质量,增加了C22滤波电容
      • SHELL引脚为SDMMC连接器固定引脚,此处接地处理,CD引脚用于探测SD卡是否插入,这一块悬空未使用

      CH340串口转USB

      此电路用于用户连接系统调试中断使用,其功能为将TTL串口转换为USB接口,使得用户可以在电脑中连接该串口进行调试。

      需要注意的是,由于F1C200S的UART0接口(PE0/PE1引脚)被触摸的I2C接口占用,所以本开发板将CH340的串口连接到了F1C200S的UART1(PA2/PA3引脚)上,后续编译U-Boot和内核时我们需要相应的修改代码。

      微信图片_20240102141216.png

      微信图片_20240102141255.png

      如上图所示,该部分除了串口转USB外,还兼顾了系统的供电。

      • 用户通过Type-C线缆连接该调试口后,将同时为开发板供电
      • 板上的5.1K电阻用于双头Type-C线缆识别从机,为其供电
      • 如果R12,R13不焊接会导致使用双头Type-C线时板子没有供电
      • D2为TVS瞬态抑制二极管用于保护PCB板上元件,防止静电击穿原件

      三路DC-DC接口

      该部分主要为主控芯片提供供电,采用SY8089A1AAC,单路最大输出电流2A。

      微信图片_20240102141259.png

      • SVREF用于给DRAM提供参考电压,该部分所需电压为VCC_DRAM/2
      • 2VCC_DRAM为DRAM供电,电压为2.5V
      • VCC_IO为GPIO供电,电压为3.3V
      • VCC_CORE为核心供电,电压为1.2V
      • AVCC为模拟供电,该部分非常重要,不接会导致USB Host无法枚举设备,同时需要注意该引脚供电范围为2.5V-3.1V,不可以使用3.3V供电,会导致内部电路损坏。
      • X1为24M晶振,为芯片提供时钟信号,采用22pF负载电容。

      在该模块中,我们使用了2520电感,与普通的电感相比,体积更小,但是2520电感在DCR(即直流电阻)参数上,会比普通的电感大一点,电感值的计算公式可以参考下方:

      微信图片_20240102141306.png

      • L为计算出的电感容量
      • Vout为降压芯片输出电压
      • L为计算出的电感容量
      • Vin为降压芯片输入电压
      • Fsw为芯片开关频率,SY8089取1.5Mhz,也就是1500000Hz
      • Iout,max为最大输出电流

      如下图所示,本开发板电感值直接参考SY8089数据手册文档,折中后取1.5Uh:

      微信图片_20240102141309.png

      芯片的反馈电阻控制着芯片的输出电压,可以参考下方公式计算:
      微信图片_20240102141313.png

      • Rh为上端分压电阻阻值
      • Rl为下端分压电阻阻值
      • 0.6V指的是芯片的Vfb,也就是反馈电阻
      • Vout即最终的电压输出值
      • 在这里,我们需要确定Rl和Vout,然后将其代入公式,计算出Rh
      • 为了最大限度地减少轻负载下的功耗,最好为 RH 和 RL 选择较大的电阻值。强烈建议 RL 使用 10k 到 200k 之间的值

      AVCC 3V LDO

      该部分用于AVCC 3V供电,使用XC6206 3V LDO,位号为U10,由于较为简单,此处不在详细说明。

      SPI Nor Flash

      Nor Flash为F1C200S芯片提供了第二种启动方式。

      • 上电后,F1C200S首先从内部BROM (芯片内置,无法擦除)启动
      • 首先检查 SD0 有没有插卡, 如果有插卡就读卡 8k偏移数据,是否是合法的启动数据, 如果是BROM 引导结束, 否则进入下一步
      • 第二步:检测SPI0 NOR FLASH是否存在, 是否有合法的启动数据, 如果是BROM 引导结束, 否则进入下一步
      • 第三步:检测SPI0 NAND FLASH 是否存在, 是否有合法的启动数据, 如果是BROM 引导结束, 否则进入下一步
      • 最后,因为找不到任何可以引导的介质,系统会进入usb fel模式,此时可以使用USB烧录

      此处SPI Nor Flash可以同时兼容Nand Flash,不过目前裸机资料基本上都是以SPI Nor Flash为基础,所以此处焊接了W25Q128JVEIQ 128Mbit(16Mbyte)SPI Nor Flash。

      微信图片_20240102141317.png

      • R4为上拉电阻(F1C200S内部也存在上拉电阻,可以不焊),防止未供电时芯片错误写入数据
      • C16为滤波电容
      • SW2为FEL模式开关,将SPI_MISO短路到地后,F1C200S将无法检测到SPI Nor Flash,从而进入USB Fel模式,此时可以松开按键,烧录内容至SPI Nor Flash
      • /WP为SPI Nor Flash保护引脚,低电平有效,有效时无法写入数据
      • /HOLDor/RESET为SPI Nor Flash保持或者复位输入引脚。
      • 最后,因为找不到任何可以引导的介质,系统会进入usb fel模式,此时可以使用USB烧录

      外部IO接口

      此处引出了未使用的IO,用户可连接其他设备,C35为滤波电容,用于保证电源质量,该部分引脚功能可以参考下图(来源:芯片数据手册14/15页):
      微信图片_20240102141320.png

      USB OTG/USB TYPE-C

      该部分连接到了芯片的DP/DM引脚,为芯片的USB接口。

      USB Type-C用于USB Fel模式烧录系统,无供电输入/输出能力。

      USB OTG处可用于连接其他USB设备,带5V输出,当然也可以接双头USB Type-A线缆用于USB Fel模式。

      微信图片_20240102141325.png

      微信图片_20240102141325.png

      需要注意的是,开发板中没有连接ID线(ID线用于识别USB模式),所以在编写设备树时,我们需要强制指定USB模式为主机或从机。

      背光驱动

      该部分用于驱动RGB屏幕背光,标准40Pin RGB屏幕基本采用串联背光,由于本身开发板供电只有5V,所以我们需要使用背光驱动芯片升压到合适的电压,来驱动屏幕背光。

      同时,背光驱动芯片采用恒流控制,可以避免电流过大导致背光LED烧毁,该部分原理图如下所示:

      微信图片_20240102141328.png

      • C19 C20为滤波电容,C19电容的耐压需要特别考虑,一般的RGB屏背光电压基本在18V以上(白光LED压降3V*6串),过低的电容耐压会导致电容损坏
      • BL_CTR为芯片背光控制引脚,此处直接接入了上拉,再开发时可以将BL_CTR引脚接入F1C200S的PWM引脚上,这样可以灵活控制屏幕亮度,同时,有恒流驱动的存在,控制亮度时,背光也不存在明显的频闪
      • L1 为升压电路的电感,按照要求一般取10uh或22uh即可,不需要使用公式详细计算,但是需要注意电流不能超过电感额定电流

      R5为芯片的反馈电阻,用于调节输出的电流,计算公式可参考下方:

      微信图片_20240102141333.png

      此处我们选择20ma,所以R1=0.25/0.020(Ω) = 12.5Ω,就近取12Ω。

      微信图片_20240102141335.png

      如上图,下方说明了LED为2并5串,额定电流为40ma,我们为了保险,选择了20ma,亮度会有所损失。

      40Pin RGB/触摸接口

      此处参考屏幕数据手册即可,由于F1C200S只支持RGB565,RGB666,此处使用RGB666,屏蔽了RGB三色的低2位,这样最终色彩影响比较小,同时,F1C200S内置色彩抖动,可以更加接近RGB888效果。

      其中需要注意的是,CTP_SDA/CTP_SCL最好加上拉电阻,此处选用了内部上拉,所以并没有加电阻,该部分原理图如下所示:

      微信图片_20240102141337.png

      开发环境搭建

      使用VSCode的DeviceTree插件,我们可以实现设备树文件的代码高亮,编辑c语言代码。

      安装VSCode后,我们开始安装设备树插件,再商店中搜索DeviceTree插件,点击安装安装即可:

      微信图片_20240102141344.png

      同理,推荐读者同时安装中文汉化,搜索CN,参考下图安装即可,安装后按照要求重启VSCode即可使用。

      微信图片_20240102141347.png

      打开安装好的Ubuntu 18.04虚拟机,将需要分区的SD卡插入电脑USB口,并右键点击VMware右下角的USB存储器图标,点击连接,将SD卡连入虚拟机。具体操作过程如下图所示:

      微信图片_20240102141351.png

      点击桌面左下角图标,进入所有应用,然后搜索GPartd,可参考下图:

      微信图片_20240102141354.png

      此时需要输入密码,输入用户密码,提权到root用户,如下图所示:

      微信图片_20240102141358.png

      接着在右上角选择我们需要格式化的SD卡,默认为/dev/sda,这个是我们虚拟机的系统盘,我们需要切换到SD卡,此处一定要小心,sdb不一定是我们的sd卡。

      完成切换后,右键点击如图所示位置,点击“卸载”,接着点击“删除”按钮删除SD卡中原有分区,最后点击确定,确认删除,具体过程可以参考下图。

      微信图片_20240102141401.png

      微信图片_20240102141404.png

      微信图片_20240102141406.png

      接着开始创建分区,首先创建boot分区,用于u-boot读取设备树、内核等文件,我们需要在分区前方空出一定的空间,用于u-boot以及SPL程序存放,如下图所示,首先点击左上角按钮,创建新分区,然后按照下图创建boot分区。

      微信图片_20240102141408.png

      微信图片_20240102141411.png

      此处为U-Boot以及SPL预留了1Mib的空间,完全足够存放这些程序。

      接着创建rootfs分区,我们将剩下的空间全部作为rootfs,文件系统选择ext4,如下图所示:

      微信图片_20240102141413.png

      最后点击保存,确认后生效,拔出SD卡备用,操作可参考下图:

      微信图片_20240102141415.png

      开源资料获取

      作者适配的U-Boot目前使用了master分支的U-Boot并给出了移植指南。由于后续master分支代码可能会存在更新,所以移植指南使用了最近的一个U-Boot版本来指导复刻打开发者进行修改和配置,编译出自己的U-Boot。

      微信图片_20240102152646.gif

      本项目所有资料均已开源,软硬件都开源了,其中软件开源了:UBoot、Kernel、Buildroot:测试镜像下载地址等……想获取资料自己DIY学习的伙伴可以前往获取

      https://oshwhub.com/fanhuacloud/f1c200s_lcd_backup

      发布在 爱搞机专区
      q1215200171
      budbool
    • 回复: 【素材汇总】R128素材汇总

      R128开发板4.jpg

      微信图片_20230406175547.jpg
      微信图片_20230406175536.jpg
      微信图片_20230406175553.jpg
      微信图片_20230406175550.jpg

      发布在 公告
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 低功耗蓝牙BLE断开连接错误码和分析?

      1、问题背景
      硬件:R系列芯片,XR806
      软件:Tina

      2、问题简述
      说明:该FAQ旨在列出和分析低功耗蓝牙BLE常见的断开连接原因,方便排查连接过程、连接之后和绑定过程中的断开连接问题。

      3、问题分析和解决办法
      蓝牙低功耗BLE连接时和连接后和绑定过程中可能会有不同原因造成蓝牙断开,下面是比较常见的几种断开错误码和原因分析。
      65BC6FC9-BABB-45fd-BA2E-C77F9E4B1FE5.png

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 回复: 新 SDK 平台下载 D1-H/D1s SDK

      @hongyancl 不能,可以下D1-H的SDK然后打补丁给T113用

      发布在 MR Series
      q1215200171
      budbool
    • 回复: 梦回2004!我用全志V3s做了个成本100元,功能媲美MP4的随身终端

      @jordonwu 可以去文末链接下问问作者

      发布在 爱搞机专区
      q1215200171
      budbool
    • 【素材汇总】R128素材汇总

      R128ZB.png

      R128ZB.png

      发布在 公告
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 XR806如何添加本地音频到flash?

      问题背景
      XR806的文件管理系统是littlefs或spifs,不像fatfs可以直接进行文件传输,有客户放映不清楚如何通过文件管理系统调用音频文件。

      问题描述
      XR806SDK中的audio_demo找不到本地mp3等音频文件。

      问题分析

      • 因为XR806的文件管理系统是littlefs或者spifs,所以需要在PC本地把文件打包成littlefs文件系统格式,否则无法识别。打包工具是SDK下的tools/fs_img_tools/mklittlefs。
      • 上一步打包好的文件,如果通过“section”的方式打包进img镜像会有64byte的偏移,所以需要用“raw_bin”的方式进行打包。

      解决方法

      打包音频文件
      新建一个文件夹,如data(名称随意),并把目标音频文件存放仅该目录下,值得注意的是因为audio_demo中默认播放的的是music文件夹下的音频文件,所以音频文件也必须放在music文件夹下。

      .
      ├── data
      │   └── music
      │       └── 1.mp3
      └── mklittlefs
      

      打包该文件夹使用如下命令

      ./mklittlefs -c data/ -d 0 -b 4096 -p 256 -s 524288 lfs.bin
      

      -c后接目标路径。
      -d后接debug等级,默认为0,不用修改。
      -b后接block的大小,littlefs默认为4096,一般情况下不用修改。
      -p后接page大小,默认为256,不用修改。
      -s后接littlefs镜像大小,和在make menuconfig中的配置必须一致。
      lfs.bin是生成的镜像文件名。名称随意,但一般是.bin后缀。

      make menuconfig配置
      进入图形化界面配置,并选中filesystem support后选项配置如下。推荐勾选上flash filesystem image pack support,编译代码后会自动把lfs.bin打包到镜像,否则只能在phoenixMC的调试界面中擦除flash地址1572864(0x18000)后的内容,并手动把lfs.bin写进flash。其中步骤1所说的镜像大小524288就是由2048*1024-1572864而来。

      --- filesystem support
      [*]   flash filesystem image pack support
      FileSystem Type Select (LittleFS)  --->
      (1572864) little filesystem start address
      (4096) little filesystem block size
      (128) little filesystem block count
      

      修改工程cfg文件配置
      把前面打包好的lfs.bin复制到project/demo/audio_demo/image/xr806目录下,并修改目录下的image.cfg。

      {
          "magic" : "AWIH",
          "version" : "0.5",
          "image" : {"max_size": "1532K"},
          "section" :[
      		{"id": "0xa5ff5a00", "bin" :"boot_40M.bin",	"cert": "null",	"flash_offs": "0K",	"sram_offs": "0x00230000", "ep": "0x00230101", "attr":"0x1"},
      		{"id": "0xa5fe5a01", "bin" :"app.bin",	"cert": "null",	"flash_offs": "71K",	"sram_offs": "0x00201000", "ep": "0x00201101", "attr":"0x1"},
      		{"id": "0xa5fd5a02", "bin" :"app_xip.bin",	"cert": "null",	"flash_offs": "104K",	"sram_offs": "0xffffffff", "ep": "0xffffffff", "attr":"0x2"},
      		{"id": "0xa5fa5a05", "bin" :"wlan_bl.bin",	"cert": "null",	"flash_offs": "1075K",	"sram_offs": "0xffffffff", "ep": "0xffffffff", "attr":"0x1"},
      		{"id": "0xa5f95a06", "bin" :"wlan_fw.bin",	"cert": "null",	"flash_offs": "1078K",	"sram_offs": "0xffffffff", "ep": "0xffffffff", "attr":"0x1"},
      		{"id": "0xa5f85a07", "bin" :"sys_sdd_40M.bin",	"cert": "null",	"flash_offs": "1103K",	"sram_offs": "0xffffffff", "ep": "0xffffffff", "attr":"0x1"},
      		{}
          ],
          "raw_bin" :[
      		{"bin" :"lfs.bin",	"flash_offs": "1536K"},
      		{}
          ]
      }
      

      编译完成后编译烧录即可。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 回复: 1月全志芯片开源项目分享合辑

      @codedogejack123 有的,已经编辑上了

      发布在 爱搞机专区
      q1215200171
      budbool
    • 回复: 【素材汇总】V853素材汇总

      V853扣.png
      V853b kou.png
      微信图片_20220523110309.png

      发布在 公告
      q1215200171
      budbool
    • 【FAQ】全志R329如何使用audiocodec如何减少snd_pcm_open的耗时

      问题背景
      客户在使用audiocodec进行声音播放时,发现调用snd_pcm_open所用的时间达400多ms,客户希望能减少耗时

      开发环境
      硬件:R328
      软件:Tina
      内核: Linux-4.9

      问题分析
      客户调用snd_pcm_open时,传入的PCM NAME是使用了dmix插件的,dmix插件的功能是可以让多个应用同时访问音频通道,实现声音同时输出的效果。

      当不使用任何插件时(-D hw:audiocodec,0),调用snd_pcm_open会马上获取对应的pcm句柄,获取成功后再配置音频通路和寄存器,而当使用dmix插件时,调用snd_pcm_open会先解析插件中的参数,再根据参数配置音频通路和寄存器,通过dapm打开功放和操作DAC寄存器,之后再获取对应的pcm句柄,执行的逻辑更多。

      当打开功放和操作DAC寄存器时,为了防止pop音的产生,驱动中加上了160ms + 2*30ms的sleep(乘以2是因为有左右声道),这里的sleep就是耗时产生的地方

      2197a6e39b014a74bb711c8e81cd5140.jfif e0ae2092f868454187ca18be8081b7cd.jfif

      解决方案

      • 保证没有pop音的前提下,可以在dts中减少pa_msleep的值,这个值是操作功放的使能位后产生的延迟,对应上图的spk_cfg->pa_msleep

      2a4ac0ca6abb46e4b764d0df99a6a3d8.jfif

      • 调整内核printk打印级别
      snd_pcm_open,2646,s:0.439500
      Used Time:0.439527                                 ----> 调整前
      
      snd_pcm_open,2646,s:0.258538
      Used Time:0.258548                                 ----> 调整后
      
      • 删去内核不必要的打印或者用ftrace代替,调试发现一条内核打印耗时约4ms,过多的打印会严重影响性能
      • 列表保证没有pop音的前提下,可以在驱动程序中直接减少sunxi_codec_playback_event的msleep值,因为这个sleep是为了避免操作DAC后出现尖刺导致的pop音,因此此方式应为最低优先级
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 4月全志芯片开源项目分享合辑

      FunnyPi-全志T113-S3卡片电脑

      作者:flose

      开源项目地址:https://oshwhub.com/flose/funnypi-quanzhi-t113-s3-card-computer

      QQ图片20240422143001.jpg

      FunnyPi-T113是一款基于全志T113-S3/D1S处理器的完全开源多功能开发板,设计FunnyPi最初的目的是想满足日常学习,结合T113高效能和低功耗的特点,来满足做语音助手,智能家居屏幕、桌面摆件屏、博客服务器等嵌入式应用的开发需求。

      FunnyPi开发板内置了丰富的外设接口,包括USB、GPIO、I2C、SPI、UART等,方便用户连接各种传感器、执行器和其他外围设备,同时板载了标准RGB接口、WiFi模组、PMIC芯片、串口转USB芯片等,方便开发者进行DIY开发。

      此外,这款开发板适配全志Tina-Linux,支持快启,最重要的一点是,本开发板所有阻容使用0603封装且将绝大部分元件放在了正面,非常方便手焊!

      16c9eQ4qnf36ZZwVhonjgcrCiTYRYLIlFuOiLN19.jpeg

      iK0BNk6CsKiRrz555Dzscby3A42ieA724vQZqj2s.png YbBaB7i6rsOa61ew7xYgtBvtiUvdNmbzRNrcNB76.png

      基于全志T113的串口助手

      作者:huerli

      开源项目地址:https://oshwhub.com/huerli/chuan-kou-zhu-shou

      9c9pQAKJxym0KrJ5YV1Isvg4osoiRnrmivhAlJU3.png

      本项目是基于全志T113-S3制作的无线串口调试器,上位机由Qt制作的串口助手客户端、下位机数据采集转发装置组成,配有无线WiFi蓝牙模组,可以对下位机采集到的数据显示以及对于数据绘制波形。

      上位机信号的转换使用的是CH343P,对串口3输出TTL信号的调试信息转换成USB差分信号,当然也可以不焊CH343P,用TTL转USB工具直接于电脑连接。电源管理方面使用的是IP5306来进行锂电池充放电管理,并由单节4.2V锂电池进行供电。屏幕则是使用比较常见的十寸RGB565,同样支持RGB666,触摸IC使用GT911。

      上位机由Awboot+Linux+Buildroot组成,作者本人开源了交叉编译器、Awboot源码、串口助手qt界面源码等内容,并详细介绍了开发环境搭建及qt界面配置等教程。

      63C0E5C2-E81F-4067-833D-F27503A6E822.png F6D1633D-D40F-44be-A70A-ADB64596873F.png

      T113智能家居86盒(圆屏版)

      作者:萨纳兰的黄昏

      开源项目地址:https://oshwhub.com/planevina/t11386-box-revision

      D55E0AA0-9FFA-4373-A24D-20A093BF9C6F.png

      如上,你所见到的这款圆滚滚的小玩意,就是魔改了一款在前几期的文章中我们所介绍过的,一款方形的T113-S3智能家居86盒,原项目因其验证过的原理图和PCB(√),可初始化的屏幕(√),详尽的SDK和保姆级的部署教程(√),从而受到了不少开发者的关注,其中也包括一些爱整活的小伙伴。

      萨纳兰的黄昏在86盒的原作者FanHuaCloud大佬加持下,又给86盒挖了个新坑,为了解决之前所驱动的圆屏只能播放MJPEG并且帧率较低的尴尬问题,集圆屏加一体化驱动板+外壳+炫酷LVGL UI于一身的圆形86盒横空出世,并命名其为——T113太极派。

      目前的版本是插电使用的超薄版本 ,后续可能会增加带扩展版的支持电池的充电版本,其最主要的特点是作者为这款圆形的太极派专门给它建模做了一个极其轻薄的CNC外壳,触摸屏直径是71.8mm,外壳直径为74mm。树脂版外壳厚度为13mm,CNC版外壳厚度为10mm。

      微信图片_20240410113945.png QQ图片20240411172645.jpg

      T113 MIPI触摸屏核心板

      作者:搞事情团队

      开源项目地址:https://oshwhub.com/gao-shi-qing-tuan-dui/t113_mipi

      YUc2yqWqwpXR9Qk3qxoMJqC2w8PvwKQwCTSn4Qks.jpeg

      此核心板尺寸小巧,板载资源极其丰富,元件均在一面,背面可直接与大显3寸MIPI液晶屏通过FPC排线相连。板载CH340,MPU6050,HUB,NANDFlash,麦克风,XR829-WIFI。仅用一根Typc线便可调试此核心板,非常方便。调试串口,ADB接口,音频接口及USB,GPIO均已用引出。扩展性极强。板载资源均已调试通过。

      F07A2075-0266-46e0-B2E3-18C7F8AE09DB.png 98082955-4962-43a8-8BC2-6F6F7401C352.png

      发布在 爱搞机专区
      q1215200171
      budbool
    • 回复: 【素材汇总】V853素材汇总

      产品包装清单
      包括:
      V853主板 *1
      7寸屏幕及转接板 *1
      双摄像头模组 *1
      亚克力支架 *1
      Type-C USB数据线 *1
      串口线 *1
      电源适配器 *1
      小喇叭 *1
      包装盒 *1
      V853开发板套件.jpg

      发布在 公告
      q1215200171
      budbool
    • 【FAQ】全志R328如何进入monitor模式

      【问题背景】
      硬件:R328+ Wi-Fi模组(XR829)
      软件:Tina
      说明:该FAQ旨在记录在Tina系统上XR829如何进入monitor模式

      【问题简述】
      我们知道xradio的xconfig配网方式,会自动切到monitor模式,那么驱动如何手动设置进入monitor模式呢?

      【问题分析】
      1.既然xconfig配网可以进入monitor模式,那么直接分析代码就可以找到对应的操作。
      2.可以通过添加打印来跟踪xconfig的调用流程。

      echo 0xff > /sys/kernel/debug/xradio_host_dbg/dbg_common
      echo 0xff > /sys/kernel/debug/xradio_host_dbg/dbg_sta
      

      【解决方法】

      手动设置进入monitor模式:

      insmod /system/vendor/modules/xradio_wlan.ko  //加载xr829.ko
      ifconfig wlan0 down                           //可能系统起来会默认进入sta模式,所以先down掉
      iw wlan0 set type monitor                     //最关键的,设置进入monitor模式
      iw wlan0 info                                 //获取wlan0网卡信息
      ifconfig wlan0 up                             //up wlan0
      iw wlan0 set channel 6                        //设置信道
      echo 0xffff,0xffff > /sys/kernel/debug/ieee80211/phy0/xradio/parse_flags   //打开收发帧调试,可以分析monitor模式
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 成本400元,DIY一个高刷新率热成像相机

      在市面上开源的热成像作品中,有一部分颜值高,但分辨率太低;也有一部分把分辨率提高了,但使用起来却不太流畅。

      基于此,作者本人结合二者的优势,设计了一款热成像相机——LiThermal,成本算下来只要400出头,还具备了万全的功能。

      ac71b06c-eeb3-47df-920b-d328846fac9d-image.png

      • 拍照
      • 录像
      • 查看相册
      • 查看温度最大值、最小值、中心值
      • 温度统计图
      • 修改调色板
      • 重定向后台管理页面,电脑访问

      这款热成像相机不仅拥有高分辨率及丝滑流畅的拍摄,在主控全志T113的加持下,UI界面的几乎所有动画都能达到90Hz刷新率,并支持随意的动画打断,最重要的是,作者将热成像相机的软硬件全部开源了出来!

      开机界面.gif
      热成像相机开机动画演示

      温度图谱.gif
      PCB温度检测演示

      远距相机检测.gif
      远距相机检测演示

      热成像相机功能

      相机不仅支持高清拍照功能,而且在拍照的同时能够即时捕捉并显示全屏范围内的温度数据,为用户提供直观的温度分布视图,拍摄后的照片和视频都可以在相册中查看。

      相册.gif

      此外,该设备还提供了温度数据的最大值、最小值以及中心值的查看功能,帮助快速识别温度异常区域,为了更直观地展示温度变化趋势,设备还贴心配备了温度统计图功能。

      8d387355-620c-4aec-9eb3-5a8e20156125-image.png

      为了满足不同用户的需求,设备还支持自定义调色板,根据个人偏好或特定应用场景调整色彩显示方案,重定向后台管理页面的功能,可以通过电脑访问后台管理系统,实现更高级的设置和数据管理操作。

      相机设置1.gif

      相机设置.gif

      系统配置

      作者直接为相机在全志Tina Linux系统上基于LVGL8设计一套全新的UI界面,并顺利的在2.4寸的320x240分辨率TFT LCD屏幕上以最高94.3 Hz的刷新率流畅运行。

      在热成像方面,该设备表现尤为突出,刷新率达到了25Hz,能够实时捕捉温度变化,测温范围也覆盖到0-106.4 ℃,零下的条件下作者未进行测试,但问题不大,基本满足了多种应用场景的需求。传感器方面,设备采用了160*120分辨率的传感器,确保了温度数据的精确捕捉。

      • 主控:全志T113
      • 存储:SIP 128MB
      • 屏幕:2.4寸 TFT LCD, 320x240 @ 94.3 Hz
      • 热成像刷新率:25Hz
      • 测温范围:0-106.4 ℃ (零下没试过,据说可以测到-20 ℃)
      • 传感器分辨率:160*120
      • 操作系统:全志Tina Linux,基于OpenWRT
      • GUI:LVGL8

      动画打断.gif

      开源资料&复刻

      本文与热成像相机相关的所有内容均转载自原作者本人立创开源硬件平台的工程页面,软硬件资料均开源,感兴趣的小伙伴可以复制下方链接或者戳文末的“阅读原文”阅读了解。

      7d705dbd-f88f-44ca-bfe3-d3181df94a36-image.png

      项目作者:小李电子实验室
      项目名称:热成像相机

      热成像相机软硬件开源:https://oshwhub.com/lxu0423/lithermal-thermal-imaging-camera
      Github开源链接:https://github.com/diylxy/LiThermal
      视频版介绍:https://www.bilibili.com/video/BV1e4xeeCEGL

      以上链接中包含硬件设计文件,程序源代码和编译工具链,可以根据这些资料完整复刻本作品,达到视频中的效果。

      复刻注意事项:本作品难度较大,想要完整复刻需要能够焊接0402元件和0.3毫米间距的QFP引脚,并且需要有一定Linux系统使用经验和计算机网络基础,请做好心理准备。

      焊接.gif

      发布在 爱搞机专区
      q1215200171
      budbool
    • 回复: 【素材汇总】V853素材汇总

      侧.jpg
      斜.jpg
      斜V853扣.png
      kuangjia.jpg

      • Arm Cortex-A7 + RISC-V E907 + 1T NPU 高性能算力组合
      • 512MB DDR3 + 8G eMMC
      • 高清双目摄像头 + 高清屏幕
      • WiFi + 蓝牙 + 以太网
      • USB/UART/SD CARD/MIC/Line-in/SPEAKER/ISP/MIPI/TP/BAT等丰富接口
      发布在 公告
      q1215200171
      budbool
    • 【FAQ】全志R329如何利用wpa_cli设置地区代码?

      问题背景

      硬件:R328+ Wi-Fi模组(XRADIO)
      软件:Tina3.0及以上
      说明:该FAQ旨在记录XRADIO驱动常见的调试Tips。与具体驱动相关,具有一般性。

      问题简述

      客户需求,如何获取和设置地区代码?

      问题分析

      地区码:表示现有的国家、独立机构或特殊地理政治区域的名称代码。

      区别于

      移动网络代码:是与移动设备国家代码(Mobile Country Code,MCC)(也称为“MCC / MNC”)相结合,以用来表示唯一一个的移动设备的网络运营商。这些运营商可以是使用的GSM/LTE、CDMA、iDEN、TETRA和通用移动通讯系统的公共陆基移动网亦或是卫星网络。

      当前xr829驱动并没有透出接口用来获取和设置地区代码。

      解决方法

      借用wpa_cli工具来获取和设置:

      root@TinaLinux:/# wpa_cli -i wlan0 -p /etc/wifi/sockets set country US
      OK
      root@TinaLinux:/# wpa_cli -i wlan0 -p /etc/wifi/sockets get country
      US
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【XR806开发板试用】shell脚本一键配置XR806开发环境

      本文是我基于官方文档整理的最新XR806开发环境搭建步骤,所有步骤都合并为几段shell脚本,可以直接复制粘贴执行。

      我的开发环境是基于Ubuntu 20.04的,目前XR806的OpenHarmony代码版本是1.0.1_release;

      每段脚本下方的注都是容易遇到坑的地方,请大家遇到问题的时候多注意。

      准备repo命令行工具

      [ "$(id -u)" == "0" ] && alias sudo=
      
      sudo apt update
      sudo apt -y install curl git python3 python3-pip
      ln -s /usr/bin/python3 /usr/bin/python
      
      # 设置pip源为阿里镜像站
      pip config set global.index-url http://mirrors.aliyun.com/pypi/simple/
      pip config set global.timeout 120
      pip config set global.trusted-host mirrors.aliyun.com
      
      # 下载repo工具
      [ -e ~/bin/ ] || mkdir ~/bin/
      curl -s https://gitee.com/oschina/repo/raw/fork_flow/repo-py3 > ~/bin/repo
      chmod +x ~/bin/repo
      pip install requests # 码云的 repo 依赖这个pip包
      echo 'export PATH=$PATH:~/bin' | tee -a ~/.bashrc
      

      注:

      repo命令行工具本身是一个python脚本,所以需要先安装python3;
      这里的repo为码云提供的版本,REPO_URL的值他们已经修改好了,不需要再修改;
      他们修改的代码依赖了requests包,因此步骤中有配置pip源和下载requests包;

      下载ARM交叉编译工具链

      # 下载 gn 压缩包
      GN_TARBALL=gn-linux-x86-1717.tar.gz
      GN_URL_PREFIX=https://repo.huaweicloud.com/harmonyos/compiler/gn/1717/linux
      curl $GN_URL_PREFIX/$GN_TARBALL > $GN_TARBALL
      
      # 下载 ninja 压缩包
      NINJA_TARBALL=ninja.1.9.0.tar
      NINJA_URL_PREFIX=https://repo.huaweicloud.com/harmonyos/compiler/ninja/1.9.0/linux
      curl $NINJA_URL_PREFIX/$NINJA_TARBALL > $NINJA_TARBALL
      
      # 下载clang 9.0 压缩包
      CLANG_TARBALL=llvm-linux-9.0.0-36191.tar
      CLANG_URL_PREFIX=https://repo.huaweicloud.com/harmonyos/compiler/clang/9.0.0-36191/linux
      curl $CLANG_URL_PREFIX/$CLANG_TARBALL > $CLANG_TARBALL
      
      # 下载 gcc-arm-none-eabi-10-2020-q4-major 压缩包
      GCC_TARBALL=gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2
      GCC_URL_PREFIX=https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/10-2020q4
      curl $GCC_URL_PREFIX/$GCC_TARBALL > $GCC_TARBALL
      
      [ -e ~/tools/ ] || mkdir ~/tools/
      
      # 解压gn和ninja压缩包
      tar -C ~/tools/ -xvf $GN_TARBALL
      tar -C ~/tools/ -xvf $NINJA_TARBALL
      echo 'export PATH=$PATH:~/tools:~/tools/ninja' | tee -a ~/.bashrc
      
      # 解压clang压缩包
      tar -C ~/tools/ -xvf $CLANG_TARBALL
      echo 'export PATH=$PATH:~/tools/llvm/bin' | tee -a ~/.bashrc
      
      # 解压gcc压缩包
      tar -C ~/tools/ -xvf $GCC_TARBALL
      echo 'export PATH=$PATH:~/tools/gcc-arm-none-eabi-10-2020-q4-major/bin' | tee -a ~/.bashrc
      
      source ~/.bashrc # 生效环境变量
      

      注:

      全志在线的步骤描述里面没有写需要下载gn/ninja/clang,但是后续的hb build命令会依赖这几个命令行工具;

      下载OpenHarmony和XR806代码

      # 配置你的git作者信息
      git config --global user.email "yourname@example.com"
      git config --global user.name "Your Name"
      
      # 创建目录
      [ -e ~/xr806_openharmony ] || mkdir ~/xr806_openharmony
      cd ~/xr806_openharmony
      
      # 初始化清单仓
      repo init -u https://gitee.com/openharmony/manifest.git -b OpenHarmony_1.0.1_release --no-repo-verify
      
      # 同步所有代码仓到本地
      repo sync -c
      repo forall -c 'git lfs pull'
      
      # 下载 xr806 的 device和vendor 仓到 device/xradio和vendor/xradio目录
      git clone https://gitee.com/XR806/devboard_device_allwinner_xr806.git device/xradio/
      git clone https://gitee.com/XR806/devboard_vendor_allwinner_xr806.git vendor/xradio/
      

      注:

      最后的两个仓是我从uncleli克隆的两个代码仓,因为全职在线文档中openharmony-sig组织下的代码仓暂设置访问权限为私有了,组织外部人员暂时无法访问;

      编译XR806的OpenHarmony代码

      配置项目
      第一次编译前需要执行“配置项目”的步骤。主要用于生成部分Kconfig配置和Makefile代码片段,后续编译不再需要执行这里的步骤。

      sudo apt install -y libncurses5-dev  # menuconfig 依赖的ncurses库
      
      # 进入SDK目录。
      cd device/xradio/xr806/xr_skylark/
      
      # 复制配置文件。
      cp project/demo/audio_demo/gcc/defconfig .config
      
      # 使用图形化界面确认配置。
      make menuconfig
      # 执行make menuconfig后,按方向键选择save保存后,选择exist退出即可。
      
      # 清除过程文件。
      make build_clean
      
      # 生成静态库已经自动生成头文件。
      make lib -j
      
      # 返回根目录。
      cd -
      

      安装hb命令
      第一次编译前,需要安装hb命令。后续的编译不再需要执行这里的命令。

      cd ~/xr806_openharmony
      cd build/lite
      pip install prompt_toolkit==1.0.14
      python setup.py install --user
      echo 'export PATH=$PATH:~/.local/bin' | tee -a ~/.bashrc # 将hb命令所在目录加到PATH环境变量
      source ~/.bashrc # 生效环境变量
      

      编译代码

      hb set  #回车,并选择wifi_skylark,第一次编译需要执行这个命令,执行完成后会生成ohos_config.json文件
      hb build -f # 编译代码
      

      烧录镜像

      运行device\xradio\xr806\xr_skylark\tools目录下的phoenixMC_v3.1.21014b.exe;
      编译完的镜像文件在device\xradio\xr806\xr_skylark\out目录下;
      烧录软件的使用参考全志在线的文档:固件烧录 - XR806 (aw-ol.com)
      烧录需要注意:记得勾选“硬件复位烧写模式”,否则进度到92%就会报错。

      观察日志

      XR806 OpenHarmony默认的串口配置为:波特率115200,无校验,8位数据位,1位停止位。

      使用PuTTY查看启动日志,需要在的Terminal配置中,勾选“Implicit CR in every LF”和“Implicit LF in every CR”这两个选项。

      参考链接

      参考了以下链接:

      全志在线XR806的文档:https://xr806.docs.aw-ol.com/ (aw-ol.com)
      码云临时代码仓:uncleli/devboard_device_allwinner_XR806 (gitee.com)

      文章转自极术社区:https://aijishu.com/a/1060000000291606
      作者:xusiwei1236

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 回复: 下载源码时卡在这里不动,请问下大佬必须要升级到lv2才能下载吗

      @xieminghao sudo git config --global credential.helper store

      发布在 代码下载问题专区
      q1215200171
      budbool
    • 【FAQ】全志V853芯片 Tina获取各个分区编译好后的分区镜像文件[脚本]

      [需求描述]

      做SDK对接过程作,应用开发有可能需要自己制作升级固件(OTA,烧录)。这就需要从SDK中找出编译好的各个分区镜像文件。本FAQ提供一个脚本,将各个分区已经编译好的镜像分区给拷贝到一个固定地方。

      [脚本安装方法]

      将附件中内容按照目录替换到sdk的相应目录当中。
      目录:scripts/.hooks (如.hooks 目录不存在,在需要创建)

      scripts/.hooks 
          |_post-pack
          |_pack_script
              |_aw_pack.sh
      

      [使用方法]

      安装完成后,直接按正常使用那样,执行pack 脚本进行打包,打包成功后回有打印:

      /home/v833-sdk/out/v831_pro_ipc/image/…/aw_pack_src

      [工具生成的目录介绍]

      ├── aw_pack.sh     #执行该脚本即可再进行打包,并输出在当前目录的out目录 
      ├── config              #打包的配置文件
      ├── image              #各种分区镜像文件,可以替换,请勿改名
      │   ├── boot0_nand.fex            #boot0 的nand镜像
      │   ├── boot0_sdcard.fex         #boot0 的SD卡镜像
      │   ├── boot0_spinor.fex          #boot0 的spinor镜像
      │   ├── boot.fex                        #内核镜像
      │   ├── boot_package.fex        # uboot打包镜像
      │   ├── boot_package_nor.fe   # uboot 在spinor方案上的打包镜像
      │   ├── env_nor.fex                  #env环境变量镜像
      │   ├── rootfs.fex                      #rootfs 镜像
      │   ├── sunxi.fex                       #GTP分区表
      │   └── other.fex                       #其他分区镜像
      ├── other        #打包所需的其他文件 
      ├── out           #执行aw_pack.sh脚本后输出的目录
      ├── tmp          #临时目录,用于打包时使用
      └── tools        #打包时需要的linux 工具
      

      脚本文件:aw_pack_src.tar.gz

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【XR806开发板试用】基于XR806的鸿蒙舵狗

      一、狗子外观图

      2097905114-61d872ef014d5.jpg

      二、PCA9685开发流程

      狗子身上有12个舵机,一条腿接3个舵机,连接到一个pca9685舵机驱动上,舵机驱动通过I2C与XR806通信,XR806有两个I2C接口,我主要是用第1个(B14, B15),通过控制PCA9685上的寄存器来简介控制舵机。

      pca9685参数:

      • I2C接口,支持高达16路PWM输出,每路12位分辨率(4096级);
      • 内置25MHz晶振,可不连接外部晶振,也可以连接外部晶振,最大50MHz;
      • 支持2.3V-5.5V电压,最大耐压值5.5V,逻辑电平3.3V;
      • 具有上电复位,以及软件复位等功能。

      引脚图示:
      772656491-61d8730b90511.jpg
      3600335544-61d8737330422.jpg

      1. pca初始化

      首先要进行i2c初始化:

      i2c_init(i2c_id);
      

      导入相关库:

      #include "driver/chip/hal_i2c.h"
      #define i2c_id 1 # 使用第1个i2c
      

      i2c初始化函数:

      void i2c_init(unsigned int id){
              I2C_InitParam initParam;
              initParam.addrMode = I2C_ADDR_MODE_7BIT;
              initParam.clockFreq = 40000;
              if (HAL_I2C_Init(id, &initParam) != HAL_OK) {
                      printf("i2c init fail!\n");
                      while(1);
              } else {
                      printf("i2c init success!\n");
              }
      }
      

      主要是调用HAL_I2C_Init函数对第1个i2c接口进行初始化。

      初始化pca9685:

      pca9685_init(60);
      

      pca9685_init函数:

      void pca9685_init(float hz) {
              pca_write(pca_mode1, 0x0);
              pca_setfreq(hz);
              OS_MSleep(500);
      }
      

      2. pca操作

      1. pca9685写寄存器

      void pca_write(uint8_t reg_addr, uint8_t data) {
              uint8_t buf[1];
              buf[0] = data;
          HAL_I2C_Master_Transmit_Mem_IT(i2c_id, pca_adrr, reg_addr, I2C_MEMADDR_SIZE_8BIT, buf, 1);
      }
      

      2. pca9685读寄存器

      uint8_t pca_read(uint8_t reg_addr) {
              uint8_t buf[1];
          HAL_I2C_Master_Receive_Mem_IT(i2c_id, pca_adrr, reg_addr, I2C_MEMADDR_SIZE_8BIT, buf, 1);
          return buf[0];
      }
      

      3. pca9685设置频率

      void pca_setfreq(float freq) {
              uint8_t prescale,old_mode,new_mode;
              double prescaleval;
              freq *= 0.92;
              prescaleval = 25000000;
              prescaleval /= 4096;
              prescaleval /= freq;
              prescaleval -= 1;
              prescale =(uint8_t)(prescaleval + 0.5f);
              old_mode = pca_read(pca_mode1);
              new_mode = (old_mode & 0x7F) | 0x10;
              pca_write(pca_mode1, new_mode);
              pca_write(pca_pre, prescale);
              pca_write(pca_mode1, old_mode);
              OS_MSleep(2);
              pca_write(pca_mode1, old_mode | 0xa1);
      }
      

      这里的代码不像读函数和写函数一样好理解,主要是一般情况下,在用pca9685内置晶振,为25MHZ,通过配置PRE_SCALE寄存器进行配置。如果在舵机控制中,采用内置晶振,取osc_clock=25000000,update_rate=50(舵机控制频率50Hz)。

      而且在写PRESCALE寄存器的时候,要先设置为Sleep模式,也就是将mode1寄存器的SLEEP标志位设置为1,具体可参考我上面写的代码。

      3601331443-61d873a4685d2.jpg

      3. pca设置pwm

      void pca_setpwm(uint8_t num, uint32_t on, uint32_t off) {
              pca_write(LED0_ON_L+4*num,on);
              pca_write(LED0_ON_H+4*num,on>>8);
              pca_write(LED0_OFF_L+4*num,off);
              pca_write(LED0_OFF_H+4*num,off>>8);
      }
      

      pwm通道寄存器如下图:
      2805468644-61d873b3717df.jpg
      由图可知,对于每一个通道,有4个寄存器,在设置PWM占空比的时候,首先配置舵机的示例如下图所示(ON < OFF的情况):
      1767587282-61d873cf4d1f6.jpg

      狗子运行图:
      3028832161-61d873f195054.gif
      3982454042-61d873dedddbd.gif

      核心代码:

      #include <stdio.h>
      #include "ohos_init.h"
      #include "kernel/os/os.h"
      
      // #include "iot_i2c.h"
      #include "driver/chip/hal_i2c.h"
      #include "iot_errno.h"
      #include "math.h"
      
      #define i2c_id 1
      #define pca_adrr 0x40 // pca9685设备地址
      
      #define pca_mode1 0x0
      #define pca_pre 0xFE
      
      #define LED0_ON_L 0x6
      #define LED0_ON_H 0x7
      #define LED0_OFF_L 0x8
      #define LED0_OFF_H 0x9
      
      static OS_Thread_t g_main_thread;
      
      void pca_write(uint8_t reg_addr, uint8_t data) {
              uint8_t buf[1];
              buf[0] = data;
          HAL_I2C_Master_Transmit_Mem_IT(i2c_id, pca_adrr, reg_addr, I2C_MEMADDR_SIZE_8BIT, buf, 1);
      }
      
      uint8_t pca_read(uint8_t reg_addr) {
              uint8_t buf[1];
          HAL_I2C_Master_Receive_Mem_IT(i2c_id, pca_adrr, reg_addr, I2C_MEMADDR_SIZE_8BIT, buf, 1);
          return buf[0];
      }
      
      void pca_setfreq(float freq) {
              uint8_t prescale,old_mode,new_mode;
              double prescaleval;
              freq *= 0.92;
              prescaleval = 25000000;
              prescaleval /= 4096;
              prescaleval /= freq;
              prescaleval -= 1;
              prescale =(uint8_t)(prescaleval + 0.5f);
              old_mode = pca_read(pca_mode1);
              new_mode = (old_mode & 0x7F) | 0x10;
              pca_write(pca_mode1, new_mode);
              pca_write(pca_pre, prescale);
              pca_write(pca_mode1, old_mode);
              OS_MSleep(2);
              pca_write(pca_mode1, old_mode | 0xa1);
      }
      
      void pca_setpwm(uint8_t num, uint32_t on, uint32_t off) {
              pca_write(LED0_ON_L+4*num,on);
              pca_write(LED0_ON_H+4*num,on>>8);
              pca_write(LED0_OFF_L+4*num,off);
              pca_write(LED0_OFF_H+4*num,off>>8);
      }
      
      void pca9685_init(float hz) {
              pca_write(pca_mode1, 0x0);
              pca_setfreq(hz);
              OS_MSleep(500);
      }
      
      void pca_rotate(uint8_t num,uint8_t angle) {
              uint32_t off=0;
              off=floor(angle * 2 + angle / 5 + 158);
              pca_setpwm(num, 0, off);
      }
      
      void i2c_init(unsigned int id){
              I2C_InitParam initParam;
              initParam.addrMode = I2C_ADDR_MODE_7BIT;
              initParam.clockFreq = 40000;
              if (HAL_I2C_Init(id, &initParam) != HAL_OK) {
                      printf("i2c init fail!\n");
                      while(1);
              } else {
                      printf("i2c init success!\n");
              }
      }
      
      static void MainThread(void *arg) {
      
              uint8_t i = 0;
      
              i2c_init(i2c_id);
              pca9685_init(60);
              printf("i2c and pca9685 init done.\n");
      
              while(1){
                      pca_rotate(0, 0);
                      OS_MSleep(1000);
                      pca_rotate(0, 180);
                      OS_MSleep(1000);
              }
      }
      
      void PCAMain(void) {
              printf("PCA9685 Motor Start.\n");
      
              if (OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL,
                                  OS_THREAD_PRIO_APP, 10 * 1024) != OS_OK) {
                      printf("[ERR] Create MainThread Failed\n");
              }
      }
      
      SYS_RUN(PCAMain);
      

      狗子的相关步态算法还在调试,使用的舵机是MG90S,走得还不是很流畅,狗腿子会抖,后面需要继续调试,而且供电也是个大问题,不过已经焊了个供电模块稍微解决了,后面还要给狗子加个壳。

      文章转自极术社区:https://aijishu.com/a/1060000000292068
      作者:堇花还没开吗

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 回复: 全志在线开源芯片 新 SDK 平台下载方法汇总

      @l1878980638 暂时还没有哦,关于SDK有什么问题都可以在论坛里发帖提问的

      发布在 代码下载问题专区
      q1215200171
      budbool
    • 回复: 【FAQ】全志V853芯片 如何在Tina V85x平台切换sensor?

      @likehengall 签NDA

      发布在 V Series
      q1215200171
      budbool
    • 【FAQ】全志V853芯片 VE debugfs调试节点信息说明

      VE debugfs调试节点信息说明

      【调试信息】

      cat /sys/kernel/debug/mpp/ve
      ********Channal[0]: H265Enc Ver.07388090580d7ad94c897633057ff0806abf4340 F119********
      MainProfile, Level:186, BitRate:1048576, FrameRate:20
      Input:1920x1080, Output:2304x1296, RotAng:0
      Crop: Left:0, Top:0, Width:0, Height:0
      IDRPeriod:40, GopSize:2, NormalP, VBR, IpcCase, Colour
      InitQp:30, IQp[10~50], PQp[10~50]
      CurPQp:29, TargetBits:23424, RealBits:25920, BitRatio:110.66%
      Scene:1, Move:0, MovingLevel:0, BinImgRatio:0.32%, MovingTh:20
      AvgBitRate:3, RealBitRate:763, AvgFrmRate:0, RealFrmRate:21
      LBC:1, Lossy2X, y&yc_stride:1152,1728
      VbvSize:622592, Unused:619328, Valid:3264, ValidFrmNum:1
      Intra4x4:1, IntraInP:1, 3DNR:1
      Quality:10, IBitsCoef:10, PBitsCoef:10
      Mad[][10]:96.21 1.55 0.42 0.23 0.17 0.10 0.07 0.03 0.00 0.00 0.00 0.00
      Mad[0][]:3.83 4.90 39.77 30.91 10.06 3.28 1.81 0.83 0.45 0.36
      ClassifyTh[]:0 0 0 0 0 0 0 0 0 0 0 0
      Lambda:0.00, LambdaC:0.00, LambdaSqrt:0.00
      Intra: Coef{31 31 31}, Th{0 0 0}
      PredTend: Inter:16, Skip:16, Merge:20
      ********End Channal[0] H265Enc********
      ********Channal[1]: H264Enc Ver.07388090580d7ad94c897633057ff0806abf4340 F119********
      MainProfile, Level:51, BitRate:512000, FrameRate:20
      Input:640x360, Output:640x360, RotAng:0
      Crop: Left:0, Top:0, Width:0, Height:0
      IDRPeriod:60, NormalP, VBR, IpcCase, Colour
      InitQp:30, IQp[10~45], PQp[10~45]
      CurPQp:20, TargetBits:20894, RealBits:25648, BitRatio:122.75%
      Scene:0, Move:1, MovingLevel:1, BinImgRatio:1.55%, MovingTh:20
      AvgBitRate:585, RealBitRate:374, AvgFrmRate:21, RealFrmRate:21
      LBC:1, Lossy2X, y&yc_stride:384,576
      VbvSize:304128, Unused:300864, Valid:3264, ValidFrmNum:1
      Intra4x4:1, IntraInP:1, 3DNR:1
      Quality:10, IBitsCoef:10, PBitsCoef:10
      Mad[][10]:46.81 7.12 1.50 0.44 0.38 0.56 0.19 0.19 0.25 0.06 0.00 0.00
      Mad[0][]:1.31 5.94 7.38 3.81 4.75 5.50 7.31 4.81 3.62 2.38
      ClassifyTh[]:0 0 0 0 0 0 0 0 0 0 0 0
      ********End Channal[1] H264Enc********
      

      【参数说明】

      参数 描述
      Channal VE通道号,0/1/2/3
      EncType 编码类型,H264:H264Enc;H265:H265Enc
      Ver 编码库版本,对应的commit ID
      FrameCnt 编码帧的帧数,例如F119表示第119帧
      Profile 编码输出视频的档次,档次越高,允许使用的编码技术越丰富。H264低于High不能使用8x8转换,质量变差,如客户没具体要求,默认H264使用Hihg,H265使用Main。H264:Base/ Main/ High,H265:Main/ Main10/ MainStill
      Level 编码输出视频的等级,按照标准规定的分辨率和帧率而定。过往有些客户的机器出现解码高Level码流性能不足的情况,所以建议由编码库内部自适应配置。H264:定义在enum H264_LEVEL_E,H265:定义在enum H265_LEVEL_E
      BitRate 码率,单位bps
      FrameRate 帧率,单位fps
      Input 编码输入分辨率
      Output 编码输出分辨率
      RotAng 旋转角度
      Crop 裁剪坐标
      IDRPeriod I帧周期
      GopSize 编码参考集大小,该参数不影响码率控制,H265的该参数会影响某些解码器的参考帧内存预分配,建议统一配置成2。
      FixQp 固定I/P帧Qp,仅在RcMode选择FixQp时生效
      InitQp RcMode为非FixQp下,首个I帧Qp
      IQp I帧Qp取值范围
      PQp P帧Qp取值范围
      TargetBits 当前帧目标bit数
      RealBits 当前帧实际bit数
      BitRatio bit数比例 = 100 * RealBits / TargetBits
      Scene 纹理复杂程度的等级,[0,2]
      Move 运动复杂程度的等级,[0,4]
      MovingLevel 场景变化剧烈程度等级,[0,3]
      BinImgRatio SAD超过MovingTh的8x8块数量比例,[0%,100%]
      MovingTh 8x8块SAD阈值,[10,31]
      AvrBitRate 到目前为止的平均码率,按编码器拿到的VIBuffer的时间戳每隔一秒更新一次
      RealBitRate 实际最近一秒内的瞬时码率,按编码器拿到的VIBuffer的时间戳每隔一秒更新一次
      AvgFrmRate 到目前为止的平均帧率,按编码器拿到的VIBuffer的时间戳每隔一秒更新一次
      RealFrmRate 实际最近一秒内的瞬时帧率,按编码器拿到的VIBuffer的时间戳每隔一秒更新一次
      AFBC VI使用LBC的开关,[0,1]
      LBC VI使用LBC的开关,[0,1]
      VbvSize 编码器输出Buffer长度
      Unused VbvBuffer剩余可用空间
      Valid VbvBuffer已占用空间
      ValidFrmNum 占用VbvBuffer未归还的帧数量
      Intra4x4 帧内4x4块预测开关,[0,1]
      IntraInP P帧使用帧内预测开关,[0,1]
      3DNR 编码器3D滤波开关,[0,1]
      Quality 静止场景下的P帧bit数比重,按10为100%计算,[0,20]
      IBitsCoef I帧bit数比重,按10为100%计算,[1,20]
      PBitsCoef 运动场景下P帧bit数比重,按10为100%计算,[1,50]
      Mad[][10] 纹理MAD直方图比例分布,以10为步长
      Mad[0][] 纹理MAD在10以内的直方图比例分布,以1为步长
      ClassifyTh MB级码控分类阈值
      Lambda H265编码器Lambda值,H264:无效,V853的H265无效
      LambdaC H265编码器LambdaC值,H264:无效,V853的H265无效
      LambdaSqrt H265编码器LambdaSqrt值,H264:无效,V853的H265无效
      IntraCoef 帧内分块决策系数,三个系数分别对应32x32、16x16、8x8块,系数越大,越倾向于分小块,H264:无效,H265:[0,31]
      IntraTh 帧内分块决策MAD阈值,三个阈值分别对应32x32、16x16、8x8块,阈值越小,越倾向于分小块,H264:无效,H265:[0,127]
      PredTendInter Inter预测模式倾向系数,系数越小,越倾向于Inter预测,H264:无效,H265:[0,63]
      PredTendSkip Skip预测模式倾向系数,系数越小,越倾向于Skip预测,H264:无效,H265:[0,63]
      PredTendMerge Merge预测模式倾向系数,系数越小,越倾向于Merge预测,H264:无效,H265:[0,36]

      【调试方法】

      app运行结束后,支持查看VE debugfs调试信息功能的开启方法。

      默认情况下,app运行结束后,通过 cat /sys/kernel/debug/mpp/ve 无法继续查看ve的debugfs调试信息。

      在app运行前执行命令 echo 1 > /sys/kernel/debug/mpp/ve 可开启该功能。
      平台重启后,修改会自动失效,需要重新打开。

      执行命令 echo 0 > /sys/kernel/debug/mpp/ve 可恢复默认情况。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 回复: 全志在线开源芯片 新 SDK 平台下载方法汇总

      @fuzhikun 联系你购买商家的客服或者代理获取

      发布在 代码下载问题专区
      q1215200171
      budbool
    • 回复: 自制V853机载视觉中枢

      @zyhao712 越来越期待成品无人机👍 👍 👍

      发布在 V Series
      q1215200171
      budbool
    • 【FAQ】全志V853芯片 编码P帧帧内如何刷新功能检查?

      编码P帧帧内刷新功能检查方法

      H264

      使用Elescard StreamEye 4.6 工具(只支持H264),按如下截图配置后,开启P帧帧内刷新后,图像看到一个橙色的竖状矩形条,同时逐帧往后查看时矩形条会从左往右移动;关闭P帧帧内刷新后,则无此矩形条。

      dddbb14abf964b9486124575651f048a.jpg

      e26c4129ad2848b79d6c850f3fbefbaa.jpg

      H265

      使用YUView 工具(需要配置ffmpeg动态库)可分析H265文件,勾选Pred Mode后,可显示一个蓝色的竖状矩形条,同时逐帧往后查看时矩形条会从左往右移动;关闭P帧帧内刷新后,则无此矩形条。

      59ba6135b21b4192a20aa1c74796d9e9.jpg

      16d9605272f84316b7494538b94d37a1.jpg

      注:

      YUView 工具配置ffmpeg动态库

      为使YUView 工具分析能力更强,需要配置ffmpeg动态库。配置方法如下:

      abfd76df39c44be39d6b08933f34dc8c.jpg

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 回复: H616的SDK可以在本论坛下载到吗

      @shenhao618 市面上有很多Pi都是基于H616开发的哦,我们欢迎大家到全志在线讨论相关的内容,SDK的话可以联系你购买商家的客服或者代理获取

      发布在 代码下载问题专区
      q1215200171
      budbool
    • 【FAQ】全志V85x芯片 OTA升级失败出现"Found installer for stream recovery ubivol"以及"cannot write 16384 bytes: Operation not permitted"报错如何解决?

      1.主题

      OTA升级失败出现"Found installer for stream recovery ubivol"以及"cannot write 16384 bytes: Operation not permitted"报错

      2.问题背景

      软件:Tina

      3.问题描述

      3.1复现步骤

      1. 在服务器生成OTA升级包。
      2. 将OTA升级包推入小机端,执行升级命令。
      3. 升级失败。

      3.2具体表现

      OTA升级失败,通过命令 cat /mnt/UDISK/swupdate.log查看升级失败log,出现 “cannot write 16384 bytes: Operation not permitted” 或 “Found installer for stream recovery ubivol” 错误。

      4.问题分析

      通过两条报错可以猜测,不允许操作,不能写入,以及报ubivol等问题。

      可以在设备端确认当前介质,执行ll dev/by-name确认(例:当前为emmc介质,为mmc*,如果为nand ubi介质为ubi* 或 nand*)
      137b03d7657e480f9684c6ff726b293e.jfif

      5.根本原因

      升级包的中文件的介质与当前板子的介质不对应,不能操作分区。

      6.解决办法

      1. 对于非ubi方案,无需选中 CONFIG_SWUPDATE_CONFIG_UBIVOL选项,在打包OTA包时,命令无需使用ubi后缀。
      2. 对于ubi方案,需要选中MTD:SWUPDATE_CONFIG_MTD选项,再选中 CONFIG_SWUPDATE_CONFIG_UBIVOL 选项,在打包OTA包时,使用ubi后缀,例如:swupdate_pack_swu -ubi 或 swupdate_pack_swu -ab-ubi。
      3. 以上操作在recovery升级中,在menuconfig和ota_menuconfig中都要执行,而AB升级,在menuconfig中执行即可。
      发布在 V Series
      q1215200171
      budbool
    • 【FAQ】全志V853芯片 如何查看NPU时钟电源配置以及信息?

      [KERNEL_DIR]/arch/arm/boot/dts/sun8iw21p1.dtsi

      npu: npu@03050000 {
          compatible = "allwinner,npu";
          reg = <0x0 0x03050000 0x0 0x1000>;
          device_type = "npu";
          dev_name = "npu";
          interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
          clocks = <&clk_npu>,
              <&clk_pll_npux4>;
          clock-frequency = <504000000>;
          interrupt-names = "npu";
          iommus = <&mmu_aw 6 1>;
          status = "okay";
          power-domains = <&pd V853_PD_NPU>;
      };
      

      一:如何使能电源控制以及电源状态确认
      在dts确认配置power-domains后,电源默认打开,如果NPU模块电源需要关闭,需要内核支持CONFIG_SUNXI_POWER_DOMAINS=y;不用的时候应用层软件会默认将其关闭;

      root@TinaLinux:/# echo 0x070010a0,0x070010ac > /sys/class/sunxi_dump/dump && cat
       /sys/class/sunxi_dump/dump
      
      0x070010a0: 0x00000002 0x00020000 0x00000000 0x00000000
      

      如上为电源处理关闭状态

      echo 0x070010a0,0x070010ac > /sys/class/sunxi_dump/dump && cat
       /sys/class/sunxi_dump/dump
      
      0x070010a0: 0x00000001 0x00010000 0x00000000 0x00000000
      

      如上电源处于开启状态

      二:如何配置支持的频率

      clock-frequency = <504000000>;代表现在设置的频率为504M;客户请严格按照原厂建议配置,或直接默认配置,勿随意更改其频点;

      clocks = <&clk_npu>,<&clk_pll_npux4>;前面为模块时钟,后面为父时钟;

      在[KERNEL_DIR]/drivers/clk/sunxi/clk-sun8iw21_tbl.c中有如下table代表目前所支持的频点;

      /* PLL_NPU(n, d1, freq)	F_N8X8_D1V1X1 */
      struct sunxi_clk_factor_freq factor_pllnpux4_tbl[] = {
      PLLNPU(24,     1,      300000000U),
      PLLNPU(40,     1,      492000000U),
      PLLNPU(20,     0,      504000000U),
      PLLNPU(25,     0,      624000000U),
      PLLNPU(28,     0,      696000000U),
      PLLNPU(41,     0,     1008000000U),
      PLLNPU(57,     0,     1392000000U),
      };
      配置规则为:
      npu4x的计算公式为:24M * (N+1) / (M+1)N:0-254M:0-1
      在clk-sun8iw21_tbl.c中截图部分添加新的频率组即可
      如:492PLLNPU(40,     1,     492000000U),24*(40+1)/(1+1)= 492
      

      通过clk_summary我们可以看到配置是否生效

      root@TinaLinux:/# cat /sys/kernel/debug/clk/clk_summary
       pll_npux4                             0            2   504000000          0 0
             npu                                0            1   504000000          0 0
      

      当然我们也可以从probe的打印看到时钟的相关配置

      [  843.717406] Want set pclk rate(504000000) support(504000000) real(504000000)
      [  843.725445] Want set mclk rate(504000000) support(504000000) real(504000000)
      

      三:怎么用命令修改时钟的频率

      reboot uboot
      #等待其处于uboot中后:
      fdt list /soc/npu
      fdt set /soc/npu clock-frequency <696000000>
      fdt list /soc/npu
      save
      boot
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 回复: 全志在线开源芯片 新 SDK 平台下载方法汇总

      @shenhao618 市面上有很多Pi都是基于H616开发的哦,我们欢迎大家到全志在线讨论相关的内容,SDK的话可以联系你购买商家的客服或者代理获取

      发布在 代码下载问题专区
      q1215200171
      budbool
    • 全志V853芯片配套辅助驾驶算法介绍

      2b610367-564b-4cec-80d6-9b08650c80fd-image.png

      全志V853处理器,是专为智慧视觉领域设计的AI处理器,配备了高效的NPU算力和丰富的外设接口,能够提供稳定的AI边缘计算支持;同时,基于V853处理器这一性能优势,全志还为客户提供了一整套完整的智能辅助驾驶算法,包括:

      • 高级辅助驾驶(ADAS)
      • 盲区检测(BSD)
      • 驾驶员监控(DMS)
      • ……

      可为 智能座舱、行车记录仪、智能后视镜、倒车影像、360°行车监控等智慧车载场景及产品提供稳定可靠的视觉技术解决方案。

      高级辅助驾驶算法(ADAS)

      ADAS是通过车载摄像头、雷达等传感器对行车时道路环境信息进行实时采集和处理的算法系统。结合 全志V853 内置的 NPU 加速模型进行系统的推理运算与分析,可以快速辅助机动车或驾驶员做出相应判断和预警,从而提高行车的舒适性与安全性。ADAS算法中包括:

      前车启停监测(FVSA)

      • 支持仅对前车进行检测,不受周围其他车辆干扰
      • 夜间准确率超过95%
      • 低系统资源占用

      车道偏离警告(LDW)

      • 支持多类型车道线识别
      • 支持自动校准路线轨迹
      • 支持夜间及恶劣气候条件下识别

      前方碰撞警告(FCW)

      • 支持仅对前车进行检测,不受周围其他车辆干扰
      • 支持实时前车距离检测

      交通标志牌识别(TSR)

      • 支持多类型交通标志识别
      • 支持50m长距离识别

      信号灯识别(TLR)

      • 支持多形态信号灯识别
      • 支持夜间及恶劣气候条件下识别

      e3b81708-9297-46b2-98ca-4e412cf4a248-image.png

      盲区检测算法(BSD)

      BSD 算法通常需要多个摄像头实时监测车辆两侧和后方的盲区,全志 V853 支持多路摄像头接口,可以很好地同时处理来自多个摄像头的数据。通过 NPU 高效执行图像处理和目标检测算法,实时对盲区内的机动车、行人等关键目标进行精准识别,对驾驶员行为做出预警。

      • 支持各类机动车动静态识别,如:小汽车、大卡车、叉车、摩托车等
      • 支持各类行人动静态识别
      • 支持环车360°盲区检测
        1544ec46-3304-4254-bc9e-5c1639aa53ce-image.png

      驾驶员监控算法(DMS)

      DMS算法是行车记录仪中至关重要的一个应用。它通过对驾驶员的面部特征、眼睛运动、头部姿态等进行实时分析,能够判断驾驶员的疲劳程度、分心状态等,并及时发出预警,提醒驾驶员注意行车安全。

      • 支持多种危险驾驶行为预警,
        包括:睡觉、转头、低头、打哈欠、打电话等
      • 支持多角度姿态识别
      • 支持RS232串行端口输出预警信息
      • 支持多国语言预警

      4c2327cc-9d3e-4790-961f-789b48482096-image.png

      全志技术团队结合CPU和NPU进行了深度性能优化,可以实现毫秒级算法快速冷启动和低算力占用。部分场景算力资源占用情况:

      ddd67b4c-2c11-423a-8798-45974e834aec-image.png

      同时,算法使用了大批量的素材对算法进行深度训练,并进行了长时间的道路实测。其中仅亚裔人种的DMS算法人脸训练素材就超过了128000份,令算法更适合亚洲道路行车场景。

      目前,全志V853智慧视觉专用处理器凭借优秀的AI智能算法支持和性能表现,为众多客户完成了产品落地;未来,随着全志V系列芯片的不断升级完善,将进一步夯实在智慧车载视觉领域的技术实力和市场地位,全志也会持续以创新的技术和产品,为全球客户提供核心算力支撑,助力更多智慧车载产品的量产提速,让人们更高效便捷的享受智慧出行美好体验。

      发布在 V Series
      q1215200171
      budbool
    • 【FAQ】全志V853芯片 如何动态打开蓝牙kernel部分的log?

      1.主题
      如何动态打开蓝牙kernel部分的log

      2.问题背景
      产品:扫描笔等Tina产品
      硬件:V853 + XR829
      软件:Tina linux4.9

      目的是为了分析问题,抓取kerne里面/net/bluetooth/、driver/bluetooth/目录下的BT_DBG打印。

      3.解决办法

      • 环境配置
      menuconfig选上CONFIG_DEBUG_FS、CONFIG_DYNAMIC_DEBUG
      
      • 小机端
      1. echo 8 > /proc/sys/kernel/printk  调整printk打印等级为7以上
      2. cat /sys/kernel/debug/dynamic_debug/control | grep bluetooth  查看目前能控制的打印
      3. echo 'file hci_core.c +p' > /sys/kernel/debug/dynamic_debug/control 指将hci_core.c文件的打印打开
      4. echo 'file hci_core.c -p' > /sys/kernel/debug/dynamic_debug/control 指将hci_core.c文件的打印关闭
      5. echo "file net/bluetooth/rfcomm/core.c line 1603 +p" > /sys/kernel/debug/dynamic_debug/control 指将文件net/bluetooth/rfcomm/core.c的第1603行的打印打开
      6. echo 'module $mod_name +p' > /sys/kernel/debug/dynaminc_debug/control 指将某个模块的打印打开。
      

      按照上面的方法配置好后,打开蓝牙调试就可以了,默认会输出到终端上或dmesg方式查看。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 回复: h618源码拉取可行性问题

      都是暂未开放下载

      发布在 代码下载问题专区
      q1215200171
      budbool
    • 【FAQ】全志R329如何解决在Audiocodec使用S24_LE格式进行录音时产生的软件分析波形异常问题?

      问题背景

      硬件:R329
      软件:Tina
      内核:Linux-4.9

      问题描述

      使用Audiocodec进行录音,格式S24_LE,录制的.wav波形在某些软件中异常

      arecord -D hw:audiocodec -f S24_LE -r 16000 -c 2 -d10 /tmp/test3_S24_LE.wav
      

      d65d357edb0842cb9d54148ed1c5e0b3.jpg
      需要放大很多倍才能看到声音波形

      3cddc50a8f214d7380305433df378993.jfif

      问题分析

      1.R329的Audiocodec用于录音的ADC只支持16bit和20bit的采样精度。采样后的数字信号会存放到RX_FIFO中,RX_FIFO的大小为256*20-bit,其他平台可以在User Manual确认支持的采样精度,从而判断是否会有这个问题产生

      4570bdb36f594591b6ec4c71310e5fe7.jfif

      2.RX_DATA是一个32位的寄存器,保存的是从RX_FIFO获取的一个channel的样本数据,当使用arecord进行录音时,RX_DATA中的值会经DMA搬至内存,最后保存到.wav中

      5c2c17d228f944fd8a4a6e8d1924e778.jfif

      其中RX_DATA有四种模式去获取RX_FIFO的数据,S24_LE和S32_LE均采用20-bit mode0

      6972b81f741b4bf9829ecb814f5dbb7a.jfif

      当设置了20bit采样精度时,对应的两种模式如下图所示:

      8b502f06666046368fafccf0d13eee46.jfif

      3.先说明一下S24_LE和S32_LE这两种格式的区别

      S24_LE指有符号整型,范围是-2^23 ~ ((2^23) - 1),有效数据在低24位
      S32_LE指有符号整型,范围是-2^31 ~ ((2^31) - 1),有效数据在高24位

      LSB                           MSB
               1st byte  2nd byte  3rd byte  4th byte   alignment
      S32_LE:   00000000  xxxxxxxx  xxxxxxxx  xxxxxxxx   32 bits
      S24_LE:   xxxxxxxx  xxxxxxxx  xxxxxxxx  00000000   32 bits
      S24_3LE:  xxxxxxxx  xxxxxxxx  xxxxxxxx             24 bits
      

      4.在驱动程序中,S24_LE和S32_LE虽然都支持,但他们两者都是使用20-bit的mode0,这导致这两种格式保存到文件中的数据排布是一致的,但生成的wav头信息中的采样位数则不一样,从下图可以看出两者的差异

      S32_LE的wav文件信息:

      b782fd998a1a42bfafb6a46a3362d79b.jfif

      若软件以S32_LE进行解析,以上红框的数据变为0x0f80f0,依然可以保留全部有效数据

      5de38b0c26a346a2bd0cc517b1cb6485.jfif

      S24_LE的wav文件信息:

      561fc954670c4a7e8f5c122acd788689.jfif

      若软件以S24_LE进行解析,以上红框的数据变为0x55f000,便会丢失一部分数据

      a185f006bee4483ebb53b3835c4053dc.jfif

      解决方案

      总结原因就是audiocodec的采样精度只支持16和20bit,因此PCM格式中S24_LE虽然也支持,但硬件的特性使驱动并不能做到很好的适配,若软件以标准S24_LE格式进行分析,则会丢失高位的有效数据,这取决于软件如何对数据进行分析,解决方法有以下三种

      • 使用audiocodec时,使用-f S32_LE,修改wav头信息中的采样位数位32,这对大部分软件都有效
      arecord -D hw:-f S32_LE -r 16000 -c 2 -d10 /tmp/test32.wav
      
      • 如果必须使用S24_LE格式进行录音,可以选择其他支持24bit采样的音频接口,如I2S等
      • 假如必须使用audiocodec声卡,S24_LE格式进行录音,可以自行调整RX_DATA寄存器的模式,结合RX_DATA寄存器中实际的有效数据分布,自己开发软件进行数据分析
        如果有分析和处理音频数据的需求,可以参考以上思路,结合RX_DATA寄存器去调整
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志R329如何在Linux Device Tree中配置预留内存?

      前言

      有时我们需要在 Linux 内核中预留一部分内存空间用作特殊用途(给安全模块使用,给其它处理器使用,或是给特定的驱动程序使用等),在 Device Tree 中有提供两种方法对预留内存进行配置:memreserve 和 reserved-memory。

      memreserve

      memreserve 的使用方法比较简单,如下所示,会将从地址 0x40000000 开始共 1MB 的内存空间预留出来:

      /memreserve/ 0x40000000 0x00100000;
      

      使用 memreserve 预留出来的内存一般无法再被 Linux 系统使用(当然,也可以通过特殊方法让代码固定访问该地址,但这种并非标准用法,在此不展开描述)。

      reserved-memory

      reserved-memory 框架提供了更多样的使用方法,并且与内核的 DMA API 和 CMA 框架紧密联系。

      推荐先阅读一下内核自带的文档 Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt,里面有其详细的语法说明和注意事项(例如 reserved-memory 节点中的 #address-cells 和 #size-cells 的值需要与根节点的保持一致)。

      下面对几种常见的使用方法进行举例说明:

      通过 memremap/ioremap 来使用
      在 Device Tree 配置如下,然后通过“memory-region”参数可将该预留内存分配给特定的设备驱动使用:

      reserved-memory {
         #address-cells = <2>;
         #size-cells = <2>;
         ranges;
       
         foobar_reserved: foobar@70000000 {
            no-map;
            reg = <0x0 0x70000000 0x0 0x10000000>;
         };
      };
       
      foobar_driver: foobar_driver@0 {
         memory-region = <&foobar_reserved>;
      };
      

      在设备驱动程序中,可解析 Device Tree 节点获得预留内存的物理地址和大小,然后通过 memremap/ioremap 映射这片内存空间来使用:

      /* Get reserved memory region from Device-tree */
      np = of_parse_phandle(dev->of_node, "memory-region", 0);
      if (!np) {
        dev_err(dev, "No %s specified\n", "memory-region");
        goto error1;
      }
        
      rc = of_address_to_resource(np, 0, &r);
      if (rc) {
        dev_err(dev, "No memory address assigned to the region\n");
        goto error1;
      }
        
      lp->paddr = r.start;
      lp->vaddr = memremap(r.start, resource_size(&r), MEMREMAP_WB);
      dev_info(dev, "Allocated reserved memory, vaddr: 0x%0llX, paddr: 0x%0llX\n", (u64)lp->vaddr, lp->paddr);
      

      通过 DMA API 来使用

      设置“shared-dma-pool”属性后,可让设备驱动通过 DMA API 来使用预留内存:

      reserved-memory {
         #address-cells = <2>;
         #size-cells = <2>;
         ranges;
       
         foobar_reserved: foobar@70000000 {
            compatible = "shared-dma-pool";
            no-map;
            reg = <0x0 0x70000000 0x0 0x10000000>;
         };
      };
       
      foobar_driver: foobar_driver@0 {
         memory-region = <&foobar_reserved>;
      };
      

      设备驱动程序中可类似常规地使用 DMA API,它申请的内存不是来源于默认的 CMA 内存池,而是来源于该预留内存:

      /* Initialize reserved memory resources */
        rc = of_reserved_mem_device_init(dev);
        if(rc) {
          dev_err(dev, "Could not get reserved memory\n");
          goto error1;
        }
        
        /* Allocate memory */
        dma_set_coherent_mask(dev, 0xFFFFFFFF);
        lp->vaddr = dma_alloc_coherent(dev, ALLOC_SIZE, &lp->paddr, GFP_KERNEL);
        dev_info(dev, "Allocated coherent memory, vaddr: 0x%0llX, paddr: 0x%0llX\n", (u64)lp->vaddr, lp->paddr);
      

      给 CMA 预留内存

      有时我们不需要将预留内存分配给特定的设备驱动,而只是想给默认 CMA 内存池分配一片固定的内存区域,这时我们可配置上“reusable”和“linux,cma-default”:

      reserved-memory {
            #address-cells = <2>;
            #size-cells = <2>;
            ranges;
        
            linux,cma {
               compatible = "shared-dma-pool";
               reusable;
               reg = <0x0 0x70000000 0x0 0x10000000>;
               linux,cma-default;
            };
         };
      

      由此可见,不同于 memreserve,通过 reserved-memory 预留的内存有可能进入系统 CMA,这需要满足以下几个条件:

      • compatible 需要为“shared-dma-pool”
      • 没有定义“no-map”属性
      • 定义了“reusable”属性
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志R系列如何在Tina下使用bootchartd来分析rootfs启动时间?

      问题背景

      硬件: R818
      软件: Tina2.5及以上
      操作: bootchart工具打开后无法开机。
      说明: 客户程序较复杂,系统应用起来时间有25秒,需要优化。bootchart无使用说明。

      问题简述

      Tina整体启动时间中rootfs占用的比重很大,但是rootfs启动过程中log很多,在自启动脚本中也添加不了打印,造成启动时间统计非常不便。

      Tina SDK有集成busybox bootchart工具,可使用该工具分析rootfs启动过程各个进程的启动时刻以及耗费时间等信息,可以让用户分析启动过程并进行针对性优化。

      解决办法

      该方法支持Tina所有方案。

      Tina上开启bootchartd方法:
      ① make menuconfig,打开CONFIG_BUSYBOX_CONFIG_BOOTCHARTD
      ② 修改文件env-x.x.cfg,将“init=/sbin/init”修改为“init=/sbin/bootchartd”
      ③ 编译,烧写固件,设备启动后,等待一段时间(1min左右),直到出现/var/log/bootlog.tgz,使用adb pull将该文件拉到PC端。
      ④ 在PC端解压附件工具bootchart.tar.xz,运行命令“./bootchart/pybootchartgui.py bootlog.tgz”,生成bootchart.png图片,打开可得系统各进程的启动时间。

      bootchart.png图片分析

      bootchart.png效果如下图所示,图中横坐标是时间,纵坐标是各进程信息。图上方两条是CPU和I/O的使用情况;下方是各个进程的运行状态,包含各个进程开始执行时间与结束时间,进程条上有颜色信息,表示对CPU、I/O的占用情况。

      e076818e05064a89b48968ee2e674996.jfif

      优化思路:

      • 将主应用程序一起主应用依赖的程序提前执行,其他程序延后执行。
      • 调整进程启动顺序,使CPU、I/O不要太高,避免竞争产生等待。

      附件:bootchart.tar.xz

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】Wi-Fi/BT MAC地址定制

      问题背景
      很多Wi-Fi/BT模组默认出厂是不带MAC地址的,整机厂需要根据需求,烧写特定的MAC地址。

      MAC地址通路
      Linux-4.9后,全志平台模组MAC地址定制流程如下

      f0b99d68a48d47fb86bbcd973ef20647.jfif

      系统启动后,引导程序会加载env中定义的key,并传递给cmdline和内核dts。 如果安全存储中没有mac/wifi_mac/bt_mac这几个key,或者值解析失败,我们将尝试从私有分区加载并解析这些key。在内核空间中,addr_mgt驱动程序读取cmdline或dts中与Mac相关的键,对其进行解析并导出到其他驱动程序以使用。 为了让用户空间可以访问这些地址值,创建了sysfs来保存地址值。

      配置
      uboot env
      请确保env.cfg中有如下配置项存在:
      5893A71A-C707-4fa3-85B5-4ACC192916E8.png

      dts
      dts配置参考如下
      123dd43781e34e049277b1fe4f600f50.jfif
      其中,type_addr_xx表示mac地址的来源,值含义如下

      • 0: 不指定类型
      • 1: 使用烧写的mac地址
      • 2: 使用chipid生成的mac地址
      • 3: 使用sysfs写入的地址
      • 其他: 不提供地址

      烧写
      使用全志烧号工具DragonSN或DragonKey烧写mac/wifi_mac/bt_mac到私有分区或secure storge中。合法的mac地址格式为xx:xx:xx:xx:xx:xx, x 是16禁止值,0-9,a-f。

      使用

      内核空间

      Linux-4.9

      • 读取Wi-Fi MAC地址
      int get_wifi_custom_mac_address(char *addr_str)
      
      • 读取BT MAC地址
      int get_bt_custom_mac_address(char *addr_str)
      
      • 读取以太网 MAC地址
      int get_eth_custom_mac_address(char *addr_str)
      

      Linux-5.4

      int get_custom_mac_address(int fmt, char *name, char *addr)
      

      fmt: 0为str,1为16进制值
      name: “wifi”、“bt”、“eth”

      用户空间
      可以通过sysfs文件节点访问对应值,linux-4.9下主要节点如下:

      root@venus-a1:/sys/class/addr_mgt# ls -l
      total 0
      -rw-r--r-- 1 root root 4096 2019-01-15 17:22 addr_bt
      -rw-r--r-- 1 root root 4096 2019-01-15 17:22 addr_eth
      -r--r--r-- 1 root root 4096 2019-01-15 17:22 addr_type
      -rw-r--r-- 1 root root 4096 2019-01-15 17:22 addr_wifi
      

      linux-5.4下主要节点如下:

      console:/ # ls -l /sys/class/addr_mgt/
      total 0
      -rw-r--r-- 1 bluetooth net_bt_admin 4096 2020-12-22 19:33 addr_bt
      -rw-r--r-- 1 root      root         4096 2020-12-23 13:10 addr_eth
      -rw-r--r-- 1 root      root         4096 2020-12-23 13:10 addr_wifi
      -r--r--r-- 1 root      root         4096 2020-12-23 13:10 summary
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志R329如何在DragonSN烧写mac地址?

      问题背景

      硬件:R528+ Wi-Fi模组(XR829)
      软件:Tina3.0及以上
      说明:该FAQ旨在介绍DragonSN烧写mac地址的过程。

      问题简述

      如何从私有分区获取mac地址?

      问题分析

      从私有分区获取mac地址,需要利用到DragonSN工具烧写mac地址到私有分区,然后借助uboot以comdline的形式传递到内核,内核addr_mgt驱动解析。

      这里简要描述一下上述过程:

      1.lichee/brandy-2.0/u-boot-2018/board/sunxi/sunxi_bootargs.c

      +int update_user_data_ali(void)
      +{
      +       int data_len;
      +       int ret;
      +       char output[SST_WIFI_MAC_ADDR_LEN+1];
      +       char *sst_info = NULL;
      +       int sec_inited      = !sunxi_secure_storage_init();  //分区初始化
      +       memset(output, 0, SST_WIFI_MAC_ADDR_LEN+1);  //获取存放mac地址的地址空间并初始化
      +       if (sec_inited) {
      +               sst_info = (char *)malloc(SST_INFO_KEY_VALUE_ACTUAL_LEN);  //分配存放mac地址的空间并赋值给sst_info结构体
      +               if (get_boot_work_mode() != WORK_MODE_BOOT) {
      +                       return 0;
      +               }
      +
      +               ret = sunxi_secure_object_read(SST_INFO_KEY_NAME, sst_info, SST_INFO_KEY_VALUE_ACTUAL_LEN, &data_len); //从flash secure storage读出
      +               if (ret)
      +                       pr_msg("=========%s->%d sunxi_secure_object_read failed==============\n", __func__, __LINE__);
      +               memcpy(output, sst_info + SST_WIFI_MAC_ADDR_OFFSET, SST_WIFI_MAC_ADDR_LEN);
      +               env_set("wifi_mac", output);
      +               pr_msg("=========%s->%d fly  test wifi_mac:%s==============\n", __func__, __LINE__, output);
      +       }else{
      +               pr_msg("=========%s->%d sunxi_secure_storage_init failed==============\n", __func__, __LINE__);
      +       }
      +
      +       free(sst_info);
      +       return 0;
      +}
      

      通过sunxi_secure_object_read()接口根据偏移量读取分区中已经烧好的mac地址,赋值给wifi_mac。在通过env_set()接口将获取到的mac地址传递到env。

      2.device/config/chips/r818/configs/ailabs_dictpen/linux/env.cfg

      27 #set kernel cmdline if boot.img or recovery.img has no cmdline we will use this
      28 setargs_nand=setenv bootargs console=${console}...mac_addr=${mac} wifi_mac=${wifi_mac} bt_mac=${bt_mac}
      29 setargs_mmc=setenv bootargs console=${console}...mac_addr=${mac} wifi_mac=${wifi_mac} bt_mac=${bt_mac}
      

      内核读取env.cfg时再把wifi_mac取出来,通过addr-mgt驱动获取。

      3.lichee/linux-4.9/drivers/misc/sunxi-addr-mgt/sunxi-addr-mgt.c

      83 int get_wifi_custom_mac_address(char *addr_str)
       84 {
       85         if (IS_TYPE_INVALID(info.type_cur_wifi) ||
       86                 addr_parse(info.addr_wifi, 1))
       87                 return -1;
       88
       89         strcpy(addr_str, info.addr_wifi);  //直接拷贝info结构体的mac地址属性,最原始的就是uboot阶段的sst_info
       90         return info.type_cur_wifi;
       91 }
      
      

      4.xr829驱动获取lichee/linux-4.9/drivers/net/wireless/xr829/wlan/main.c

      478 extern int get_wifi_custom_mac_address(char *addr_str);
      479
      480 #define MAC_FROM_CHIPID
      481 static void xradio_get_mac_addrs(u8 *macaddr)
      482 {
      483         int ret = 0;
      484         char addr_str[20];
      485         SYS_BUG(!macaddr);
      486         /* Check mac addrs param, if exsist, use it first.*/
      487 #ifdef XRADIO_MACPARAM_HEX
      488         memcpy(macaddr, xradio_macaddr_param, ETH_ALEN);
      489 #else
      490         if (xradio_macaddr_param) {
      491                 ret = xradio_macaddr_char2val(macaddr, xradio_macaddr_param);
      492         }
      493 #endif
      494         if (ret < 0 || !MACADDR_VAILID(macaddr)) {
      495                 ret = get_wifi_custom_mac_address(addr_str);  //直接调用addr_mgt驱动的接口,即从分区读的方式获取mac地址。
      496                 if (ret != -1) {
      497                         sscanf(addr_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
      498                                                 &macaddr[0], &macaddr[1], &macaddr[2],
      499                                                 &macaddr[3], &macaddr[4], &macaddr[5]);
      500                 }
      501         }
      502
      503         /* Use random value to set mac addr for the first time,
      504          * and save it in  wifi config file. TODO: read from product ID*/
      505         if (ret < 0 || !MACADDR_VAILID(macaddr)) {
      506 #ifdef XRADIO_MACPARAM_HEX
      507                 ret = access_file(WIFI_CONF_PATH, macaddr, ETH_ALEN, 1);  //自定义mac地址写入文件后,从文件获取mac地址
      508 #else
      509                 char  c_mac[XRADIO_MAC_CHARLEN+2] = {0};
      510                 ret = access_file(WIFI_CONF_PATH, c_mac, XRADIO_MAC_CHARLEN, 1);
      511                 if (ret >= 0) {
      512                         ret = xradio_macaddr_char2val(macaddr, c_mac);
      513                 }
      514 #endif
      515
      516                 if (ret < 0 || !MACADDR_VAILID(macaddr)) {
      517 #if defined(MAC_FROM_CHIPID)
      518                         u32 databuf[4] = {0};
      519
      520                         sunxi_get_soc_chipid((u8 *)databuf); //获取chipid后定制mac地址的方式
      521                         macaddr[0] = (((databuf[1] >> 28) & 0x0f) | ((databuf[2] & 0x0f) << 4)) & 0xff;
      522                         macaddr[1] = (databuf[2] >> 4)  & 0xff;
      523                         macaddr[2] = (databuf[2] >> 12) & 0xff;
      524                         macaddr[3] = (databuf[3] >> 6)  & 0xff;
      525                         macaddr[4] = (databuf[3] >> 16) & 0xff;
      526                         macaddr[5] = (databuf[3] >> 26) & 0xff;
      527 #else
      528                         get_random_bytes(macaddr, 6);  //随机生成mac地址的方式
      529 #endif
      530                         macaddr[0] &= 0xFC;
      531 #ifdef XRADIO_MACPARAM_HEX
      532                         ret = access_file(WIFI_CONF_PATH, macaddr, ETH_ALEN, 0);
      533 #else
      534                         ret = xradio_macaddr_val2char(c_mac, macaddr);
      535                         ret = access_file(WIFI_CONF_PATH, c_mac, ret, 0);
      536 #endif
      537                         if (ret < 0)
      538                                 xradio_dbg(XRADIO_DBG_ERROR, "Access_file failed, path:%s!\n",
      539                                            WIFI_CONF_PATH);
      540                         if (!MACADDR_VAILID(macaddr)) {
      541                                 xradio_dbg(XRADIO_DBG_WARN, "Use default Mac addr!\n"); //驱动默认可以写死一个mac地址。
      542                                 macaddr[0] = 0xDC;
      543                                 macaddr[1] = 0x44;
      544                                 macaddr[2] = 0x6D;
      545                         } else {
      546                                 xradio_dbg(XRADIO_DBG_NIY, "Use random Mac addr!\n");
      547                         }
      548                 } else {
      549                         xradio_dbg(XRADIO_DBG_NIY, "Use Mac addr in file!\n");
      550                 }
      551         }
      552         xradio_dbg(XRADIO_DBG_NIY, "MACADDR=%02x:%02x:%02x:%02x:%02x:%02x\n",
      553                    macaddr[0], macaddr[1], macaddr[2],
      554                    macaddr[3], macaddr[4], macaddr[5]);
      555 }
      

      解决方法

      1.工作获取

      从全志一号通入口获取
      https://one.allwinnertech.com/#/devtool?menuID=37
      a8203b64ba8e4e7aa280601c97a2e095.jfif

      2.烧写流程

      前提条件:软件支持从private分区获取mac地址。

      2.1配置添加类型
      464f186fa856440b973c1ae85f141fe0.jfif

      2.2设置key类型

      7db4b3c81ae64de9b131a0e7605d14dd.jfif

      2.3开始烧写

      2efb03b1da4f40baac83c9a5f7fcb766.jfif

      2.4烧写成功

      0ad8ea85eb80430a9e8442ba373aaaf0.jfif

      3.确认操作
      可以直接通过系统起来后ifconfig命令查看mac地址是否与烧写的一致

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志R329在Tina如何在蓝牙已连接情况下拒绝其他耳机回连

      问题背景
      系统:Tina
      平台:R818、V833 扫描笔产品
      蓝牙功能:a2dp source

      问题概述
      (1)客户有一个蓝牙音箱和一个蓝牙耳机,并且这两个设备之前都已经跟扫描笔连接配对过了。
      (2)客户主动让扫描笔连接上蓝牙音箱。
      (3)打开蓝牙耳机,此时蓝牙耳机回连上扫描笔。
      但是客户不想要这个场景存在,希望只有一个连接存在。

      问题分析
      蓝牙耳机打开后回连这个动作,我们无法阻止它,只能想办法拒绝他。
      如果在应用层处理,连上了再把它断开,这个会影响状态的管理,也不是最好的解决方法。
      所以我们考虑再收到连接请求事件时,就拒绝了它。linux的蓝牙驱动层会处理HCI上报的
      事件,因此我们可以在驱动完成这个逻辑。

      解决方法
      代码路径:
      lichee/linux-4.9/net/bluetooth/hci_event.c
      连接请求处理函数:hci_conn_request_evt 中增加如下代码:
      首先判断连接类型是否是ACL_LINK,然后获取当前连接数,如果当前已经有连接了,就拒绝本次的连接请求。

      if (ev->link_type == ACL_LINK) {
              if ((hci_conn_num(hdev, ACL_LINK) != 0) && (hdev->dev_type == HCI_PRIMARY)) {
                  BT_INFO("already exist acl link, reject new! %s, %d", __func__, __LINE__);
                  hci_reject_conn(hdev, &ev->bdaddr);
                  return;
              }
          }
      

      修改过之后的代码如下:

      static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
      {
          struct hci_ev_conn_request *ev = (void *) skb->data;
          int mask = hdev->link_mode;
          struct inquiry_entry *ie;
          struct hci_conn *conn;
          __u8 flags = 0;
      
          BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr,
                 ev->link_type);
      
          mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type,
                            &flags);
      
          if (!(mask & HCI_LM_ACCEPT)) {
              hci_reject_conn(hdev, &ev->bdaddr);
              return;
          }
      
          if (ev->link_type == ACL_LINK) {
              if ((hci_conn_num(hdev, ACL_LINK) != 0) && (hdev->dev_type == HCI_PRIMARY)) {
                  BT_INFO("already exist acl link, reject new! %s, %d", __func__, __LINE__);
                  hci_reject_conn(hdev, &ev->bdaddr);
                  return;
              }
          }
      
          if (hci_bdaddr_list_lookup(&hdev->blacklist, &ev->bdaddr,
                         BDADDR_BREDR)) {
              hci_reject_conn(hdev, &ev->bdaddr);
              return;
          }
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 1
    • 2
    • 2 / 2