导航

    全志在线开发者论坛

    • 注册
    • 登录
    • 搜索
    • 版块
    • 话题
    • 在线文档
    • 社区主页
    1. 主页
    2. yanmingjian
    Y
    • 资料
    • 关注 1
    • 粉丝 5
    • 我的积分 4185
    • 主题 45
    • 帖子 72
    • 最佳 12
    • 群组 0

    giaoLV 6

    @yanmingjian

    4185
    积分
    21
    声望
    77
    资料浏览
    72
    帖子
    5
    粉丝
    1
    关注
    注册时间 最后登录
    位置 直布罗陀

    yanmingjian 取消关注 关注

    yanmingjian 发布的最佳帖子

    • 【全志T113-S3_100ask】Linux蓝牙通信实战

      (一)初始化蓝牙

      # 复位蓝牙
      echo 0 > /sys/class/rfkill/rfkill0/state
      sleep 1
      echo 1 > /sys/class/rfkill/rfkill0/state
      sleep 1
      
      # 绑定蓝牙设备
      hciattach -n ttyS1 xradio > /dev/null 2>&1 &
      sleep 8
      
      # 启用蓝牙设备
      hciconfig hci0 up
      hciconfig hci0 piscan
      

      (二)Linux下蓝牙工具(bluez 工具集)

      • hcitool、bluetoothctl等工具,可以进行BLE设备的扫描、连接、配对、广播等操作
      • hcitool 可以发送HCI command,设置BLE的广播数据
      • bluetoothctl 可以新增蓝牙服务,返回回调等操作
      • sdptool 查看蓝牙信息和提供的服务
      • hciconfig 查看蓝牙信息
      • l2ping 测试蓝牙的连通性
      • gatttool :可以在GATT层面,完成GATT profile的连接、service
      • attribute的读写等操作

      (三)蓝牙扫描

      hcitool scan 	#扫描经典蓝牙
      
      hcitool lescan	 #扫描BL低功耗蓝牙
      

      (四)使用Bluetoothctl创建蓝牙服务

      1、先启动蓝牙,进入可搜索状态

      # 复位蓝牙
      echo 0 > /sys/class/rfkill/rfkill0/state
      sleep 1
      echo 1 > /sys/class/rfkill/rfkill0/state
      sleep 1
      
      # 绑定设备
      hciattach -n ttyS1 xradio > /dev/null 2>&1 &
      sleep 8
      
      # 启用蓝牙设备
      hciconfig hci0 up
      hciconfig hci0 piscan
      
      # 免认证
      hciconfig hci0 auth
      # 广播
      hciconfig hci0 leadv
      

      2、进入 bluetoothctl 交互界面

      # bluetoothctl
      Agent registered
      [CHG] Controller 22:92:C9:8C:04:EA Pairable: yes
      [bluetooth]#
      

      3、手机使用BLE调试助手连接蓝牙,如下图所示

      d0b7a80a50f54b4b97d83d16901c7a69.jpeg

      4、连接后,bluetoothctl会发生变化,此时已经进入交互界面

      60c7807b5b42449cb17eb4e0e8d8b178.png

      4、但是我们没有其他服务,只能做一些简单的操作,比如读取,因为现有的服务是 bluetoothctl 提供的

      4d528dd7f4f743b997a69f9eeb76f4f5.jpeg

      5、下面我们添加自己的服务

      5.1 进入菜单

      [6B-3C-BF-AD-2A-A8]# menu gatt
      Menu gatt:
      Available commands:
      -------------------
      list-attributes [dev/local]                       List attributes
      select-attribute <attribute/UUID>                 Select attribute
      attribute-info [attribute/UUID]                   Select attribute
      read [offset]                                     Read attribute value
      write <data=xx xx ...> [offset] [type]            Write attribute value
      acquire-write                                     Acquire Write file descriptor
      release-write                                     Release Write file descriptor
      ....
      

      5.2 添加自己的service和characteristic

      [bluetoothctl] register-service 0xFFFF # (Choose yes when asked if primary service)
      [bluetoothctl] register-characteristic 0xAAAA read       # (Select a value of 1 when prompted)# 输入的值是初始值,每次读取,会加一
      [bluetoothctl] register-characteristic 0xBBBB read,write # (Select a value of 0 when prompted)
      [bluetoothctl] register-characteristic 0xCCCC read       # (Select a value of 2 when prompted)
      [bluetoothctl] register-application # (This commits the services/characteristics and registers the profile)
      [bluetoothctl] back
      [bluetoothctl] advertise on
      

      通过 show 操作可以看到刚才添加的0xffff 服务

      5.3 手机重新连接蓝牙
      服务从 3 项变为 4 项,第 4 项即为我们刚才添加的服务。

      be8fe95d320e42ccb5be219f087fee32.png

      5.4 读写操作
      在有上传按钮的服务上传数据

      92d75d26a94440e5aa84a19d9298ed2f.png

      此时收到:

      75c9a34123c246318a871e302ba74cd4.png

      读操作的话,直接读取就好了,值为刚才我们设置的值。
      至此测试完毕

      (五)其他操作

      1、启动/关闭/重启蓝牙

      hciconfig hci0 up  		#启动蓝牙设备
      hciconfig hci0 off 		#关闭蓝牙设备
      hciconfig hci0 reset 	#重启蓝牙设备
      

      2、测试蓝牙是否可达 l2ping

      l2ping -i hci0 -c 4 21:12:A3:C4:50:66
      

      3、查看功能与服务

      sdptool browse local    # local可以改成其它蓝牙的mac地址
      

      4、查看蓝牙的状态和信息

      hciconfig -a
      

      5、查看蓝牙设备

      hcitool dev
      Devices:
              hci0    22:22:2A:B0:9C:3C
      

      6、开启/关闭蓝牙广播

      hciconfig hci0 leadv / noleadv
      

      7、查看已经连接的BLE设备
      (此时调试助手已经连接)

      hcitool -i hci0 con
      Connections:
              > LE 60:AB:D1:B5:A6:FB handle 0 state 1 lm PERIPHERAL
      

      8、 蓝牙认证打开/关闭
      直接体现在进行蓝牙连接时,是否输入连接PIN密码,用于PIN配对

      hciconfig hci0 auth/noauth
      

      9、 查看/改变蓝牙主从状态

      hciconfig hci0 lm master、hciconfig hci0 lm slave
      

      10、查看/设置蓝牙名称

      hciconfig hci0 name 、hciconfig hci0 name BLXX
      

      11、 查看支持的链路层状态

      hciconfig hci0 lestates
      

      12、列出低功耗蓝牙的服务

      bluetoothctl --monitor gatt.list-attributes
      

      其他操作自己慢慢摸索哈,我一个人只能啃成这样了,如有写得不对的地方大佬指正。

      原文链接:https://blog.csdn.net/qq_46079439/article/details/126244998

      发布在 T Series
      Y
      giao
    • 香橙派One(全志H3芯片)编译烧写U-boot、Linux内核zImage、dtb

      一、编译烧写u-boot

      1.1 源码和工具下载:

      香橙派提供了u-boot源码和交叉编译链工具:
      (1)u-boot(2020.04)下载地址:https://github.com/orangepi-xunlong/u-boot-orangepi
      (2)交叉编译工具链(arm-linux-gnueabihf-)下载地址:https://github.com/orangepi-xunlong/toolchain

      1.2 编译烧写u-boot

      (1)进入到u-boot源码目录下,先清理一下工程:

      make -j8 ARCH=arm CROSS_COMPILE=/home/jing/orangepi/toolchain-master/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- distclean
      

      交叉编译工具的路径根据自己实际情况修改

      (2)编译生成.config配置文件

      make -j8 ARCH=arm CROSS_COMPILE=/home/jing/orangepi/toolchain-master/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- orangepi_one_defconfig
      

      注意:需要的defconfig配置信息在u-boot源码的configs文件夹下,我用的是香橙派One开发板,所以make的是orangepi_one_defconfig

      编译完成后如下图:

      f2bda6737073451cacbf1b4f4b36deb0.png

      (3)编译u-boot

      make -j8 ARCH=arm CROSS_COMPILE=/home/jing/orangepi/toolchain-master/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
      

      编译成功后会在u-boot目录下面生成一个.bin文件,这个文件就是我们要烧写到SD卡的u-boot二进制文件

      1c5b8a0616d643a1b17500d5e94bb46f.png

      (4)烧写u-boot

      将SD卡插入读卡器,将读卡器连接电脑,在u-boot目录下,将.bin文件烧写到SD卡中

      sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdb bs=1024 seek=8
      

      1.3 u-boot启动

      将SD卡插入到香橙派开发板,连接开发板串口,启动测试,若输出如下则启动正常

      8db895e996c547d893e16a49177f49ff.png

      可以看出u-boot会把版本号、板载硬件信息等都打印出来

      二、烧录Linux内核zImage、dtb

      2.1 Linux内核源码下载
      这里使用香橙派官方提供的linux内核源码,版本为Linux5.4.65:

      https://github.com/orangepi-xunlong/linux-orangepi
      

      2.2 Linux内核编译
      进入linux内核目录,依次输入以下命令,指定交叉编译器和处理器架构:

      make -j8 ARCH=arm CROSS_COMPILE=/home/jing/orangepi/toolchain-master/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- distclean // 清理工程
      make -j8 ARCH=arm CROSS_COMPILE=/home/jing/orangepi/toolchain-master/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- sunxi_defconfig // 生成.config配置文件
      make -j8 ARCH=arm CROSS_COMPILE=/home/jing/orangepi/toolchain-master/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- // 开始编译
      

      编译完成后,我们需要的镜像zImage,设备树文件sun8i-h3-orangepi-pc.dtb都出现了:

      • zImage在/arch/arm/boot目录下

      • sun8i-h3-orangepi-pc.dtb在/arch/arm/boot/dts目录下

      2.3 zImage和dtb加载

      zImage和dtb烧录有两种办法,一种是通过tftp远程加载,另一种是直接从SD卡加载,在加载之前,需要知道全志H3芯片从内存启动内核和设备树的地址,在u-boot输入命令printenv,查看环境变量,会看到如下两个信息:

      fdt_addr_r=0x43000000
      kernel_addr_r=0x42000000
      

      可知设备树文件是从内存的0x43000000地址启动,内核是从内存的0x42000000地址启动。

      (1)tftp远程加载zImage和dtb
      本文所有的开发都是基于Ubuntu18.04虚拟机,所以为了方便传输,直接将zImage和dtb文件拷贝到windows下,建立开发板与windows之间的tftp传输,这里借助Mobaxterm软件直接设置tftp服务,在图中红框部分填写好tftp连接到的本地目录。

      e0925fb07bbd4ba2849103fe4e04e332.png

      需要先对开发板环境变量进行以下设置:

      setenv ipaddr=192.168.1.101 // 设置开发板ip地址
      setenv gatewayip=192.168.1.1 // 设置网关
      setenv netmask=255.255.255.0 // 设置子网掩码
      setenv serverip=192.168.1.104 // 设置tftp主机的ip地址
      saveenv // 保存环境变量
      

      注意:开发板的ip地址和主机的ip地址要保存在一个网关下(连接到同一个路由器),开发板的网关和子网掩码与主机设置一致,设置完后重启一下开发板

      ping一下主机ip,试一下能不能连接到主机,出现alive就代表可以连接

      f2bda6737073451cacbf1b4f4b36deb0.png

      接着在开发板u-boot敲入以下命令行,将两个文件加载到内存:

      tftp 42000000 zImage // 将zImage加载到内存的0x42000000位置处
      tftp 43000000 sun8i-h3-orangepi-pc.dtb // 将设备树加载到内存0x43000000位置处
      

      加载成功的话,会有一个Loading的进度条和done表示完成。

      接着启动内核和设备树:

      bootz 42000000 - 43000000 // 启动内核和设备树
      

      启动成功的话,会有以下界面,另外开发板上的led灯也会从红色变为绿色:

      525fceb67752412997e4b456a961800a.png

      由于没有加载根文件系统,所以启动过程会卡在VFS:Unable to mount root f…

      (2)从SD卡加载zImage和dtb
      有的文章会对SD卡进行分区,然后将两个文件放在不同的分区中,参考文献[2]。本文这里为了方便操作,不对SD卡分区,直接将两个文件拷贝到SD卡中,然后将SD卡插到开发板上。启动u-boot,输入以下命令:

      load mmc 0:1 0x43000000 sun8i-h3-orangepi-pc.dtb
      load mmc 0:1 0x42000000 zImage
      
      • 第一个命令解释:从mmc(SD卡)的第0个和第1个分区寻找名字叫做sun8i-h3-orangepi-pc.dtb的文件,然后加载到内存的0x43000000位置上

      • 第二个命令解释:从mmc(SD卡)的第0个和第1个分区寻找名字叫做zImage的文件,然后加载到内存的0x42000000位置上
        接着加载内核和设备树:

      bootz 42000000 - 43000000
      

      启动成功的话,会有以下界面:另外开发板上的led灯也会从红色变为绿色

      525fceb67752412997e4b456a961800a (1).png

      由于没有加载根文件系统,所以启动过程会卡在VFS:Unable to mount root f…

      如果不想每次都load加载,可以设置开机环境变量,每次开机都可以自动加载:

      setenv bootcmd 'load mmc 0:1 0x43000000 sun8i-h3-orangepi-pc.dtb; load mmc 0:1 0x42000000 zImage; bootz 0x42000000 - 0x43000000'
      saveenv
      

      要想真正启动Linux系统,下一步还需要建立根文件系统,敬请期待!

      ————————————————
      版权声明:本文为CSDN博主「小景-SCUT」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
      原文链接:https://blog.csdn.net/weixin_39954922/article/details/130984241

      发布在 H/F/TV Series
      Y
      giao
    • 我们拆了一款将ChatGPT“落地”的AI语音交互机器人,八核A7全志R58主控

      视频版本拆机:【60块钱,垃圾佬的第一台机器人,国产8核CPU全志R58】 https://www.bilibili.com/video/BV1Qk4y177ja/?share_source=copy_web&vd_source=6ec797f0de1d275e996fb7de54dea06b

      公子·小白是一对由狗尾草智能科技推出的人工智能机器人,该系列中的产品包括公子小白、公子小白Pro、Smart Plus公子小白、公子小白成长版、公子小白青春版......这次要拆的这个机器人是公子小白系列,它在16/17年左右首发价是1880元,但这次从闲鱼淘来它,只花了60元。

      微信图片_2023050810343520.jpg

      微信图片_20230428181738.jpg

      公子小白机器人主打“情感社交”场景,机器人背后的狗尾草智能科技算是国内比较早一批进行AI语音交互机器人设计的公司,这要是放到现在也可以算是半个ChatGPT概念公司了。

      拆开外包装,看到这个说明书,中间连接的钉子都已经生锈了,生产时间写的是2017年的2月。17年生产的东西到现在还是全新未开封啊,可见当时的备货太多了,也是奔着百万级市场去做的,但是现在公司的官网和APP都显示不可用了,微信公众号的最新推文日期已然停留在了2020年,估计已经停止官方支持了。

      微信图片_20230508170302.jpg

      微信图片_20230504152246.png

      确实,当时这个产品是领先时代的,他们的slogan是“AI虚拟生命终将走进每一个人的生活”,翻译一下就是前些时间爆火的元宇宙概念吗?AI、智慧生命、元宇宙、ChatGPT,这些都是时下最火热的行业话题。

      但回到16/17年,那时的人工智能发展尚未成熟,只能进行单论的对话,并且经常答非所问,难一点的问题都无法回答,也无法通过图灵测试,那时候我们经常把人工智能说是“人工智障”,但是如果这个产品放到现在来做,接任ChatGPT,或许会是另一番光景啊。

      拆解

      这个机器人的表面十分圆滑,想拆开它还要费点劲,在机器人外部找不到任何一颗裸露的螺丝钉,经常一番捣鼓才发现它的拆解之道,首先需要找到隐藏的硅胶塞把它挖出来,把钉子卸了,然后强行把头给撬下来,这样就可以看到里面的大致结构了。

      微信图片_20230428163457.jpg

      首先看到主板上,主控是全志的R58,一款8核的芯片,上面固定了散热片,这颗芯片的价格差不多是10美金,折合人民币60多块钱,如果单从淘散料倒卖的角度来说,就凭这一颗主控就已经差不多回本了,那么到这里拆解就结束了。

      微信图片_202304281656143.jpg
      20181225021710234.jpg

      全志R58,8核A7*1.8GHz,这差不多是十年前的芯片啊,十年前的国产8核芯片,早期很多国内的带屏智能音箱、视频电话用的都是全志这颗R58的芯片,比如小鱼在家的视频电话,小鱼在家后来被百度收购了,于是也就成了后来小度在家智能视频音箱的原型。由此可见R58性能还是很高的,也有一些安卓平板选用了R58作为主控,在此基础上应该可以升级出很多有趣的玩法。

      a507808496b8650f6fc493f0ea28bc7a.jpg

      640.png

      这里有一颗AXP813,是一颗电源管理芯片,集成电源管理,音频解码器,兼容USB3.0的充电器,RTC,模数转换器和硬件DSP,内部音频模块集成动态范围控制器,和自动增益控制,可在录音时提高信噪比,降低背景噪声干扰。这颗芯片也是全志旗下的,作为电源管理芯片一般都是跟主控成套片出售。

      微信图片_202304281656144.jpg

      两颗1GB 的SK 海力士的DDR3。

      微信图片_202304281656141.jpg

      一颗镁光的8GB的nand flash。

      微信图片_202304281656142.jpg

      这有一颗AP6255的wifi/蓝牙模组,这个模组应该是支持2.4G和5G的,16年的时候5G的路由器都不是很普及,机器人内容没有选用AP6212而是用AP6255,真的是对未来充满了期待,是奔着这个产品生命周期会延续很多年来设计的。

      微信图片_20230428165614.jpg

      这里有两颗科声讯的CX208,这是两颗语音处理芯片,里面集成了语音算法。比如降噪、回声消除、声源定位、唤醒词识别等等。但是我们现在基本都不用这种外挂的语音处理芯片了,一般是把语音处理部分放到主控里去跑,有的主控里还集成了专门跑语音算法的DSP或者NPU。

      微信图片_20230504140934.jpg

      每颗CX208可以连接2颗麦克风,所以我们看到上面是一个4麦克风的阵列,用的是早期的驻极体麦克风,现在的智能语音AIOT产品基本都不用这种麦克风了,基本上的都是硅麦。

      图片1.png 微信图片_202305081702491.jpg

      主板后面接了一个屏幕,是一个方形的5寸左右的屏幕,然后用这个结构件把它框起来,这样看起来就是弧形的脸,把边角的部分挡住,就可以显示那个机器人的各种表情了。这个挡板的结构设计也很有意思。

      微信图片_202305041447128.jpg 微信图片_202305081702494.jpg

      如果设备还能运行的话,可以看到这个屏幕上会显示很多表情。因为现在这家公司的服务器都不运行了,所以都玩不了了。但是我要是这家公司最后的员工啊,我就让这个屏幕继续播放广告,会像某不退押金的共享单车一样,榨干他的最后价值。

      这上面还有一个摄像头,是用来扫码和人脸试别用的,他会试别人脸的位置,跟着人动,也可以对人的表情做出判断,比如你不开心就给你讲笑话安慰你,或者是识别到前面是小朋友的时候,就播放适合小朋友的内容。当然这些都是理论功能啊,不知道这些功能有没有实现。

      微信图片_2023050414471211.jpg 微信图片_20230504151318.jpg

      然后下面是一个舵机,控制值这个机器人头转动的。我们来听一下这个声音,很有机器人感觉的那个声音,很有未来感,这么多年过去了和是很有质感,一看就是贵东西啊。

      微信图片_20230508170249.jpg

      然后下面这个是充电环的设计,跟airpod耳机底部的充电环是一样的。airpod耳机那个是有专利的,很多耳机厂商早年做tws耳机的时候就中过招。

      微信图片_20230504151324.jpg

      以上是比较重要的几个零部件介绍,其它的还有很多就不一一介绍了,最后上一张拆解的总览图。

      微信图片_202305081702492.jpg

      结语

      这是一个16年时候的人工智能产品啊,当时还处于智能语音发展的早期,算法、方案、供应链成熟度都还处于一个刚刚能做产品的状态。AI对话只能试别简单的内容,只能做单轮对话不能做多轮对话,我们说那个时候的人工智能是弱人工智能。

      今年随着chatGPT的大火,国内外资本纷纷入局,人工智能又被推到了一个新的高度,如果这个产品放到现在做,或许或有更好的体验和更广阔的市场。

      现在的chatGPT已经可以通过图灵测试了,智商达到了一个大学生的水平,但是这些输出在2023年4月的今天,还只是停留在纸面上,不过从技术难度上来说,让它和机器人结合落地已经不存在瓶颈了,只是把输出结果再转化一次成为行代命令而且,所以,我们很期待马上到来的强人工智能时代,期待有更多改变我们生活的伟大产品。

      视频版本拆机:【60块钱,垃圾佬的第一台机器人,国产8核CPU全志R58】 https://www.bilibili.com/video/BV1Qk4y177ja/?share_source=copy_web&vd_source=6ec797f0de1d275e996fb7de54dea06b

      发布在 灌水区
      Y
      giao
    • 全志平台A40I 读写寄存器操作

      1、查看规格书

      30f9c4049ab2d12985e5587b5ddaca20.png d63b16eb2458971e96c4d2f7d67e3fcb.png

      我们以A40平台为例,可以找到一些寄存器的地址和含义。

      例如:

      • 0x01C20400 偏移0x100+7*0x04=0x01C20528=GP_DATA_REG,这是GPIO端口数据寄存器,用于控制GPIO的输出电平。

      • 0x01C20400 偏移0x190=0x01C20590=VDD_RT_REG,这是实时电压调节寄存器,用于控制CPU核心电压。

      2、查看地址

      我们可以使用adb shell进入设备的命令行界面,然后使用sunxi_dump类来读取或写入寄存器。

      首先,需要进入sunxi_dump类的目录:

      adb shell
      cd /sys/class/sunxi_dump
      

      可以使用echo命令将寄存器的地址写入dump文件:

      echo 0x01C20590 > dump
      

      可以使用cat命令来查看dump文件的内容,即寄存器的值:

      cat dump
      

      3、读取寄存器
      读取寄存器的方法和查看地址的方法相同,只需要将想要读取的寄存器的地址写入dump文件,然后查看dump文件的内容即可。

      例如,我们想要读取VDD_RT_REG寄存器的值,就可以这样做:

      adb shell
      cd /sys/class/sunxi_dump
      echo 0x01C20590 > dump
      cat dump
      

      4、写入寄存器
      写入寄存器的方法和读取寄存器的方法类似,只需要将想要写入的寄存器的地址和值用空格分隔写入write文件即可。

      c4875ebeeba9445b7e8f0c95949faeb6.png

      例如,我们想要将VDD_RT_REG寄存器的值设置为1.1V,就可以这样做:

      adb shell
      cd /sys/class/sunxi_dump
      echo 0x01C20590 0x00000022 > write
      

      注意:写入寄存器可能会影响设备的正常运行或造成损坏,请谨慎搞

      发布在 创龙科技专区
      Y
      giao
    • 2022年7月版——在“哪吒”上跑AI 全志D1 ncnn框架移植笔记

      ncnn框架是当前边缘计算的主流框架,关于全志D1运行ncnn框架的笔记,nihui大佬曾经于2021年发表了相关的帖子。但是目前工具链和ncnn版本有所变化,因此在大佬的基础上将,完整过程记录如下。

      相关链接:
      1.https://bbs.aw-ol.com/topic/705/
      2.https://zhuanlan.zhihu.com/p/386312071?utm_source=qq&utm_medium=social&utm_oi=872955404320141312

      1 准备交叉编译工具链

      目前使用的交叉工具链是v2.2.6版本,具体下载链接见:https://occ.t-head.cn/community/download?id=4046947553902661632

      下载这个文件:Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz

      tar -xf Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz
      export RISCV_ROOT_PATH=/home/{你的用户名}/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6
      

      2 下载和编译ncnn

      这边的toolchain file选用c906-v226.toolchain.cmake,其余的不用修改,在toolchain file里面都已经改好了。其中可能有路径问题,根据ncnn文件夹,实际所在的路径修改即可。

      git clone https://github.com/Tencent/ncnn.git
      cd ncnn
      mkdir build-c906
      cd build-c906
      cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/c906-v226.toolchain.cmake -DCMAKE_BUILD_TYPE=release -DNCNN_OPENMP=OFF -DNCNN_THREADS=OFF -DNCNN_RUNTIME_CPU=OFF -DNCNN_RVV=ON -DNCNN_SIMPLEOCV=ON -DNCNN_BUILD_EXAMPLES=ON ..
      make -j4
      

      3 测试benchncnn

      目前2.0版本的TinaLinux 执行 ncnn 程序已经不会有问题

      将 ncnn/build-c906/benchmark/benchncnn 和 ncnn/benchmark/*.param 拷贝到 d1开发板上,路径结构如下:

      80abd156fc86ba2c318912d87e220577.png

      chmod 0777 benchncnn 
      ./benchncnn 4 1 0 -1 0
      
      oot@TinaLinux:~/ncnn# ./benchncnn 4 1 0 -1 0
      syscall error -1
      loop_count = 4
      num_threads = 1
      powersave = 0
      gpu_device = -1
      cooling_down = 0
      fopen squeezenet.param failed
      network graph not ready
      Segmentation fault
      root@TinaLinux:~/ncnn# ./benchncnn 4 1 0 -1 0
      syscall error -1
      loop_count = 4
      num_threads = 1
      powersave = 0
      gpu_device = -1
      cooling_down = 0
                squeezenet  min =  382.77  max =  385.92  avg =  384.66
           squeezenet_int8  min = 8975.18  max = 8979.84  avg = 8977.72
                 mobilenet  min =  702.76  max =  704.76  avg =  703.74
            mobilenet_int8  min = 29501.19  max = 29546.07  avg = 29514.59
              mobilenet_v2  min =  451.34  max =  452.27  avg =  451.78
              mobilenet_v3  min =  358.12  max =  359.24  avg =  358.42
                shufflenet  min =  527.04  max =  528.48  avg =  527.69
             shufflenet_v2  min =  310.96  max =  312.30  avg =  311.59
                   mnasnet  min =  435.13  max =  437.02  avg =  435.94
           proxylessnasnet  min =  473.05  max =  476.37  avg =  475.19
           efficientnet_b0  min =  601.75  max =  610.41  avg =  606.18
         efficientnetv2_b0  min =  859.37  max =  861.75  avg =  860.67
              regnety_400m  min =  653.71  max =  654.24  avg =  653.88
                 blazeface  min =  154.08  max =  154.67  avg =  154.38
                 googlenet  min = 1404.80  max = 1409.50  avg = 1407.33
            googlenet_int8  min = 42586.56  max = 42608.04  avg = 42597.36
                  resnet18  min = 1047.81  max = 1050.59  avg = 1049.40
             resnet18_int8  min = 45011.41  max = 45185.10  avg = 45098.12
                   alexnet  min =  955.34  max =  956.98  avg =  956.06
                     vgg16  min = 5355.40  max = 5356.05  avg = 5355.75
      

      如果一切运行正常,则会出现上述信息。

      4 测试example

      将 ncnn/build-c906/examples/nanodet 和测试图片拷贝到 d1开发板上

      从这里下载 nanodet 模型文件并拷贝到 d1开发板上

      nihui/ncnn-assets​github.com/nihui/ncnn-assets/tree/master/models

      目录结构如下:

      35b2dd1eb5e8a25b37f92325da1c0b16.png

      注意,进过测试,jpg格式的图像读取时会报错,png格式没有问题

      ./nanodet test.png
      

      bd0e8ab3ee50032c1a82e873a5aa8576.png
      177b58a5b1e4b24788974154c648b8b8.png

      发布在 MR Series
      Y
      giao
    • 通过物联网管理多台MQTT设备-基于米尔T527开发板

      一、系统概述

      基于米尔-全志 T527设计一个简易的物联网网关,该网关能够管理多台MQTT设备,通过MQTT协议对设备进行读写操作,同时提供HTTP接口,允许用户通过HTTP协议与网关进行交互,并对设备进行读写操作。

      二、系统架构

      • 网关服务:基于FastAPI框架构建的Web服务,提供HTTP接口。
      • MQTT客户端:负责与MQTT设备通信,管理设备连接、消息发布和订阅。
      • 设备管理:维护一个设备列表,记录设备的基本信息和状态。
      • 数据存储:使用内存或数据库存储设备数据,确保数据持久化。

      三、组件设计

      MQTT组件:

      • 负责与MQTT broker建立连接。
      • 订阅设备主题,接收设备发送的消息。
      • 发布消息到设备,实现远程控制。

      设备管理组件:

      • 维护一个设备列表,记录设备的唯一标识符(如设备ID)、MQTT主题、连接状态等信息。
      • 提供设备增删改查的方法。

      HTTP组件:

      • 基于FastAPI定义HTTP接口。
      • 接收用户请求,调用MQTT组件和设备管理组件进行相应操作。
      • 返回操作结果给用户。

      四、接口设计

      设备列表:

      • GET /devices:返回所有设备的列表。
      • POST /devices:添加新设备到网关。
      • DELETE /devices/{device_id}:从网关中删除指定设备。

      设备详情:

      • GET /devices/{device_id}:返回指定设备的详细信息。

      设备数据:

      • GET /devices/{device_id}/data:获取指定设备的最新数据。
      • POST /devices/{device_id}/data:发送数据到指定设备。

      设备控制:

      P* OST /devices/{device_id}/control:发送控制命令到指定设备。

      五、数据结构设计

      设备信息:

      • 设备ID (device_id):唯一标识设备的字符串。
      • MQTT主题 (mqtt_topic):设备在MQTT broker上的主题。
      • 连接状态 (connection_status):表示设备是否在线的布尔值。
      • 其他设备属性(如名称、描述等)。

      设备数据:

      • 设备ID (device_id):关联设备信息的设备ID。
      • 时间戳 (timestamp):数据发送或接收的时间。
      • 数据内容 (data):设备发送或接收的具体数据,可以是JSON格式或* 其他格式。

      六、安全性考虑

      • 使用HTTPS协议提供安全的HTTP通信。
      • 实现用户认证和授权机制,确保只有授权用户可以访问和操作设备。
      • 对于敏感操作(如删除设备),要求用户进行二次确认或提供额外的安全措施。

      七、部署与扩展

      • 使用Docker容器化部署网关服务,便于管理和扩展。
      • 根据需要,可以水平扩展网关实例以处理更多的设备连接和请求。

      八、实现步骤

      • 安装所需的Python库:fastapi, uvicorn, paho-mqtt等。
      • 创建FastAPI应用并定义路由。
      • 实现MQTT组件,包括与MQTT broker的连接、订阅、发布等功能。
      • 实现设备管理组件,维护设备列表并提供增删改查的方法。
      • 实现HTTP组件,调用MQTT组件和设备管理组件处理用户请求。
      • 编写测试代码,验证网关的各项功能是否正常工作。
      • 部署网关服务并监控其运行状态。

      该设计方案仅仅是概述,具体实现细节可能需要根据实际需求和项目环境进行调整和优化。在实际开发中,还需要考虑异常处理、日志记录、性能优化等方面的问题。基于上述设计方案,以下是一个简化版的参考代码,展示了如何使用FastAPI和paho-mqtt库来创建一个物联网网关。需要注意,示例中不包含完整的错误处理、用户认证和授权机制,这些在实际生产环境中都是必不可少的。依赖的主要库版本:

      
      fastapi==0.108.0
      paho-mqtt==1.6.1
      

      网关模拟代码gateway.py:

      
      from fastapi import FastAPI, HTTPException, Body, status  
      from paho.mqtt.client import Client as MQTTClient
      from typing import List, Dict, Any  
      import asyncio  
      import json  
        
      app = FastAPI()  
      mqtt_client = None  
      device_data = {}  
      
      subtopic="gateway/device/#"
      
        
      # MQTT回调函数  
      def on_message(client, userdata, msg):  
          payload = msg.payload.decode()  
          topic = msg.topic  
          device_id = topic.split('/')[-1]  
          device_data[device_id] = payload 
          print(f"Received message from {device_id}: {payload}")  
        
      # MQTT连接和订阅  
      def mqtt_connect_and_subscribe(broker_url, broker_port):  
          global mqtt_client  
          mqtt_client = MQTTClient()  
          mqtt_client.on_message = on_message  
          mqtt_client.connect(broker_url, broker_port, 60)  
          mqtt_client.subscribe(subtopic)  
          mqtt_client.loop_start()  
        
      # MQTT发布消息  
      async def mqtt_publish(topic: str, message: str):  
          if mqtt_client is not None and mqtt_client.is_connected():  
              mqtt_client.publish(topic, message)  
          else:  
              print("MQTT client is not connected!")  
        
      # 设备管理:添加设备  
      @app.post("/devices/", status_code=status.HTTP_201_CREATED)  
      async def add_device(device_id: str):  
          device_data[device_id] = None  
          return {"message": f"Device {device_id} added"}  
        
      # 设备管理:获取设备列表  
      @app.get("/devices/")  
      async def get_devices():  
          return list(device_data.keys())  
        
      # 设备管理:获取设备数据  
      @app.get("/devices/{device_id}/data")  
      async def get_device_data(device_id: str):  
          if device_id not in device_data:  
              raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Device {device_id} not found")  
          return device_data.get(device_id)  
        
      # 设备管理:发送数据到设备  
      @app.post("/devices/{device_id}/data")  
      async def send_data_to_device(device_id: str, data: Dict[str, Any] = Body(...)):  
          topic = f"devices/{device_id}"  
          message = json.dumps(data)  
          await mqtt_publish(topic, message)  
          return {"message": f"Data sent to {device_id}"}  
        
      # 设备控制:发送控制命令到设备  
      @app.post("/devices/{device_id}/control")  
      async def control_device(device_id: str, command: str):  
          topic = f"devices/device/{device_id}"  
          await mqtt_publish(topic, command)  
          return {"message": f"Control command sent to {device_id}"}  
        
      # FastAPI启动事件  
      @app.on_event("startup")  
      async def startup_event():  
          mqtt_connect_and_subscribe("127.0.0.1", 1883)  
        
      # FastAPI关闭事件  
      @app.on_event("shutdown")  
      async def shutdown_event():  
          if mqtt_client is not None:  
              mqtt_client.loop_stop()  
              mqtt_client.disconnect()  
        
      # 运行FastAPI应用  
      if __name__ == "__main__":  
          import uvicorn  
          uvicorn.run(app, host="127.0.0.1", port=8000)   
      
      
      

      设备1模拟代码 dev1.py:

      
      import paho.mqtt.client as mqtt
      
      # 连接成功回调
      def on_connect(client, userdata, flags, rc):
          print('Connected with result code '+str(rc))
          client.subscribe('devices/1')
      
      # 消息接收回调
      def on_message(client, userdata, msg):
          print(msg.topic+" "+str(msg.payload))
          client.publish('gateway/device/1',payload=f'echo {msg.payload}',qos=0)
      
      client = mqtt.Client()
      
      # 指定回调函数
      client.on_connect = on_connect
      client.on_message = on_message
      
      # 建立连接
      client.connect('127.0.0.1', 1883)
      # 发布消息
      client.publish('gateway/device/1',payload='Hello, I am device',qos=0)
      
      client.loop_forever()
      

      设备2模拟代码 dev2.py

      import paho.mqtt.client as mqtt# 连接成功回调def on_connect(client, userdata, flags, rc):    print('Connected with result code '+str(rc))    client.subscribe('devices/2')# 消息接收回调def on_message(client, userdata, msg):    print(msg.topic+" "+str(msg.payload))    client.publish('gateway/device/2',payload=f'echo {msg.payload}',qos=0)client = mqtt.Client()# 指定回调函数client.on_connect = on_connectclient.on_message = on_message# 建立连接client.connect('127.0.0.1', 1883)# 发布消息client.publish('gateway/device/2',payload='Hello, I am device',qos=0)client.loop_forever()
      

      运行网关代码,打开网页得到api接口:
      1f6ec1bf-8616-4028-b98f-5a711f5a8ebc-image.png

      通过api分别添加设备1和设备2,
      f5df9b1b-94d3-48b1-834c-8291e7fb1c72-image.png

      在另外两个控制台中分别运行模拟设备1和模拟设备2的代码

      通过网页API向设备1发送数据

      09c62349-cada-4196-9b02-17c378f1a9e5-image.png

      通过网页API获得设备回复的数据,设备代码中只是简单的把网关发过来的数据进行回传

      5339ebb2-5e88-4265-bb7a-d234c9cf6f99-image.png

      我们在网关的后台可以看到完整的数据流

      c261a61d-68b3-4e7b-ad18-bce1ff0852ca-image.png

      至此一个简易的网关已经实现了,接下来将会尝试实现楼宇里的最常见的bacnet设备进行通讯管理。

      发布在 T Series
      Y
      giao
    • 回复: 启动卡在这,就不会动了,然后也无法烧录了

      短接这两个触点
      然后上电烧录

      微信图片_20230922105738.jpg

      发布在 Wireless & Analog Series
      Y
      giao
    • 【全志T113-S3_100ask】4-编写按键驱动(atomic + poll)

      前言

      本来想写一下点灯的驱动的,结果发现板子上没有用户的led灯?????那就试着写一下按键的驱动吧。

      (一)查看原理图

      在原理图里,找到了用户按键USER KEY的内容

      9615353f06ef4042b70e91e77e520006.png

      并且是连接在核心板的PB 4 引脚上

      f908d56c63824ae79d531898b7db6ff1.png

      看起来没有用作其他功能。

      (二)修改设备树

      设备树在以下目录里
      /disk/buildroot-100ask_t113-pro/buildroot/output/build/linux-d96275805a67d54998123d36e59108cb1ed52ad5/arch/arm/boot/dts

      添加一级子节点

      key { 
      	#address-cells = <1>; 
      	#size-cells = <1>;
      	reg = <0x0 0x0 0x0 0x0>;
        	compatible = "allwinner,sunxi-pinctrl-test"; 
        	pinctrl-names = "default"; 
       	pinctrl-0 = <&key_pins_a>; 
        	key-gpio = <&pio PB 4 GPIO_ACTIVE_LOW>; /* KEY0 */ 
        	status = "okay"; 
      };
      

      添加 pio

      key_pins_a: userkey { 
      	allwinner,pins = "PB4" ; 
      };
      

      添加后如下:
      6fe9c7a2005e4587951203a03e00a11b.png

      (三)编写驱动 key_drv.c

      #include <linux/types.h>
      #include <linux/kernel.h>
      #include <linux/delay.h>
      #include <linux/ide.h>
      #include <linux/init.h>
      #include <linux/module.h>
      #include <linux/errno.h>
      #include <linux/gpio.h>
      #include <linux/cdev.h>
      #include <linux/device.h>
      #include <linux/of.h>
      #include <linux/of_address.h>
      #include <linux/of_gpio.h>
      #include <linux/semaphore.h>
      #include <asm/mach/map.h>
      #include <asm/uaccess.h>
      #include <asm/io.h>
      
      #define KEY_CNT			1		/* 设备号个数 	*/
      #define KEY_NAME		"key"	/* 名字 		*/
      
      /* 定义按键值 */
      #define KEY0VALUE		0XF0	/* 按键值 		*/
      #define INVAKEY			0X00	/* 无效的按键值  */
      
      /* key设备结构体 */
      struct key_dev{
      	dev_t devid;			/* 设备号 	 */
      	struct cdev cdev;		/* cdev 	*/
      	struct class *class;	/* 类 		*/
      	struct device *device;	/* 设备 	 */
      	int major;				/* 主设备号	  */
      	int minor;				/* 次设备号   */
      	struct device_node	*nd; /* 设备节点 */
      	int key_gpio;			/* key所使用的GPIO编号		*/
      	atomic_t keyvalue;		/* 按键值 		*/	
      };
      
      struct key_dev keydev;		/* key设备 */
      
      /*
       * @description	: 初始化按键IO,open函数打开驱动的时候
       * 				  初始化按键所使用的GPIO引脚。
       * @param 		: 无
       * @return 		: 无
       */
      static int keyio_init(void)
      {
      	keydev.nd = of_find_node_by_path("/key");
      	if (keydev.nd== NULL) {
      		return -EINVAL;
      	}
      
      	keydev.key_gpio = of_get_named_gpio(keydev.nd ,"key-gpio", 0);
      	if (keydev.key_gpio < 0) {
      		printk("can't get key0\r\n");
      		return -EINVAL;
      	}
      	printk("key_gpio=%d\r\n", keydev.key_gpio);
      	
      	/* 初始化key所使用的IO */
      	gpio_request(keydev.key_gpio, "key0");	/* 请求IO */
      	gpio_direction_input(keydev.key_gpio);	/* 设置为输入 */
      	return 0;
      }
      
      /*
       * @description		: 打开设备
       * @param - inode 	: 传递给驱动的inode
       * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
       * 					  一般在open的时候将private_data指向设备结构体。
       * @return 			: 0 成功;其他 失败
       */
      static int key_open(struct inode *inode, struct file *filp)
      {
      	int ret = 0;
      	filp->private_data = &keydev; 	/* 设置私有数据 */
      
      	ret = keyio_init();				/* 初始化按键IO */
      	if (ret < 0) {
      		return ret;
      	}
      
      	return 0;
      }
      
      /*
       * @description		: 从设备读取数据 
       * @param - filp 	: 要打开的设备文件(文件描述符)
       * @param - buf 	: 返回给用户空间的数据缓冲区
       * @param - cnt 	: 要读取的数据长度
       * @param - offt 	: 相对于文件首地址的偏移
       * @return 			: 读取的字节数,如果为负值,表示读取失败
       */
      static ssize_t key_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
      {
      	int ret = 0;
      	int value;
      	struct key_dev *dev = filp->private_data;
      
      	if (gpio_get_value(dev->key_gpio) == 0) { 		/* key0按下 */
      		while(!gpio_get_value(dev->key_gpio));		/* 等待按键释放 */
      		atomic_set(&dev->keyvalue, KEY0VALUE);	
      	} else {	
      		atomic_set(&dev->keyvalue, INVAKEY);		/* 无效的按键值 */
      	}
      
      	value = atomic_read(&dev->keyvalue);
      	ret = copy_to_user(buf, &value, sizeof(value));
      	return ret;
      }
      
      /*
       * @description		: 向设备写数据 
       * @param - filp 	: 设备文件,表示打开的文件描述符
       * @param - buf 	: 要写给设备写入的数据
       * @param - cnt 	: 要写入的数据长度
       * @param - offt 	: 相对于文件首地址的偏移
       * @return 			: 写入的字节数,如果为负值,表示写入失败
       */
      static ssize_t key_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
      {
      	return 0;
      }
      
      /*
       * @description		: 关闭/释放设备
       * @param - filp 	: 要关闭的设备文件(文件描述符)
       * @return 			: 0 成功;其他 失败
       */
      static int key_release(struct inode *inode, struct file *filp)
      {
      	return 0;
      }
      
      /* 设备操作函数 */
      static struct file_operations key_fops = {
      	.owner = THIS_MODULE,
      	.open = key_open,
      	.read = key_read,
      	.write = key_write,
      	.release = 	key_release,
      };
      
      /*
       * @description	: 驱动入口函数
       * @param 		: 无
       * @return 		: 无
       */
      static int __init mykey_init(void)
      {
      	/* 初始化原子变量 */
      	atomic_set(&keydev.keyvalue, INVAKEY);
      
      	/* 注册字符设备驱动 */
      	/* 1、创建设备号 */
      	if (keydev.major) {		/*  定义了设备号 */
      		keydev.devid = MKDEV(keydev.major, 0);
      		register_chrdev_region(keydev.devid, KEY_CNT, KEY_NAME);
      	} else {						/* 没有定义设备号 */
      		alloc_chrdev_region(&keydev.devid, 0, KEY_CNT, KEY_NAME);	/* 申请设备号 */
      		keydev.major = MAJOR(keydev.devid);	/* 获取分配号的主设备号 */
      		keydev.minor = MINOR(keydev.devid);	/* 获取分配号的次设备号 */
      	}
      	
      	/* 2、初始化cdev */
      	keydev.cdev.owner = THIS_MODULE;
      	cdev_init(&keydev.cdev, &key_fops);
      	
      	/* 3、添加一个cdev */
      	cdev_add(&keydev.cdev, keydev.devid, KEY_CNT);
      
      	/* 4、创建类 */
      	keydev.class = class_create(THIS_MODULE, KEY_NAME);
      	if (IS_ERR(keydev.class)) {
      		return PTR_ERR(keydev.class);
      	}
      
      	/* 5、创建设备 */
      	keydev.device = device_create(keydev.class, NULL, keydev.devid, NULL, KEY_NAME);
      	if (IS_ERR(keydev.device)) {
      		return PTR_ERR(keydev.device);
      	}
      	
      	return 0;
      }
      
      /*
       * @description	: 驱动出口函数
       * @param 		: 无
       * @return 		: 无
       */
      static void __exit mykey_exit(void)
      {
      	/* 注销字符设备驱动 */
      	gpio_free(keydev.key_gpio);
      	cdev_del(&keydev.cdev);/*  删除cdev */
      	unregister_chrdev_region(keydev.devid, KEY_CNT); /* 注销设备号 */
      
      	device_destroy(keydev.class, keydev.devid);
      	class_destroy(keydev.class);
      }
      
      module_init(mykey_init);
      module_exit(mykey_exit);
      MODULE_LICENSE("GPL");
      MODULE_AUTHOR("z");
      

      参考了正点原子的按键驱动:

      (四)编写测试应用 key_drv_test.c

      #include "stdio.h"
      #include "unistd.h"
      #include "sys/types.h"
      #include "sys/stat.h"
      #include "fcntl.h"
      #include "stdlib.h"
      #include "string.h"
      
      /* 定义按键值 */
      #define KEY0VALUE	0XF0
      #define INVAKEY		0X00
      
      /*
       * @description		: main主程序
       * @param - argc 	: argv数组元素个数
       * @param - argv 	: 具体参数
       * @return 			: 0 成功;其他 失败
       */
      int main(int argc, char *argv[])
      {
      	int fd, ret;
      	char *filename;
      	int keyvalue;
      	
      	if(argc != 2){
      		printf("Error Usage!\r\n");
      		return -1;
      	}
      
      	filename = argv[1];
      
      	/* 打开key驱动 */
      	fd = open(filename, O_RDWR);
      	if(fd < 0){
      		printf("file %s open failed!\r\n", argv[1]);
      		return -1;
      	}
      
      	/* 循环读取按键值数据! */
      	while(1) {
      		read(fd, &keyvalue, sizeof(keyvalue));
      		if (keyvalue == KEY0VALUE) {	/* KEY0 */
      			printf("KEY0 Press, value = %#X\r\n", keyvalue);	/* 按下 */
      		}
      	}
      
      	ret= close(fd); /* 关闭文件 */
      	if(ret < 0){
      		printf("file %s close failed!\r\n", argv[1]);
      		return -1;
      	}
      	return 0;
      }
      

      (五)编写Makefile

      KERN_DIR = /disk/buildroot-100ask_t113-pro/buildroot/output/build/linux-d96275805a67d54998123d36e59108cb1ed52ad5
      
      
      all:
      	make -C $(KERN_DIR) M=`pwd` modules 
      	$(CROSS_COMPILE)gcc -o key_drv_test key_drv_test.c 
      
      clean:
      	make -C $(KERN_DIR) M=`pwd` modules clean
      	rm -rf modules.order
      	rm -f key_drv_test
      
      obj-m	+= key_drv.o
      

      (六)测试

      编译驱动

      root@znh-ubuntu:/disk/vsCode/04_key# ls
      key_drv.c  key_drv_test.c  Makefile
      
      root@znh-ubuntu:/disk/vsCode/04_key# make
      make -C /disk/buildroot-100ask_t113-pro/buildroot/output/build/linux-d96275805a67d54998123d36e59108cb1ed52ad5 M=`pwd` modules
      make[1]: 进入目录“/disk/buildroot-100ask_t113-pro/buildroot/output/build/linux-d96275805a67d54998123d36e59108cb1ed52ad5”
        CC [M]  /disk/vsCode/04_key/key_drv.o
        Building modules, stage 2.
        MODPOST 1 modules
        CC [M]  /disk/vsCode/04_key/key_drv.mod.o
        LD [M]  /disk/vsCode/04_key/key_drv.ko
      make[1]: 离开目录“/disk/buildroot-100ask_t113-pro/buildroot/output/build/linux-d96275805a67d54998123d36e59108cb1ed52ad5”
      arm-linux-gnueabi-gcc -o key_drv_test key_drv_test.c
      
      root@znh-ubuntu:/disk/vsCode/04_key# ls
      key_drv.c   key_drv.mod    key_drv.mod.o  key_drv_test    Makefile       Module.symvers
      key_drv.ko  key_drv.mod.c  key_drv.o      key_drv_test.c  modules.order
      root@znh-ubuntu:/disk/vsCode/04_key#
      

      编译kernel、buildroot、烧卡、tftp:略

      测试驱动

      # chmod 777 key_drv_test
      # ls
      key_drv.ko    key_drv_test
      
      # insmod key_drv.ko
      [  162.979954] key_drv: loading out-of-tree module taints kernel.
      
      # ./key_drv_test /dev/key
      [  166.293872] key_gpio=36
      KEY0 Press, value = 0XF0
      KEY0 Press, value = 0XF0
      KEY0 Press, value = 0XF0
      ^C
      
      # ls /proc/device-tree
      #address-cells                memory@40000000
      #size-cells                   model
      aliases                       name
      chosen                        pio-18
      compatible                    pio-33
      cpu-opp-table                 pmu
      cpus                          power-management@ff000000
      dcxo24M_clk                   psci
      dram                          rc16m_clk
      dump_reg@20000                share_space@0x42100000
      ext32k_clk                    soc@3000000
      firmware                      thermal-zones
      interrupt-controller@3020000  timer_arch
      interrupt-parent              usb1-vbus
      iommu@2010000                 vdd-cpu
      key
      

      至此,按键驱动完成,但是还有很多需要修改的地方吧,或者很多冗余的东西,以后再修改了。

      原文链接:https://blog.csdn.net/qq_46079439/article/details/125899592

      发布在 其它全志芯片讨论区
      Y
      giao
    • 使用 D1s (RDC2022 纪念版) 连接 thingspeak

      D1s 连接网络

      硬件

      • D1s 开发板
      • RW007 模块

      D1s 开发板 RW007 模块 连接图
      1be560f99717c71203eaa6dcb15d4446.png.webp

      配置 RW007 软件包

      e5113c656db614ac2dfa5121542b6a93.png

      D1s 开发板 通过 SPI0 连接到 RW007 WiFi 模块
      c850f902f35d0cf99afaff939a8f991a.png

      使用 pkgs —update 更新软件包

      更新软件包之后 将 rw007 软件包中的 struct rw007_spi 结构体定义中的 ALIGN 改为 rt_align

      即可使用 wifi 指令连接 wifi 了

      d9b338ead18dc751decf8baff8e1bde8.png

      注: D1s 开发板 和 RW007 模块 之间同时使用将会有一些小问题

      • 在上电情况下插 RW007 模块 串口终端将会断掉,重新打开串口终端软件即可
      • 插着 RW007 模块 上电、复位 都将进入 FEL 模式,需要通过 xfel.exe reset 命令退出

      配置 thingspeak

      • 第一次使用时需要注册用户

      • 新建频道

      这里只使用最基本的功能,创建了一个数据接口 field1 后续需要通过 field1 来上传数据

      50b82be02283298b8bf698c28a235c50.png.webp

      查看创建好频道的相关 http 的 api

      1ff02f0469f34cd290e57e76904105b1.png

      如下图所示 Write a Channel Feed API 中最后的 field1=0 就是上传的数据(这里 0 不局限于数字,经验证字符串也是可以的)

      bc0fa0047f77d062dc8cd666379359ed.png.webp

      由于 thingspeak 使用了 GET 协议 我们这里使用了 webclient 软件包来进行数据的上传

      添加 webclient 软件包

      7cd0921c801e5e1cd69308bf762f7adc.png

      添加 rt-thread/bsp/allwinner/d1s/applications/thingspeak.c 文件

      将 GET_LOCAL_URI 宏定义的值换为你自己的 Write a Channel Feed API

      #include <stdio.h>
      #include <webclient.h>
      #define GET_LOCAL_URI "http://api.thingspeak.com/update?api_key=XXXXXXXXXXXX&field1="
      static int webclient_get_smpl(const char *uri)
      {
          char *response = RT_NULL;
          size_t resp_len = 0;
          int index;
          if (webclient_request(uri, RT_NULL, RT_NULL, 0, (void **)&response, &resp_len) < 0)
          {
              rt_kprintf("webclient send get request failed.");
              return -RT_ERROR;
          }
          rt_kprintf("webclient send get request by simplify request interface.\n");
          rt_kprintf("webclient get response data: \n");
          for (index = 0; index < rt_strlen(response); index++)
          {
              rt_kprintf("%c", response[index]);
          }
          rt_kprintf("\n");
          if (response)
          {
              web_free(response);
          }
          return 0;
      }
      static int thingspeak(void)
      {
          char uri[80];
          srand();
          int number;
          while(1)
          {
              number = rand() % 100;
              sprintf(uri, "%s%d", GET_LOCAL_URI, number);
              webclient_get_smpl(uri);
              rt_kprintf("random number is %d\r\n",number);
              rt_thread_mdelay(20000);
          }
      }
      MSH_CMD_EXPORT(thingspeak, thingspeak);
      
      

      上述文件为 每隔 20 秒,将开发板随机出来的 0~100 值上传到 thingspeak

      编译,下载,运行之后,连接 WIFI 后 使用 thingspeak 命令运行程序,如果出现下面这种情况则表明成功
      thread.org/ask/article/a5b655730a865335.html

      0adcb59be2a03db460356a4d1a4cbf37.png

      也可以通过 API Keys 中的其他 API 查询到开发板上传的数据

      20d48684d3cadde52e1bd71660cd0e3a.png

      另外这里还有可视化的图标供我们观看

      42a83f4369a07a302ab9ec81f5541972.png

      原文链接:https://club.rt-thread.org/ask/article/a5b655730a865335.html

      发布在 MR Series
      Y
      giao
    • 【全志T113-S3_100ask】使用内核驱动点灯(控制继电器)

      背景

      开发板上没有led灯,且没用其他引出的GPIO,所以就借rgb屏幕的引脚来点个灯(不过分吧@狗头),实现控制继电器。

      (一)寻找合适的GPIO

      看了好久的原理图,怕与其他功能冲突,所以就使用了 PD13 作为本次实验的引脚。

      该引脚除了作为rgb屏幕的功能外,好像没其他作用了,好,就它了。

      4f64437d6891425bbdf72cd15c831ea1.png

      (二)跳线

      焊接飞线接到继电器上。

      88d1fc81a8da470eb4dab00da065c4d0.png

      (三)修改设备树

      参考开发文档

      Documentation/devicetree/bindings/leds/leds-gpio.txt

      LEDs connected to GPIO lines
      
      Required properties:
      - compatible : should be "gpio-leds".
      
      Each LED is represented as a sub-node of the gpio-leds device.  Each
      node's name represents the name of the corresponding LED.
      
      LED sub-node properties:
      - gpios :  Should specify the LED's GPIO, see "gpios property" in
        Documentation/devicetree/bindings/gpio/gpio.txt.  Active low LEDs should be
        indicated using flags in the GPIO specifier.
      - function :  (optional)
        see Documentation/devicetree/bindings/leds/common.txt
      - color :  (optional)
        see Documentation/devicetree/bindings/leds/common.txt
      - label :  (optional)
        see Documentation/devicetree/bindings/leds/common.txt (deprecated)
      - linux,default-trigger :  (optional)
        see Documentation/devicetree/bindings/leds/common.txt
      - default-state:  (optional) The initial state of the LED.
        see Documentation/devicetree/bindings/leds/common.txt
      - retain-state-suspended: (optional) The suspend state can be retained.Such
        as charge-led gpio.
      - retain-state-shutdown: (optional) Retain the state of the LED on shutdown.
        Useful in BMC systems, for example when the BMC is rebooted while the host
        remains up.
      - panic-indicator : (optional)
        see Documentation/devicetree/bindings/leds/common.txt
      
      Examples:
      
      #include <dt-bindings/gpio/gpio.h>
      #include <dt-bindings/leds/common.h>
      
      leds {
              compatible = "gpio-leds";
              led0 {
                      gpios = <&mcu_pio 0 GPIO_ACTIVE_LOW>;
                      linux,default-trigger = "disk-activity";
                      function = LED_FUNCTION_DISK;
              };
      
              led1 {
                      gpios = <&mcu_pio 1 GPIO_ACTIVE_HIGH>;
                      /* Keep LED on if BIOS detected hardware fault */
                      default-state = "keep";
                      function = LED_FUNCTION_FAULT;
              };
      };
      
      run-control {
              compatible = "gpio-leds";
              led0 {
                      gpios = <&mpc8572 6 GPIO_ACTIVE_HIGH>;
                      color = <LED_COLOR_ID_RED>;
                      default-state = "off";
              };
              led1 {
                      gpios = <&mpc8572 7 GPIO_ACTIVE_HIGH>;
                      color = <LED_COLOR_ID_GREEN>;
                      default-state = "on";
              };
      };
      
      leds {
              compatible = "gpio-leds";
      
              led0 {
                      gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
                      linux,default-trigger = "max8903-charger-charging";
                      retain-state-suspended;
                      function = LED_FUNCTION_CHARGE;
              };
      };
      

      简单来说就是指定 compatible = “gpio-leds” 就好了

      在根节点下添加:

      dtsleds { 
       	compatible = "gpio-leds";
       	led0 { 
      	 	label = "red";
      	  	gpios = <&pio PD 13 GPIO_ACTIVE_HIGH>; 
      	  	default-state = "off"; 
      	}; 
      };
      

      实例:

      ccc98029b00242ca904ebe910195495c.png

      (四)使能内核的LED驱动

      cbb51d2bde1b437a81d953fc17574778.png

      路径参考:

      Symbol: LEDS_GPIO [=y]                                                                                       │
       │ Type  : tristate                                                                                             │
       │ Prompt: LED Support for GPIO connected LEDs                                                                  │
       │   Location:                                                                                                  │
       │     -> Device Drivers                                                                                        │
       │       -> LED Support (NEW_LEDS [=y])                                                                         │
       │   Defined at drivers/leds/Kconfig:307                                                                        │
       │   Depends on: NEW_LEDS [=y] && LEDS_CLASS [=y] && (GPIOLIB [=y] || COMPILE_TEST [=n])                        │
       │   Selected by [n]:                                                                                           │
       │   - PCENGINES_APU2 [=n] && X86 && X86_PLATFORM_DEVICES [=n] && INPUT [=y] && INPUT_KEYBOARD [=y] && \        │
       │ GPIOLIB [=y] && LEDS_CLASS [=y]
      

      然后编译烧写系统。

      (五)测试验证

      1、寻找设备树,在 /proc/device-tree 下

      9ffd69cded23467d85204c0a6efdeb78.png

      2、点亮

      在 /sys/class/leds/red 下可以找到相关的属性

      下面使 brightness 属性为 1 .即可点亮

      echo 1 > /sys/class/leds/red/brightness
      

      继电器接通!!

      关闭的话,使用以下命令即可

      echo 0 > /sys/class/leds/red/brightness
      

      至此测试完毕

      原文链接:https://blog.csdn.net/qq_46079439/article/details/126131219
      作者@第四维度

      发布在 MR Series
      Y
      giao

    yanmingjian 发布的最新帖子

    • 通过物联网管理多台MQTT设备-基于米尔T527开发板

      一、系统概述

      基于米尔-全志 T527设计一个简易的物联网网关,该网关能够管理多台MQTT设备,通过MQTT协议对设备进行读写操作,同时提供HTTP接口,允许用户通过HTTP协议与网关进行交互,并对设备进行读写操作。

      二、系统架构

      • 网关服务:基于FastAPI框架构建的Web服务,提供HTTP接口。
      • MQTT客户端:负责与MQTT设备通信,管理设备连接、消息发布和订阅。
      • 设备管理:维护一个设备列表,记录设备的基本信息和状态。
      • 数据存储:使用内存或数据库存储设备数据,确保数据持久化。

      三、组件设计

      MQTT组件:

      • 负责与MQTT broker建立连接。
      • 订阅设备主题,接收设备发送的消息。
      • 发布消息到设备,实现远程控制。

      设备管理组件:

      • 维护一个设备列表,记录设备的唯一标识符(如设备ID)、MQTT主题、连接状态等信息。
      • 提供设备增删改查的方法。

      HTTP组件:

      • 基于FastAPI定义HTTP接口。
      • 接收用户请求,调用MQTT组件和设备管理组件进行相应操作。
      • 返回操作结果给用户。

      四、接口设计

      设备列表:

      • GET /devices:返回所有设备的列表。
      • POST /devices:添加新设备到网关。
      • DELETE /devices/{device_id}:从网关中删除指定设备。

      设备详情:

      • GET /devices/{device_id}:返回指定设备的详细信息。

      设备数据:

      • GET /devices/{device_id}/data:获取指定设备的最新数据。
      • POST /devices/{device_id}/data:发送数据到指定设备。

      设备控制:

      P* OST /devices/{device_id}/control:发送控制命令到指定设备。

      五、数据结构设计

      设备信息:

      • 设备ID (device_id):唯一标识设备的字符串。
      • MQTT主题 (mqtt_topic):设备在MQTT broker上的主题。
      • 连接状态 (connection_status):表示设备是否在线的布尔值。
      • 其他设备属性(如名称、描述等)。

      设备数据:

      • 设备ID (device_id):关联设备信息的设备ID。
      • 时间戳 (timestamp):数据发送或接收的时间。
      • 数据内容 (data):设备发送或接收的具体数据,可以是JSON格式或* 其他格式。

      六、安全性考虑

      • 使用HTTPS协议提供安全的HTTP通信。
      • 实现用户认证和授权机制,确保只有授权用户可以访问和操作设备。
      • 对于敏感操作(如删除设备),要求用户进行二次确认或提供额外的安全措施。

      七、部署与扩展

      • 使用Docker容器化部署网关服务,便于管理和扩展。
      • 根据需要,可以水平扩展网关实例以处理更多的设备连接和请求。

      八、实现步骤

      • 安装所需的Python库:fastapi, uvicorn, paho-mqtt等。
      • 创建FastAPI应用并定义路由。
      • 实现MQTT组件,包括与MQTT broker的连接、订阅、发布等功能。
      • 实现设备管理组件,维护设备列表并提供增删改查的方法。
      • 实现HTTP组件,调用MQTT组件和设备管理组件处理用户请求。
      • 编写测试代码,验证网关的各项功能是否正常工作。
      • 部署网关服务并监控其运行状态。

      该设计方案仅仅是概述,具体实现细节可能需要根据实际需求和项目环境进行调整和优化。在实际开发中,还需要考虑异常处理、日志记录、性能优化等方面的问题。基于上述设计方案,以下是一个简化版的参考代码,展示了如何使用FastAPI和paho-mqtt库来创建一个物联网网关。需要注意,示例中不包含完整的错误处理、用户认证和授权机制,这些在实际生产环境中都是必不可少的。依赖的主要库版本:

      
      fastapi==0.108.0
      paho-mqtt==1.6.1
      

      网关模拟代码gateway.py:

      
      from fastapi import FastAPI, HTTPException, Body, status  
      from paho.mqtt.client import Client as MQTTClient
      from typing import List, Dict, Any  
      import asyncio  
      import json  
        
      app = FastAPI()  
      mqtt_client = None  
      device_data = {}  
      
      subtopic="gateway/device/#"
      
        
      # MQTT回调函数  
      def on_message(client, userdata, msg):  
          payload = msg.payload.decode()  
          topic = msg.topic  
          device_id = topic.split('/')[-1]  
          device_data[device_id] = payload 
          print(f"Received message from {device_id}: {payload}")  
        
      # MQTT连接和订阅  
      def mqtt_connect_and_subscribe(broker_url, broker_port):  
          global mqtt_client  
          mqtt_client = MQTTClient()  
          mqtt_client.on_message = on_message  
          mqtt_client.connect(broker_url, broker_port, 60)  
          mqtt_client.subscribe(subtopic)  
          mqtt_client.loop_start()  
        
      # MQTT发布消息  
      async def mqtt_publish(topic: str, message: str):  
          if mqtt_client is not None and mqtt_client.is_connected():  
              mqtt_client.publish(topic, message)  
          else:  
              print("MQTT client is not connected!")  
        
      # 设备管理:添加设备  
      @app.post("/devices/", status_code=status.HTTP_201_CREATED)  
      async def add_device(device_id: str):  
          device_data[device_id] = None  
          return {"message": f"Device {device_id} added"}  
        
      # 设备管理:获取设备列表  
      @app.get("/devices/")  
      async def get_devices():  
          return list(device_data.keys())  
        
      # 设备管理:获取设备数据  
      @app.get("/devices/{device_id}/data")  
      async def get_device_data(device_id: str):  
          if device_id not in device_data:  
              raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Device {device_id} not found")  
          return device_data.get(device_id)  
        
      # 设备管理:发送数据到设备  
      @app.post("/devices/{device_id}/data")  
      async def send_data_to_device(device_id: str, data: Dict[str, Any] = Body(...)):  
          topic = f"devices/{device_id}"  
          message = json.dumps(data)  
          await mqtt_publish(topic, message)  
          return {"message": f"Data sent to {device_id}"}  
        
      # 设备控制:发送控制命令到设备  
      @app.post("/devices/{device_id}/control")  
      async def control_device(device_id: str, command: str):  
          topic = f"devices/device/{device_id}"  
          await mqtt_publish(topic, command)  
          return {"message": f"Control command sent to {device_id}"}  
        
      # FastAPI启动事件  
      @app.on_event("startup")  
      async def startup_event():  
          mqtt_connect_and_subscribe("127.0.0.1", 1883)  
        
      # FastAPI关闭事件  
      @app.on_event("shutdown")  
      async def shutdown_event():  
          if mqtt_client is not None:  
              mqtt_client.loop_stop()  
              mqtt_client.disconnect()  
        
      # 运行FastAPI应用  
      if __name__ == "__main__":  
          import uvicorn  
          uvicorn.run(app, host="127.0.0.1", port=8000)   
      
      
      

      设备1模拟代码 dev1.py:

      
      import paho.mqtt.client as mqtt
      
      # 连接成功回调
      def on_connect(client, userdata, flags, rc):
          print('Connected with result code '+str(rc))
          client.subscribe('devices/1')
      
      # 消息接收回调
      def on_message(client, userdata, msg):
          print(msg.topic+" "+str(msg.payload))
          client.publish('gateway/device/1',payload=f'echo {msg.payload}',qos=0)
      
      client = mqtt.Client()
      
      # 指定回调函数
      client.on_connect = on_connect
      client.on_message = on_message
      
      # 建立连接
      client.connect('127.0.0.1', 1883)
      # 发布消息
      client.publish('gateway/device/1',payload='Hello, I am device',qos=0)
      
      client.loop_forever()
      

      设备2模拟代码 dev2.py

      import paho.mqtt.client as mqtt# 连接成功回调def on_connect(client, userdata, flags, rc):    print('Connected with result code '+str(rc))    client.subscribe('devices/2')# 消息接收回调def on_message(client, userdata, msg):    print(msg.topic+" "+str(msg.payload))    client.publish('gateway/device/2',payload=f'echo {msg.payload}',qos=0)client = mqtt.Client()# 指定回调函数client.on_connect = on_connectclient.on_message = on_message# 建立连接client.connect('127.0.0.1', 1883)# 发布消息client.publish('gateway/device/2',payload='Hello, I am device',qos=0)client.loop_forever()
      

      运行网关代码,打开网页得到api接口:
      1f6ec1bf-8616-4028-b98f-5a711f5a8ebc-image.png

      通过api分别添加设备1和设备2,
      f5df9b1b-94d3-48b1-834c-8291e7fb1c72-image.png

      在另外两个控制台中分别运行模拟设备1和模拟设备2的代码

      通过网页API向设备1发送数据

      09c62349-cada-4196-9b02-17c378f1a9e5-image.png

      通过网页API获得设备回复的数据,设备代码中只是简单的把网关发过来的数据进行回传

      5339ebb2-5e88-4265-bb7a-d234c9cf6f99-image.png

      我们在网关的后台可以看到完整的数据流

      c261a61d-68b3-4e7b-ad18-bce1ff0852ca-image.png

      至此一个简易的网关已经实现了,接下来将会尝试实现楼宇里的最常见的bacnet设备进行通讯管理。

      发布在 T Series
      Y
      giao
    • 5个步骤,让你的核桃派玩回当年火爆全球NES游戏

      1.准备好你的nes游戏:

      nes游戏链接:链接:百度网盘 请输入提取码
      提取码:k6sh

      2.安装nes游戏模拟器:

      sudo apt-get install nestopia
      

      3.打开安装好的nes游戏模拟器:

      • 终端打开:
      nestopia
      
      • 桌面系统可左下角开始菜单打开:
        71184d546561c999065082b34e456f7a8d877761.png

      4.选择运行你准备好的nes游戏文件:

      b1d626a793d2f66dc10d69900653fe462c1b58e2_2_669x500.jpeg

      598ed6b0728270c02faf0d8619aef4d8edf54a46_2_669x500.jpeg

      • 找到你存放nes游戏的目录打开运行即可。

      以下运行效果图:
      2e33e2cee23779bfa130c52f2a683a70e3e010f2_2_669x500.jpeg

      5. 键盘操作:Nestopia模拟器的默认键盘操作方式可能如下:

      • 方向键(上、下、左、右):用于控制游戏角色的移动。
      • A键:用于游戏中的确认、攻击或跳跃操作。
      • B键:用于游戏中的取消、特殊技能或射击操作。
      • Start键:用于开始游戏或暂停游戏。
      • Select键:用于选择游戏中的选项或功能

      注:我也没运行完游戏去测评,这个模拟器后面玩一些别的游戏会不会报错暂时不知!!!模拟器手柄操作玩法也是支持的,只是我还没去用,暂时不知道怎么用手柄来玩这个模拟器

      本文转载自:https://forum.walnutpi.com/t/topic/74
      作者@DbL

      发布在 H/F/TV Series
      Y
      giao
    • 回复: 想给R128移植上LVGL按照教程结果失败

      输入cconfig 指令跳转到配置文件夹,然后在这个文件夹找到sys_partition_xip.fex,编辑sys_partition将分区表改大空间

      发布在 A Series
      Y
      giao
    • R128休眠流程前期卡住问题定位思路

      内容背景

      本文在开发过程中或新设备模块添加到休眠框架后,发现前期休眠流程卡住时的快速定位思路。其中前期休眠流程指全局中断未关闭,系统仍可输出log的阶段。

      定位思路

      (1)若只是休眠流程卡住,系统未崩溃,仍可正常处理中断:
      在全局中断未关闭,系统可输出log的阶段,AMP框架仍可正常使用,因此可用另一个核来监控本核的状态或触发本核的backtrace;

      (2)若系统已不再响应事件:
      需要利用休眠不会被清空的寄存器,确认卡住前的最近一次写入情况;

      定位方法

      (1)休眠流程卡住,系统未崩溃,仍可正常处理中断
      示例:系统休眠时,C906概率性卡在AXP设备的休眠回调中:

      • 控制台切换为DSP,使能DSP端PM测试工具宏COMPONENTS_PM_TEST_TOOLS;

      • 上电后DSP使能一个软件唤醒源,此时不会休眠DSP,例如DSP输入

      pm_init_wakesrc -500 2
      pm_list_wakesrc
      pm_enable_wakesrc
      
      • 跑休眠唤醒,在C906复现问题时,对休眠task进行backtrace,例如:
      确认task名称:rpccli rv ts
      对pm task backtrace:rpccli rv backtrace pm_suspend
      

      快速定位C906卡住位置。

      (2)系统已不再响应事件:
      需要利用休眠不会被清空的寄存器,确认卡住前的最近一次写入位置;

      • 使能该核上PM测试工具宏COMPONENTS_PM_TEST_TOOLS;
      • 输入pm_set_record 1,之后休眠唤醒流程会进行阶段记录;
      • 查看pm_record_stage()函数使用的记录寄存器;
      • 若支持不掉电复位,可直接复位后查看该寄存器值,也可使用另一个核或JTAG查看寄存器值,定位到最近一次写入位置。
      发布在 A Series
      Y
      giao
    • 回复: R128 LCD调试报错

      @newcastle 这个是音频那边的问题,可以把audiosystem关闭下先调试屏

      发布在 A Series
      Y
      giao
    • R128 BLE最高吞吐量测试正确配置测试

      在R128使用前我们需要了解BLE的最高吞吐量,以方便评估相关功能的开发。

      首先我们了解一下哪些因素会影响蓝牙的吞吐量:

      1、蓝牙版本与PHY: 蓝牙设备的版本和物理层(PHY)对于吞吐量有很大影响。例如,R128设备支持蓝牙5.0,而蓝牙5.0版本后支持2M PHY,使用2M PHY会获得更高的数据吞吐量。

      2、DLE(数据长度扩展): 在蓝牙4.2版本之后,BLE(蓝牙低功耗)开始支持DLE(也称为长包),使用长包可以使单个BLE数据包传输的payload达到251字节。通常,此功能是默认启用的,这有助于提高数据吞吐量。

      3、MTU与数据发送量: 协议规定LL data PDU的Payload最大为251字节,即一次可以传输251字节的L2CAP数据。在L2CAP Data之上还有4个字节的头部,因此L2CAP的Payload为251-4=247字节,即一次可以传输247字节的ATT data。而在ATT Data之上还有3个字节的头部,所以ATT的payload为247-3=244字节,即一次可以传输244字节的应用数据。MTU(最大传输单元)通常指的是L2CAP的Payload,即ATT data,其大小为247字节。在发送数据时,应尽量减少拆包和组包的过程,以便提高吞吐量。这意味着应用在发送数据时,应尽量每次发送不超过244字节的数据。

      downloadFileByUrl.png

      4、连接间隔: BLE技术的特点是低功耗,这主要是因为BLE的两个设备并不是传统意义上的长连接,而是间隔一段时间进行周期性交互。这个周期性的间隔称为连接间隔。连接间隔越小,单位时间内可以发送的数据包就越多。因此,为了提高吞吐量,应尽量减小连接间隔。

      downloadFile1ByUrl.png

      5、每个连接事件的最大数据包数: 在蓝牙连接过程中,每个连接事件内可以发送的数据包数量通常为7个。如果在一个连接事件内发送过多的数据包,可能会导致吞吐量下降。因此,应尽量保证在一个连接事件内发送不超过7个数据包。

      6、写操作: 在蓝牙通信中,write和write_without_response、indicate和notify是常见的操作方式。write操作需要对方确认,效率相对较低;而write_without_response和notify操作则不需要对方确认,效率较高。因此,为了提高吞吐量,应优先使用write_without_response和notify操作。

      针对以上因素,我们可以制定出一套可以满足最大吞吐需求的正确配置

      1、使用2M PHY
      (1)若我方作为GATTC,应该由我方发起PHY UPDATE的动作。
      在较新的btmanager中已经适配(在SDK V0.9版本后才有),老版本上未有。若客户不使用btmanager,需要自行检查适配。
      (2)若我放作为GATTS,一般支持蓝牙的5.0的手机设备默认有PHY UPDATE的动作。

      2、更新LL data length
      虽然默认支持长包功能,但是为了兼容4.0和4.1版本,蓝牙controller默认还是使用27字节的包发送。
      需要在连接的时候主动更新LL data length为251字节。在较新的btmanager中已经适配(在SDK V0.9版本后才有)。若客户不使用btmanager,需要自行检查适配。

      3、MTU与数据发送量
      L2CAP MTU 设置为247:

      -CONFIG_BT_L2CAP_RX_MTU=65
      +CONFIG_BT_L2CAP_RX_MTU=247
      -CONFIG_BT_L2CAP_TX_MTU=65
      +CONFIG_BT_L2CAP_TX_MTU=247
      

      同时,应用或测试demo在发送数据时,应该每次最多发送244字节。

      4、连接间隔
      连接间隔范围是7.5ms ~ 4s。
      但是并不是越小就越好

      • 连接间隔越小,抗干扰能力就越差。

      • 若蓝牙controller在一个连接事件中能发送7个数据包,连接间隔应该设置大于12.5ms,因为这7个包已经占用了大概9.5ms了。

      • 建议连接间隔在12.5ms、13.75ms、15ms中尝试。

      (1)若我方作为GATTC,可以在btmg_le_connect中指定为连接间隔即可。
      (2)若我放作为GATTS,对方使用的连接间隔太大,我方可以通过协议栈主动更新,相关配置

      -# CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS is not set
      +CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS=y
      +CONFIG_BT_PERIPHERAL_PREF_MIN_INT=11
      +CONFIG_BT_PERIPHERAL_PREF_MAX_INT=11
      +CONFIG_BT_PERIPHERAL_PREF_SLAVE_LATENCY=0
      +CONFIG_BT_PERIPHERAL_PREF_TIMEOUT=42
      

      5、增大协议栈TX和RX buff
      增大协议栈TX buff可以让数据能快速送到蓝牙controller。

      -CONFIG_BT_CONN_TX_MAX=3
      +CONFIG_BT_CONN_TX_MAX=8
      
      -CONFIG_BT_L2CAP_TX_BUF_COUNT=3
      +CONFIG_BT_L2CAP_TX_BUF_COUNT=8
      

      增大RX buff 可以提高接收效率:
      设置为255是因为包含HCI的包头4个字节。

      -CONFIG_BT_RX_BUF_LEN=88
      +CONFIG_BT_RX_BUF_LEN=255
      
      -CONFIG_BT_DISCARDABLE_BUF_SIZE=88
      +CONFIG_BT_DISCARDABLE_BUF_SIZE=255
      

      6、使用write_without_response和notify发送数据

      发布在 A Series
      Y
      giao
    • 回复: 电阻屏反应速度查看

      尝试将android工具getevent移植到linux中,可以成功查看电阻屏的反馈速度。
      参考了 https://www.cnblogs.com/liangliangge/p/12921889.html 中的办法
      工具的源码路径为:android/system/core/toolbox/getevent.c
      其中源码中getevent.c文件中内容有修改
      由于头文件input.h-labels.h生成过程中涉及权限问题,直接新建了input.h-labels.h文件并复制黏贴了参考链接中的内容
      Makefile文件参考了 lichee/buildroot-201611/target/user_rootfs_apps/cmd/subs 下的工程里的Makefile

      用getevent -lrt命令输出时间戳、上报速率等,要计算事件之间的时间间隔,我们可以取两个连续事件的时间戳(括号内的数值)并计算它们之间的差值。这个时间戳的单位不太清楚。

      发布在 飞凌嵌入式专区
      Y
      giao
    • 回复: 启动卡在这,就不会动了,然后也无法烧录了

      短接这两个触点
      然后上电烧录

      微信图片_20230922105738.jpg

      发布在 Wireless & Analog Series
      Y
      giao
    • 回复: t113单独aplay可以播放语音文件但是mplayer没声音报错

      我也遇到这个问题 跟楼主是一样的 希望大佬们帮助解决一下
      如果用aplay 也是这样

      # aplay /root/test.wav
      ALSA lib pcm_hw.c:2021:(_snd_pcm_hw_open) Unknown field slave
      aplay: main:828: audio open error: Invalid argument
      
      发布在 其它全志芯片讨论区
      Y
      giao
    • 回复: 【米尔T113测评】开机点灯+TCP编程

      udp --- 用户数据报协议,是一个无连接的简单的面向数据报的运输层协议。
      udp不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。
      udp在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
      udp是一种面向无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。

      udp通讯流程很简单,具体步骤如下:

      微信图片_20230908105059.png

      udp服务端代码

      #include <stdio.h>
      #include <string.h>
      #include <unistd.h>
      #include <sys/types.h>
      #include <sys/socket.h>
      #include <stdlib.h>
      #include <netinet/in.h>
      #include <arpa/inet.h>
      #include <stdbool.h>
      #include <pthread.h>
      
      #define BUFFER_SIZE 1024 // buf size
      
      struct CONNECT_INFO {
          struct sockaddr_in client_addr;
      };
      
      static int sock_fd;
      static volatile bool is_connect = false;
      
      bool udp_server_init(short port) {
          struct sockaddr_in server_addr;
      
          sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
          if (sock_fd == -1) {
              perror("socket");
              return false;
          }
      
          // initialize address.
          bzero(&server_addr, sizeof(server_addr));
          server_addr.sin_family = AF_INET;
          server_addr.sin_port = htons(port);
          server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
      
          // bind the local port.
          if ((bind(sock_fd, (struct sockaddr *)&server_addr, 
                                  sizeof(struct sockaddr_in))) == -1) {
              perror("bind");
              return false;
          }
      
          return true;
      }
      
      void *send_thread(void *arg) {
          struct CONNECT_INFO *info = (struct CONNECT_INFO *)arg;
          if (info == NULL) {
              printf("error connect info");
              return (void*)-1;
          }
      
          while (1) {
              char send_buf[BUFFER_SIZE];
              bzero(send_buf, sizeof(send_buf));
      
              // input from keyboard.
              char *str = fgets(send_buf, sizeof(send_buf), stdin);
              if (str == NULL) {
                  perror("fgets");
                  continue;
              }
              if (strlen(str) <= 1) {
                  continue;
              }
      
              if(is_connect == false) {
                  printf("No client are available!\n");
                  continue;
              }
      
              // send data.
              if ((sendto(sock_fd, send_buf, strlen(str) - 1, 0,
                              (struct sockaddr *)&info->client_addr,
                              sizeof(struct sockaddr_in))) < 0) {
                  perror("sendto");
                  continue;
              }
          }
      
          return (void*)0;
      }
      
      int main(int argc, char *argv[]) {
          // check your input.
          if (argc != 2) {
              printf("Usage:\n");
              printf("    %s <port number>\n", argv[0]);
              return -1;
          }
      
          short port = atoi(argv[1]);
      
          bool ret = udp_server_init(port);
          if (ret == false) {
              goto err;
          }
      
          pthread_t t_id;
          struct CONNECT_INFO info;
          socklen_t addr_len = sizeof(struct sockaddr_in);
      
          memset(&info, 0, sizeof(info));
      
          pthread_create(&t_id, NULL, send_thread, (void *)&info);
          pthread_detach(t_id);
      
          printf("Waiting for client connectionn\n");
          while (1) {
              // recive from client.
              char recv_buf[BUFFER_SIZE];
              bzero(recv_buf, sizeof(recv_buf));
              if ((recvfrom(sock_fd, recv_buf, sizeof(recv_buf), 0,
                              (struct sockaddr *)&info.client_addr, &addr_len)) <= 0) {
                  perror("recvfrom");
                  goto err;
              }
      
              printf("[Recv from client %s:%d] : %s\n",
                      inet_ntoa(info.client_addr.sin_addr),
                      htons(info.client_addr.sin_port),
                      recv_buf);
              
              is_connect = true;
          }
      
          close(sock_fd);
          return 0;
      
      err:
          close(sock_fd);
          return -1;
      }
      
      

      udp客户端代码:

      #include <stdio.h>
      #include <string.h>
      #include <netinet/in.h>
      #include <sys/types.h>
      #include <sys/socket.h>
      #include <stdlib.h>
      #include <unistd.h>
      #include <errno.h>
      #include <arpa/inet.h>
      
      #define BUFFER_SIZE 1024 // buf size
      
      int main(int argc, char *argv[]) {
          // check the arguments.
          if (argc != 3) {
              printf("Usage:\n");
              printf("    %s <server_addr> <portnumber>\n", argv[0]);
              return -1;
          }
      
          int sock_fd;
          char send_buf[BUFFER_SIZE];
          char recv_buf[BUFFER_SIZE];
          struct sockaddr_in server_addr;
      
          char *addr = argv[1];
          short port = atoi(argv[2]);
      
          // initialize address.
          bzero(&server_addr, sizeof(server_addr));
          server_addr.sin_family = AF_INET;
          server_addr.sin_addr.s_addr = inet_addr(addr);
          server_addr.sin_port = htons(port);
      
          // create udp socket.
          sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
          if (sock_fd == -1) {
              perror("socket");
              return -1;
          }
      
          pid_t pid = fork();
          if (pid > 0) {
              // The parent process is responsible for sending messages.
              while (1) {
                  bzero(send_buf, sizeof(send_buf));    
      
                  // read from stdin.
                  char *str = fgets(send_buf, sizeof(send_buf), stdin);
                  if (str == NULL) {
                      perror("fgets");
                      goto err;
                  }
                  if (strlen(str) <= 1) {
                      continue;
                  }
      
                  // send data.
                  if ((sendto(sock_fd, send_buf, strlen(str) - 1, 0,
                                  (struct sockaddr *)&server_addr,
                                  sizeof(struct sockaddr_in))) < 0) {
                      perror("sendto");
                      goto err;
                  }
              }
          }
          else if (pid == 0) {
              // The child process is responsible for receiving messages.
              while (1) {
                  bzero(recv_buf, sizeof(recv_buf));
                  socklen_t addr_len = sizeof(struct sockaddr_in);
                  if ((recvfrom(sock_fd, recv_buf, sizeof(recv_buf), 0,
                                  (struct sockaddr *)&server_addr,
                                  &addr_len)) <= 0) {
                      perror("recvfrom");
                      goto err;
                  }
      
                  printf("[Recv from server %s:%d] : %s\n",
                          inet_ntoa(server_addr.sin_addr),
                          htons(server_addr.sin_port),
                          recv_buf);
              }
          }
      
          close(sock_fd);
          return 0;
      
      err:
          close(sock_fd);
          return -1;
      }
      
      
      

      编译后运行结果:

      160406w8j9cocly2a3ncsl.png.thumb.jpg

      160442vfuv6gvfuq518fuf.png.thumb.jpg

      发布在 其它全志芯片讨论区
      Y
      giao