导航

    全志在线开发者论坛

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

    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
    • 【米尔T113测评】开机点灯+TCP编程

      米尔电子的 MYD-YT113X 板卡由核心板 MYC-YT113X 和底板 MYB-YT113X 组成,核心板与底板采用邮票孔焊接方式。此外 MYIR 提供了丰富的软件资源以及文档资料。开发板在出厂时已经烧录了镜像,只需要按照手册上电即可使用。

      系统以文件的形式为 LED 设备提供操作接口。这些接口位于/sys/class/leds 目录下。在硬件资源列表中,可以通过命令读写 sysfs 的方式对 LED 进行测试。其中 0 表示 LED 点亮,1 表示 LED 熄灭, None表示关闭心跳灯。现在以心跳灯 led-blue 为例测试 LED:

      171351u4vfp61zdv63o6k6.png.thumb.jpg

      最后附上开发板点灯图:

      171533h0s8lh4okjo6tlvk.jpg.thumb.jpg

      TCP协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。通讯过程如下:

      154424vlinyg2nz6o6ooup.png.thumb.jpg

      服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

      服务端代码:

      #include <stdio.h>
      #include <stdlib.h>
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <netinet/in.h>
      #include <sys/socket.h>
      #include <string.h>
      #include <unistd.h>
      #include <signal.h>
      #include <sys/ipc.h>
      #include <errno.h>
      #include <sys/shm.h>
      #include <time.h>
      #include <pthread.h>
      #include <arpa/inet.h>
      
      #define BUFFER_SIZE     1024    // buf size
      #define LISTENQ         1       // the max quote
      
      #define SIZE_SHMADD 2048
      
      int main(int argc, char *argv[]) {
          // check the arguments.
          if (argc != 2) {
              printf("Usage:\n");
              printf("    %s <port number>\n", argv[0]);
              return -1;
          }
      
          struct sockaddr_in server_addr;
          struct sockaddr_in client_addr;
      
          char recv_buf[BUFFER_SIZE];
          char send_buf[BUFFER_SIZE];
      
          pid_t pid;
          int sock_fd, conn_fd = -1;
          int optval = 1;
          int port = atoi(argv[1]);
      
          if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
              perror("socket");
              return -1;
          }
      
          // setting bind port crycled.
          if ((setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
                                          (void *)&optval, sizeof(int))) < 0) {
              perror("setsockopt");
              goto err;
          }
      
          // initized address.
          bzero(&server_addr, sizeof(struct sockaddr_in));
          server_addr.sin_family=AF_INET;
          server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
          server_addr.sin_port = htons(port);
      
          // bind the port.
          if (bind(sock_fd, (struct sockaddr *)(&server_addr),
                                              sizeof(struct sockaddr)) == -1) {
              perror("bind");
              goto err;
          }
          
          // transform the socket into listen socket.
          if (listen(sock_fd, LISTENQ) == -1) {
              perror("listen");
              goto err;
          }
      
          printf("Waiting for client connectionn...\n");
      
          socklen_t cli_len = sizeof(struct sockaddr_in);
          conn_fd = accept(sock_fd, (struct sockaddr *)(&client_addr), &cli_len);
          if (conn_fd == -1) {
              perror("accept");
              close(sock_fd);
              return -1;
          }
      
          printf("Client accepted : %s:%d \n",
                  inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
      
          pid = fork();
          if (pid > 0) {
              // The parent process is responsible for sending messages.
              while (1) {
                  bzero(send_buf, sizeof(send_buf));
                  char *str = fgets(send_buf, sizeof(send_buf), stdin);
                  if (str == NULL) {
                      perror("fgets");
                      goto err;
                  }
      
                  if (send(conn_fd, send_buf, strlen(send_buf) - 1, 0) < 0) {
                      perror("send");
                      goto err;
                  }
              } 
          }
          else if (pid == 0) {
              // The child process is responsible for receiving messages.
              while (1) {
                  bzero(recv_buf, sizeof(recv_buf));
                  if ((recv(conn_fd, recv_buf, BUFFER_SIZE, 0)) <= 0) {
                      perror("recv");
                      goto err;
                  }
      
                  printf("[Recv from client %s:%d] : %s\n",
                          inet_ntoa(server_addr.sin_addr),
                          htons(server_addr.sin_port),
                          recv_buf);
              }
          }
          else {
              perror("fork");
              goto err;
          }
      
          close(conn_fd);
          close(sock_fd);
          return 0;
      
      err:
          close(conn_fd);
          close(sock_fd);
          return -1;
      }
      
      
      

      客户端代码

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <unistd.h>
      #include <errno.h>
      #include <sys/socket.h>
      #include <sys/types.h>
      #include <netinet/in.h>
      #include <arpa/inet.h>
      
      #define BUFFER_SIZE 1024
      
      int main(int argc, char *argv[]) {
          // check the arguments.
          if (argc != 3) {
              printf("Usage:\n");
              printf("    %s <server addr> <port number>\n", argv[0]);
              return -1;
          }
      
          char *addr = argv[1];
          short port = atoi(argv[2]);
      
          int sock_fd;
          int ret;
          char recv_buf[BUFFER_SIZE], send_buf[BUFFER_SIZE];
          struct sockaddr_in server_addr;
      
          // 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 = inet_addr(addr);
      
          // create socket fd.
          sock_fd = socket(AF_INET, SOCK_STREAM, 0);
          if (sock_fd == -1) {
              perror("socket");
              return -1;
          }
      
          // connect.
          ret = connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
          if (ret == -1) {
              perror("connect");
              goto err;
          }
      
          printf("connect server(IP:%s Port: %d).\n", addr, port);
      
          pid_t pid = fork();
          if (pid > 0) {
              // The parent process is responsible for sending messages.
              while (1) {
                  bzero(send_buf, sizeof(send_buf));
                  char *str = fgets(send_buf, sizeof(send_buf), stdin);
                  if (str == NULL) {
                      perror("fgets");
                      goto err;
                  }
      
                  if (send(sock_fd, send_buf, strlen(send_buf) - 1, 0) < 0) {
                      perror("send");
                      goto err;
                  }
              }
          }
          else if (pid == 0) {
              // The child process is responsible for receiving messages.
              while (1) {
                  bzero(recv_buf, sizeof(recv_buf));
                  if (sock_fd > 0) {
                      if ((recv(sock_fd, recv_buf, BUFFER_SIZE, 0)) <= 0) {
                          perror("recv");
                          goto err;
                      }
      
                      printf("[Recv from server %s:%d] : %s\n",
                              inet_ntoa(server_addr.sin_addr),
                              htons(server_addr.sin_port),
                              recv_buf);
                  }
              }
          }
          else {
              perror("fork");
              goto err;
          }
      
          close(sock_fd);
          return 0;
      
      err:
          close(sock_fd);
          return -1;
      }
      
      
      

      编译后运行结果如下:

      服务端启起来,等待客户端连接。 启动客户端,发送数据, 服务端接收数据。

      154952srwr2vamzuabvkwm.png.thumb.jpg

      155100ng33im8gi5j8f3br.png.thumb.jpg

      发布在 其它全志芯片讨论区
      Y
      giao
    • 【资料分享】全志科技T507-H工业核心板规格书

      1 核心板简介

      创龙科技SOM-TLT507是一款基于全志科技T507-H处理器设计的4核ARM Cortex-A53全国产工业核心板,主频高达1.416GHz。核心板CPU、ROM、RAM、电源、晶振等所有元器件均采用国产工业级方案,国产化率100%。

      核心板通过邮票孔连接方式引出MIPI CSI、HDMI OUT、RGB DISPLAY、LVDS DISPLAY、CVBS OUT、2x EMAC、4x USB2.0、6x UART、SPI、TWI等接口,支持双屏异显、G31 MP2 GPU、4K@60fps H.265视频硬件解码、4K@25fps H.264视频硬件编码。核心板经过专业的PCB Layout和高低温测试验证,稳定可靠,可满足各种工业应用环境。

      用户使用核心板进行二次开发时,仅需专注上层运用,降低了开发难度和时间成本,可快速进行产品方案评估与技术预研。

      df59bbc6ce990a57338f216d51ec1f0a.png

      94c3aa34fc2e47ab34c89e4f817359ea.png

      f2caf9ceb84102784d81f1c857722ccf.png

      64bd3efc0f6390e731c0a9dbc71a9db9.png

      典型应用领域

      工业控制,工业网关,能源电力,轨道交通,仪器仪表

      软硬件参数

      硬件框图

      7b11e080cde73f475b11ea6337bf21da.png

      d28c6e1fc09fdc052bdbe5387ce5a63e.png

      硬件参数

      903C435A-EF05-43d8-9AC5-C3AC1F44D1BC.png
      备注:部分引脚资源存在复用关系。

      软件参数

      263AD0A5-0710-4b9a-B881-3363C5611A62.png

      开发资料

      (1) 提供核心板引脚定义、可编辑底板原理图、可编辑底板PCB、芯片Datasheet,协助国产元器件方案选型,缩短硬件设计周期;

      (2) 提供系统固化镜像、文件系统镜像、内核驱动源码,以及丰富的Demo程序;

      (3) 提供完整的平台开发包、入门教程,节省软件整理时间,让应用开发更简单。

      开发案例主要包括:

      • ARM与FPGA通信开发案例(SPI/SDIO)
      • 8/16通道国产同步AD采集开发案例(与AD7606/AD7616管脚兼容)
      • Linux、Linux-RT、Qt应用开发案例
      • Docker容器技术、MQTT通信协议、Ubuntu操作系统演示案例
      • 4G/WIFI/Bluetooth开发案例
      • IgH EtherCAT主站、SPI转CAN开发案例
      • 双屏异显、OpenCV、H.264/H.265视频硬件编解码开发案例

      电气特性

      工作环境

      F85772AA-78F2-4609-9841-0BA3EFC02637.png

      功耗测试

      957F8E3C-42A1-401b-AE16-C69486F03FD8.png

      备注:功耗基于TLT507-EVM评估板测得。测试数据与具体应用场景有关,仅供参考。

      空闲状态:系统启动,评估板不接入其他外接模块,不执行程序。

      满负荷状态:系统启动,评估板不接入其他外接模块,运行DDR压力读写测试程序,4个ARM Cortex-A53核心的资源使用率约为100%。

      机械尺寸

      C8D22ED3-534C-4a68-A2D4-95E778D272AF.png

      947fca2d1283247609bcc2d031b8a8cf.png

      发布在 创龙科技专区
      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
    • 香橙派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
    • 使用docker环境arm交叉编译OpenCV出错

      我用V3S的docker环境准备交叉编译一个OpenCV的程序去v3s
      我编译成功helloworld后准备弄OpenCV
      但是很奇怪的事情发生了

      当我的cpp文件还是helloworld原来的样子
      我单独编译arm程序可以编译
      或者单独编译opencv程序也可以正常编译
      当我在cmakelists.txt同时启用arm交叉编译和opencv时候就报错报错如下

      /usr/local/lib/libopencv_highgui.so.4.8.0: file not recognized: File format not recognized
      collect2: error: ld returned 1 exit status
      CMakeFiles/Test2.dir/build.make:109: recipe for target 'Test2' failed
      make[2]: *** [Test2] Error 1
      CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/Test2.dir/all' failed
      make[1]: *** [CMakeFiles/Test2.dir/all] Error 2
      Makefile:83: recipe for target 'all' failed
      make: *** [all] Error 2
      

      当我编译一个正常的opencv程序cmake启用opencv,不启用交叉编译时,他也能编译

      #include <opencv2/highgui/highgui.hpp>
      #include <opencv2/imgproc/imgproc.hpp>
      #include <opencv2/core/core.hpp>
      #include<iostream>
      #include <string>
      #include <sstream>
      using namespace cv;
      using namespace std;
      int main()
      {
      // Capture the Image from the webcam
      VideoCapture cap(0);
      
      // Get the frame
      Mat save_img; cap >> save_img;
      
      if(save_img.empty())
      {
        std::cerr << "Something is wrong with the webcam, could not get frame." << std::endl;
      }
      // Save the frame into a file
      imwrite("test.jpg", save_img); // A JPG FILE IS BEING SAVED
      }
      
      发布在 其它全志芯片讨论区
      Y
      giao
    • 芒果派MangoPi MQ Pro+Tina Linux 开发环境搭建

      板载资源

      主板搭载D1(RISC-V核心)作为主控芯片,提供各种常用外设接口:GPIO、I2C&SPI、SDIO、音频接口(录制、播放)、视频接口(触摸、HDMI、DVP、DSI和LVDS)、USB Host、OTG等。另外,板子内置1GB DDR和板载WiFi/BT,全面支持Linux生态,运行完整的Python。

      • D1、C906 内核、高达 1GHz 的 RISC-V 内核
      • 1GB DDR3/DDR3L
      • USB-OTG C 型
      • USB-HOST Type-C
      • 40Pin RPI-展开
      • 24Pin DVP/RGMII 连接器
      • 迷你 HDMI 连接器
      • TF卡
      • RTL8723ds WiFi/蓝牙模块
      • 20Pins DSI/CTP/LVDS FPC连接器
      • 音频输出垫

      实物如下所示:
      wKgaomSqxc6AOqXAAAaxIdQcrbE097.png

      环境搭建

      本次使用的ubuntu18.04的开发环境,首先安装一些工具,lib等,输入以下命令:

      sudo apt-get install build-essential subversion git-core libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip lib32z1 lib32z1-dev lib32stdc++6 libstdc++6 libmpc-dev libgmp-dev -y
      

      这一步安装基本不会出现问题,接下来就是下载SDK,这里官方已经提供,在ubuntu下下载,输入以下命令:

      git clone https://github.com/mangopi-sbc/Tina-Linux.git
      

      这里下载可能比较慢,可以寻找一些加速的玩意,下载完成后进入Tina-Linux文件夹:

      wKgZomSqxgiAAP93AAHAszqnQWk576.png

      接下来输入以下命令对子模块进行下载,其主要是在下载lichee/linux-5.4

      git submodule update --init –recursive
      

      下载完成后如下所示:

      wKgaomSqxhaABeTtAAZmw9Geojo682.png

      下载Prebuild,pre-built就是在build之前先pre-built出来.so或.ko或可执行档案等。通常是你的程序需要其它模块,而其它模块你却无权限去阅读其source code,

      所以它们将先build好.so或.ko或可执行档案给你使用。输入以下命令:

      wget http://dl.mangopi.org/tina/prebuilt.tar.gz .
      

      解压,输入以下命令:

      tar xzvf prebuilt.tar.gz
      

      下载dl库,这个大概3个G的样子,输入以下命令:

      wget http://dl.mangopi.org/tina/dl.tar .
      

      解压:

      tar xvf dl.tar
      

      下载工具链:

      wget http://dl.mangopi.org/tina/toolchain/riscv64-linux-x86_64-20200528.tar.xz -P ./lichee/brandy-2.0/tools/toolchain/
      
      wget http://dl.mangopi.org/tina/toolchain/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabi.tar.xz -P ./lichee/brandy-2.0/tools/toolchain/
      

      完成以上步骤后就可以进行编译了,以上的步骤确保都进行了且没错误,不然后面编译的时候也会出错。

      wKgaomSqximAfZwdAAB28Sf7u4s821.png

      编译前输入以下命令:

      source build/envsetup.sh
      

      然后输入lunch,选择1即可,如下所示:
      wKgaomSqxjaAcdZ2AAMQMyTCjKQ897.png

      接下来可以进行编译了,输入make命令,等待编译
      wKgZomSqxkSAcIGsAAI2FSVZNRA280.png

      编译完成,大概花了一个小时左右吧,如图:
      wKgaomSqxkyAXKiBAAMJUn-5m0w256.png

      接下来输入mboot,出现错误
      wKgZomSqxlOAe1DiAAQYux0tRCQ384.png

      这里开发环境选错了,选成了ubuntu20,准备重新搭建,不过步骤不会变,mboot完成后,在输入pack命令,打包成镜像文件,使用烧录工具烧录即可。

      烧录

      接下来使用官方给的镜像文件进行烧录演示,打开烧录软件
      wKgaomSqxl6AINf7AALgRCr5AwQ341.png
      wKgZomSqxmaAdeY6AAF4XC6IwyI350.png

      打开软件,选择官方固件,选择启动卡,烧卡即可,接下来将内存卡插到开发板,启动开发板即可
      wKgaomSqxnKASXtAAAWyWhxwZSs016.png

      五、总结

      本次环境搭建就到这里,将整个搭建过程进行了一遍,总的来说搭建还是比较麻烦,可能会出现各种问题,然后板子比较小,好像复位引脚没有引出来,使用不太方便,同时由于体积原因,没有添加网口类的外设,使用起来没那么方便,资料好像也那啥,暂时先这样吧,后面在继续。

      发布在 MR Series
      Y
      giao
    • 想将t113-s3的usb模拟成一个串口,要怎么做

      请教,想用usb模拟串口,该咋搞?搜到了个usb cdc类。之前做的其他板子,是用usb虚拟串口向板子里传参数的,所以这次也想这么搞。

      是不是在这里面选择一个来做usb虚拟串口?以下两个应该选哪一个

      QQ图片20230731100547.png
      QQ图片20230731100549.png

      发布在 其它全志芯片讨论区
      Y
      giao
    • 全志 T113核心板驱动开发环境搭建

      获取Tina-Linux源码
      1、百度云:https://pan.baidu.com/s/13uKlqDXImmMl9cgKc41tZg?pwd=qcw7#list/path=%2F
      提取码:qcw7
      2、全志官网:https://open.allwinnertech.com/

      将所有源码复制到ubuntu,然后解压

      新建文件夹

      mkdir T113
      

      将所有文件拷贝到 T113文件夹

      解压

      cat tina-d1-h.tar.bz2.* | tar -jxv
      

      然后会生成文件夹

      d7b2af08c25442bb84e3310a569d10f5.png

      安装编译必须的工具

      sudo apt-get install -y sed make binutils build-essential gcc g++ bash patch gzip bzip2 perl tar cpio unzip rsync file bc wget python cvs git mercurial rsync subversion android-tools-mkbootimg vim libssl-dev android-tools-fastboot
      

      配置额外的支持T113的开发环境

      sudo apt-get install build-essential subversion git libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip lib32z1 lib32z1-dev lib32stdc++6 libstdc++6 libc6:i386 libstdc++6:i386 lib32ncurses-dev lib32z1 -y
      

      单独获取100ASKT113板级扩展补丁

      https://gitee.com/weidongshan/100ASK_T113-Pro_TinaSDK

      或者直接ubuntu使用git获取:

      git clone https://gitee.com/weidongshan/100ASK_T113-Pro_TinaSDK.git
      

      下载补丁完成以后 ,复制到 tina-d1-h

      cd 100ASK_T113-Pro_TinaSDK/
      git submodule update --init     //更新
      cp ./* -rfvd ~/T113/tina-d1-h
      

      编译T113源码

      进入目录

      cd ../tina-d1-h/
      
      source build/envsetup.sh		//配置环境
      lunch
      
      
      You’re building on Linux
      
      Lunch menu… pick a combo:
      1. d1-h_nezha_min-tina
      2. d1-h_nezha-tina
      3. d1s_nezha-tina
      4. t113_100ask-tina
      
      
      Which would you like?: 4
      

      编译

      make -j6 V=s			//编译 
      
      pack				//打包
      

      编译问题记录

      遇见没有安装工具问题

      1、 ‘gperf’ is missing on your system
      解决办法:

      sudo apt install -y gperf
      

      2、 No such file or directory
      这个主要是文件夹及文件权限问题,给这几个文件及它的文件夹777权限。

      发布在 其它全志芯片讨论区
      Y
      giao
    • V853调试MPP遇到的几个问题

      目前在mpp外编上遇到有几处问题无法解决,特来请教各位大佬。

      执行sample_smartPreview_demo时会提示段错误

      9a017256ba351e279125cc096285527f675d5dac.png

      I0101 03:22:03.445359  1275 sample_smartPreview_demo.c:254] <MPPCallbackWrapper> VO callback: VO Layer[0] chn[0] event:258
      I0101 03:22:03.445496  1275 sample_smartPreview_demo.c:271] <MPPCallbackWrapper> vo layer[0] report rendering start
      [ISP_WARN]gc2053_mipi get sensor_temp failed: Invalid argument (22).
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      I0101 03:22:03.529241  1271 VideoVirVi_Component.c:1160]    <VideoViComponentInit> VideoVirvi component Init! thread_id[0xb55f9d50]
      I0101 03:22:03.529488  1271 aiservice_mpp_helper.c:118]     <mpp_helper_create_vipp> vipp8 chn0 create success
      I0101 03:22:03.529752  1271 aiservice_detect.c:526]         <aw_service_start> create face ch0 detect worker thread success.
      I0101 03:22:03.529864  1271 aiservice_detect.c:530]         <aw_service_start> success
      I0101 03:22:03.529935  1271 sample_smartPrevi[ 1584.644475] npu[4f7][500] gckvip_drv_exit, aw_vip_mem_free
      ew_demo.c:706]                                              <main> [ 1584.653095] aw_vip_mem_free vir 0xe3782000, phy 0x49a00000
      [ 1584.661941] aw_vip_mem_free dma_unmap_sg_atrs
      
      [ 1584.669698] aw_vip_mem_free ion_unmap_kernel
      [ 1584.674549] aw_vip_mem_free ion_free
      [ 1584.678793] aw_vip_mem_free ion_client_destroy
      [ 1584.685449] npu[4f7][500] vipcore, device un-init..
      [ 1584.710038] [DISP] disp_mgr_set_layer_config,line:1504:
      [ 1584.715822] NULL hdl!
      [ 1584.718657] L1 PageTable Invalid
      [ 1584.718661] 0x48ffe000 is not mapped!
      [ 1584.718665] DE invalid address: 0x48ffe000, data:0x0, id:0x4
      [ 1584.734891] L1 PageTable Invalid
      [ 1584.738506] 0x48ffe000 is not mapped!
      [ 1584.742605] DE invalid address: 0x48ffe000, data:0x0, id:0x4
      [ 1584.751990] L1 PageTable Invalid
      [ 1584.755608] 0x48ffe000 is not mapped!
      [ 1584.759708] DE invalid address: 0x48ffe000, data:0x0, id:0x4
      [ 1584.766144] lcd_close_flow
      [ 1584.769274] L1 PageTable Invalid
      [ 1584.769277] 0x48ffe000 is not mapped!
      [ 1584.769280] DE invalid address: 0x48ffe000, data:0x0, id:0x4
      [ 1584.783421] lcd_bl_close
      [ 1584.786365] L1 PageTable Invalid
      [ 1584.786368] 0x48ffe000 is not mapped!
      [ 1584.786371] DE invalid address: 0x48ffe000, data:0x0, id:0x4
      [ 1584.800751] lcd_panel_exit
      [ 1584.803885] L1 PageTable Invalid
      [ 1584.803888] 0x48ffe000 is not mapped!
      [ 1584.803892] DE invalid address: 0x48ffe000, data:0x0, id:0x4
      [ 1584.820381] L1 PageTable Invalid
      [ 1584.823995] 0x48ffe000 is not mapped!
      [ 1584.828095] DE invalid address: 0x48ffe000, data:0x0, id:0x4
      [ 1584.995930] lcd_power_off
      [ 1584.998968] [DISP] disp_sys_gpio_set_value,line:416:
      [ 1585.004332] OSAL_GPIO_DevWRITE_ONEPIN_DATA, hdl is NULL
      [ 1585.166331] [DISP] de_fcm_set_para,line:491:
      [ 1585.170924] fcm lut 0 not find, auto retry after init
      [ 1585.177046] [DISP] de_fcm_set_para,line:491:
      [ 1585.181637] fcm lut 0 not find, auto retry after init
      Segmentation fault (core dumped)
      

      执行sample_virvi2venc2muxer demo时提示

      a90dc0c4a6b12e386cd85fcf93e9fc856f4ccb64.png

      [ISP]find gc2053_mipi_1920_1088_20_0 [gc2053_mipi_isp600_20220511_164617_vlc4_day] isp config
      [ISP]create isp0 server thread!
      I0101 03:32:36.212247  1314 mpi_vi.c:1018]                  <AW_MPI_VI_CreateVirChn> we allow to create virChn[0] in disable status of vipp[0]
      I0101 03:32:36.212561  1314 VideoVirVi_Component.c:1160]    <VideoViComponentInit> VideoVirvi component Init! thread_id[0xb6c32d50]
      I0101 03:32:36.248254  1314 samp[ 2217.252031] VE: before freq=300000000
       2217.257644] VE: real freq=300000000
      60C<configVencChnAttr> pixfmt:0x[ 2217.264021] VE: before freq=300000000
      20, colorSpace:0x3
      I0101 03:32:[ 2217.270975] VE: real freq=300000000
      36.248432  1314 sample_vi2venc2muxer.c:1078]                <configVencChnAttr> DropFrameNum:0
      I0101 03:32:36.248520  1314 sample_vi2venc2muxer.c:1240]    <configVencChnAttr> venc set Rcmode=2
      I0101 03:32:36.249077  1314 VideoEnc_Component.c:7042]      <VideoEncComponentInit> create VideoEnc threadId:0xb5ff8d50
      I0101 03:32:36.249227  1314 VideoEnc_Component.c:5422]      <VideoEncSendCommand> set VencChn[0] Comp StateIdle
      I0101 03:32:36.249368  1318 media_debug.c:45]               <getDictByConfPath> MPP_DEDIA_DEBUG_FILE_PATH=(null)
      I0101 03:32:36.249539  1318 VideoEnc_Component.c:1110]      <CedarvEncInit> VencChn[0] Create VeType=96
      iniparser: cannot open /tmp/libcedarc_dynamic_log_level
      INFO   : cedarc <cdc_log_set_level:43>: Set log level to 5 from /vendor/etc/cedarc.conf
      WARNING: cedarc <LogVersionInfo:44>:
      >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Cedar Codec <<<<<<<<<<<<<<<<<<<<<<<<<<<<
      tag   :
      branch: tina-v853-dev
      commit: ee230a47e5a2392ec315795121c2d112492fac1c
      date  : Fri Jul 22 10:37:50 2022 +0800
      author: wuguanjian
      change-id : I28fe0c31c718f097d61ad6bdbcb4cb5df0bd3575
      release_author : lichaopdc
      patch :
      ----------------------------------------------------------------------
      
      I0101 03:32:36.255536  1317 videoInputHw.c:4787]            <VideoInputHw_CapThread> loop VideoInputHw_CapThread vipp_id = 0, buf_num=4.
      I0101 03:32:36.276050  1314 sample_vi2venc2muxer.c:1291]    <createVencChn> create venc channel[0] success!
      I0101 03:32:36.276198  1314 sample_vi2venc2muxer.c:1324]    <createVencChn> set venc framerate: src 20fps, dst 20fps
      I0101 03:32:36.276286  1314 VideoEnc_Component.c:3961]      <VideoEncSetFrameRate> vencChn[0] set new framerate:20
      E0101 03:32:36.276449  1314 glog_helper.cpp:16] *** Aborted at 12756 (unix time) try "date -d @12756" if you are using GNU date ***
      E0101 03:32:36.277036  1314 glog_helper.cpp:16] PC: @        0x0 (unknown)
      Segmentation fault (core dumped)
      

      执行sample_virvi2venc demo时循环提示 无法获取视频流报错

      839f03788cd68bf13f2241bc81425b7729eed578.png

      WARNING: cedarc <EncAdapterPrintEncReg:138>: --------- register of ve encoder base:0xb6f4eb00 -----------
      WARNING: cedarc <EncAdapterPrintEncReg:141>: timeout-enc-reg00:00f00088 0066c100 001c0623 00000000
      WARNING: cedarc <EncAdapterPrintEncReg:141>: timeout-enc-reg10:58c00000 00000007 00030000 90070200
      WARNING: cedarc <EncAdapterPrintEncReg:141>: timeout-enc-reg20:00000080 00000000 00000000 9805ffff
      WARNING: cedarc <EncAdapterPrintEncReg:141>: timeout-enc-reg30:0a080604 12100e0c 1a181614 00503600
      WARNING: cedarc <EncAdapterPrintEncReg:141>: timeout-enc-reg40:00000000 00000000 00000000 00000000
      WARNING: cedarc <EncAdapterPrintEncReg:141>: timeout-enc-reg50:00000000 00000000 00000000 00000000
      WARNING: cedarc <EncAdapterPrintEncReg:141>: timeout-enc-reg60:00503400 000000^C000000 00000000 00000000
      WARNING: cedarc <EncAdapterPrintIspReg:157>: timeout-isp-reg50:00000000 00000000 01ba03b8 004000ff
      WARNING: cedarc <EncAdapterPrintIspReg:157>: timeout-isp-reg60:00000010 00000210 00000000 00000000
      WARNING: cedarc <EncAdapterPrintIspReg:157>: timeout-isp-reg70:00000000 00000000 48e00000 48ffe000
      WARNING: cedarc <EncAdapterPrintIspReg:157>: timeout-isp-reg80:48ffe000 00000000 00000000 00000202
      WARNING: cedarc <EncAdapterPrintIspReg:157>: timeout-isp-reg90:03ff03ff 02061011 00800044 00000000
      WARNING: cedarc <EncAdapterPrintIspReg:157>: timeout-isp-rega0:00141010 00000000 00000000 00670127
      WARNING: cedarc <EncAdapterPrintIspReg:157>: timeout-isp-regb0:00670127 1002102a 00200080 01010101
      WARNING: cedarc <EncAdapterPrintIspReg:157>: timeout-isp-regc0:005a0155 00000040 5038b000 00000000
      WARNING: cedarc <EncAdapterPrintIspReg:157>: timeout-isp-regd0:00000000 00000000 00000000 00000000
      WARNING: cedarc <EncAdapterPrintIspReg:157>: timeout-isp-rege0:00000100 01000000 00000000 00000000
      WARNING: cedarc <EncAdapterPrintIspReg:157>: timeout-isp-regf0:00000200 00000000 00000000 00000000
      WARNING: cedarc <EncAdapterPrintIspReg:160>:
      
      WARNING: cedarc <h265SramPrintf:8565>:
      ***************F0 Sram Addr Val ***************
      WARNING: cedarc <h265SramPrintf:8566>: 0x400: 0050b000 0050b700 0050b000 0050b700
      WARNING: cedarc <h265SramPrintf:8567>: 0x410: 00504000 00504000 00503000 00503000
      
      ERROR  : cedarc <h265OvertimeRencodeCfg:9318>: F0 Overtime, VBV: Total:3110912, Valid:0, Unused:3110912; Qp: Last:35, Next:41
      
      I0101 03:34:50.087629  1322 sample_virvi2venc.c:34]         <handle_exit> user want to exit!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      W0101 03:34:50.126057  1325 videoInputHw.c:4870]            <VideoInputHw_CapThread> vi_v_frm_pts_invalid:vipp0--2350981953-2349673863=1308090(us)
      I0101 03:34:50.126306  1324 VideoEnc_Component.c:6390]      <VideoEncEmptyThisBuffer> Be careful! VencChn[0] vencInputPts[2350981953]-[2349673863]=[1308090]us, vBufSize[1920x1088]
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      I0101 03:34:50.197534  1327 sample_virvi2venc.c:1257]       <GetEncoderFrameThread> get first frmae failed!
      I0101 03:34:50.197830  1322 sample_virvi2venc.c:1519]       <main> start to free res
      I0101 03:34:50.197967  1322 sample_virvi2venc.c:1166]       <stop> stop
      W0101 03:34:50.198096  1324 VideoVirVi_Component.c:1236]    <Vi_ComponentThread> Be careful! virChn[0-0] using frame is not empty!
      W0101 03:34:50.198184  1324 VideoVirVi_Component.c:388]     <DoVideoViReturnAllValidFrames> Be careful! remain [1] usingFrames after return all valid frames
      I0101 03:34:50.198280  1322 sample_virvi2venc.c:1175]       <stop> stop venc
      I0101 03:34:50.198360  1322 VideoEnc_Component.c:5422]      <VideoEncSendCommand> set VencChn[0] Comp StateIdle
      I0101 03:34:50.198481  1326 VideoEnc_Component.c:7943]      <ComponentThread> VencChn[0]: pause/executing[0x3]->idle ...
      W0101 03:34:50.198564  1326 VideoEnc_Component.c:7405]      <ReturnUseOrigFrameBeforeSetStateIdle> wait for VencChn[0] input orig usingFrameList empty, left frames cnt = [1]
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      ^CI0101 03:34:50.697247  1322 sample_virvi2venc.c:34]       <handle_exit> user want to exit!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      [ISP_ERR]isp_sync_debug_info, line: 747,VIDIOC_VIN_ISP_GET_INFO error!
      
      发布在 V Series
      Y
      giao
    • 芒果派MangoPi MQ Pro环境搭建

      第一次应用这种单板计算机类的板卡,完全的小白,因此开发使用流程完全不清楚,所以在网上查了很多资料总算把系统烧录上,跑了起来。

      wKgaomSYQRuAAtFGAAruty4qVfc864.png

      咱先把系统及工具准备好,登录mangopi官方网站https://mangopi.org/mqpro

      我下载的armbian

      然后准备一张大于8G的内存卡,用来烧录系统,我还购买一根hdmi转minihdmi的视频线。

      通过Raspberry Pi Imager将之前下载的armbian系统烧录到内存卡。
      wKgaomSYQreAWa4SAAMvUY-Ndjg130.png

      选择好系统及存储卡后点击烧录,等待四五分钟就烧录好了。
      接下来就是连接硬件,将mangopi板卡通过hdmi视频线与显示器连接,通过OTG Typec口对板卡供电。连接如图

      wKgZomSYQ_mAW2ohAAIQDMl7twc837.jpg

      然后屏幕上就开始答应LOG信息了

      wKgaomSYRB-AWVuEAAPsndCmBrA291.jpg

      对于新手小白我卡在这个界面很久,输了很多账号密码都不对,最后百度找到armbian的登录账号和密码,账号root,密码1234,第一次登录后系统会提示你创建新的账号和密码。终于进入桌面了,不过这个过程得有四五分钟,时间比较长。

      wKgZomSYRdmAX1yoAAIdLucJmG0519.jpg

      之后就是配置WiFi。在控制台中输入armbian-config,进入图形配置界面。找到wifi选项,选择网络设置完密码就好了,下次上电后板卡会自动连接WiFi。

      下一步就是通过PUTTY连接到板卡。连接注意事项,连接时需要填写板卡的ip地址,我通过我家路由器查询到板卡的地址,然后输入到Host Name位置,其他选项默认。点击open。

      wKgZomSYRzyABuYhAAJCFt3l-UM793.png

      然后会跳出界面,输入你的账号的密码就可以登录到板卡控制台了。

      wKgZomSYSBqABcXxAAM5OKx3r20916.jpg

      至此基本的使用环境应该搭建完毕。

      发布在 MR Series
      Y
      giao
    • T113的VDRAM可以接在LDOA和LDOB吗

      为啥看到有些板子,只用一个LDO

      麻雀派的VDRAMIO用外置1.8V,搞得我不太敢用...是不是会过热

      发布在 其它全志芯片讨论区
      Y
      giao
    • 回复: 2022年7月版——在“哪吒”上跑AI 全志D1 ncnn框架移植笔记

      @copper 这个真是不清楚,应该是不可以的?没试过

      发布在 MR Series
      Y
      giao
    • 回复: NPU模块vpm_run例程运行时sample.txt读取错误

      读取sample.txt失败,检查一下vpm_run.c源码,查看获取文件名的换行符类型

      windows操作系统的换行为:CR/LF或\r\n,而Linux的换行符为LF或\n

      发布在 V 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
    • 回复: 【FAQ】全志V853芯片 Tina下RTSP环境搭建方法

      @igbt70 你从哪里拉的SDK

      发布在 其它全志芯片讨论区
      Y
      giao
    • 回复: 支持DDR4的芯片(如H616)想用DDR3时引脚该怎么接

      @zznzzn A14,A15,A16 这3个引脚都有复用的第二个功能,A14~WEN,A15~CAS,A16~RAS 这样,H616可能没标 H6是标上的QQ图片20230406090017.png

      发布在 其它全志芯片讨论区
      Y
      giao
    • 在DongshanPI-D1上实现MPU6050数据读取

      前言

      上一篇文章使用RT-Smart的IIC驱动OLED屏幕,进行基本的字符串显示,在使用过程中对RT-Smart有了一定熟悉,准备使用SPI驱动ST7789,但SPI接口没有引出,本次使用手上已有的传感器MPU6050进行使用。

      过程

      本次直接开始添加离线包

      在/D1S/userapps/rt-thread/bsp/allwinner/d1s下输入scons –menuconfig进行内核配置,添加MPU605使用所需的配置。

      wKgZomQeZFuAdaP3AAC4y4IWXug1 (2).png

      使用IIC0进行陀螺仪数据的读取,在RT-Thread Compents 下选择Device Drivers

      wKgZomQpB36AKtliAAB1qQs8ZWA2.png

      使能I2C device drivers

      wKgaomQpB3-ANeGfAAOctasnCXg0.png

      在RT-Thread online packages下选择MPU6050离线包

      wKgaomQpB3-AeFmuAAMcAFXRLlc7.png

      在General Drivers Configuration下配置IIC

      wKgZomQpB4CAL7WqAACD0V3c37U0.png

      保存退出,更新一下,发现报错,不能更新MPU6050的离线包

      wKgaomQpB4CAAIzjAABlLilpEnc4.png

      解决方法,打开rt-studio随意新建一个工程,下发MPU6050的芯片包

      wKgZomQpB4GAEpQ_AAFEkUtpDwQ0.png

      查看离线包的json文件,如下所示:

      wKgZomQpB4GARmDtAAEjz8WRzO40.png

      打开自己的工程,发现使能的MPU6050后.json文件中没有进行相应的配置,将rt-studio生成的.json文件生成的内容复制到自己的工程。

      wKgaomQpB4KASyxbAAI8aGFdzjE0.png

      在次更新,下载成功

      wKgZomQpB4KAYSnNAAA_Tro3h1s1.png

      将mpu使用的I2C设备修改为I2C0

      wKgaomQpB4OAXpWUAADId5OzbR88.png

      保存,使用scons编译

      wKgZomQeZF-AKcwbAAB7rPOi8Kc1 (2).png

      将sd.bin拖到xfel同级目录下

      wKgZomQeZF-AVRgSAAD8NbdLH3A1 (2).png

      替换掉原来的sd.bin

      wKgaomQeZGCACXBhAAEdKHDg5NM6 (2).png

      三、固件下载

      先将SD卡格式化

      wKgZomQeZGGAFErHAAA8rI5KS2M5 (2).png

      然后插入开发板中,先安全FEL按键,然后按一下复位按键,使开发板进入FEL模式。

      wKgaomQeZGGAeymaAABOjlAet-M0 (2).png

      按一下复位按键,查看串口输出

      wKgaomQpB4WAamfeAAEzshPsYTg0.png

      输入help命令

      wKgZomQpB4aAPcfqAADG9vnlhVo7.png

      输入mpu5xxx_test

      wKgaomQpB4aAHo9sAABOrEoaJcM2.png

      将陀螺仪换个位置读取,数据读取成功

      wKgZomQpB4aAUTihAABvA_OUkZE2.png

      硬件连接

      对应芯片引脚:

      wKgaomQeZGaATBvsAAVTC6RjldM7 (2).png

      对应排针:

      wKgaomQeZGaACzi4AAFv4kFlHRM8 (2).png

      五、总结

      本次完成了MPU6050的数据读取,成功的使用的该外设,当然是底层驱动,还为进行应用层的开发,在驱动层已经有了大致的了解,驱动使用时容易出现MenuConfig配置了但rtconfig.h不更新,每次都要手动的添加,当然在使用的过程中也遇到了很多错误,然后重新下载源码进行开发。

      发布在 MR Series
      Y
      giao
    • D1S在rt-smart下驱动OLED

      D1S使用rt-smart驱动OLED

      前言

      本次使用RT-Smart的IIC驱动OLED屏幕,进行基本的字符串显示,在使用的过程中遇到一些问题,在这里做记录分享,本次以熟悉RT-Smart使用为主。

      过程

      本次直接开始添加离线包,环境搭建请参考上一篇文章:

      https://bbs.aw-ol.com/topic/3145/

      在/D1S/userapps/rt-thread/bsp/allwinner/d1s下输入scons –menuconfig进行内核配置,添加OLED使用所需的配置。

      wKgZomQeZFuAdaP3AAC4y4IWXug1.png

      选择SSD1306离线包

      wKgaomQeZFyAHiFQAATIwgQIjj01.png

      使用IIC3,同时使用ssd1306 sample

      wKgZomQeZFyAAYeqAAEXihAyLAc4.png

      使能IIC3驱动

      wKgaomQeZF2AWplkAAC1iCbcfF06.png

      保存退出,更新一下

      wKgaomQeZF2AKLLhAABCXyXFCAM9.png

      修改rtconfig.h

      wKgZomQeZF6AGetrAAVWWZNsKn40.png

      保存,使用scons编译

      wKgZomQeZF-AKcwbAAB7rPOi8Kc1.png

      将sd.bin拖到xfel同级目录下

      wKgZomQeZF-AVRgSAAD8NbdLH3A1.png

      替换掉原来的sd.bin

      wKgaomQeZGCACXBhAAEdKHDg5NM6.png

      三、固件下载

      先将SD卡格式化

      wKgZomQeZGGAFErHAAA8rI5KS2M5.png

      然后插入开发板中,先安全FEL按键,然后按一下复位按键,使开发板进入FEL模式。

      wKgaomQeZGGAeymaAABOjlAet-M0.png

      按一下复位按键,查看串口输出

      wKgZomQeZGGAXDa-AAFskPuq7PI8.png

      输入help命令

      wKgaomQeZGKAAD4eAADsT-b2KJg0.png

      输入ssd1306_test进行测试,报错

      wKgaomQeZGKAIzvQAAIbrfJNdFA8.png wKgZomQeZGOAeo7lAABjuEiw-_M3.png

      查看硬件原理图,PB6,PB7被占用,使用IIC0进行。

      wKgaomQeZGOAM_yoAAE8CUIzs-U6.png

      重新下载程序后,复位开发板,IIC0已经注册

      wKgZomQeZGSAGwFbAAC8C90DQ1s8.png

      输入ssd1306测试命令

      wKgZomQeZGSAKAz5AABkkBrIcRA1.png

      查看OLED屏幕输出

      wKgaomQeZGWAWG68AAWWrt6QGuM2.png

      硬件连接

      对应芯片引脚:

      wKgaomQeZGaATBvsAAVTC6RjldM7.png

      对应排针:

      wKgaomQeZGaACzi4AAFv4kFlHRM8.png

      五、总结

      RT-Smart文档使用资料有点少,花费大量时间摸索完成了OLED屏幕显示,在摸索过程中也逐渐知道了外设的使用方式。接下里下一步开始驱动2.8寸的LCDTFT。

      原文链接:https://bbs.elecfans.com/jishu_2344522_1_1.html

      发布在 MR Series
      Y
      giao
    • 回复: 淘到一块吃灰的A20,各位大佬麻烦问一下这个板怎么刷

      灰多先用毛巾刷刷

      发布在 其它全志芯片讨论区
      Y
      giao
    • 在东山派DongshanPI-D1s上运行RT-Smart系统

      前言

      根据测评计划,本次在D1S开发板芯片上体验RT-Smart系统,在整个过程中也遇到了很多问题,熬了几个晚上,终于把坑铺平了,本篇文章记录整个过程,本篇文章是完成后才写的,中间可能有部分遗漏,遇到问题的可以在文章下留言,欢迎一起讨论。

      环境搭建

      虚拟机建议使用unbuntu20,因为之前使用的是unbuntu16的,在搭建环境出现了各种问题,所以放弃了unbuntu16上进行开发,新建了unbuntu20进行了开发。

      首先需要获取RT-Smart源码和应用层代码,新建文件夹D1S用于存放应用层代码。

      终端打开输入命令:

      git clone https://github.com/RT-Thread/userapps.git
      

      接下来进入userapps,下载RT-Smart内核代码,使用一下命令:

      git clone https://github.com/RT-Thread/rt-thread.git
      

      在下载源码的过程中可能出现下载失败,连接不上,关闭代理服务器设置就可以了。

      接下来配置开发环境,进入tools,输入以下命令:

      python3 tools/get_toolchain.py riscv64
      

      退出tools,进入到userapps,输入以下命令进行配置:

      source smart-env.sh riscv64
      

      wKgZomQNZP6AVBbTAAB-xhDHew8746.png

      接下来进入/userapps/rt-thread/bsp/allwinner/d1s目录下,输入scons -- menuconfig,进行工程配置或者信息查看。

      wKgZomQNZcuAX0-tAAEQxV76rdA957.png

      查看输出串口信息,同时也可以在rtconfig.h中查看,这里主要进行工程配置。

      wKgaomQNZgWAYKo4AAEbkd8SNQY542.png

      接下来在General Drivers Configruation 下选择General Prupose UARTs中查看串口输出引脚。

      wKgZomQNZrOAVU-pAADND6gdoVs301.png

      接下来进行编译输入scons可以得到sd.bin

      wKgaomQNZ0iAfzicAACw59aUdLc458.png

      在编译过程中可能出现编译工具链不对,在rtconfig.py中修改到自己的路径即可。

      wKgaomQNaAWAGVfnAAHfU2J0fb0087.png

      编译过程中还可能出现找不到openssl,这里只需要安装libssl-dev将编译的sd.bin和tools下的boot0_sdcard_sun20iw1p1_d1s.bin拷贝到windows下借助xfel工具进行烧录。

      硬件连接

      本次需要串口和USB进行下载,串口使用的是uart0,引脚是PE2和PE3。

      查看原理图中的排针接口
      wKgaomQNafOAMdUcAAFdvY1AiRY356.png
      对应芯片引脚,这里使用其他串口进行连接,不使用板载的BL702

      Dongshanpi-d1s_pe2pe3uart_002.png
      实物连接:

      wKgZomQNabuAGLHuABk6noV9OZU532.jpg

      烧录

      烧录需要使用zadig这个软件给该设备强制安装winusb驱动,需要使用xfel进行烧录,这里需要注意的是这块板子的SD卡和Bl702有冲突,需要将拨码开关调整OFF,不然永远也下不进去。全部拨到OFF

      wKgaomQNbAqAOEt7ADRpL81vYwQ336.png

      首先按着开发板的FEL键,然后按一下复位按键进入FEL模式,打开zadig软件强制安装驱动

      wKgZomQNbMSAXHtVAAFbXtDINLQ539.png

      打开zadig软件进行驱动安装

      wKgaomQNbQ2ABrYGAAC0-_MqdSo105.png

      安装完成后开始下载程序,将sd.bin和boot0_sdcard_sun20iw1p1_d1s.bin拷贝到FEL的同级目录:

      wKgZomQNbi6Ae4YAAABPGKdpSLI940.png

      接下来使用SD工具SD Card Formatter格式化SD卡。
      wKgZomQNbvWAFL1RAAA2X3ijuXk393.png

      格式化完成后进入FEL文件路径输入cmd,进入命令行,使用XFEL.EXE进行烧录

      wKgZomQNbyiAayKsAAFjiSaTyDY578.png

      下载前确保开发板已经进入了FEL模式,不然会报错,同时确认拨码开关已拨至SD卡。
      烧录boot镜像:

      xfel.exe sd write 8192 boot0_sdcard_sun20iw1p1_f133.bin
      

      烧录内核镜像:

      xfel.exe sd write 8388608 sdroot.bin
      

      wKgaomQNb-2AHRGNAAAodBAGjrw538.png

      接下来打开串口助手,复位开发板,查看输出

      wKgaomQNcC-ARj23AAHMpEErQv8940.png

      总结

      本次RT-Smart已经跑起来了,过程中也遇到了很多坑,熬了几个晚上,坚持多尝试总会找到解决办法的,接下来会进行下一步的开发。

      本文转载自:https://bbs.elecfans.com/jishu_2340575_1_1.html

      发布在 MR Series
      Y
      giao
    • 回复: 【FAQ】全志R128芯片 在FreeRTOS下如何查看并更改各CPU核的默认运行频率?

      @zhenxin 应该快出了吧,之前看到的消息
      https://www.cnx-software.com/2023/03/06/allwinner-r128-wireless-soc-features-64-bit-risc-v-core-arm-cortex-m33-core-and-hifi-5-audio-dsp/

      发布在 A Series
      Y
      giao
    • 回复: 使用 D1s (RDC2022 纪念版) 连接 thingspeak

      @xiaowenge 好,板子不错挺容易上手的,已经私聊你了😁 谢谢老板

      发布在 MR Series
      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】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
    • 【全志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
    • 【全志T113-S3_100ask】音频输入与输出

      背景

      之前查看系统命令,发现有个aplay命令,然后尝试使用 aplay -Dhw:audiocodec -vvv gz.wav 播放音频,然后报错 aplay: pcm_write:2127: write error: Input/output error

      # aplay -Dhw:audiocodec  gz.wav
      Playing WAVE 'gz.wav' : [   46.786665] [SNDCODEC][sunxi_card_hw_params][620]:stream_flag: 0
      Signed 16 bit Little Endian, Rate 16000 Hz, Mono
      aplay: pcm_write:2127: write error: Input/output error
      

      然后就不会了。

      8月2日100ask出了简单的教程,是需要先使用tinymix 设置参数的,但是。-bash: tinymix: command not found

      我又不想再去编译安装 tinymix ,发现有个 amixer 命令,查阅资料成功配置,播放了音乐。

      (一)amixer 的使用

      1、查看用法

      # amixer -h
      Usage: amixer <options> [command]
      
      Available options:
        -h,--help       this help
        -c,--card N     select the card
        -D,--device N   select the device, default 'default'
        -d,--debug      debug mode
        -n,--nocheck    do not perform range checking
        -v,--version    print version of this program
        -q,--quiet      be quiet
        -i,--inactive   show also inactive controls
        -a,--abstract L select abstraction level (none or basic)
        -s,--stdin      Read and execute commands from stdin sequentially
        -R,--raw-volume Use the raw value (default)
        -M,--mapped-volume Use the mapped volume
      
      Available commands:
        scontrols       show all mixer simple controls
        scontents       show contents of all mixer simple controls (default command)
        sset sID P      set contents for one mixer simple control
        sget sID        get contents for one mixer simple control
        controls        show all controls for given card
        contents        show contents of all controls for given card
        cset cID P      set control contents for one control
        cget cID        get control contents for one control
      
      Available advanced commands:
        sevents         show the mixer events for simple controls
        events          show the mixer events for simple controls
      

      有点复杂看不懂。。。查阅资料。

      2、常用命令

      本节参考 https://blog.csdn.net/meirixuexi/article/details/71513007

      amixer controls 用于查看音频系统提供的操作接口
      amixer contents 用于查看接口配置参数
      amixer cget + 接口函数
      amixer cset + 接口函数 + 设置值
      

      解释:比如想要设置主音量,第一次使用的话先得查询一下接口函数的配置参数,但是又不知道接口叫什么,先查询所有接口

      # amixer controls
      numid=17,iface=MIXER,name='Headphone volume'
      numid=30,iface=MIXER,name='Headphone Switch'
      numid=12,iface=MIXER,name='FMINL gain volume'
      numid=13,iface=MIXER,name='FMINR gain volume'
      numid=2,iface=MIXER,name='ADC1 ADC2 swap'
      numid=24,iface=MIXER,name='ADC1 Input FMINL Switch'
      numid=25,iface=MIXER,name='ADC1 Input LINEINL Switch'
      numid=23,iface=MIXER,name='ADC1 Input MIC1 Boost Switch'
      numid=6,iface=MIXER,name='ADC1 volume'
      ...省略...
      

      找到了Headphone volume,意思是耳机音量,因为我们是使用3.5mm接口的,所以这一项和我们想要的很像。

      使用 amixer cget + 接口函数查询现在的参数,如:

      # amixer cget numid=17,iface=MIXER,name='Headphone volume'
      
      numid=17,iface=MIXER,name='Headphone volume'
        ; type=INTEGER,access=rw---R--,values=1,min=0,max=7,step=0
        : values=4
        | dBscale-min=-42.00dB,step=6.00dB,mute=0
      

      value = 4,最大值为7

      修改音量值为6:

      # amixer cset numid=17,iface=MIXER,name='Headphone volume' 6
      
      numid=17,iface=MIXER,name='Headphone volume'
        ; type=INTEGER,access=rw---R--,values=1,min=0,max=7,step=0
        : values=6
        | dBscale-min=-42.00dB,step=6.00dB,mute=0
      

      (二)amixer 设置音频输出参数

      经过查询,之所以出现 aplay: pcm_write:2127: write error: Input/output error 错误是因为没有输出设备。

      # amixer cget numid=30,iface=MIXER,name='Headphone Switch'
      
      numid=30,iface=MIXER,name='Headphone Switch'
        ; type=BOOLEAN,access=rw------,values=1
        : values=off
      

      耳机开关的输出是 off !!!

      将其开启:

      # amixer cset numid=30,iface=MIXER,name='Headphone Switch' on
      
      numid=30,iface=MIXER,name='Headphone Switch'
        ; type=BOOLEAN,access=rw------,values=1
        : values=on
      

      使用 aplay 可以从耳机输出音乐了!!

      (三)使用 aplay 播放音乐

      1、配置音频输出渠道:

      # amixer cset numid=30,iface=MIXER,name='Headphone Switch' on
      
      numid=30,iface=MIXER,name='Headphone Switch'
        ; type=BOOLEAN,access=rw------,values=1
        : values=on
      

      2、设置音量1:

      # amixer cset numid=17,iface=MIXER,name='Headphone volume' 6
      
      numid=17,iface=MIXER,name='Headphone volume'
        ; type=INTEGER,access=rw---R--,values=1,min=0,max=7,step=0
        : values=6
        | dBscale-min=-42.00dB,step=6.00dB,mute=0
      

      设置音量2:

      # amixer cset numid=5,iface=MIXER,name="PCM Volume" 170
      
      numid=5,iface=MIXER,name='DAC volume'
        ; type=INTEGER,access=rw---R--,values=2,min=0,max=255,step=0
        : values=170,170
        | dBscale-min=-119.25dB,step=0.75dB,mute=0
      

      3、播放音乐:

      # aplay -Dhw:audiocodec -vvv piao.wav
      
      Playing WAVE 'piao.wav' : [  228.205229] [SNDCODEC][sunxi_card_hw_params][620]:stream_flag: 0
      Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
      Hardware PCM card 0 'audiocodec' device 0 subdevice 0
      Its setup is:
        stream       : PLAYBACK
        access       : RW_INTERLEAVED
        format       : S16_LE
        subformat    : STD
      ...省略...
      

      实测:

      3bd5a2f03b5b4b3cb835dd8a7af85391.png

      (四)使用 arecord 录音

      配置音频输入渠道:

      amixer cset numid=29,iface=MIXER,name='ADC3 Input MIC3 Boost Switch' on
      amixer cset numid=31,iface=MIXER,name='HpSpeaker Switch' on
      

      录音

      arecord -Dhw:audiocodec -f S24_LE -r 16000 -c 1 -d 10 -vv ./in.wav
      

      解释:使用 设备audiocodec
      录制 格式为S24_LE
      输入比特率为16000
      通道1
      时间为10s
      保存在 ./in.wav
      更多内容\查看帮助 arecord -h

      实测:

      8b880533322f40d7a396b588da537fd6.png

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

      发布在 MR Series
      Y
      giao
    • 回复: uboot正确启动了,RGB屏点不亮

      @zznzzn

      运气不错~竟然没烧哈哈

      Licheepi这个支持电阻屏,想要测试触摸功能要重新买块电阻屏哦

      也是通用的

      QQ图片20220922163413.jpg

      发布在 其它全志芯片讨论区
      Y
      giao
    • 回复: uboot正确启动了,RGB屏点不亮

      屏是标准的rgb接口屏,可是正点原子转接过啦

      应该是用这个,插Licheepi,这个是通用的RGB 40pin接口

      QQ图片20220922160245.jpg

      不确定接口顺序就直接插上去,不怕冒烟嘛?

      发布在 其它全志芯片讨论区
      Y
      giao
    • 【全志T113-S3_100ask】USB串口获取GPS数据

      背景

      板子上有两个串口,但是串口1被xr829模块占用了,串口3主要用于调试,为简单实现串口功能,本讲将实现usb转串口(ch340)来采集gps的数据,并解析。

      (一)USB串口驱动

      @本讲不使用Tina系统,使用 百问Buildroot 。

      Tips:CH340是CH341的阉割版,CH340不支持并口、打印口、IIC,专为串口应用设计

      在buildroot已经集成了ch341的驱动,我们将其 使能 即可使用,非常简单。

      Symbol: USB_SERIAL_CH341 [=y]                                                                                
         Type  : tristate                                                                                             
         Prompt: USB Winchiphead CH341 Single Port Serial Driver                                                      
           Location:                                                                                                  
             -> Device Drivers                                                                                        
               -> USB support (USB_SUPPORT [=y])                                                                      
         (1)     -> USB Serial Converter support (USB_SERIAL [=y])                                                    
           Defined at drivers/usb/serial/Kconfig:105                                                                  
           Depends on: USB_SUPPORT [=y] && USB [=y] && USB_SERIAL [=y]
      

      (二)驱动加载

      驱动是编译进内核的,不用手动加载,把USB转TTL插到USB口就自动匹配识别,生成ttyUSB0设备。
      以下是开机显示信息:

      [   11.529946] usbcore: registered new interface driver ch341
      [   11.537840] usbserial: USB Serial support registered for ch341-uart
      [   11.545934] ch341 1-1.2:1.0: ch341-uart converter detected
      [   11.578483] usb 1-1.2: ch341-uart converter now attached to ttyUSB0
      
      ls /dev
      

      e70eb4435354446080861b476af87b14.png

      (三)简单读取串口数据

      此时已经将ch340和gps模块连接上开发板了
      5de7d28df1c44082a5227e0c256a338e.jpeg

      使用 cat 命令即可简单读取串口返回的信息。

      # cat /dev/ttyUSB0
      
      A*7B
      
      $GPVTG,,T,,M,1.070,N,1.982,K,A*27
      
      $GPGGA,072008.00,2306.6$GPTXT,01,01,01,NMEA unknown msg*58
      
      $GPRMC,072232.00,A,2306.62360,N,11316.59966,E,0.311,,020822,,,A*78
      
      $GPVTG,,T,,M,0.311,N,0.577,K,A*25
      
      $GPGGA,072232.00,2306.62360,N,11316.59966,E,1,08,1.62,21.7,M,-5.6,M,,*7A
      
      $GPGSA,A,3,13,02,05,11,20,18,24,23,,,,,3.06,1.62,2.59*05
      
      $GPGSV,3,1,11,02,49,126,20,05,43,034,37,11,28,123,12,13,58,033,35*72
      
      $GPGSV,3,2,11,15,73,291,21,18,27,324,37,20,24,071,29,23,10,286,32*78
      
      $GPGSV,3,3,11,24,26,175,20,29,48,259,10,30,06,046,*45
      
      $GPGLL,2306.62360,N,11316.59966,E,072232.00,A,A*68
      

      (四)数据解析

      本解析参考: https://blog.csdn.net/qq_30665009/article/details/121434507

      我们在编写正式的应用程序之前,先了解这一堆数据里面我们想要的部分 --> $GPRMC

      $GPRMC格式:

      $GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh<CR><LF>
      
      $GPRMC,072232.00,A,2306.62360,N,11316.59966,E,0.311,,020822,,,A*78
      

      其中:

      99299559-7F78-4cb0-9987-DC72A0B68F3F.png

      (五)编写应用程序

      参考 https://www.likecs.com/show-205110023.html

      1、定义结构体

      typedef struct __gprmc__
      {
          UINT time;         /* gps定位时间 */
          char pos_state;    /*gps状态位*/
          float latitude;    /*纬度 */
          float longitude;   /* 经度 */
          float speed;       /* 速度 */
          float direction;   /*航向 */
          UINT date;         /*日期  */
          float declination; /* 磁偏角 */
          char dd;
          char mode; /* GPS模式位 */
      } GPRMC;
      

      2、使用 open 和 read 函数读取串口数据

      3、获取想要的部分

      /* 如果buff字符串中包含字符"$GPRMC"则将$GPRMC的地址赋值给ptr */
      if (NULL == (ptr = strstr(buff, "$GPRMC")))
      {
          return -1;
      }
      

      4、使用 sscanf 进行格式化处理,存进结构体

      5、计算、回显处理

      (六)测试

      编译后放到开发板,测试程序

      # ls
      gps_test
      
      # ./gps_test
      buff:1,13,36,033,33*7F
      $GPGSV,3,2,10,15,62,356,30,18,48,324,20,20,14,092,19,23,21,306,23*7A
      $GPGSV,3,3,10,24,48,164,20,29,35,229,25*70
      $GPGLL,2306.62377,N,11316.59930,E,081227.00,A,A*65
      $GPRMC,081228.00,A,2306.62398,N,11316.59935,E,0.294,,020822,,,A*72
      $GPVTG,,T,,M,0.294,N,0.545,K,A*28
      $GPGGA,081228.00,2306.62398,N,11316.59935,E,1,08,1.04,-0.4,M,-5.6,M,,*61
      $GPGSA,A,3,15,18,24,13,05,02,23,20,,,,,2.10,1.04,1.82*02
      $GPGSV,3,1,10,02,29,144,21,05,36,062,35,11,10,138,,13,36,033,32*7E
      $GPGSV,3,2,10,15,62,356,30,18,48,324,17,20,14,092,20,23,21,306,22*75
      $GPGSV,3,3,10,24,48,164,20,29,35,229,26*73
      $GPGLL,2306.62398,N,11316.59935,E,081228.00,A,A*6E
      $GPRMC,081229.00,A,2306.62396,N,11316.59928,E,0.427,,020822,,,A*7F
      $GPVTG,,T,,M,0.427,N,0.791,K,A*2D
      $GPGGA,081229.00,2306.62396,N,11316.59928,E,1,09,1.04,-0.8,M,-5.6,M,,*6F
      $GPGSA,A,3,15,18,24,13,05,02,23,20,11,,,,2.10,1.04,1.82*02
      $GPGSV,3,1,10,02,29,144,21,05,36,062,35,11,10,138,1,1144,15,05,36,062,36,11,10,138,12)▒▒
      ===========================================================
      ==
      ==   GPS state bit : A  [A:有效状态 V:无效状态]
      ==   GPS mode  bit : A  [A:自主定位 D:差分定位]
      ==   Date : 2022-08-02
      ==   Time : 16:12:28
      ==   纬度 : 北纬:23度6分37秒
      ==   经度 : 东经:113度16分35秒
      ==   速度 : 0.294  m/s
      ==
      ============================================================
      

      但是要留意,某些gps模块获取不到该字段的数据,需要将其对应修改匹配。

      至此,测试完毕。

      源码地址:
      https://download.csdn.net/download/qq_46079439/86272180
      原文链接:https://blog.csdn.net/qq_46079439/article/details/126122756

      发布在 MR Series
      Y
      giao
    • 回复: 全志V853编译出现问题

      缺少一个命令,需要安装uboot-tools包

      发布在 V Series
      Y
      giao
    • 【全志T113-S3_100ask】编译Tina系统初体验

      背景

      7月28日,百问网官方发布适配Tina系统的SDK。因为使用Tina系统开发还是比较方便的,有全志的SDK支持,可以参考的内容比较多。
      https://forums.100ask.net/t/topic/399

      (一)SDK准备

      通过上面的百度网盘下载SDK,拷贝到linux下。
      解压缩命令:

      cat Tina-t113-pro.tar.bz2.* | tar jx
      

      (二)环境准备

      全志Tina官方推荐下载:

      sudo apt-get update
      
      sudo apt-get install build-essential subversion git-core libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip lib32z1 lib32z1-dev lib32stdc++6 libstdc++6 -y
      

      对于Ubuntu 16.04以上版本,部分软件包已不再提供或者采用了其他的包,执行上述命令时, 安装失败的包可先忽略,进一步执行以下命令:

      sudo apt-get install libc6:i386 libstdc++6:i386 lib32ncurses5 lib32z1
      

      (三)编译系统

      1、初次编译系统

      root@znh-ubuntu:~# cd Tina-t113-pro
      root@znh-ubuntu:~/Tina-t113-pro# ls
      build   Config.in  dl      linux     package   rules.mk  target  toolchain
      config  device     lichee  Makefile  prebuilt  scripts   tmp     tools
      

      步骤:

      source build/envsetup.sh
      lunch
      make
      pack
      
      • source build/envsetup.sh :获取环境变量(一个shell生效一次)
      • lunch 会提供方案选项以供选。
      • make -j8 :编译,其中-j后面的数字参数为编译用的线程数,可根据开发者编译用的PC实际情况选择。
      • pack : 打包,将编译好的固件打包成一个.img格式的固件,固件路径 /out

      实例:

      root@znh-ubuntu:~/Tina-t113-pro# source build/envsetup.sh
      Setup env done! Please run lunch next.
      
      root@znh-ubuntu:~/Tina-t113-pro# lunch
      
      You're building on Linux
      
      Lunch menu... pick a combo:
           1. t113_pro-tina
      
      Which would you like? [Default t113_mq]: 1
      ============================================
      TINA_BUILD_TOP=/disk/Tina_T113_100ask/Tina-t113-pro
      TINA_TARGET_ARCH=arm
      TARGET_PRODUCT=t113_pro
      TARGET_PLATFORM=t113
      TARGET_BOARD=t113-pro
      TARGET_PLAN=pro
      TARGET_BUILD_VARIANT=tina
      TARGET_BUILD_TYPE=release
      TARGET_KERNEL_VERSION=5.4
      TARGET_UBOOT=u-boot-2018
      TARGET_CHIP=sun8iw20p1
      ============================================
      no buildserver to clean
      [1] 4054
      root@znh-ubuntu:~/Tina-t113-pro#
      [1]+  已完成               $T/tools/build/buildserver --path $T 2> /dev/null 1>&2
      root@znh-ubuntu:~/Tina-t113-pro#
      root@znh-ubuntu:~/Tina-t113-pro# ls
      build   Config.in  dl      linux     package   rules.mk  target     tools
      config  device     lichee  Makefile  prebuilt  scripts   toolchain
      root@znh-ubuntu:~/Tina-t113-pro# make -j8
      ...
      make[1]: Leaving directory '/disk/Tina_T113_100ask/Tina-t113-pro'
      [2]+  已完成               $T/tools/build/buildserver --path $T 2> /dev/null 1>&2
      
      #### make completed successfully (02:49:28 (hh:mm:ss)) ####
      
      root@znh-ubuntu:~/Tina-t113-pro#
      

      当然我的编译过程没有那么顺利

      错误1:

      you should not run configure as root (set FORCE_UNSAFE_CONFIGURE=1 in environment
      

      解决(大概意思就是root用户需要设置这个):

      export FORCE_UNSAFE_CONFIGURE=1
      

      错误2:缺失 gmp.h

      enwrt-linux-muslgnueabi/6.4.1/plugin/include/system.h:681:10: fatal error: gmp.h: No such file or directory
      

      解决:

      sudo apt-get install libgmp-dev
      

      错误3:缺失 mpc.h

      enwrt-linux-muslgnueabi/6.4.1/plugin/include/builtins.h:23:10: fatal error: mpc.h: No such file or directory
      

      解决:

      sudo apt-get install libmpc-dev
      

      错误4 致命:不安全的存储库由其他人拥有

      `atal: detected dubious ownership in repository at '/disk/Tina_T113_100ask/Tina-t113-pro'
      To add an exception for this directory, call:
      
              git config --global --add safe.directory /disk/Tina_T113_100ask/Tina-t113-pro
      Makefile:646: recipe for target '/disk/Tina_T113_100ask/Tina-t113-pro/out/t113-pro/packages/base/libgcc_-1_sunxi.ipk' failed
      make[3]: *** [/disk/Tina_T113_100ask/Tina-t113-pro/out/t113-pro/packages/base/libgcc_-1_sunxi.ipk] Error 128
      make[3]: Leaving directory '/disk/Tina_T113_100ask/Tina-t113-pro/package/libs/toolchain'
      package/Makefile:192: recipe for target 'package/libs/toolchain/compile' failed
      make[2]: *** [package/libs/toolchain/compile] Error 2
      make[2]: Leaving directory '/disk/Tina_T113_100ask/Tina-t113-pro'
      package/Makefile:189: recipe for target '/disk/Tina_T113_100ask/Tina-t113-pro/out/t113-pro/staging_dir/target/stamp/.package_compile' failed
      make[1]: *** [/disk/Tina_T113_100ask/Tina-t113-pro/out/t113-pro/staging_dir/target/stamp/.package_compile] Error 2
      make[1]: Leaving directory '/disk/Tina_T113_100ask/Tina-t113-pro'
      /disk/Tina_T113_100ask/Tina-t113-pro/build/toplevel.mk:304: recipe for target 'world' failed
      make: *** [world] Error 2
      
      #### make failed to build some targets (01:18 (mm:ss)) ####
      
      root@znh-ubuntu:~/Tina-t113-pro#
      

      解决(该目录每个人都不一样):

      git config --global --add safe.directory /disk/Tina_T113_100ask/Tina-t113-pro
      

      2、进阶编译操作

      如果不需要完整编译整个系统,也可以对部分模块进行编译,如单独编译boot0、单独编译uboot、单独编译内核和单独编译某个包等,Tina环境都提供了相应的快捷命令:

      mboot
      - 单独编译boot0和uboot,可在Tina任意目录下使用.
      
      mboot0
      - 单独编译boot0,可在Tina任意目录下使用
      - 
      muboot
      - 单独编译uboot,可在Tina任意目录下使用
      
      mkernel
      - 单独编译内核,可在Tina任意目录下使用
      
      mm
      - 单独编译某个包,只能在编译的包路径下操作,如包路径为 tina/package/utils/rwcheck,则需要进入到 tina/package/utils/rwcheck路径下再输入 mm 命令,编译出来对应的安装包的路径在 tina/out/d1-nezha/packages/base下
      
      
      - 在根目录下编译某个软件包:make <应用包的路径>/install,需要在根目录下操作
      如 make package/utils/rwcheck/install
      - 在根目录下清空应用包临时文件:make <应用包的路径>/clean,需要在根目录下操作
      如 make package/utils/rwcheck/clean0.img。
      

      (四)烧录系统

      编译出来的镜像可以通过sd卡启动。通过全志工具PhoenixCard烧写。

      d800bd1605ed4cb4b672c2c6018e8f5c.png

      启动系统

      14b9b32df3bd43e88523026431bc28f0.png

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

      发布在 MR Series
      Y
      giao
    • 回复: D1 DOCK PRO buildroot编译的内核烧录之后上电

      udhcpc一直在尝试获取ip,可以关了udhcpc或者启用wlan/net

      发布在 MR Series
      Y
      giao
    • 回复: V853 NPU的demo试玩

      @haaland 正有此意,最近在做模型转换,突然发现CPU不支持AVX指令集…

      发布在 V Series
      Y
      giao
    • 交叉编译一个打印Hello World的小应用

      使用电脑(上位机)交叉编译一个打印 Hello World 的小应用,并将其上传到开发板(下位机)上运行起来,打印出 hello world。

      参考文章地址:https://v853.docs.aw-ol.com/study/study_6helloword/

      在用ADB向开发板push文件的时候遇到了和这位兄弟同样的问题,感谢一下这位兄弟👍 https://bbs.aw-ol.com/topic/2051/

      在交叉编译上遇见了路径略有不同,特做记载:

      1、创建main.c的过程是一样的,建一个文件夹,在文件夹里创建一个main.c文件。

      #include <stdio.h>
      int main(int argc, char const *argv[])
      {
          printf("Hello World\n");
          return 0;
      }
      

      2、叉编译前,你要知道

      交叉编译所使用的交叉编译工具链名叫toolchain-sunxi-musl-gcc-830存放路径

      ~/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/
      

      3、编译使用的 gcc 编译器路径:

      ~/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/bin/arm-openwrt-linux-gcc
      

      4、光有编译器还不够,还需要提供编译时需要用到的那些库文件,头文件。这些文件存放路径:

      ~/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/arm-openwrt-linux-muslgnueabi
      

      5、开始交叉编译

      首先,指定存放交叉编译需要使用的库文件头文件的文件夹

      export STAGING_DIR=~/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/arm-openwrt-linux-muslgnueabi
      

      6、然后就可以使用交叉编译工具链来编译了,可以看到编译出的 helloworld 可执行文件已经生成了。

      ~/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/bin/arm-openwrt-linux-gcc -o helloworld main.c
      

      pYYBAGMSExKAKI1hAAEZ0f2aVH0527.jpg

      发布在 V Series
      Y
      giao
    • 回复: kernel输出串口bootargs设置ttyS0没输出

      看着像内核没起来,kernel内也要配置console index和uart地址,要到kernel的menuconfig里找到kernel hacking部分进行配置 (arm的一个坑,两边两边地址不一样kernel就不起来了

      发布在 Linux
      Y
      giao
    • 【全志V853试用】buildroot 编译 Tina Linux 时gdbusauth.c/gdbusmessage.c/strerror-sym.c三个文件陆续报错

      buildroot 的编译大致分为以下流程:

      (1) ./build.sh config  # 配置编译模式和项目文件
      (2) ./build.sh         # 编译
      (3) ./build.sh pack    # 打包
      

      有三个文件在编译过程中陆续会报错:

      1、其中把gdbusauth.c和gdbusmessage.c两个文件的报错位置注释掉就行。

      2、strerror-sym.c报错,目前暂时修改如下:

      pYYBAGMQx7-AIAIdAANMpSpUS8U671.png

      成功编译的结果:
      pYYBAGMQx_KAN7GPAAIseSx0GT8622.png
      pYYBAGMQx_qABdd-AAMfpsO5XI8397.png

      打包完成的固件的文件路径:

      /home/sysroot/tina-v853-open/out/v853/vision/buildroot/v853_linux_vision_uart0.img
      

      再一次开始愉快的玩耍了!!!

      发布在 V Series
      Y
      giao
    • 【全志V853试用】adb连接异常问题解决方法分享

      之前已经试玩了NPU的demo。这里记录一下使用V853开发板的过程以及踩过的几个坑。

      在开发板包装盒里有随开发板送了一条Type-C 的线,把线插入开发板usb口,另外插入电脑。查看电脑的设备管理,看使用的什么驱动。初始我的电脑没有提示找到新设备,难道意味着电脑已经有驱动了?查看设备管理器,发现在通用串行设备管理里出现一个带警告标志的设备,但看它已经有了驱动。于是就不管它,直接看系统的端口。

      pYYBAGMNtEGAVaWOAAEtL04xw20510.png

      在查看串口端口时,电脑的虚机弹出是否连接ADB 到虚机的提示?此时想它使用的是ADB作为连接,那么我本机刚好有AndroidStudio的开发环境,而AndroidStudio里是有ADB 工具的,于是选择ADB连接主机,然后启动AndroidStudio开发平台,进入里面去查看设备管理,果然发现新设备,显示下图:

      pYYBAGMNtEGAG3FJAAK_NBLqOtM291.png

      在设备管理里出现一个Android设备,但比较奇怪,没有设备名称和设备属性(这里说一下,正是这个提示,说明它并不是一个Android设备,后面才搞明白,这里入一坑)。不管三七二十一就按标准的Android设备进行连接测试。

      打开一个在其它板子上运行完好的Android程序,然后编译,下载,运行。过程一路流畅,没有报错,并且显示编译成功,运行成功,如下图:

      poYBAGMNtEKAPkbeAALkQeeUcMw954.png

      但出现一个奇怪的问题,程序运行后,在开发板上没看到任何反应,该程序是一个测试GPU的OpenGL三维渲染的程序,即便板子不支持OpenGL的话,也应该出现报错提示,至少加载界面应该显示。但启动加载也看不到。

      于是进入AndroidStudio的平台工具命令行,启动ADB进入设备查看,首先使用ADB扫描设备:adbdevices

      在输入上面命令后,显示找到一个设备,并且正确找到V853开发板,扫描到设备后,再使用命令进入设备交互环境:adbshell

      可以看到开发板输出了tinaLinux 的shell欢迎画面,说明正确的连入了开发板。

      poYBAGMNtEOABkORAABGsRTJvHM796.png
      此时可以查看系统的文件,开发板设备信息等。如下图所示:

      poYBAGMNtESAD0lVAAB1nCvktBY003.png

      也可以查看系统软件的版本,以及网络配置,从下图可见,开发板带的系统,没有有线网卡的设备,也没有获取IP地址,此时把局域网线插入开发板的网口,板上网络灯不亮。

      pYYBAGMNtESAVo1RAABm7bHAU_U683.png

      回到开始编译的测试程序,使用adb进行手动安装,命令如下:

      adbinstall -r textured-teaopt.apk
      

      但奇怪的是,开发板没有反应,命令行没有任何提示,即不显示成功,也没有报错。又尝试推送文件到板子上,也出现不报错,但文件也没推送成功。

      于是想通过TCP/IP网络来与板子建立连接,由于开发板有线网口不通,就尝试使用wifi 方式来连接,查了一下资料,按资料说明,在adb shell 下启动wifi ,输入wifi后能够正确执行出现命令提示,但是操作启动wifi sta 模式,连接热点时,没有任何反应,也不报错,网络也连接不成功。

      poYBAGMNtEaAaWhCAACO7sBv2yg284.png

      结合以上种种奇怪的现象,一度怀疑开发板系统是否有故障。在多次验证后,发现开发板系统内缺少Android软件的很多组件,于是开始怀疑开发板并不是Android设备,仅仅用到了adb的调试工具。然后开始到全志开发社区,查看相关资料。

      这一看,才发现全志有一个自己的adb工具 ADB(tab自动补全版),果断下载安装,再对比一看,两个文件size不一样,显然不是一个工具。 这次再使用全志版本的adb进入开发板,然后重新配置wifi时,此次竟然一下顺利的配置成功。

      经过分析看来,踩坑的主要问题是由于全志有专用的ADB工具包,虽然名字跟 android 开发包里的一致,但是可能在版本和协议上并不完全一样,导致部分功能正常,而部分功能不正常。

      结论就是现有的开发环境不一定和板子的开发环境一致,要仔细阅读相关开发文档,并且保持环境的一致很重要。按官方的文档操作才能避免一些不必要的踩坑

      发布在 V Series
      Y
      giao
    • 回复: V853 NPU的demo试玩

      @nideyida 拓展包这里下 ->https://www.aw-ol.com/downloads?cat=18
      各个芯片的文档、软件固件资料都在这里

      发布在 V Series
      Y
      giao
    • V853 NPU的demo试玩

      一、Tina Linux 5.0编译

      (一)下载源码

      V853的Tina Linux 5.0 SDK源码在全志客服服务平台 下载即可,这个要绝对表扬,平台上D1、V853、XR806的芯片相关SDK等资料全部直接可以下载。

      pYYBAGMCQsOACfieAAOTfprqV7I572.png

      官方V853 SDK使用的kernel是4.9,比D1的5.4 kernel版本低点,问了大佬,大约4.9上V853板子的驱动完善。

      按照官方下载文档,一步步走即可,要注意的是中间不要切换用户,SSH key-gen获得的密钥放在跟后续repo操作用户不同的目录下,导致repo失败。

      (二)源码编译

      Tina Linux 5.0 SDK源码编译有2中方式,一种常规Linux编译,另外一种buildroot方式,本人直接选择Linux(openWRT)方式。从源码到img固件,需要二部分配置,一块是Linux(openWRT)系统相关工具配置,另外一部分是Tina 5.0相关功能的配置。本人采取如下步骤

      1、编译环境设置;

      root@EliteDesk:/media/tina-v853$ source build/envsetup.sh
      NOTE: The SDK(/media/tina-v853) was successfully loaded
      load openwrt... ok
      Please run lunch next for openwrt.
      load buildroot,bsp...ok
      Please run ./build.sh config next for buildroot,bsp.
      

      2、选择编译方案;

      root@EliteDesk:/media/tina-v853$ lunch
      
      You're building on Linux
      
      Lunch menu... pick a combo:
           1  v853-vision-tina
      Which would you like? [Default v853-vision]: 1
      Jump to longan autoconfig
      /media/tina-v853/build.sh autoconfig -o openwrt -i v853 -b vision               -n default
      ========ACTION List: mk_autoconfig -o openwrt -i v853 -b vision -n default;========
      options :
      INFO: Prepare toolchain ...
      INFO: kernel defconfig: generate /media/tina-v853/kernel/linux-4.9/.config by /media/tina-v853/device/config/chips/v853/configs/visi                                                                     on/linux-4.9/config-4.9
      INFO: Prepare toolchain ...
      make: Entering directory '/media/tina-v853/kernel/linux-4.9'
      *** Default configuration is based on '../../../../../device/config/chips/v853/configs/vision/linux-4.9/config-4.9'
      #
      # configuration written to .config
      #
      make: Leaving directory '/media/tina-v853/kernel/linux-4.9'
      INFO: clean buildserver
      INFO: prepare_buildserver
      

      3、Tina系统配置;

      因为第二章是NPU相关功能使用,所以在第三步将NPU扩展包安装还有配置也放进来了。

      将V853 NPU扩展包下载后放在Tina-V853目录下解压,如果解压有问题,基本是下载的问题,直接重新下载。

      tar xvf npu_package.tar.gz

      解压后的文件放在openwrt/packages/npu文件夹中:

      pYYBAGMCSDSAK4R4AAAv19jIDBg609.png

      make menuconfig将NPU相关功能加进来。

      pYYBAGMCSOeADq5HAACE_J06O6g166.png

      反正全部选上,后面用:

      poYBAGMCSR-ALxXIAABZ8-ZYptw332.png

      退出后保存,当然还可以选择配置Tina 5.0的其他功能,保存后退出。

      4、make;

      没啥好说的,这里面会有个mkImage的错误,问了很多人,后来在这个帖子里找到了答案【V853开发板试用】V853编译烧录疑难杂症汇总篇

      make的时候可以看到NPU扩展包编译的情况:

      pYYBAGMCSfyAD63WAAET8gEoCMY319.png

      最后就是编译成功:

      poYBAGMCSmWAaheBAACD1mK0IPA682.png

      5、pack。

      PACK就是利用Tina的工具将之前make生成的文件打包,加入NPU扩展包后的img约70M,比起之前没加NPU扩展包的33M大了很多。

      pYYBAGMCSyWAC1kfAACDzEjU26c267.png

      二、烧录

      全志提供了很多种方法,本人选择的是PhoenixSuit,连上Type-C和计算机,打开PhoenixSuit待确认连接后将img烧入即可。

      poYBAGMCTEyAVxERAAH-yF_IM60284.png

      三、NPU功能测试

      (一)Tina 5.0体验

      IMG烧写完后,在PhoenixSuit上可以看到系统版本。

      poYBAGMCTUOAUHIrAALeu9T4EWU547.png

      也可以通过ADB shell登录系统验证,比起开箱的ABD SHELL,可以明显看到Tina Linux 5.0字样,BusyBox版本也提升了。
      poYBAGMCTgiAG5EEAAAkeWEIwsI360.png

      可以看到,目录下已经有NPU扩展包的模型了,一个lenet模型,一个yolov3模型。

      root@TinaLinux:/# ls /etc/models/
      lenet_model.nb   yolov3_model.nb
      

      (二)NPU使用

      V853内置最大 1T 算力 NPU,必须用上,第一章已经把官方NUP扩展包加入,选了三组图片测试。

      1、Kids原图:

      pYYBAGMCT2-AcWpGAAGR1dk5Ruo475.jpg

      NPU执行log:

      root@TinaLinux:~# yolov3 /etc/models/yolov3_model.nb kids.jpg
      [0xb6f28560]vip_init[104],
      The version of Viplite is: 1.8.0-0-AW-2022-04-21
      Create Neural Network: 72.49ms or 72488.49us
      Start run graph [1] times...
      Run the 1 time: 204.67ms or 204672.98us
      vip run network execution time:
      Total   205.50ms or 205502.34us
      Average 205.50ms or 205502.34us
      data_format=2 buff_size=43095
      data_format=2 buff_size=172380
      data_format=2 buff_size=689520
      person  99% 274 413 70 415
      person  99% 153 309 106 415
      person  99% 96 206 31 415
      person  95% 2 141 71 415
      person  86% 0 87 23 339
      

      输出结果,很优秀:

      999FD017-C3DE-462f-B448-1CFD39A5FF2F.png

      2、cars原图

      poYBAGMCUF6AI7BAAAFvzC_5kQc787.jpg

      执行过程:

      root@TinaLinux:~# yolov3 /etc/models/yolov3_model.nb cars.jpg
      [0xb6f62560]vip_init[104],
      The version of Viplite is: 1.8.0-0-AW-2022-04-21
      Create Neural Network: 71.73ms or 71734.62us
      Start run graph [1] times...
      Run the 1 time: 204.71ms or 204714.50us
      vip run network execution time:
      Total   205.67ms or 205669.88us
      Average 205.67ms or 205669.88us
      data_format=2 buff_size=43095
      data_format=2 buff_size=172380
      data_format=2 buff_size=689520
      car  100% 65 195 59 160
      car  99% 23 154 185 298
      car  99% 71 227 223 363
      car  99% 204 343 83 240
      car  97% 0 155 117 257
      car  97% 349 415 175 294
      car  92% 132 307 271 411
      car  92% 0 49 13 107
      car  88% 280 410 47 149
      car  81% 19 123 3 83
      

      识别结果:

      C9129ECC-B545-43dc-8C2A-DA7836ED25DA.png

      3、人脸识别

      原图:

      pYYBAGMCUYCABnaqAAFjR8hHaO0702.jpg

      执行过程:

      root@TinaLinux:~# yolov3 /etc/models/yolov3_model.nb people.jpg
      [0xb6f8b560]vip_init[104],
      The version of Viplite is: 1.8.0-0-AW-2022-04-21
      Create Neural Network: 71.99ms or 71992.21us
      Start run graph [1] times...
      Run the 1 time: 204.73ms or 204726.08us
      vip run network execution time:
      Total   205.66ms or 205664.12us
      Average 205.66ms or 205664.12us
      data_format=2 buff_size=43095
      data_format=2 buff_size=172380
      data_format=2 buff_size=689520
      person  100% 107 263 33 231
      person  100% 239 414 138 415
      person  100% 98 172 121 240
      person  99% 279 382 0 158
      person  99% 0 95 107 415
      person  95% 307 415 28 382
      person  94% 80 277 217 415
      person  93% 24 122 235 412
      person  92% 164 268 0 143
      person  83% 6 109 4 148
      

      识别结果:

      2B92F5EF-94BC-4e2a-8ECC-6A93663127A5.png

      发布在 V Series
      Y
      giao
    • 【全志T113-S3_100ask】5-编写IIC驱动GY-302(twi)

      前言

      在100ask的板子上预留了一个IIC接口,下面通过这个IIC接口来采集光照强度传感器GY-302(BH1750)。

      4a9720dde0fd4e8798ca7040c407c009.png

      (一)不使用设备树操作

      1、预操作
      通过查看设备,我们可以看到上面挂载着一个i2c-2设备,且没有其他的i2c。

      01c6e523f7724701afa6ef3aeff97e64.png

      2、使用i2c tools测试iic

      i2c-tools编译,安装步骤

      /1、下载i2c-tools-4.0
      wget  https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/i2c-tools-4.0.tar.gz  
      //2、解压
      tar -xzvf i2c-tools-4.0.tar.gz
      //3、修改交叉编译:Makefile中的CC该为使用的交叉编译器
      CC      ?= arm-linux-gnueabi-gcc
      //4、编译
      Make
      

      然后将该工具拷贝到开发板,nfs也好,U盘也行。
      然后使用该工具检测设备

      # ls
      i2c-tools-4.0
      
      # cd i2c-tools-4.0/
      # ls
      CHANGES       Makefile      eeprom        lib           tools
      COPYING       README        eepromer      py-smbus      version.h
      COPYING.LGPL  eeprog        include       stub
      
      # cd tools/
      # ls
      Module.mk      i2cdetect.c    i2cget         i2cset.c       util.c
      i2cbusses.c    i2cdetect.o    i2cget.8       i2cset.o       util.h
      i2cbusses.h    i2cdump        i2cget.c       i2ctransfer    util.o
      i2cbusses.o    i2cdump.8      i2cget.o       i2ctransfer.8
      i2cdetect      i2cdump.c      i2cset         i2ctransfer.c
      i2cdetect.8    i2cdump.o      i2cset.8       i2ctransfer.o
      
      !目前只挂载i2c-2
      # i2cdetect -l
      i2c-2   i2c             twi2                                    I2C adapter
      
      # i2cdetect -y 2
           0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
       00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
       10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
       20: -- -- -- 23 -- -- -- -- -- -- -- -- -- -- -- --
       30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
       40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
       50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
       60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
       70: -- -- -- -- -- -- -- --
      

      3、编写测试应用

      打开设备文件然后设置i2c设备的地址,按照GY-302数据手册中操作流程,连续写0x01和0x11,就可以读出光照信息。

      • 初始化 写寄存器0x01 上电

      • 设置 0x11 设置成高精度模式 Continuously H-Resolution Mode,即连续高分辨率模式。

      • 读数据 unsigned char Buf[3] data=Buf[0]; data=(data<<8)+Buf[1] tmp=data/1.2

      #include <stdio.h>
      #include <fcntl.h>
      #include <linux/i2c-dev.h>
      #include <errno.h>
      #define I2C_ADDR 0x23
      
      int main(void)
      {
          int fd;
          char buf[3];
          char val, value;
          float flight;
          fd = open("/dev/i2c-2", O_RDWR);
          if (fd < 0)
          {
              printf("打开文件错误:%s\r\n", strerror(errno));
              return 1;
          }
          if (ioctl(fd, I2C_SLAVE, I2C_ADDR) < 0)
          {
              printf("ioctl 错误 : %s\r\n", strerror(errno));
              return 1;
          }
          val = 0x01;
          if (write(fd, &val, 1) < 0)
          {
              printf("上电失败\r\n");
          }
          val = 0x11;
          if (write(fd, &val, 1) < 0)
          {
              printf("开启高分辨率模式2\r\n");
          }
          usleep(200000);
          while (1)
          {
              if (read(fd, &buf, 3))
              {
                  flight = (buf[0] * 256 + buf[1]) * 0.5 / 1.2;
                  printf("光照度: %6.2flx\r\n", flight);
              }
              else
              {
                  printf("读取错误\r\n");
              }
              sleep(3);
          }
      }
      

      4、测试

      # ./iic_gy30_test
      光照度:  75.42lx
      光照度:  95.14lx
      光照度:  311.47lx
      

      (二)使用设备树操作

      1、TWI 两线串行接口简介

      • 在设备树中,找不到任何i2c的节点信息,只找到twi。
        TWI(Two-wire Serial Interface)两线串行接口,TWI 完全兼容 I2C 总线。

      • 由于TWI总线与传统的I2C总线极其相似。因此不少人误以为TWI总线就是I2C总线,其实这只是一种简单化的理解。TWI总线是对I2C总线的继承和发展。它定义了自已的功能

      • 模块和寄存器,寄存器各位功能的定义与I2C总线并不相同;而且TWI总线引入了状奁寄存器,使得TWI总线在操作和使用上比I2C总线更为灵活。

      2、添加节点

      添加到 &twi2 下

      light-sensor@23 {
      			compatible = "gy,bh1750";
      			reg = <0x23>;
      	};
      

      如图所示:

      0bf2a21a51884a33bbc42096c427b3bd.jpg

      编译烧录后在以下目录可以找得到:

      # cd /sys/firmware/devicetree/base/soc@3000000/twi@2502800/
      
      # ls
      #address-cells   compatible       interrupts       pinctrl-names
      #size-cells      ctp@14           light-sensor@23  reg
      clock-frequency  device_type      name             resets
      clock-names      dma-names        pinctrl-0        status
      clocks           dmas             pinctrl-1
      #
      

      3、编写驱动

      #include <linux/ide.h>
      #include <linux/module.h>
      #include <linux/i2c.h>
      
      struct class *class;    /* 类 		*/
      int major;              /* 主设备号 */
      struct i2c_client *gy_sensor_client;
      
      // 构造i2c_msg通过这个client调用i2c_tansfer来读写
      static int gy_sensor_write_reg(unsigned char addr)
      {
          int ret = -1;
          struct i2c_msg msgs;
      
          printk("gy_sensor_client -> addr=%d\n", gy_sensor_client->addr);
          msgs.addr = gy_sensor_client->addr; //   GY302_ADDR,直接封装于i2c_msg
          msgs.buf = &addr;
          msgs.len = 1;   //长度1 byte
          msgs.flags = 0; //表示写
      
          ret = i2c_transfer(gy_sensor_client->adapter, &msgs, 1); 
          //这里都封装好了,本来根据i2c协议写数据需要先写入器件写地址,然后才能读
          if (ret < 0)
          {
              printk("i2c_transfer write err\n");
              return -1;
          }
          return 0;
      }
      static int gy_sensor_read_reg(unsigned char *buf)
      {
          int ret = -1;
          struct i2c_msg msg;
          msg.addr = gy_sensor_client->addr; // GY30_ADDR
          msg.buf = buf;
          msg.len = 2;                                            //长度1 byte
          msg.flags = I2C_M_RD;                                   //表示读
          ret = i2c_transfer(gy_sensor_client->adapter, &msg, 1); //这里都封装好了,本来根据i2c协议读数据需要先写入读地址,然后才能读
          if (ret < 0)
          {
              printk("i2c_transfer write err\n");
              return -1;
          }
          return 0;
      }
      
      // 初始化光线传感器
      int gy_sensor_open(struct inode *inode, struct file *file)
      {
          printk("open gy_sensor\n");
          gy_sensor_write_reg(0x01); // power up
          gy_sensor_write_reg(0x11);
          return 0;
      }
      
      // 读出传感器的两个字节
      static ssize_t gy_sensor_read(struct file *file, char __user *buf, size_t count, loff_t *off)
      {
          unsigned char addr = 0, data[2];
          gy_sensor_read_reg(data);
          copy_to_user(buf, data, 2);
          return 1;
      }
      
      /* bh1750 操作函数 */
      static const struct file_operations gy_sensor_fops = {
          .owner = THIS_MODULE,
          .open = gy_sensor_open, 
          .read = gy_sensor_read, 
      };
      
      /* 构造一个platform_driver,
      其中的of_match_table字段需要与 light-sensor@23 节点的compatible属性值一致,
      当匹配时则调用platform_driver的probe函数 */
      static const struct of_device_id ids[] =
      {
          {.compatible = "gy,bh1750"},
          {  }
      };
      
      // 在i2c_driver的probe函数中得到在总线驱动程序中解析得到的i2c_client,
      // 并为该光线传感器注册一个字符设备
      static int gy_sensor_probe(struct i2c_client *client,
                                 const struct i2c_device_id *id)
      {
          gy_sensor_client = client;
      
          printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
          major = register_chrdev(0, "gy_sensor", &gy_sensor_fops);
          class = class_create(THIS_MODULE, "gy_sensor");
          device_create(class, NULL, MKDEV(major, 0), NULL, "gy_sensor"); /* /dev/gy_sensor */
          return 0;
      }
      
      // 在platform_driver的remove函数中,注销该字符设备
      static int gy_sensor_remove(struct i2c_client *client)
      {
          device_destroy(class, MKDEV(major, 0));
          class_destroy(class);
          unregister_chrdev(major, "gy_sensor");
      
          return 0;
      }
      
      /* 分配/设置i2c_driver */
      static struct i2c_driver gy_sensor_driver = {
          .driver = {
              .name = "bh1750",
              .owner = THIS_MODULE,
              .of_match_table = ids,
          },
          .probe = gy_sensor_probe,
          .remove = gy_sensor_remove,
      };
      
      /*
       * @description	: 驱动入口函数
       */
      static int __init bh1750_init(void)
      {
          int ret = 0;
      
          ret = i2c_add_driver(&gy_sensor_driver);
          return ret;
      }
      
      /*
       * @description	: 驱动出口函数
       */
      static void __exit bh1750_exit(void)
      {
          i2c_del_driver(&gy_sensor_driver);
      }
      
      /* module_i2c_driver(bh1750_driver) */
      module_init(bh1750_init);
      module_exit(bh1750_exit);
      MODULE_LICENSE("GPL");
      MODULE_AUTHOR("zhu");
      

      4、编写测试程序

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>
       
      int main(int argc, char **argv)
      {
      	int fd;
      	char val;
      	unsigned char buf[3];
      	float flight;
      	fd = open("/dev/gy_sensor", O_RDWR);
      	if (fd < 0)
      	{
      		printf("can't open /dev/gy_sensor\n");
      		return -1;
      	}
       
      	usleep(200000);
      	while(1)
      		{
      	     if(read(fd,&buf,3)){
      	         flight=(buf[0]*256+buf[1])*0.5/1.2;
      	         printf("light: %6.2flx\r\n",flight);
      	     }
      	     else{
      	         printf("read err!\r\n");
      	     }
      	    sleep(4);
      	}
       
      	return 0;
      }
      

      5、测试

      加载驱动

      # insmod iic_gy302_dts.ko
      [   62.979905] iic_gy302_dts: loading out-of-tree module taints kernel.
      [   62.988058] /disk/vsCode/09_iic_gy302_dts/iic_gy302_dts.c gy_sensor_probe 120
      
      
      # lsmod
      Module                  Size  Used by    Tainted: G
      iic_gy302_dts          16384  0
      sunxi_ce               57344  0
      

      采集数据

      # ./iic_gy302_dts_test
      [  164.872116] open gy_sensor
      [  164.875291] gy_sensor_client -> addr=35
      [  164.879870] gy_sensor_client -> addr=35
      light:  46.67lx
      light:  46.25lx
      light:  40.42lx
      light:  61.67lx
      light:  65.42lx
      light: 2098.33lx
      light: 4914.17lx
      light: 17047.50lx
      light:  40.83lx
      light:  40.42lx
      

      测试完成。

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

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

      👍 👍 👍

      发布在 公告
      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
    • 【全志T113-S3_100ask】3-自动烧录系统脚本

      背景

      在Ubuntu下进行了镜像img的制作,需要向sd卡进行镜像的烧录,但是过程繁琐。

      • 一是将带系统的sd卡插进电脑,因为存在多个分区,一次性弹出多个窗口。
        e46e38330b614a9ba67f330d24fc5fd6.png

      • 二是需要将img移动到window下,然后通过 Win32DiskImager.exe 进行烧写。

      • 三是在烧录前经常提示拒绝访问。

      8f4ed06a4bdb40169083f383cd9e2f58.png

      我通常的解决办法是到磁盘管理器将sd卡复原
      906528d58b9641ca819d33cb12a91f0d.png
      但是这数量有点多啊,每次烧录都复原太麻烦了吧。
      官方提供的 PhoenixCard.exe 有恢复卡的选项,但是每次都要点击两次才能完全恢复。
      b2967e2b224b4f65a679e390411e7a27.png

      • 四是烧写完还会给我打开若干个窗口。。。。。

      总上所述,既然镜像系统在linux下,为什么不通过Ubuntu向sd卡烧录系统呢?于是研究了linux下的dd命令。

      编写烧写脚本

      1、查看U盘挂载在哪

      root@znh-ubuntu:~# fdisk -l
      ......
      Disk /dev/sdc:29.7 GiB,31914983424 字节,62333952 个扇区
      单元:扇区 / 1 * 512 = 512 字节
      扇区大小(逻辑/物理):512 字节 / 512 字节
      I/O 大小(最小/最佳):512 字节 / 512 字节
      磁盘标签类型:gpt
      磁盘标识符:EAEF2A25-B105-4441-BF9F-A904F3B16E16
      
      设备         起点    末尾   扇区  大小 类型
      /dev/sdc1   35392   39487   4096    2M Linux 文件系统
      /dev/sdc2   39488   39743    256  128K Linux 文件系统
      /dev/sdc3   39744   39999    256  128K Linux 文件系统
      /dev/sdc4   40000  105535  65536   32M Linux 文件系统
      /dev/sdc5  105536  629823 524288  256M Linux 文件系统
      /dev/sdc6  629824 1154111 524288  256M Linux 文件系统
      

      结论:u盘挂载在 /dev/sdc下

      2、格式化前先取消挂载

      sudo umount /dev/sdc*
      

      3、格式化(合并)分区

      sudo mkfs.vfat /dev/sdc -I
      
      

      4、烧写系统
      替换自己的 img 路径

      sudo dd if=/disk/buildroot-100ask_t113-pro/buildroot/output/images/100ask-t113-pro_sdcard.img of=/dev/sdc bs=4M status=progress
      

      一键脚本

      writeImage.sh

      #/bin/sh
      echo "执行一键烧写系统脚本"
      
      echo "取消分区挂载"
      sudo umount /dev/sdc*
      
      echo "格式化分区"
      sudo mkfs.vfat /dev/sdc -I
      
      echo "烧写系统"
      echo "path = /disk/buildroot-100ask_t113-pro/buildroot/output/images/100ask-t113-pro_sdcard.img"
      sudo dd if=/disk/buildroot-100ask_t113-pro/buildroot/output/images/100ask-t113-pro_sdcard.img of=/dev/sdc bs=4M status=progress
      
      echo "结束烧录"
      

      效果:

      root@znh-ubuntu:~# ./writeImage.sh
      执行一键烧写系统脚本
      取消分区挂载
      umount: /dev/sdc: not mounted.
      umount: /dev/sdc1: not mounted.
      umount: /dev/sdc2: not mounted.
      umount: /dev/sdc3: not mounted.
      umount: /dev/sdc4: not mounted.
      umount: /dev/sdc5: not mounted.
      umount: /dev/sdc6: not mounted.
      格式化分区
      mkfs.fat 4.1 (2017-01-24)
      attribute "partition" not found
      烧写系统
      path = /disk/buildroot-100ask_t113-pro/buildroot/output/images/100ask-t113-pro_sdcard.img
      553648128 bytes (554 MB, 528 MiB) copied, 1 s, 552 MB/s
      记录了140+1 的读入
      记录了140+1 的写出
      590925824 bytes (591 MB, 564 MiB) copied, 68.5244 s, 8.6 MB/s
      结束烧录
      root@znh-ubuntu:~#
      

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

      发布在 其它全志芯片讨论区
      Y
      giao
    • 【全志T113-S3_100ask】2-编写第一个驱动

      (1)开发环境

      windows开发环境:VsCode
      linux 开发环境:Ubuntu 18.04 环境参考

      1、指定交叉编译

      在buildroot 目录下发现两个 arm-linux-gnueabi-gcc

      root@znh-ubuntu:/disk/buildroot-100ask_t113-pro/buildroot# find ./* -name "*gnueabi-gcc"
      ./output/host/opt/ext-toolchain/bin/arm-linux-gnueabi-gcc
      ./output/host/bin/arm-linux-gnueabi-gcc
      

      但 ./output/host/bin/arm-linux-gnueabi-gcc 是链接过去的

      c7a46f0a61d24d149466e43da584b784.png

      ./output/host/opt/ext-toolchain/bin/arm-linux-gnueabi-gcc 是原始的

      f577b95a46d9419dbbb2dc632ba6c0f1.png

      在这里我使用链接后的gcc
      加载环境变量:

      export PATH=$PATH:/disk/buildroot-100ask_t113-pro/buildroot/output/host/bin
      export ARCH=arm
      export CROSS_COMPILE=arm-linux-gnueabi-
      
      root@znh-ubuntu:~# export PATH=$PATH:/disk/buildroot-100ask_t113-pro/buildroot/output/host/bin
      root@znh-ubuntu:~# export ARCH=arm
      root@znh-ubuntu:~# export CROSS_COMPILE=arm-linux-gnueabi-
      root@znh-ubuntu:~#
      root@znh-ubuntu:~# arm-linux-gnueabi-gcc -v
      使用内建 specs。
      COLLECT_GCC=arm-linux-gnueabi-gcc
      COLLECT_LTO_WRAPPER=/disk/t113GitHub/eLinuxCore_100ask-t113-pro/toolchain/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabi/bin/../libexec/gcc/arm-linux-gnueabi/7.2.1/lto-wrapper
      目标:arm-linux-gnueabi
      配置为:'/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/arm-linux-gnueabi/snapshots/gcc.git~linaro-7.2-2017.11/configure' SHELL=/bin/bash --with-mpc=/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/arm-linux-gnueabi/_build/builds/destdir/x86_64-unknown-linux-gnu --with-mpfr=/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/arm-linux-gnueabi/_build/builds/destdir/x86_64-unknown-linux-gnu --with-gmp=/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/arm-linux-gnueabi/_build/builds/destdir/x86_64-unknown-linux-gnu --with-gnu-as --with-gnu-ld --disable-libmudflap --enable-lto --enable-shared --without-included-gettext --enable-nls --disable-sjlj-exceptions --enable-gnu-unique-object --enable-linker-build-id --disable-libstdcxx-pch --enable-c99 --enable-clocale=gnu --enable-libstdcxx-debug --enable-long-long --with-cloog=no --with-ppl=no --with-isl=no --disable-multilib --with-float=soft --with-mode=thumb --with-tune=cortex-a9 --with-arch=armv7-a --enable-threads=posix --enable-multiarch --enable-libstdcxx-time=yes --enable-gnu-indirect-function --with-build-sysroot=/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/arm-linux-gnueabi/_build/sysroots/arm-linux-gnueabi --with-sysroot=/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/arm-linux-gnueabi/_build/builds/destdir/x86_64-unknown-linux-gnu/arm-linux-gnueabi/libc --enable-checking=release --disable-bootstrap --enable-languages=c,c++,fortran,lto --build=x86_64-unknown-linux-gnu --host=x86_64-unknown-linux-gnu --target=arm-linux-gnueabi --prefix=/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/arm-linux-gnueabi/_build/builds/destdir/x86_64-unknown-linux-gnu
      线程模型:posix
      gcc 版本 7.2.1 20171011 (Linaro GCC 7.2-2017.11)
      

      不想每次否加载可以写在自启动脚本

      vim ~/.bashrc
      

      f71d9f87bd1542bdb05759c4ee985910.png

      ##(2)编写驱动

      1、编写 helloword驱动 hello_drv.c

      #include <linux/module.h>
      
      #include <linux/fs.h>
      #include <linux/errno.h>
      #include <linux/miscdevice.h>
      #include <linux/kernel.h>
      #include <linux/major.h>
      #include <linux/mutex.h>
      #include <linux/proc_fs.h>
      #include <linux/seq_file.h>
      #include <linux/stat.h>
      #include <linux/init.h>
      #include <linux/device.h>
      #include <linux/tty.h>
      #include <linux/kmod.h>
      #include <linux/gfp.h>
      
      /* 1. 确定主设备号                                                                 */
      static int major = 0;
      static char kernel_buf[1024];
      static struct class *hello_class;
      
      
      #define MIN(a, b) (a < b ? a : b)
      
      /* 3. 实现对应的open/read/write等函数,填入file_operations结构体                   */
      static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
      {
      	int err;
      	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      	err = copy_to_user(buf, kernel_buf, MIN(1024, size));
      	return MIN(1024, size);
      }
      
      static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
      {
      	int err;
      	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      	err = copy_from_user(kernel_buf, buf, MIN(1024, size));
      	return MIN(1024, size);
      }
      
      static int hello_drv_open (struct inode *node, struct file *file)
      {
      	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      	return 0;
      }
      
      static int hello_drv_close (struct inode *node, struct file *file)
      {
      	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      	return 0;
      }
      
      /* 2. 定义自己的file_operations结构体                                              */
      static struct file_operations hello_drv = {
      	.owner	 = THIS_MODULE,
      	.open    = hello_drv_open,
      	.read    = hello_drv_read,
      	.write   = hello_drv_write,
      	.release = hello_drv_close,
      };
      
      /* 4. 把file_operations结构体告诉内核:注册驱动程序                                */
      /* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
      static int __init hello_init(void)
      {
      	int err;
      	
      	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      	major = register_chrdev(0, "hello", &hello_drv);  /* /dev/hello */
      
      
      	hello_class = class_create(THIS_MODULE, "hello_class");
      	err = PTR_ERR(hello_class);
      	if (IS_ERR(hello_class)) {
      		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      		unregister_chrdev(major, "hello");
      		return -1;
      	}
      	
      	device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */
      	
      	return 0;
      }
      
      /* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数           */
      static void __exit hello_exit(void)
      {
      	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      	device_destroy(hello_class, MKDEV(major, 0));
      	class_destroy(hello_class);
      	unregister_chrdev(major, "hello");
      }
      
      
      /* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
      
      module_init(hello_init);
      module_exit(hello_exit);
      
      MODULE_LICENSE("GPL");
      

      2、编写测试驱动文件 hello_drv_test.c

      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>
      #include <unistd.h>
      #include <stdio.h>
      #include <string.h>
      
      /*
       * ./hello_drv_test -w abc
       * ./hello_drv_test -r
       */
      int main(int argc, char **argv)
      {
      	int fd;
      	char buf[1024];
      	int len;
      	
      	/* 1. 判断参数 */
      	if (argc < 2) 
      	{
      		printf("Usage: %s -w <string>\n", argv[0]);
      		printf("       %s -r\n", argv[0]);
      		return -1;
      	}
      
      	/* 2. 打开文件 */
      	fd = open("/dev/hello", O_RDWR);
      	if (fd == -1)
      	{
      		printf("can not open file /dev/hello\n");
      		return -1;
      	}
      
      	/* 3. 写文件或读文件 */
      	if ((0 == strcmp(argv[1], "-w")) && (argc == 3))
      	{
      		len = strlen(argv[2]) + 1;
      		len = len < 1024 ? len : 1024;
      		write(fd, argv[2], len);
      	}
      	else
      	{
      		len = read(fd, buf, 1024);		
      		buf[1023] = '\0';
      		printf("APP read : %s\n", buf);
      	}
      	
      	close(fd);
      	
      	return 0;
      }
      

      3、编写Makefile

      # 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
      # 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
      # 2.1 ARCH,          比如: export ARCH=arm64
      # 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
      # 2.3 PATH,          比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin 
      # 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
      #       请参考各开发板的高级用户使用手册
      
      KERN_DIR = /disk/buildroot-100ask_t113-pro/buildroot/output/build/linux-d96275805a67d54998123d36e59108cb1ed52ad5
      
      all:
      	make -C $(KERN_DIR) M=`pwd` modules 
      	$(CROSS_COMPILE)gcc -o hello_drv_test hello_drv_test.c 
      
      clean:
      	make -C $(KERN_DIR) M=`pwd` modules clean
      	rm -rf modules.order
      	rm -f hello_drv_test
      
      obj-m	+= hello_drv.o
      

      关于 KERN_DIR ,本环境使用的是 buildroot ,通过GitHub把kernel下载下来的,源码在./buildroot-100ask_t113-pro/buildroot/dl/linux/git 下,但是该源码未经过编译,而上一节已经编译过 buildroot 生成镜像img了,那就是已经编译过了,但是指定该目录编译不了

      82c44d9bc6af4be29e232d1fe8f53cd3.png

      真正的编译目录在
      ./buildroot-100ask_t113-pro/buildroot/output/build/linux-d96275805a67d54998123d36e59108cb1ed52ad5
      (我不确实后面的字母数字是不是每个人一样)

      f98a38e3af8544d090c968382aa25756.png

      (3)测试

      将生成的 hello_drv.ko、hello_drv_test 放到开发板上
      在这里使用 tftp 下载。(TFTP的搭建参考:链接)
      但第一次使用系统没有连接网络(现在已经插入网线)

      # ifconfig
      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:6 errors:0 dropped:0 overruns:0 frame:0
                TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:1000
                RX bytes:603 (603.0 B)  TX bytes:603 (603.0 B)
      

      1、使用udhcpc 自动联网

      # udhcpc
      udhcpc: started, v1.35.0
      [ 3538.458305] libphy: 4500000.eth: probed
      [ 3538.462913] sunxi-gmac 4500000.eth eth0: eth0: Type(7) PHY ID 001cc816 at 0 IRQ poll (4500000.eth-0:00)
      udhcpc: broadcasting discover
      [ 3541.673890] sunxi-gmac 4500000.eth eth0: Link is Up - 100Mbps/Full - flow control off
      [ 3541.682714] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
      udhcpc: broadcasting discover
      udhcpc: broadcasting select for 192.168.3.45, server 192.168.3.1
      udhcpc: lease of 192.168.3.45 obtained from 192.168.3.1, lease time 604800
      deleting routers
      adding dns 192.168.3.1
      

      2、通过 tftp 下载资源

      # tftp -g -r hello_drv.ko 192.168.3.44
      # tftp -g -r hello_drv_test 192.168.3.44
      #
      # ls
      hello_drv.ko    hello_drv_test
      

      3、测试驱动

      (1)加载驱动

      #  insmod hello_drv.ko
      [ 3860.564181] hello_drv: loading out-of-tree module taints kernel.
      [ 3860.571552] /disk/vsCode/01_hello/hello_drv.c hello_init line 70
      
      
      
      (2)查看驱动是否加载
      # ls /dev/hello*
      /dev/hello
      # lsmod
      Module                  Size  Used by    Tainted: G
      hello_drv              16384  0
      
      (3)添加权限
      # chmod 777 ./hello_drv_test
      
      
      (4)向驱动写入数据
      # ./hello_drv_test  -w abc
      [ 3906.061995] /disk/vsCode/01_hello/hello_drv.c hello_drv_open line 45
      [ 3906.069274] /disk/vsCode/01_hello/hello_drv.c hello_drv_write line 38
      [ 3906.076579] /disk/vsCode/01_hello/hello_drv.c hello_drv_close line 51
      
      (5)读取驱动数据
      # ./hello_drv_test  -r
      [ 3913.268282] /disk/vsCode/01_hello/hello_drv.c hello_drv_open line 45
      [ 3913.275535] /disk/vsCode/01_hello/hello_drv.c hello_drv_read line 30
      APP read : abc
      [ 3913.283024] /disk/vsCode/01_hello/hello_drv.c hello_drv_close line 51
      
      (6)卸载驱动
      # rmmod hello_drv
      [ 4304.419170] /disk/vsCode/01_hello/hello_drv.c hello_exit line 90
      # lsmod
      Module                  Size  Used by    Tainted: G
      sunxi_ce               57344  0
      
      

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

      发布在 其它全志芯片讨论区
      Y
      giao
    • 【全志T113-S3_100ask】1-编译buildroot初体验

      (1)100ask_T113-PRO 简介

      接触了一块新的开发板:

      硬件资源配置如下:

      cd21cf0fd30140fda46960e847e4b3d8.png DFA578CD-CDD9-4869-88D3-B9BF65BF3EF3.png

      GitHub地址:
      https://github.com/DongshanPI/buildroot_100ask_t113-pro

      (2)开发环境

      • 开发板 :淘宝
      • 镜像:Ubuntu 18.04 (官方推荐)
      • SD卡:8G以上 (烧写工具:Win32DiskImager.exe)
      • 为更好地开发,建议安装以下linux环境:

      sudo apt-get install -y sed make binutils build-essential gcc g++ bash patch gzip bzip2 perl tar cpio unzip rsync file bc wget python cvs git mercurial rsync subversion android-tools-mkbootimg vim libssl-dev android-tools-fastboot

      sudo apt-get -y install build-essential subversion git-core libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip lib32z1 lib32z1-dev lib32stdc++6 libstdc++6 libncurses-dev u-boot-tools

      root@znh-ubuntu:~# sudo apt-get install -y  sed make binutils build-essential  gcc g++ bash patch gzip bzip2 perl  tar cpio unzip rsync file  bc wget python  cvs git mercurial rsync  subversion android-tools-mkbootimg vim  libssl-dev  android-tools-fastboot
      正在读取软件包列表... 完成
      正在分析软件包的依赖关系树
      正在读取状态信息... 完成
      bc 已经是最新版 (1.07.1-2)。
      build-essential 已经是最新版 (12.4ubuntu1)。
      make 已经是最新版 (4.1-9.1ubuntu1)。
      python 已经是最新版 (2.7.15~rc1-1)。
      sed 已经是最新版 (4.4-2)。
      cvs 已经是最新版 (2:1.12.13+real-26)。
      bash 已经是最新版 (4.4.18-2ubuntu1.3)。
      binutils 已经是最新版 (2.30-21ubuntu1~18.04.7)。
      bzip2 已经是最新版 (1.0.6-8.1ubuntu0.2)。
      cpio 已经是最新版 (2.12+dfsg-6ubuntu0.18.04.4)。
      file 已经是最新版 (1:5.32-2ubuntu0.4)。
      g++ 已经是最新版 (4:7.4.0-1ubuntu2.3)。
      gcc 已经是最新版 (4:7.4.0-1ubuntu2.3)。
      git 已经是最新版 (1:2.17.1-1ubuntu0.12)。
      gzip 已经是最新版 (1.6-5ubuntu1.2)。
      libssl-dev 已经是最新版 (1.1.1-1ubuntu2.1~18.04.20)。
      patch 已经是最新版 (2.7.6-2ubuntu1.1)。
      perl 已经是最新版 (5.26.1-6ubuntu0.5)。
      rsync 已经是最新版 (3.1.2-2.1ubuntu1.4)。
      tar 已经是最新版 (1.29b-2ubuntu0.3)。
      unzip 已经是最新版 (6.0-21ubuntu1.1)。
      vim 已经是最新版 (2:8.0.1453-1ubuntu1.8)。
      wget 已经是最新版 (1.19.4-1ubuntu2.2)。
      android-tools-fastboot 已经是最新版 (1:8.1.0+r23-5~18.04)。
      android-tools-mkbootimg 已经是最新版 (1:8.1.0+r23-5~18.04)。
      mercurial 已经是最新版 (4.5.3-1ubuntu2.2)。
      subversion 已经是最新版 (1.9.7-4ubuntu1.1)。
      升级了 0 个软件包,新安装了 0 个软件包,要卸载 0 个软件包,有 6 个软件包未被升级。
      
      root@znh-ubuntu:~# sudo apt-get -y install build-essential subversion git-core libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip lib32z1 lib32z1-dev lib32stdc++6 libstdc++6 libncurses-dev   u-boot-tools
      正在读取软件包列表... 完成
      正在分析软件包的依赖关系树
      正在读取状态信息... 完成
      注意,选中 'git' 而非 'git-core'
      注意,选中 'libncurses5-dev' 而非 'libncurses-dev'
      build-essential 已经是最新版 (12.4ubuntu1)。
      bzr 已经是最新版 (2.7.0+bzr6622-10)。
      flex 已经是最新版 (2.6.4-6)。
      gawk 已经是最新版 (1:4.1.4+dfsg-1build1)。
      libxml-parser-perl 已经是最新版 (2.44-2build3)。
      cvs 已经是最新版 (2:1.12.13+real-26)。
      quilt 已经是最新版 (0.63-8.2)。
      git 已经是最新版 (1:2.17.1-1ubuntu0.12)。
      lib32stdc++6 已经是最新版 (8.4.0-1ubuntu1~18.04)。
      lib32z1 已经是最新版 (1:1.2.11.dfsg-0ubuntu2.1)。
      lib32z1-dev 已经是最新版 (1:1.2.11.dfsg-0ubuntu2.1)。
      libncurses5-dev 已经是最新版 (6.1-1ubuntu1.18.04)。
      libssl-dev 已经是最新版 (1.1.1-1ubuntu2.1~18.04.20)。
      libstdc++6 已经是最新版 (8.4.0-1ubuntu1~18.04)。
      u-boot-tools 已经是最新版 (2020.10+dfsg-1ubuntu0~18.04.2)。
      unzip 已经是最新版 (6.0-21ubuntu1.1)。
      xsltproc 已经是最新版 (1.1.29-5ubuntu0.2)。
      zlib1g-dev 已经是最新版 (1:1.2.11.dfsg-0ubuntu2.1)。
      ecj 已经是最新版 (3.16.0-1~18.04)。
      mercurial 已经是最新版 (4.5.3-1ubuntu2.2)。
      subversion 已经是最新版 (1.9.7-4ubuntu1.1)。
      升级了 0 个软件包,新安装了 0 个软件包,要卸载 0 个软件包,有 6 个软件包未被升级。
      root@znh-ubuntu:~#
      
      • SDK源码(以下为官方教程)2022-7-20:
        默认源码都存放在github仓库内,请使用如下命令获取
      book@100ask:~$ git clone  https://github.com/DongshanPI/buildroot-100ask_t113-pro
      book@100ask:~$ cd buildroot-100ask_t113-pro/
      book@100ask:~/buildroot-100ask_t113-pro$ git submodule update --init --recursive
      book@100ask:~/buildroot-100ask_t113-pro$ git submodule update --recursive --remote
      book@100ask:~/buildroot-100ask_t113-pro$ cd  buildroot/
      book@100ask:~/buildroot-100ask_t113-pro/buildroot$ git submodule update --init --recursive
      

      对于国内无法访问github的同学,可以使用国内备用gitee站点, 如下命令。

      book@100ask:~$ git clone  https://gitee.com/weidongshan/buildroot-100ask_t113-pro
      book@100ask:~$ cd buildroot-100ask_t113-pro/
      book@100ask:~/buildroot-100ask_t113-pro$ git submodule update --init --recursive
      book@100ask:~/buildroot-100ask_t113-pro$ git submodule update --recursive --remote
      book@100ask:~/buildroot-100ask_t113-pro$ cd  buildroot/
      book@100ask:~/buildroot-100ask_t113-pro/buildroot$ git submodule update --init --recursive
      

      (3)最小系统编译烧写

      1、sdcard

      1.1 编译sdcard 最小系统镜像

      book@100ask:~/buildroot-100ask_t113-pro/buildroot$ make  BR2_EXTERNAL="../br2t113pro ../br2lvgl "  100ask_t113-pro_sdcard_core_defconfig
      book@100ask:~/buildroot-100ask_t113-pro/buildroot$ make  V=1
      

      编译完成:

      Creating regular file /disk/buildroot-100ask_t113-pro/buildroot/output/images/rootfs.ext2
      64-bit filesystem support is not enabled.  The larger fields afforded by this feature enable full-strength checksumming.  Pass -O 64bit to rectify.
      Creating filesystem with 262144 1k blocks and 65536 inodes
      Filesystem UUID: 2227dcad-9607-4996-8d36-e5870d09c83f
      Superblock backups stored on blocks:
              8193, 24577, 40961, 57345, 73729, 204801, 221185
      
      Allocating group tables: done
      Writing inode tables: done
      Creating journal (8192 blocks): done
      Copying files into the device: done
      Writing superblocks and filesystem accounting information: done
      
      rm -rf /disk/buildroot-100ask_t113-pro/buildroot/output/build/buildroot-fs/ext2/target
      ln -sf rootfs.ext2 /disk/buildroot-100ask_t113-pro/buildroot/output/images/rootfs.ext4
      ln -snf /disk/buildroot-100ask_t113-pro/buildroot/output/host/arm-buildroot-linux-gnueabi/sysroot /disk/buildroot-100ask_t113-pro/buildroot/output/staging
      mkdir -p /disk/buildroot-100ask_t113-pro/buildroot/output/images
      >>>   Executing post-image script support/scripts/genimage.sh
      INFO: cmd: "mkdir -p "/disk/buildroot-100ask_t113-pro/buildroot/output/build/genimage.tmp"" (stderr):
      INFO: cmd: "rm -rf "/disk/buildroot-100ask_t113-pro/buildroot/output/build/genimage.tmp"/*" (stderr):
      INFO: cmd: "mkdir -p "/disk/buildroot-100ask_t113-pro/buildroot/output/build/genimage.tmp"" (stderr):
      INFO: cmd: "cp -a "/tmp/tmp.TzeMUTGJbs" "/disk/buildroot-100ask_t113-pro/buildroot/output/build/genimage.tmp/root"" (stderr):
      INFO: cmd: "find '/disk/buildroot-100ask_t113-pro/buildroot/output/build/genimage.tmp/root' -depth -type d -printf '%P\0' | xargs -0 -I {} touch -r '/tmp/tmp.                      TzeMUTGJbs/{}' '/disk/buildroot-100ask_t113-pro/buildroot/output/build/genimage.tmp/root/{}'" (stderr):
      INFO: cmd: "mkdir -p "/disk/buildroot-100ask_t113-pro/buildroot/output/images"" (stderr):
      INFO: vfat(boot.vfat): cmd: "dd if=/dev/zero of="/disk/buildroot-100ask_t113-pro/buildroot/output/images/boot.vfat" seek=33554432 count=0 bs=1 2>/dev/null" (s                      tderr):
      INFO: vfat(boot.vfat): cmd: "mkdosfs   '/disk/buildroot-100ask_t113-pro/buildroot/output/images/boot.vfat'" (stderr):
      INFO: vfat(boot.vfat): adding file 'boot.img' as 'boot.img' ...
      INFO: vfat(boot.vfat): cmd: "MTOOLS_SKIP_CHECK=1 mcopy -sp -i '/disk/buildroot-100ask_t113-pro/buildroot/output/images/boot.vfat' '/disk/buildroot-100ask_t113                      -pro/buildroot/output/images/boot.img' '::'" (stderr):
      INFO: vfat(boot.vfat): adding file 'zImage' as 'zImage' ...
      INFO: vfat(boot.vfat): cmd: "MTOOLS_SKIP_CHECK=1 mcopy -sp -i '/disk/buildroot-100ask_t113-pro/buildroot/output/images/boot.vfat' '/disk/buildroot-100ask_t113                      -pro/buildroot/output/images/zImage' '::'" (stderr):
      INFO: vfat(boot.vfat): adding file 'sun8iw20p1-t113-100ask-t113-pro.dtb' as 'sun8iw20p1-t113-100ask-t113-pro.dtb' ...
      INFO: vfat(boot.vfat): cmd: "MTOOLS_SKIP_CHECK=1 mcopy -sp -i '/disk/buildroot-100ask_t113-pro/buildroot/output/images/boot.vfat' '/disk/buildroot-100ask_t113                      -pro/buildroot/output/images/sun8iw20p1-t113-100ask-t113-pro.dtb' '::'" (stderr):
      INFO: vfat(boot.vfat): adding file 'dsp0.fex' as 'dsp0.fex' ...
      INFO: vfat(boot.vfat): cmd: "MTOOLS_SKIP_CHECK=1 mcopy -sp -i '/disk/buildroot-100ask_t113-pro/buildroot/output/images/boot.vfat' '/disk/buildroot-100ask_t113                      -pro/buildroot/output/images/dsp0.fex' '::'" (stderr):
      INFO: hdimage(100ask-t113-pro_sdcard.img): adding partition 'boot0' from 'boot0_sdcard.fex' ...
      INFO: hdimage(100ask-t113-pro_sdcard.img): adding partition 'boot-packages' from 'boot_package.fex' ...
      INFO: hdimage(100ask-t113-pro_sdcard.img): adding partition 'boot-resource' (in MBR) from 'boot-resource.fex' ...
      INFO: hdimage(100ask-t113-pro_sdcard.img): adding partition 'env' (in MBR) from 'env.fex' ...
      INFO: hdimage(100ask-t113-pro_sdcard.img): adding partition 'env-redund' (in MBR) from 'env.fex' ...
      INFO: hdimage(100ask-t113-pro_sdcard.img): adding partition 'boot' (in MBR) from 'boot.vfat' ...
      INFO: hdimage(100ask-t113-pro_sdcard.img): adding partition 'rootfs' (in MBR) from 'rootfs.ext4' ...
      INFO: hdimage(100ask-t113-pro_sdcard.img): adding partition 'share' (in MBR) ...
      INFO: hdimage(100ask-t113-pro_sdcard.img): adding partition '[MBR]' ...
      INFO: hdimage(100ask-t113-pro_sdcard.img): adding partition '[GPT header]' ...
      INFO: hdimage(100ask-t113-pro_sdcard.img): adding partition '[GPT array]' ...
      INFO: hdimage(100ask-t113-pro_sdcard.img): adding partition '[GPT backup]' ...
      INFO: hdimage(100ask-t113-pro_sdcard.img): writing GPT
      INFO: hdimage(100ask-t113-pro_sdcard.img): writing hybrid MBR
      root@znh-ubuntu:/disk/buildroot-100ask_t113-pro/buildroot#
      

      1.2 烧写sdcard 最小系统镜像
      编译完成后会在 output/images目录下输出 sdcard.img(100ask-t113-pro_sdcard.img) 文件,将文件拷贝到Windows系统下使用 wind32diskimage烧写,或者使用dd if 烧录到tf卡内, 之后插到开发板上,即可启动。

      2、spi nand

      2.1 编译 spi nand最小系统镜像

      book@100ask:~/buildroot-100ask_t113-pro/buildroot$ make   BR2_EXTERNAL="../br2t113pro  ../br2lvgl"  100ask_t113-pro_spinand_core_defconfig
      book@100ask:~/buildroot-100ask_t113-pro/buildroot$ make  V=1
      

      2.2 烧写spi nand最小系统镜像

      编译完成后会在 output/images目录下输出 buildroot_linux_nand_uart3.img 文件,将文件拷贝到Windows系统下使用 使用 全志官方的 AllwinnertechPhoeniSuit 进行烧写

      (4)启动开发板

      [153]HELLO! BOOT0 is starting!
      [156]BOOT0 commit : 2c94b33
      [159]set pll start
      [165]periph0 has been enabled
      [168]set pll end
      [170][pmu]: bus read error
      [172]board init ok
      
      ......
      
      [245]sdcard 0 line count 4
      [248][mmc]: mmc driver ver 2021-03-22 20:20
      [257][mmc]: Wrong media type 0x0
      [260][mmc]: ***Try SD card 0***
      [279][mmc]: HSSDR52/SDR25 4 bit
      [282][mmc]: 50000000 Hz
      [285][mmc]: 30436 MB
      [286][mmc]: ***SD/MMC 0 init OK!!!***
      [382]Loading boot-pkg Succeed(index=0).
      [385]Entry_name        = u-boot
      [393]Entry_name        = optee
      [397]Entry_name        = logo
      [399]Entry_name        = dtb
      [402]mmc not para
      [404]Jump to second Boot.
      M/TC: OP-TEE version: 6aef7bb2-dirty (gcc version 5.3.1 20160412 (Linaro GCC 5.3-2016.05)) #1 F
      
      
      U-Boot 2018.05 (Jun 30 2022 - 06:55:01 +0000) Allwinner Technology
      
      [00.459]CPU:   Allwinner Family
      [00.462]Model: sun8iw20
      [00.465]DRAM:  128 MiB
      [00.468]Relocation Offset is: 04ebd000
      [00.495]secure enable bit: 0
      [00.498]smc_tee_inform_fdt failed with: -65526[00.502]CPU=1008 MHz,PLL6=600 Mhz,AHB=200 Mhz, AP
      [00.508]gic: sec monitor mode
      
       ......
       
       261240 bytes read in 13 ms (19.2 MiB/s)
      4810752 bytes read in 202 ms (22.7 MiB/s)
      [06.431]no vendor_boot partition is found
      Android's image name: sun8iw20p1
      [06.443]Starting kernel ...
      
      [06.446][mmc]: MMC Device 2 not found
      [06.449][mmc]: mmc 2 not find, so not exit
      
      ......
      

      账号为 root

      如果启动出现(后期可能会修复):

      [   21.044877] configfs-gadget 4100000.udc-controller: failed to start g1: -19
      Initializing random number generator: /etc/init.d/S11adb_server: line 14: echo: write error: No
      FAIL
      Starting network: OK
      Starting swupdate: OK
      
      Welcome to T113 Pro
      t113 login: 
      [   24.163699] configfs-gadget 4100000.udc-controller: failed to start g1: -19
      /etc/init.d/S11adb_server: line 14: echo: write error: No such device
      

      开机后可将adb服务移除:

      rm  /etc/init.d/S11adb_server
      

      或在 config 加上adb配置

      BR2_PACKAGE_ANDROID_TOOLS=y
      BR2_PACKAGE_ANDROID_TOOLS_ADB=y
      BR2_PACKAGE_ANDROID_TOOLS_ADBD=y
      

      转载自:https://blog.csdn.net/qq_46079439/article/details/125896105?spm=1001.2014.3001.5502

      发布在 其它全志芯片讨论区
      Y
      giao
    • H618?Android 12 电视盒?

      目前全志 H618 处理器已陆续在几款运行 Android 12 的电视盒中使用了,例如:T95Z Plus 和 T95 Max 等设备就可以播放 6K/4K VP9 和 H.265 视频。

      全志 H618 配备了四核 Cortex-A53 处理器、Arm Mali-G31 MP2 GPU、支持 6K 视频,全志 H618 看起来与全志 H616 处理器完全相同,比较不同的就是它可以运行更新的 Android 12 操作系统。

      Allwinner-H618-TV-Box-Android-12.webp

      全志 H618 公开信息并不多,看一下 T95Z Plus 的规格

      C7A27786-D800-4a24-B75C-CC8ABA59FB82.png

      除了全志 H618 可以支持 Android 12 之外,全志 H618 和 H616 至少还有一个区别,就像 linux-sunxi wiki 所述的,全志 H616 缺少全志 H6处理器上的 PCIe 和 USB 3.0 接口。 对了,我看过全志 H618 的数据表(抱歉,我不能分享出来),上面显示也没有 USB 3.0 或 PCIe 接口。而且其主要的区别似乎是更大的 1MB L2 缓存。他们的数据表还显示 WiFi+ 蓝牙就像通常一样,连接到了SDIO 3.0、UART 和 I2S。

      搭载全志 H618 处理器的 T95Z Plus Android 12 电视盒目前可以在aliexpress 或 Banggood上购买,价格是 39 至 54 美元不等,具体的价格要取决于用户需要的配置。

      发布在 H/F/TV Series
      Y
      giao
    • 回复: 【V853开发板试用】我做个RTSP推流demo吧

      @tevet https://bbs.aw-ol.com/topic/1844/ MPPPP

      发布在 V Series
      Y
      giao
    • 回复: 【Sipeed D1 Dock Pro】QT初体验

      @guozhaifa everything ok!😊

      发布在 MR Series
      Y
      giao
    • 回复: 【V853开发板试用】AI生成山水画,每一幅都是世间独一无二

      666🤙 我也去生成一幅玩

      发布在 V Series
      Y
      giao
    • 回复: 2022年7月版——在“哪吒”上跑AI 全志D1 ncnn框架移植笔记

      @xiaowenge 有提升的;

      2.2.2 的性能数据在这里:https://bbs.aw-ol.com/topic/705

      2.2.6和 2.2.2相比,各模型性能均有一定程度提升

      发布在 MR Series
      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
    • 【Sipeed D1 Dock Pro】QT初体验

      前提

      想要完成qt交叉编译的功能,会涉及到以下几个重要的组件

      • qmake和库文件
        qmake对于QT来讲是一个非常重要的工具,编译qt源码时会生成qmake,它对应的平台为qt程序工作的平台(如Windows),因此configure配置时,-platform选项实际上指的是qmake工作的平台。

      库文件包含了qt内置功能\函数的实现,在程序链接或运行时生效,-xplatform选项指的是库文件对应的平台(如开发板)。

      • 交叉编译工具链
        既用于编译目标程序需要用到的库文件,也编译实际项目中的代码文件。

      主要过程如下:

      • 准备工作

      在windows下编译QT,需要安装active perlhttps://www.perl.org/get.html和python,安装过程不在叙述,安装完成后需要将其可执行文件所在目录(一般为bin目录)加入到环境变量中。

      需要注意的是perl的目录比较绕,我的目录在用户目录下的AppData\Local\ActiveState\cache\bin,而且不是exe文件,而是bat脚本,最终执行perl.exe文件,因此添加脚本目录或者exe目录到环境变量都行。

      d662297074d31a26e0a53aac61aee65e.png

      在第二次编译时,提到需要安装msvc工具链和ruby。

      msvc可以使用visual studio installer安装编译器和Windows sdk,安装完成后使用msvc的环境能执行cl指令即可。

      d32336e58ca888c0f8261ff7ae9bfe36.png

      ruby下载安装即可。

      1a4e241302d4016d0cd0ba54fc5b851c.png

      下载交叉编译工具链,开发板工具链官方整理的非常好,直接在 https://occ.t-head.cn/community/download?id=4032826170687950848 页面下载然后解压即可,为了后续的流程简单一点,也建议将其bin目录加入到环境变量。

      f2427e7a30e8750d1eedc8d416a3b23e.png

      因为是在Windows下编译源码,因此还需要安装g++,这个很多软件都会带有g++工具链(如vs、cygwin64、qt等),这里就不再详述了,g++所在目录页需要加入到环境变量中。这是我用到的g++版本。

      5074df790bf098a7568cf9e353c5fd3c.png

      • QT源码下载
        直接在qt官网( https://www.qt.io/offline-installers ) 下载即可,Windows平台下载zip文件,下载完成之后解压。

      在第二次尝试编译时得知需要将解压后的flex.exe所在目录加入到环境变量,目录为压缩包下gnuwin32\bin。

      修改工具链位置由于我们的目标程序适用于开发板,因此这里的库必须使用开发板对应的交叉编译工具链来编译,qt源码中并没有预设该工具链,因此需要对现有的工具链文件做一定修改,办法如下:

      修改源码目录下qtbase\mkspecs\linux-aarch64-gnu-g++\qmake.conf文件,将其工具链更改为开发板对应的工具链。

      0c3f26ae3f56b493283da5e97b17b5f6.png

      修改这个文件是因为我们等会configure配置会用到-xplatform linux-aarch64-gnu-g++选项,该选项指向了这个文件,你也可以自己创建一个文件夹,按照模板填写qmake.conf文件也可以,只需要保证-xplatform能找到新建的 文件即可。

      • Windows下编译QT源码 - 1
        这部分是在51假日期间做的尝试,实际上方法不对,导致了在编译过程中出现很多问题,不过当时仅记录了一部分内容,在掉进编译的问题旋涡之后,就没有记录了。正确的编译方式请看《Windows下编译QT源码 - 2》章节。

      • 执行编译
        在源码文件夹顶层目录下,执行以下指令:

      configure.bat -release -static -opensource -nomake tests -nomake examples -no-opengl -skip qtvirtualkeyboard -platform win32-g++ -xplatform linux-aarch64-gnu-g++ -prefix D:\Qt\Qt5.12.10\5.12.10\xuantie_900_mingw_v2.2.5
      

      关于配置选项的说明,可以查看qtbase\config_help.txt文件,这里只简单介绍一下:

      C7D25657-6831-48d5-8C77-2724E518B0D9.png

      先尝试了qt 5.15.1版本(因为我本地的qt是该版本),编译过程中遇到的错误如下:

      g++报错,找不到输入文件(g++: fatal error: no input files)

      03b2fc40585b5929ebabfb615e0be54f.png

      原因是g++在处理转义字符\时,截断了后面后面的参数,需要修改qtbase\qmake\Makefile.unix文件(为啥不是qtbase\qmake\Makefile.win32文件?),去掉QT_VERSION_STR后面的转义字符。修改完成之后,不再报这个错误。

      c9b3d10ce662b9eeb497f9a34a47751d.png

      • ::symlink未被申明

      efbe772e0487f1f4c4ded1e8b265ffd1.png

      查看报错的源码,发现这个函数应该是unix下特有的,我在Windows下编译,但是实际上启用了Q_OS_UNIX的宏。从qtbase\src\corelib\global\qsystemdetection.h文件来看,如果未指定平台,则会默认Unix,而定义Q_OS_WIN宏的条件,是要定义Q_OS_WIN32、Q_OS_WIN64、Q_OS_WINRT其中至少一个宏,而这三个宏在定义条件如下:

      #elif !defined(SAG_COM) && (!defined(WINAPI_FAMILY) || WINAPI_FAMILY==WINAPI_FAMILY_DESKTOP_APP) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__))
      
      #  define Q_OS_WIN32
      
      #  define Q_OS_WIN64
      
      #elif !defined(SAG_COM) && (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
      
      #  if defined(WINAPI_FAMILY)
      
      #    ifndef WINAPI_FAMILY_PC_APP
      
      #      define WINAPI_FAMILY_PC_APP WINAPI_FAMILY_APP
      
      #    endif
      
      #    if defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP
      
      #      define Q_OS_WINRT
      
      #    elif WINAPI_FAMILY==WINAPI_FAMILY_PC_APP
      
      #      define Q_OS_WINRT
      
      #    else
      
      #      define Q_OS_WIN32
      
      #    endif
      
      #  else
      
      #    define Q_OS_WIN32
      
      #  endif
      

      Win32、win64看起来应该是在编译的时候传入的参数,最终找到qtbase\mkspecs\common\g++-win32.conf文件中定义了_WIN32宏,这个文件又被qtbase\mkspecs\win32-g++\qmake.conf文件包含,我的编译选线里面指定了-platform win32-g++,按道理这个宏应该在编译的时候已经定义了才对,为什么实际编译的时候被使能的是Q_OS_UNIX宏呢???


      51期间的记录仅上述两点,实际上后来我尝试了很多办法,包括直接指定Windows的编译宏等,结局非常凄惨,就和一个谎言需要无数个谎言来掩盖类似,绕开一个编译错误的动作导致了后面出现更多的编译报错,直接钻进了牛角尖。后来还尝试过在Linux下编译,configure确实没有报错,但是编译的时候出现了其他错误,尝试解决也是以失败告终,在这里消耗了大约1天多的时间,直接清空了假期余额,因此这件事情也向后拖了很长时间。

      后来在一个周末比较空闲的时间,打算继续研究一下,在查看qtbase\configure.bat文件时,发现以下代码:

      if "%PLATFORM:g++=%" == "%PLATFORM%" (
      
          if "%MAKE%" == "" (
      
              if not "%jom.exe%" == "" (
      
                  set MAKE=jom
      
              ) else (
      
                  set MAKE=nmake
      
              )
      
          )
      
          set tmpl=win32
      
      ) else (
      
          if "%MAKE%" == "" (
      
              set MAKE=mingw32-make
      
          )
      
          set tmpl=unix
      
      )
      

      大意是如果指定的平台已g++结尾,就走else的逻辑,我指定的平台为win32-g++,所以按Unix编译了?看了下还支持win32-msvc平台,我电脑上安装过vs,刚好有msvc的工具链,因此打算切换到msvc,使用-platform win32-msvc参数,依然出现上述错误,在网上收罗解决办法的时候,翻到了下面这篇文章:

      里面提到要使用x64 Native Tools Command Prompt for VS 2022 Current命令行执行编译编译指令,尝试之后果然没有报错了!!(充分说明了查找资料也是初级技术人员的一项必不可少的能力),编译过程在下面的章节记录。

      Windows下编译QT源码 - 2

      • 重新解压qt源码
        修改交叉编译工具链名称。这里要注意库编译为动态还是静态(我还不理解啥意思),摘抄文章如下:
        QT静态库的编译需要注意编译选项/MD 、 /MT要和开发项目中引用的其他库相匹配。如果要修改此编译选项,可以在QT源文件根目录下的 qtbase\mkspecs\common\msvc-desktop.conf 中修改
      QMAKE_CFLAGS_RELEASE    = $$QMAKE_CFLAGS_OPTIMIZE -MD
      
      QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_OPTIMIZE -Zi -MD
      
      QMAKE_CFLAGS_DEBUG      = -Zi -MDd
      

      或者

      QMAKE_CFLAGS_RELEASE    = $$QMAKE_CFLAGS_OPTIMIZE -MT
      
      QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_OPTIMIZE -Zi -MT
      
      QMAKE_CFLAGS_DEBUG      = -Zi -MTd
      

      打开msvc对应的命令行(x86 Native Tools Command Prompt for VS 2022 Current,编译64位库则打开x64 Native Tools Command Prompt for VS 2022 Current),切换到qt源码解压目录下,注意可能直接cd到解压目录会失败,可以逐级切换目录。
      这次使用的指令为 configure -static -release -mp -opensource -confirm-license -platform win32-msvc -xplatform linux-aarch64-gnu-g++ -prefix D:\Qt\Qt5.12.10\5.12.10\xuantie_900_mingw_v2.2.5 -nomake examples -nomake tests -no-opengl -no-iconv -no-assimp -no-qt3d-profile-jobs -no-qt3d-profile-gl -skip qtvirtualkeyboard -skip qtwebengine -skip qtlocation ,依然需要在qt解压出来的文件夹根目录下执行。

      configure执行的结果如下:

      7459524374276ce319e3abe53fe25600.png
      (上述指令红色部分是后面发现问题之后加的,到后面其实我重新解压编译了一次,用的指令如下 configure -prefix D:\Qt\Qt5.12.10\5.12.10\xuantie_900_mingw_v2.2.5 -opensource -confirm-license -release -strip -shared -xplatform linux-aarch64-gnu-g++ -platform win32-msvc -optimized-qmake -c++std c++11 --rpath=no -pch -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcanvas3d -skip qtconnectivity -skip qtdatavis3d -skip qtdoc -skip qtgamepad -skip qtlocation -skip qtmacextras -skip qtnetworkauth -skip qtpurchasing -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtspeech -skip qtsvg -skip qttools -skip qttranslations -skip qtwayland -skip qtwebengine -skip qtwebview -skip qtwinextras -skip qtx11extras -skip qtxmlpatterns -make libs -make examples -nomake tools -nomake tests -gui -widgets -dbus-runtime --glib=no --iconv=no --pcre=qt --zlib=qt -no-openssl --freetype=qt --harfbuzz=qt -no-opengl -linuxfb --xcb=no --libpng=qt --libjpeg=qt --sqlite=qt -plugin-sql-sqlite -recheck-all)

      • 接下来执行nmake

      在编译过程中,遇到的错误以及对应的解决办法如下:

      • 在编译过程中出现如下错误

      6d419f8c5e3b8d9c05ec7e711c2a0bed.png

      看起来是在调用python时,命令行将指令中文件夹名称中的空格截断了。改动现有的文件目录比较麻烦,我直接重装了python,这次安装的目录就比较简单了,确保没有空格。继续执行nmake,不再报该错误。

      • 编译过程中出现如下错误:

      d:/private_toolchain/xuantie-900-gcc-linux-5.10.4-glibc-mingw-v2.2.5/bin/../lib/gcc/riscv64-unknown-linux-gnu/10.2.0/../../../../riscv64-unknown-linux-gnu/bin/ld.exe: E:/qt-everywhere-src-5.15.1/qtdeclarative/lib/libQt5Qml.a(qv4typedarray.obj): in function `unsigned long long atomicExchange<unsigned short>(char*, QV4::Value)':

      qv4typedarray.cpp:(.text._Z14atomicExchangeItEyPcN3QV45ValueE[_Z14atomicExchangeItEyPcN3QV45ValueE]+0x16): undefined reference to `__atomic_exchange_2'

      在网上收罗了一下资料(参考 https://twd2.me/archives/10597)
      ,缺少的这个函数是RV64的对8位整数和16位整数的原子操作,类似的函数还有__atomic_exchange_4(32位)和__atomic_exchange_8(64位),出现这个问题可主动指定lib文件(-latomic)解决,我报错的这个地方在qtdeclarative\tools\qml\目录下(此时已经是使用刚编译出来的qmake在编译了),需要修改该目录下的makefile文件,在LIBS变量中加入 -latomic。继续编译,不再报__atomic_exchange_2等函数的错误。

      在后续的编译中,还需要按这种方式修改如下文件:

      qtdeclarative\tools\qmltestrunner\Makefile

      • 编译过程中出现如下错误:
      d:/private_toolchain/xuantie-900-gcc-linux-5.10.4-glibc-mingw-v2.2.5/bin/../lib/gcc/riscv64-unknown-linux-gnu/10.2.0/../../../../riscv64-unknown-linux-gnu/bin/ld.exe: E:/qt-everywhere-src-5.15.1/qtdeclarative/lib/libQt5Qml.a(YarrInterpreter.obj): in function `.L433':
      
      YarrInterpreter.cpp:(.text._ZN3JSC4Yarr11byteCompileERNS0_11YarrPatternEPN3WTF20BumpPointerAllocatorEPNS_6NoLockE+0x3b8): undefined reference to `JSC::Yarr::wordUnicodeIgnoreCaseCharCreate()'
      

      收罗到如下解决办法( https://forum.qt.io/topic/32634/unresolved-external-symbol-attempting-to-build-5-2/4):

      in "qt\qtdeclarative\src\qml", check the file "RegExpJitTables.h"
      
      if it's empty, delete it (it's autogenerated with python)
      

      上述办法是针对5.2版本的qt,我现在使用的是5.15.1,这个文件的路径在qtdeclarative\src\qml.generated\RegExpJitTables.h。实际上我在删除这个文件之后依然报错,发现创建的还是一个空文件,直接进入到qtdeclarative\src\qml目录,手动执行python E:/qt-everywhere-src-5.15.1/qtdeclarative/src/3rdparty/masm/yarr/create_regex_tables > .generated\RegExpJitTables.h 命令,才成功创建这个文件(创建出来的文件是由一个超大的数组开头 static const char _wordcharData[65536])。

      (文章里面还提到另一个办法是从git下载源码,但是我未尝试)。

      • 在编译过程中遇到如下错误:
      In file included from declarativemaps\qdeclarativepolylinemapitem.cpp:38:
      
      declarativemaps\qdeclarativepolylinemapitem_p_p.h:381:17: error: 'const char* MapPolylineShaderLineStrip::vertexShader() const' marked 'override', but does not override
      
        381 |     const char *vertexShader() const override {
      

      这个问题,后来发现是各个模块之间有依赖导致的,我在configure的时候加了-no opengl,而这里的qtlocation模块对opengl模块有依赖,所以编译报错,重新configure一次,加上 -no qtlocation,然后重新nmake即可。

      在漫长的等待之后,编译终于完成了。

      执行nmake install,将编译的文件安装到 -prefix 指定的目录。

      • 创建测试工程
        在配置完kit(构建套件)之后,使用creator新建一个测试项目,在选择kit时勾选上我们刚刚配置好的套件,然后随便敲点代码,准备编译工程。

      • 编译工程
        直接点击运行或者构建,将会出现失败,对比了正常构建和失败构建的输出如下:

      8239492397e1e24d301fa93aafff4fe2.png

      很明显是因为没有在工具链的目录下找到make程序导致的,但是此时已经通过qmake创建了makefile文件,我们可以直接进入到工程所在目录,然后直接执行make指令,即可完成程序的编译,我这边成功生成test可执行文件。

      (后来不知道为啥就能直接找到make程序了,此时直接点击构建即可创建出test可执行程序,无需手动执行make指令了)

      d28de5808ae4c3899cf2cebf3a8ed0e8.png

      将编译生成的测试程序上传到开发板并执行,得到如下错误提示:

      bfce1c3167f27f00496bf0618970d73e.png

      原因是因为 libstdc++.so.6库的版本不够高,因此需要更新库文件,我直接将下载的工具链中的库文件(位于工具链目录riscv64-unknown-linux-gnu\lib64v_xthead\lp64d目录下)更新到开发板上。

      e0bfb66bf2212a5d8bd60c3abac7f7d9.png

      然后将libstdc++.so.6软连接到这个库文件即可。

      4358c3710a20967f8c87f285d390108c.png

      重新执行测试程序,得到如下错误:

      ./test: error while loading shared libraries: ld-linux-riscv64v_xthead-lp64d.so.1: cannot open shared object file: No such file or directory
      

      这看起来是库文件缺失导致的报错,将工具链中的库文件更新到开发板上

      d3e12faa056af697b3abcd305a455633.png

      重新执行测试程序,得到如下错误:

      d11941c796d84f8d848ac8613a544e1d.png

      前面两行是因为在编译qt源码时,configure没有加-no-iconv,在没加的情况下编译后,qt会使用QIconvCodec类进行编码的转换,而qt本身不再使用该类,所以不要使用该库,因此重新configure一次然后重新编译即可。

      当然也可以下载去这个网址http://ftp.gnu.org/gnu/libiconv/下载libiconv源码,配置(./configure --prefix=E:\libiconv-1.17\libiconv-1.17\build --host=riscv64-unknown-linux-gnu-gcc)编译后安装,将产生的libiconv.so复制到开发板上。

      编译完成后重新构建测试工程,将得到的可执行文件上传并执行,出现找不到qt库的错误,将缺失的库上传到开发板,重新执行,最终出现BUS ERROR的错误。

      7d29f4eb46e941b17e5150c7a45724d3.png

      查询了资料,说error bus基本上可以肯定是板子上运行的qt库和编译器使用的qt库不一致造成的。那么最好的办法就是将交叉编译的qt库文件直接拷贝到开发板上,并设置其路径。

      直接将整个编译出来的文件拷贝到SD卡的目录下

      cb15792c99f89fe9608974ca99d8daca.png

      并设置qt的环境变量如下:

      export QT_ROOT=/mnt/UDISK/qtlib
      
      export QT_QPA_PLATFORM_PLUGIN_PATH=$QT_ROOT/plugins
      
      export QT_QPA_PLATFORM=linuxfb:tty=/dev/fb0
      
      export QT_PLUGIN_PATH=$QT_ROOT/plugins
      
      export LD_LIBRARY_PATH=$QT_ROOT/lib:$QT_ROOT/plugins/platforms
      
      export QML2_IMPORT_PATH=$QT_ROOT/qml
      
      export QT_QPA_FONTDIR=/resources/fonts
      

      这些环境变量的设置可加入到 /etc/profile 文件中,并通过重启或者执行 source /etc/profile 的方式使其生效。

      在配置完成后,重新执行测试程序(测试程序的功能为点击一个按钮,会更新一个文本框)。

      界面得以显示,但是文字都没有显示出来,点击测试按钮,本应该更新文字,但是文本框依然空白,控制台输出如下信息:

      Note that Qt no longer ships fonts. Deploy some (from https://dejavu-fonts.github.io/for example) or switch to fontconfig.
      

      看这意思,是因为缺少字符库导致的,在开发板全局搜索 fonts,找到如下两个路径:

      /resources/fonts
      
      /usr/share/directfb-examples/fonts
      

      将第一个路径加入到环境变量中 ( export QT_QPA_FONTDIR=/resources/fonts/ ),重新执行程序,终于正常显示了,效果如下:

      6f9753b2041e8aea1a2c590d5fd14260.png

      直接上一个官方炫酷一点的例程(官方例程需要编译example模块才会生成),路径在编译安装路径下"examples\widgets\animation\animatedtiles\animatedtiles",执行的效果如视频,还是非常的丝滑的。

      发布在 MR Series
      Y
      giao
    • Sipeed LicheeRV 86 Panel 基于WAFT的家居控制

      采用waft系统完成一个家居参数监视和控制的终端

      基于WAFT的家居控制——测试项目

      项目测试的硬件基于平头哥LicheeRV 86 Panel开发板,采用waft系统完成软件开发,项目采用客户端-服务器模式架构。

      项目以waft示例程序横向列表Demo为基础,开发了两种类型画面,建立了5个场景,分别为天气预报展示画面、厨房监视控制画面、卧室监视控制画面、客厅监视控制画面、门廊监视控制画面。

      项目建立一个基于python的服务器,用来为设备提供数据和服务支持。

      1、服务器建立

      为了便于后面画面的描述,这里首先介绍一下简易服务器。

      服务器采用Python建立了支持CGI的简易服务器,服务器支持提供文件和执行CGI脚本程序。

      c1e1026eb95b8e6e17492e9a1c41cb5e.jpg

      服务器下面包含三个目录和一个服务器启动文件,分别为文件夹cgi-bin、ico、img和pywebserver.py文件。
      
      img文件夹中存放了主画面所需的图片文件。
      

      3e9efcf97e253502f19224897bad6494 (1).jpg

      ico文件夹中存放了开发板中显示的一些图标文件。
      

      ef6568aef285589431fdf54602760cd2 (1).jpg

      cgi-bin文件夹中存放了CGI脚本程序。

      5895fe01e8e6c482bbae0380d48abe95 (1).jpg

      2、画面开发

      项目采用waft开发平台,基于横向列表示例程序为基础,开发了三种类型画面。利用这三种类型画面开发了一个主画面和5个场景实例。

      2.1 第一种画面类型:主画面,横向列表画面

      主画面采用横向列表Demo为基础,横向列表为纯Waft开发的示例,共设计了5个场景实例,分别为天气预报、厨房、客厅、门廊、卧室。屏幕包含标题“WAFT 家居控制”,下面对应5个图标,分别代表5个场景,这5个图标支持通过服务器上传,只需要按照规则修改服务器目录下相关的图标即可,路径为webserver根目录/img。画面支持左右滑动选择不同的场景,用过点击场景图片,进入到相关场景的细节描述。

      24abeae5a192ef448db68b16854f921d (1).jpg 8485efdf0785bd2804ba4e6fa879b2f1 (1).jpg 502daaba7c191a028d18daea33f1e197 (1).jpg

      2.2 第二种画面类型:天气预报画面

      通过在主画面点击“天气预报”场景图片,进入到天气预报显示子画面,画面显示的信息按照20秒间隔(时间可以在程序中调整)刷新显示画面的内容信息。

      画面内容如下图所示,包含标题和显示内容。

      天气预报子画面采用Waft-UI技术设计完成,包含标题“天气预报”,标题采用waft-ui中nav-bar控件实现,具有向上级画面和向下级画面索引的功能。

      天气显示内容包含城市,日期,星期,天气情况图标,温度和湿度显示,风力和风向,紫外线等级,空气质量。数据的刷新来源于建立的服务器,服务器会定时的向数据源请求数据,并记录到数据库或文件中,为了简化,我这里直接存储到文件中。

      8a34fe5441047f30527766053314a7de (1).jpg

      2.3 第三种画面类型:监视控制画面

      其它几个画面,包括厨房、客厅、门廊、卧室,通过在主画面点击相应的场景图片进入。由于这几个画面类型相同,所以这里以“门廊”画面为例说明,通过在主画面点击“门廊”场景图片,进入到门廊显示和控制子画面,画面显示的信息按照20秒间隔(时间可以在程序中调整)刷新显示画面的内容信息。

      画面内容如下图所示,包含标题和显示内容。

      门廊显示和控制子画面采用Waft-UI技术设计完成,包含标题,标题采用waft-ui中nav-bar控件实现,具有向上级画面和向下级画面索引的功能。

      显示和控制内容包括灯光显示状态和控制按钮,温度和湿度数字显示及图标显示。画面采用的waft-ui控件如下所示。

      "x-nav-bar": "waft-ui/assembly/nav-bar/nav-bar",
          "x-toast": "waft-ui/assembly/toast/toast",
          "x-overlay": "waft-ui/assembly/overlay/overlay",
          "x-card": "waft-ui/assembly/card/card",
          "x-dialog": "waft-ui/assembly/dialog/dialog",
          "x-button": "waft-ui/assembly/button/button",
          "x-image": "waft-ui/assembly/image/image"
      

      画面中的灯光控制状态发送到服务器,服务器会将该命令转发给相应的灯光控制模块,并且将灯光控制模块上送的灯光状态和控制状态反馈到画面上来。

      画面按照20秒间隔向服务器请求温湿度数据信息,这些信息是服务器定时获取的相应场景环境参数监视模块上送的信息,并存储到数据库或文件中。

      灯光控制为关闭状态效果图:

      4db9285e60d68c50c8453d84dcae961a (1).jpg

      灯光控制为打开状态效果图:

      eea0c25f7e5ca142459985e2c47d872f (1).jpg

      3、实测效果

      3.1 服务器运行画面

      3.2 演示视频

      4、目前开发中遇到的问题

      现在的waft系统对于json相关特性的支持还有待完善,例如关于UTF-8类型的中文到GBK类型中文字符串的转换,还需要提供合适的接口函数

      发布在 MR Series
      Y
      giao
    • waft-ui组件的学习和测试 - picker,switch和card

      接着之前waft-UI中组件的测试,本次继续测试picker,switch和card。

      1. picker组件的学习

      Waft-UI中提供了picker组件,picker组件是一个两级的列表选择组件,我们可以通过调用这个组件构造一个选择器。

      1.1 组件的调用方法

      在index.json中增加button组件的引用,方法为:

      {
       "usingComponents": {
             "x-picker": "waft-ui/assembly/picker/picker"
        }
      }
      

      1.2picker的显示

      在index.axml文件中,增加显示脚本。

      <view class="flex">
              <x-picker
                  show="{{showPicker}}"
                 pickerData="{{pickerData}}"
                  change="handleChange"
                 clickConfirm="clickConfirm"
                  clickCancel="clickCancel"
              >
              </x-picker>
            </view>
      

      实际显示效果

      8f8101f8ecd621a9be48d725608b6cf8.jpg

      1.3 picker的事件响应

      在index.ts中编写picker的事件响应函数,picker提供了三个事件响应,一个是change事件,一个确认,一个取消。

      this.addEventListener("clickConfirm",(event,target) => {
           console.log("===test-picker的clickConfirm事件===")
           console.log(event.toString());
           (target as Index).setState(
             JSON.parseObject(`{"showPicker":false}`)
           );
           (target as Index).setState(
             JSON.parseObject(`{"showTimePicker":false}`)
           );
         })
         this.addEventListener("clickCancel",(event,target) => {
           console.log("===test-picker的clickCancel事件===")
           console.log(event.toString());
           (target as Index).setState(
             JSON.parseObject(`{"showPicker":false}`)
           );
           (target as Index).setState(
              JSON.parseObject(`{"showTimePicker":false}`)
           );
         })
         this.addEventListener("handleChange",(event,target) => {
           console.log("===test-picker的handleChange事件===")
           console.log(event.toString());
      });
      

      事件的响应结果展示

      28609c7b0995d66a0f3da6186276ea89.jpg

      滚动选项列表时的事件信息。

      2d0a923a217b198e893a0590ae0c8490.jpg

      按下确定按键时的响应信息,信息中含有当前选中一级条目、二级条目索引和值。

      0e35609281cc8f097cf734ecafb760b0.jpg

      按下取消键时的响应信息,信息中也含有当前选中一级条目、二级条目索引和值。这个需要通过程序去判断,是否取用当前的返回值。

      2. card组件的学习

      Waft-UI中提供了card卡片组件,这个卡片可以作为容器,可以放置其它的组件。

      2.1 组件的调用方法

      在index.json中增加card组件的引用,方法为:

      {
       "usingComponents": {
              "x-card": "waft-ui/assembly/card/card",
        }
      }
      

      2.2 card组件的显示

      在index.axml文件中添加card组件的显示部分,可以为card组件设置标题,调整宽度和长度,背景色,相当的灵活。

      <view class="flex">
            <view style="height: 10rpx"> </view>
            <x-card title="SWITCH" width="55vw" height="40vh" titleAlign="center" bgColor="green">
              <x-switch checked="{{true}}"> </x-switch><view class="dot"></view>
             <view class="doth"></view>
              <x-switch checked="{{false}}" onTap="change1"></x-switch><view class="dot"></view>
            </x-card>
            </view>
      

      3. switch组件的学习

      Waft-UI中提供了switch显示组件,switch是一个二值组件,类似开关一样。

      3.1组件的调用方法

      在index.json中增加card组件的引用,方法为:

      {
       "usingComponents": {
              "x-card": "waft-ui/assembly/card/card",
        }
      }
      

      3.2 switch组件的显示

      在index.axml中增加switch组件的调用,这里将前面的card组件和switch组件组成一个部件显示,将switch组件放置在card内。

      <view class="flex">
           <view style="height: 10rpx"> </view>
           <x-card title="SWITCH" width="55vw" height="40vh" titleAlign="center" bgColor="green">
             <x-switch checked="{{true}}"> </x-switch><view class="dot"></view>
            <view class="doth"></view>
             <x-switch checked="{{false}}" onTap="change1"></x-switch><view class="dot"></view>
           </x-card>
           </view>
      

      实际显示效果,包含了card组件,背景色设置为绿色和switch组件

      17bad67b5d99fd3b77300ce12b510640.jpg

      3.3 switch的事件响应

      前面的显示调用中,我们将switch的onTap事件导出名为“change1“的事件。我们只需要响应这个事件就可以了。

      this.addEventListener("change1", (e, target): void => {
           console.log("----> switch事件:changed!");
      });
      

      事件的响应结果展示

      33ad3cefa351c3055a0bd4b28b47dbd5.jpg

      发布在 灌水区
      Y
      giao
    • waft-ui组件的学习和测试

      完成waft开发环境搭建后,就到了waft开发的学习过程,首先学习waft-UI中组件的使用。在使用过程中遇到了一些问题,经过waft开发团队的帮助得到解决,但是还有部分问题需要在学习和使用过程中不断的摸索。

      1. Waft-UI组件的安装

      以下组件测试基于,Waft-UI组件的最新版本是0.3,waft版本0.7。在创建了新的工程后,在工程目录下安装waft-ui,命令为

      npm i waft-ui –save

      更新waft为0.7版,执行命令:

      ncu
      nuc –u
      npm install
      

      将会将当前工程中的组件更新到最新。

      2. Button组件的学习

      Waft-UI中提供了基本的Button组件,我们可以直接调用这个组件来使用。

      2.1 组件的调用方法

      在index.json中增加button组件的引用,方法为:

      {
       "usingComponents": {
         "x-button": "waft-ui/assembly/button/button"
        }
      }
      

      2.2 Button的显示

      在index.axml文件中,编写显示脚本。

      <view class="wrapper">
        <x-nav-bar showArrow="{{true}}" title="Button"></x-nav-bar>
        <view style="flex: 1; padding-top: 30rpx; display: flex;flex-direction: column;">
          <x-button type="primary" text="按钮"
              onTap="priclick" >
          </x-button>
          <view class="dot"></view>
          <x-button type="secondary" text="按钮"
              onTap="secclick" >
          </x-button>
          <view class="dot"></view>
          <view class="title">带图标</view>
          <view class="flex">
            <x-button
              text="按钮" 
              iconURL="http://172.17.64.61:8001/ico/bulb-24x24-23415.png"
              onTap="btnclick" >
            <view class="dot"></view>
          </view>
        </view>
        <view class="title">自定义颜色</view>
        <view class="flex">
            <x-button text="按钮" bgColor="#ff976a" borderColor="#ff976a" textColor="#ffffff"></x-button><view class="dot"></view>
        </view>
      </view>
      

      实际的显示效果如下图所示:

      c5dbb15085a23b87efaa49e2dcfe9ac1.jpg

      2.3 Button的事件响应

      在index.ts中编写Button的事件响应函数

      import { FuncPage, MessageEvent, Target, history, Event } from 'waft';
      import { JSON, JSONObject } from "waft-json";
       
      export function Main(page: FuncPage): void {
        // page.addEventListener("btnclick", (e: MessageEvent): void => {
        //  console.log("this is button test!");
        // });
        page.addEventListener("btnclick", (e, target): void => {
          console.log("this is button test!");
        });
        page.addEventListener("priclick", (e, target): void => {
          console.log("this is primary button test!");
        });
        page.addEventListener("secclick", (e, target): void => {
          console.log("this is secondary button test!");
        });
       
        page.onload = function (data: JSONObject, target?: Target | null) {
          console.log('--> onLoad tigger with launchData =  ' + data.toString());
        };
         page.onmessage = function (event: MessageEvent) {
          console.log('--> onMessage args =  ' + event.toString());
        }
      }
      

      事件的响应结果展示如下图所示,可见,当按键被按下时,按键的响应函数被执行了,在终端打印了我们的输出信息。

      9c94f0acca1f1ce9d4525876b12238ba.jpg

      3. Toast组件的学习

      Waft-UI中提供了Toast轻提示组件,我们可以直接调用这个组件显示提示信息。

      3.1 组件的调用方法
      在index.json中增加Toast组件的引用,方法为:

      {
       "usingComponents": {
          "x-toast": "waft-ui/assembly/toast/toast"
        }
      }
      

      3.2 组件使用

      组件的显示是通过程序调用完成的。

      import { Page, Props } from "waft";
      import { JSON, JSONObject } from "waft-json";
      import { Toast, ToastOptions } from "waft-ui";
       
      export class ComponentTest extends Page {
        constructor(props: Props) {
          super(props);
          this.addEventListener("clickToast1Btn", (e, target): void => {
            // 未测试多个toast同时调用的问题
            let toastOptions = new ToastOptions();
            toastOptions.message = "测试Toast1";
            toastOptions.type = "fail";
            toastOptions.iconURL = "http://172.17.64.61:8001/ico/O1CN01cSL5BS1d7bmgm1pxt_!!6000000003689-2-tps-200-200.png"
            toastOptions.position = "middle";
            Toast.show(toastOptions);
          });
         this.addEventListener("clickToast2Btn", (e, target): void => {
            let toastOptions = new ToastOptions();
            toastOptions.message = "测试Toast2";
            toastOptions.type = "success";
            toastOptions.iconURL = "http://172.17.64.61:8001/ico/O1CN01evbrT81s2JRO3tkra_!!6000000005708-2-tps-200-200.png"
            toastOptions.duration = 5000;
            toastOptions.position = "middle";
            Toast.show(toastOptions);
          });
         this.addEventListener("clickOverlayBtn", (e, target): void => {
            (target as ComponentTest).setState(
             JSON.parseObject(`{"showOverlay":true}`)
            );
            console.log("====打开遮罩");
       
          });
          this.addEventListener("clickOverlay", (e, target): void => {
            (target as ComponentTest).setState(
             JSON.parseObject(`{"showOverlay":false}`)
            );
            console.log("====关闭遮罩");
          });
         this.addEventListener("clickDialogBtn", (e, target): void => {
            console.log("dadsada");
       
            (target as ComponentTest).setState(
             JSON.parseObject(`{"showDialog":true}`)
            );
          });
         this.addEventListener("clickConfirm", (e, target): void => {
            console.log("****关闭弹窗****");
            (target as ComponentTest).setState(
             JSON.parseObject(`{"showDialog":false}`)
            );
          });
         this.addEventListener("clickCancel", (e, target): void => {
            console.log("****关闭弹窗****");
            (target as ComponentTest).setState(
             JSON.parseObject(`{"showDialog":false}`)
            );
          });
        }
      }
      

      实际显示效果如下图所示:

      4f79db6ecb3d041fd6820071b44cb6b4.jpg

      4. Image组件的学习

      Waft-UI中提供了Image显示组件,我们可以直接调用这个组件显示图片。

      4.1 组件的调用方法

      在index.axml中增加image组件的调用

      <view class="wrapper">
       <x-nav-bar showArrow="{{true}}" title="测试图片"></x-nav-bar>
       <view class="content">
         <x-image full="{{ true }}" width="320rpx" height="240rpx" src="http://172.17.64.61:8001/ico/O1CN01dudMzQ1eY0BV29999_!!6000000003882-2-tps-1920-1080.png"></x-image>
       </view>
      </view>
      

      其中width和height根据屏幕尺寸适当调整,图片需要指明获取来源。

        在index.json中增加image组件的引用,方法为:
      
      {
       "usingComponents": {
          "x-image": "waft-ui/assembly/image/image"
        }
      }
      

      4.2实际显示效果如下图所示

      6afc793eed1a7f38a3ad72f817d52623.jpg

      显示的图片源的大小会根据设定的width和heigth自动的调整。

      发布在 MR Series
      Y
      giao
    • Waft开发环境的建立

      Waft开发环境的建立

      1. waft介绍
      再阿里云网站中,包含Waft的介绍。Waft(WebAssembly Framework for Things) 是一个面向 AIoT 的高性能应用研发框架,Waft 基于 WebAssembly 和自研的渲染引擎技术打造,适用于智能终端的软件应用研发场景。

      它的特点网站从框架特性,技术优势,应用场景几个方面展开。其中强调的AIoT的应用,高性能几乎接近原生应用体验,跨平台等特点令人关注。

      2. 资料收集
      官方提供的语雀中包含了Waft快速开发指导,框架使用,组件文档,API手册等内容。
      平头哥OCC社区 https://occ.t-head.cn/community/post 其中包含多篇博文教程,还有很多试用贴可供参考。

      3. 环境搭建
      我这里使用ubuntu 18.04 版本作为开发平台。

      首先再windows下安装虚拟机,安装virtualBox,开源的虚拟机软件,挺好用。在其中安装ubuntu 18.04 64位桌面版系统。

      系统安装完成后就可以开始构建waft的开发环境了。这个过程主要参考语雀的快速开始教程完成,配合各种搜索引擎来解决这个过程的坑。

      • 安装node环境
        直接去https://nodejs.org/zh-cn/download/下载编译好的Linux的二进制包,然后解压到用户目录下,并添加全局路径。

      我感觉这样的好处是后面的安装过程基本不用使用sudo来强制。

      npm软件安装的过程比较坎坷,无法获取到安装包是常有的事,所以有时候需要更换国内的一些镜像源,就快多了。

      可以采用命令 npm config set registry https://registry.npm.taobao.org 来更换源。

      也可以使用cnpm来安装一些必要的安装包。

      • 安装waft-cli工具

      安装好了nodejs环境后,接下来就是安装waft-cli这个称为脚手架的工具了。如果存在权限问题可以使用sudo,不过我没有遇到这个问题。

      命令为:

      npm i waft-cli -g
      

      如果指令顺利执行完成的话,我们就可以开始基本waft的工程创建了。

      • vscode

      这个工具用来编辑工程文件非常好,所以还要安装这个代码编辑器。

      可以通过vscode的官网下载安装包

      https://code.visualstudio.com/Download

      也可以直接使用ubuntu的软件包管理软件搜索vscode安装,这个中方法比较简单,一键完成,推荐。

      4. 第一个例程测试

      一切准备就绪,就是开始第一个程序测试了,安装语雀中快速开始的说明,我们一步一步执行下去就可以了。

      • 创建项目

      首先我们新建一个目录,就命名为waft_app吧,进入目录后,运行

      waft  init
      

      a0db47b4e141dc82fd752f22d2285705.jpg

      输入我们希望的用户名,比如waft_test

      359d7226e1f5886d053e946deb026c71.jpg

      接下来就是选择模板了,按方向下键选择,我们选择9) 平头哥天气demo,然后回车。

      接下来就是工程项目初始化过程,网络必须畅通,否则就够呛了。我们可以看到他在执行npm install的一个进度条。

      e437da83af70c12b6453bfec4fbc8a11.jpg

      当进度条走完了,出现init done的字样后,项目创建就完成了。

      • 启动服务和项目预览

      进入刚才创建的项目目录, cd waft_test

      然后执行 npm run start

      6f47ceec4b6c88e4c68374884930e469.jpg

      命令执行后,可以看到终端的提示,我们来静态预览一下看看效果,再浏览器中打开

      bb38544339ca303bfb2a4b67d5d4ceeb.jpg

      再打开动态预览看看效果,结果什么都没有看到,屏幕是黑的,但是终端中出现了对当前项目的编译过程,目前还不知道产生的原因。

      c88cfadf07b3ea06e21165b140996aa4.jpg

      • 编译

      输入命令:

      waft>.build  –aot=true –aotTarget=riscv64
      

      3b2ad6dc0599921a7236a378761b18c5.jpg

      编译成功后,会出现Compile success字样。同时我们可以察看工程文件的编译结果如下,存放在项目文件夹下的build文件夹内。

      8446f21472e7eda285693879e20a9652.jpg

      • 开发套件配网

      无线网络配置参数存放在/etc/wifi目录下,我们通过串口终端连接到开发套件,编辑/etc/wifi/wpa_supplicant.conf文件,输入实际的wifi的ssid和psk,保存文件后重启。

      检查实际网络连接情况:执行 ifconfig

      root@MaixLinux:~# ifconfig 
      
      wlan0    Link encap:Ethernet  HWaddr 4C:21:1E:CF:C7:89  
      
               inet addr:192.168.95.2 Bcast:192.168.95.255 Mask:255.255.255.0
      
               inet6 addr: fe80::4e21:1eff:fecf:c789/64 Scope:Link
      
               UP BROADCAST RUNNING MULTICAST MTU:1500  Metric:1
      
               RX packets:160 errors:0 dropped:0 overruns:0 frame:0
      
               TX packets:204 errors:0 dropped:0 overruns:0 carrier:0
      
               collisions:0 txqueuelen:1000 
      
               RX bytes:32889 (32.1 KiB)  TX bytes:24151 (23.5 KiB)
      

      已知ip地址为:192.168.95.2

      • 推送编译结果

      这里采用FTP的方式完成结果推送,采用ftp软件将刚才编译的app.wasm上传到开发套件中。

      2f8925ea1151ceba32622cd18734c6f4.jpg

      • 实测

      再串口终端中,执行刚刚上传的app.wasm文件。命令为:waft_app app.wasm

      140f6a338cd1c36a3234c47f3f582055.jpg

      可见系统已经运行了,并且屏幕上出现了预设的组件信息。

      原文链接:https://occ.t-head.cn/community/post/detail?spm=a2cl5.14300979.0.0.6bfa180fAfsCNS&id=4024185942624505856
      作者@我爱下载

      发布在 其它全志芯片讨论区
      Y
      giao
    • 回复: 【素材汇总】V853素材汇总

      @q1215200171 不仅偷跑照片,还偷偷开了在线文档

      发布在 公告
      Y
      giao
    • 回复: 太干了,OpenPPL做的RISC-V技术解析

      @nihui 要对ncnn有信心🙃

      发布在 MR Series
      Y
      giao
    • 太干了,OpenPPL做的RISC-V技术解析

      转自OpenPPL公众号:https://mp.weixin.qq.com/s/jw_8BSlZKjM9-0KBPqX2vw

      2月24日(周四)19:00,OpenPPL 实战训练营系列课程第七期,商汤科技高性能计算工程师焦明俊为大家带来了「OpenPPL RISC-V 技术分享」的专题课程。

      OpenPPL RISC-V 是针对全志 AllWinner D1 平台 RISC-V 架构的深度学习推理引擎。

      本期课程结合了 RISC-V V 指令集以及全志 D1 开发板的微架构特点,对推理引擎的算法设计进行技术解析。

      以下为本次公开课的课程总结~

      Part 1 | RVV 指令集概述
      Part 2 | AllWinner D1 微架构特点
      Part 3 | OpenPPL RISC-V 算法设计
      Part 4 | OpenPPL RISC-V 性能展示
      Part 5 | Q&A
      Part 6 | 课程表

      Part 1 RVV指令集概述

      1.1 RISC-V定义
      RISC-V 是一个基于精简指令集 risc 原则的开源指令集架构,其指令使用模块化设计,包括基本指令集以及额外可选择的扩展指令集。

      640.png

      1.2 微指令集的使用

      • 向量设置/控制指令

      • vsetvl、vsetvli —— 用来配置 vl、vtype 寄存器

      • 向量加载存储指令

      • vle.v、vse.v

      • 读取/修改向量寄存器指令

      • vmv.v.v、vmv.v.x、vmv.v.i

      • vrgather.v.v、vrgather.v.x、vrgather.v.i

      640 (1).png

      1.3 向量算数运算指令

      • vfadd.vv、vfadd.vf

      • vfsub.vv、vfsub.vf

      • vfmul.vv、vfmul.vf

      • vfdiv.vv、vfdiv.vf

      • vfmacc.vv、vfmacc.vf

      • 对比 arm neon :vfma —— 支持向量-向量元素乘累加操作

      640 (2).png

      Part 2 AllWinner D1 微架构特点

      2.1 C906 处理器的体系结构特点(用户手册)

      • 支持 RV64 IMA[FD]C[V]指令子集

      • 5级单发射顺序执行流水线

      • 一级哈佛结构的指令/数据缓存(各32K)

      • 算力可达 4GFlops(@1GHz)

      • 遵循 RVV 向量扩展标准(RVV 0.7.1)

      • 支持 int8/ int16/ int32/ int64/ fp16/ fp32/ fp64/ bfp16 向量运算

      2.2 性能参数实测

      • 指令吞吐

      通过构建无数据依赖的相互独立的指令流来测试每条指令的执行周期数(CPI)。

      • 指令延迟

      通过构建具有写后读相关性的指令流序列来测试不同指令的执行延迟。

      • 访存带宽

      通过构建 Cache 命中率为百分百和零的两种指令流分别测试 Cache 和主存 DDR 的带宽。

      2.3 实测性能参数结果

      • 指令吞吐、指令延迟

      640 (3).png

      • 访存带宽

      Cache :8 GB/s

      Memory : 2.727 GB/s (DDR3 792 MHz)

      • 构建roofline模型

      640 (4).png

      Part 3 OpenPPL RISC-V算法设计

      3.1 通用GEMM KERNEL的设计

      • 向量广播乘累加操作性能分析

      1. 由于采取 NBCX 的数据排布,需要将 V0 各通道元素广播分别与 V16 进行乘累加

      640 (5).png

      2)相关代码

      640 (6).png

      i. 代码左:2 * 4 + 2 * 4 = 16 (cycle)

      ii.代码右:2 + 3 * 3 + 2 = 13 (cycle)

      3)由于需要使用 gather 指令

      i. 占用了向量寄存器

      ii.添加了与计算无关的寄存器间数据传递指令

      • gemm_kernel 的设计

      假设数据都在Cache中并且k足够大,在寄存器的约束下寻找最合适的kernel size (m/n)来达到最高的gemm_kernel性能。

      1. 方式一:

        权重、输入均放入向量寄存器,使用向量-向量(vv)算数指令计算

        weight/input : vle.v、vse.v

        compute: vfmacc.vv

      640 (7).png

      1. 方式二:

        权重放入向量寄存器,输入放入标量寄存器,使用向量-标量(vf)指令计算

        weight : vle.v、vse.v

        input : flw

        compute : vfmacc.vf
        640 (8).png

      • 不同kernel size下计算指令的占用率

      1. vv指令在不同kernel size下计算指令的占用率

      640 (9).png

      1. vf指令在不同kernel size下计算指令的占用率

      640 (10).png

      1. 对应到roofline模型中的位置

      640 (11).png

      3.2 gemm实现的两种选择

      640 (12).png

      naive-gemm 优劣

      • 需要开辟一块额外内存空间用来存放整张图的 im2col 结果

      • im2col 过程仅需一次

      • 由于Cache大小的局限性,无法合并 im2col 与 tiling 流程

      • 非 1x1 卷积核下,无额外 tiling 开销

      tile-gemm 优劣

      • 仅需一小块 tile 大小的内存空间来存放 tile 的 im2col 结果

      • 由于 Output Station 的循环计算策略,im2col 过程需要执行多次

      • 可合并 tiling 与 im2col 流程,并将结果直接送入 Cache 中

      • 非 1x1 卷积核下,在原图上 tiling 划分会有重叠数据开销

      • 举例:

      在IC较大的网络下,添加 naive-gemm对性能提升的效果。

      640 (13).png

      3.3 快速卷积算法-Winograd分析

      • direct conv

       Td = OC * OH * OW * IC * f * f * 2
      

      • winograd conv
      640 (14).png
      640 (15).png

      • 加速比

      640 (16).png

      分析

      • 随着 IC/OC 的增大, TBTdB / TATMA 两者减小,加速效益更明显

      • 以上 IC/OC 较大的前提下,

       • f 固定,随着 b 的增大,加速效益更明显
      
       • b 固定,随着 f 的增大,加速效益更明显
      
          • f 为 1 时,加速比为 1
      

      640 (17).png

      • Winograd算法提升性能的本质

      640 (18).png

      Part 4 OpenPPL RISC-V性能展示

      4.1 OpenPPL RISC-V使用方式

      fp32 测试

      • ./pplnn --use-riscv -- onnx-model model.onnx --inputs input.bin

      fp16 测试

      • ./pplnn --use-riscv --use-fp16 --onnx-model model.onnx --inputs input.bin

      其他命令设置项

      •--help :显示所有命令设置项

      •--enable-profiling :显示网络性能分析详细结果

      •--save-inputs :保存输入数据到指定文件

      •--save-outputs :保存输出数据到指定文件

      •--min-profiling-iterations :设置最小profiling迭代次数

      •--wg-level :设置winograd快速算法级别

      4.2 性能结果

      640 (19).png

      OpenPPL在 fp16 和 fp32 精度上均能够达到平均 1.5 倍于框架A的性能。

      4.3 OpenPPL RISC-V开发计划与展望

      支持更多的网络模型和算子

      • 语义分割、目标检测等网络

      • 视觉 CV 算子

      支持

      • 兼容 RVV 0.7.1 和 RVV 1.0 标准版本

      • 可变长 VLEN 支持

      Part 5 Q&A

      Q1. Tile-gemm 的优势 case 有多快?
      Tile-gemm的优势在于,在tile划分较少的情况下,它相对于naive-gemm会有比较大的优势。这种情况下,在一些比较小的网络里面会有一些比较好的效果,比如mobile net。具体数据可以在微信群做进一步探讨。

      Q2. RISC-V 上 depth-wise 卷积有优势吗?gemm kernel 的性能是多少?

      关于depth-wise卷积,这边暂时没有去做具体的测试,但据了解应该是不会有劣势的。

      关于gemm kernel的性能上限,可以参考内容截图。如果使用vv的计算方式,理论上限大概在50%,理论峰值就是4GFLOPs的50%左右;但如果使用vf指令,能够达到它理论峰值的80%,即4*80%,3.2GFLOPs。

      发布在 MR Series
      Y
      giao
    • OpenPPL也已支持了在RISC-V的D1上跑啦!

      本文转自OpenPPL公众号
      原文链接:https://mp.weixin.qq.com/s/6h-r-xWzcHf2SksmQyJf_Q

      RISC-V 最近风头正劲,各家都在紧锣密鼓打造基于 RISC-V 指令集的各种处理器。在 AI 热潮的推动下,RISC-V 上面部署 AI 的需求也越发凸显。

      同时市场上终于出了带 V 指令的 RVBoards,基于玄铁 C906 架构,我们就决定开启 RISC-V 后端。初版支持 128 位向量,fp32 和 fp16 两种数据格式,性能较现有开源框架更优,欢迎体验!

      RISC-V 支持情况概述

      OpenPPL 针对 RISC-V 指令集进行了深度优化,支持部分分类网络(比如 alexnet, resnet, resnext, shufflenet, squeezenet, mobilenet, mnasnet 等)在 fp32 和 fp16 精度下的推理。

      同时,与 OpenPPL 其他架构类似,RISC-V 架构支持算子融合等图优化策略进行网络性能优化,从而达到理想的性能效果。

      目前市面上支持 RISC-V 向量指令集 (RVV) 的开发板较少,OpenPPL RISC-V 暂时仅支持全志D1(rvv-0.71,128bit 向量长度),后续会逐步添加对 rvv-1.0 和动态向量长度的支持。

      RISC-V 算子支持

      在 RISC-V 向量指令集 (RVV) 的使用上,我们主要采用了 intrinsic 和内联汇编的方式。

      由于编译器的限制,intrinsic 并不能达到非常优秀的性能,因此我们选择在卷积的计算代码中使用内联汇编,一方面,这能使性能优化更加准确;另一方面,内联汇编可以借助 C++ 的模板和宏等功能生成不同规模的计算代码。

      intrinsic 的可读性更高,用起来也更加方便,在其他执行时间占比较低的算子中,我们选择用 intrinsic 进行开发。

      OpenPPL RISC-V 实现了一些常用的卷积优化算法,包括 img2col+gemm,winograd 等。同时,OpenPPL RISC-V 针对 rvv 做了一系列的调优工作,使得卷积算子在全志 D1 上能够拥有不错的性能,但由于某些限制,OpenPPL RISC-V 仍没有发挥出 rvv 的全部能力:

      • rvv 提供了功能非常丰富的指令,这提高了 rvv 的可玩性,但也对向量单元的硬件设计提出了挑战。c906 支持了 rvv-0.71 的大部分功能,但仍放弃了一些有用的功能,比如 Vector Register Grouping,OpenPPL RISC-V 也并未支持这些功能。
      • RISC-V 的向量寄存器堆独立于浮点寄存器堆,在计算中合理地使用两个寄存器堆往往可以提高计算效率。但需要注意的是,rvv 支持半精度浮点的向量操作,但 RISC-V 并没有和 FD 扩展一样稳定的半精度浮点标量指令规范。如果需要手动操作浮点寄存器,就要用到 c906 自定义的半精度浮点扩展或是一些有损性能的特殊方式。出于芯片兼容性的考虑,OpenPPL RISC-V 在 fp16 精度的推理中并没有使用该自定义的半精度浮点扩展(也没有显式地使用浮点寄存器),而是用 rvv 中的指令进行代替。

      在全志 D1 上运行 OpenPPL

      首先需要在 occ.t-head.cn 中下载所需的编译工具链并解压,可以选择 riscv64-linux-x86_64-20210512.tar.gz。
      微信图片_20220125133628.jpg
      https://occ.t-head.cn/community/download?id=3913221581316624384

      tar -xf riscv64-linux-x86_64-20210512.tar.gz
      

      下载 ppl.nn

      git clone https://github.com/openppl-public/ppl.nn.git
      cd ppl.nn
      

      指定编译工具链的路径,进行交叉编译

      ./build.sh -DHPCC_TOOLCHAIN_DIR=/path/to/riscv64-linux-x86_64-20210512 -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/riscv64-linux-gnu.cmake -DHPCC_USE_RISCV=ON -DPPLNN_ENABLE_KERNEL_PROFILING=ON -DPPLNN_ENABLE_PYTHON_API=OFF -DPPLNN_ENABLE_LUA_API=OFF
      

      编译完成后将文件 pplnn-build/tools/pplnn 传至全志 D1 即可运行

      # fp32
      ./pplnn --use-riscv --onnx-model model.onnx --inputs input.bin --in-shapes n_c_h_w [--warmup-iterations m] --enable-profiling
      
      # fp16
      ./pplnn --use-riscv --use-fp16 --onnx-model model.onnx --inputs input.bin --in-shapes n_c_h_w [--warmup-iterations m] --enable-profiling
      

      可以通过添加 --tuning-level=1 开启动态算法选择以达到更高的性能。

      性能展示

      OpenPPL RISC-V 在全志 D1 上的性能数据统计
      微信图片_20220125133634.jpg

      欢迎Star

      https://github.com/openppl-public
      扫码添加小助手,加入 OpenPPL 大家庭!

      发布在 MR Series
      Y
      giao
    • 看到一篇关于D1 RVV性能评测文,这性能什么水平?

      转自嵌入式IoT公众号
      https://mp.weixin.qq.com/s/N3bkMyJwc4HWI_M1Docghg

      D1 riscv芯片上运行rt-thread进行RVV性能评估

      • 概述
      • rt-thread在D1芯片上的移植
      • 如何开启D1&&D1s的rvv扩展
      • RVV性能对比评估
      • RVV在RTOS如何使用的更好

      概述

      D1 && D1s(f133)采用的是平头哥C906的core,上面已经支持了RVV 0.7.1版本,虽然目前RVV1.0已经frozen,这就意味着上游编译器或者一些相关的生态软件将支持RVV1.0,但是作为性能评估RVV0.7.1与RVV1.0影响并不大。下面的文章主要描述如何在D1 && D1s芯片上运行rt-thread,并且描述如何开启RVV,同时对RVV性能进行一个简单的评估,最后讨论RVV如何与RTOS使用的问题。

      rt-thread在D1芯片上的移植

      目前D1s有64MB的内置DDR2,这非常适合运行RTOS,所以将rtos移植到D1s上是非常不错的选择。

      其移植的细节不详细介绍,可以查看源代码

      https://github.com/bigmagic123/d1-nezha-rtthread
      

      移植的难点在于:

      1.启动,从芯片上电启动入口处跳转到rt-thread入口处的汇编代码
      2.硬件串口的初始化,这里会涉及到时钟配置
      3.tick时钟中断,目前采用的是riscv的通用timer,需要配置clic
      4.任务切换和上下文的保存与恢复,这部分需要对入栈出栈的顺序十分的清晰
      5.串口中断,这里需要弄清楚plic中断处理机制

      解决上述问题,移植rt-thread将非常的简单,当前的rt-thread运行在M-mode,具有比较高的权限,可以随意操作寄存器进行配置。

      编译与运行在windows和Linux上均可操作,主要参考如下的文档:

      https://github.com/bigmagic123/d1-nezha-rtthread/blob/main/README.md
      

      目前已经实现的功能有:

      1.timer
      2.uart
      3.gpio
      4.vector
      5.FPU

      如何开启D1&&D1s的rvv扩展

      想要使用RVV功能,需要开启VS标志位,该位位于

      微信图片_20220114161643.jpg

      VS位于MSTATUS寄存器的23到24位。但是需要注意的是,当使用RVV时,需要开启浮点寄存器(FS),不然会报错。

      这部分在rt-thread的体现是在上下文切换的时候,需要将使用RVV的线程的MSTATUS设置成开启VS的模式。

      微信图片_20220114161711.jpg

      可以VS设置b01。

      只有当使能该位,才能正常使用RVV指令,不然运行会直接报错。

      接着,编译选项中还需要添加成如下选项

      -march=rv64gcvxtheadc -mabi=lp64d -mtune=c906
      

      这样才能告诉编译器支持RVV指令。

      RVV性能对比评估

      riscv 的RVV其编程模型主要有两种方式,第一种采用rvv-intrinsic。这就是在编译器中进行intrinsic函数的构建,可以将相关的rvv操作变成编辑器的内置函数。采用类似下面的函数方式进行编程。

      vint8mf8_t vcopy_v_i8mf8 (vint8mf8_t src);
      vint8mf4_t vcopy_v_i8mf4 (vint8mf4_t src);
      ...
      

      其操作详情可以参考:

      https://github.com/riscv-non-isa/rvv-intrinsic-doc/
      

      本质上就是将复杂的汇编代码操作换成C语言函数的形式,这种方式可读性更强。rvv1.0后面也会提供这一种方式进行。

      第二种就是采用汇编进行操作,裸写汇编代码的难度很大,但是可以实现比较好的优化,这特别是在关键耗时的操作上进行汇编级别的优化,可以很大程度上提升程序运行的性能。

      在平头哥开源出来的GCC工具链中,并没有rvv-intrinsic功能,所以只能通过汇编函数的方式进行操作。

      平头哥开源出来了一个神经网络的库,里面有C906的RVV底层操作。

      https://github.com/T-head-Semi/csi-nn2
      

      实现了一些基本的操作,抽象了各种常用的网络层的接口,并且提供一系列已优化的二进制库。

      其主要的使用类似于CMSIS,Tensorflow等等。有了这些抽象接口,在使用RVV进行特定优化的时候,难度也会有所降低。

      下面主要从csi-nn2抽取出vertor add, vertor mul,memcpy,也就是加法计算,乘法计算和内存拷贝,三个方面,对其性能进行评估。

      https://github.com/bigmagic123/d1-nezha-rtthread/blob/main/bsp/d1-nezha/applications/vector.c
      

      浮点数加法

      采用向量操作

      float a[10] = {1.2,1.3,1.4,1.5,1.6,1.7,1.8,2.0,2.1,2.2};
      float b[10] = {1.2,1.3,1.4,1.5,1.6,1.7,1.8,2.0,2.1,2.2};
      float c[10];
      element_mul_f32(a, b, c, 10);
      

      一次性处理10个元素,采用RVV向量的操作。

      普通的加法

      for(ii = 0; ii < 10; ii++)
      {
       d[ii] = a[ii] + b[ii];
      }
      

      单个元素相加。

      分别计算30000次。

      最后的结果如下:

      微信图片_20220114161719.png

      采用向量加法只需要7ms,而直接相加,则消耗了36ms,性能相差5倍左右。

      浮点数相乘

      与加法操作类似,也是一次性处理10个元素

      float a[10] = {1.2,1.3,1.4,1.5,1.6,1.7,1.8,2.0,2.1,2.2};
      float b[10] = {1.2,1.3,1.4,1.5,1.6,1.7,1.8,2.0,2.1,2.2};
      float c[10];
      element_mul_f32(a, b, c, 10);
      

      普通的乘法

      for(ii = 0; ii < 10; ii++)
      {
       d[ii] = a[ii] * b[ii];
      }
      

      两者性能对比
      微信图片_20220114161725.jpg
      向量乘法也比普通的乘法性能强大一些,接近5倍的差别。

      内存拷贝

      内存拷贝的测试方法是测试rt_memcpy,memcpy,csi_c906_memcpy。分别代表rt-thread内置的内存拷贝函数,采用C语言进行实现,memcpy是newlib库函数的实现,里面会对riscv架构进行优化处理,csi_c906_memcpy则是采用向量操作,进行内存拷贝。

      测试是先申请1MB的目标内存,1MB的源内存,往源内存中写随机数。

      拷贝源内存中的数据到目标内存,拷贝100次,也就是100M的内存拷贝数据量。

      结果如下:

      微信图片_20220114161736.jpg

      显然,内存拷贝操作newlib中的memcpy性能是最佳的,而向量操作的memcpy反而其次,最差的是rt-thread的rt_memcpy。这里的原因是newlib的memcpy的是经过优化后的,而vector memcpy也可能是优化的不好导致性能与newlib的memcpy相当。rt-thread采用纯C语言实现,其通用性比较好,但是性能不佳。

      RVV在RTOS如何使用的更好

      这是一个关于更好的在RTOS上使用RVV的问题,由于RTOS是为了追求实时性,一般来说,开启了FPU和RVV后,其寄存器的数量会非常的多,每次入栈和出栈的操作,如果每次都将全部的寄存器压入和弹出,将会让切换任务的时间变长,影响了系统的实时性。对于这种情况,其实可以利用mstatus中的VS和FS的标志位进行判断。

      微信图片_20220114161747.jpg
      微信图片_20220114161741.png

      在切换任务时,可以通过这些标识,选择是否压栈和出栈,这样保证了一部分性能实时性的情况下,也可以很好的处理FPU和RVV。

      发布在 MR Series
      Y
      giao
    • 嘉楠K510芯片datasheet

      嘉楠K510终于出来了,双核RISC-V,音视频啥都有,看着还不错

      B1C2A36A-C957-4fc1-BC42-542693678588.png

      datasheet下载:
      K510_Full Datasheet.pdf

      发布在 灌水区
      Y
      giao
    • 1 / 1