导航

    全志在线开发者论坛

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

    q1215200171 发布的帖子

    • 回复: 【素材汇总】D1开发板图片素材汇总

      @bedrock 😎

      发布在 公告
      q1215200171
      budbool
    • 回复: 【素材汇总】D1开发板图片素材汇总

      D1H计算条.png

      发布在 公告
      q1215200171
      budbool
    • 回复: 【素材汇总】D1开发板图片素材汇总

      哪吒D1H.jpg

      发布在 公告
      q1215200171
      budbool
    • 回复: 【素材汇总】D1开发板图片素材汇总

      D1HH.png
      D1H哪吒.png

      发布在 公告
      q1215200171
      budbool
    • 回复: 【芯片型号变更公告】D1芯片型号变更为D1-H

      D1H哪吒.png D1HH.png

      发布在 公告
      q1215200171
      budbool
    • 回复: 【素材汇总】D1开发板图片素材汇总

      D1H哪吒.png

      发布在 公告
      q1215200171
      budbool
    • 【全志&OpenHarmony】全志两款支持OpenHarmony开发板在开放原子开源基金会OpenHarmony见面会实况分享

      2021年12月28日,OpenAtom OpenHarmony开源见面会首站在江苏南京圆满举行。本次活动为OpenHarmony城市和高校全年巡回活动的首发站,以“融合行业需求,夯实关键技术”为主题,精彩呈现OpenHarmony 2021年度的共建成果及未来发展规划。

      mmexportc9903db9a2f0e00fbfae09463b8d176e_1640659967765.jpeg

      本次会议特别设立了Dev-Board-SIG分论坛,各家共建单位详尽阐述了OpenHarmony开发板目前的开发概况和未来规划。目前,在众家共建单位的努力下,小组已经有40余块开发板完成或计划完成基于OpenHarmony 3.0 LTS版本的移植适配工作,给OpenHarmony主线代码演进提供了源源不断的硬件基础。

      全志也在本次见面会的Dev-Board-SIG分论坛上展出了两款支持OpenHarmony的开发板,分别为哪吒D1开发板、XR806开源鸿蒙开发板,除了本次大会上展出的开发板,全志T507等多个芯片平台的开发版也在适配OpenHarmony系统。

      1640675603462.jpg

      哪吒D1开发板

      目前,主干代码里已经支持部分友商的芯片,计划在2022年支持ARM、MIPS、RISC-V等构架及多数主流芯片,全志D1也在即将支持的RISC-V框架芯片范围之内。因为它的CPU是RISC-V架构的,使用的是阿里平头哥的C906核心。中科院软件所于佳耕团队和全志一同进行OpenHarmony系统的移植,并已经完成适配工作。作为全志在线基于全志D1芯片定制的AIoT开发板,是全球首款支持64bit RISC-V指令集并支持Linux系统的可量产开发板。可以应用于科研教学、产品项目预研、开发爱好者DIY等。

      1640675554611.jpg

      XR806开源鸿蒙开发板

      XR806开源鸿蒙开发板是在Dev-Board-SIG开发板展区展出的第二块全志的板子,也是全志首款适配OpenHarmony系统的开发板,XR806开发板使用的是全志自研的XR806芯片,支持wifi和ble,可以应用于智能家居、工业控制等场景的无线互联,同时也使用的是Arm-Star ARMv8-M MCU,sip了ddr和flash。高集成度的特点,可以帮助我们的客户和开发者最大化地降低硬件设计的复杂度,降低bom成本。同时支持efuse和security,留给了开发者更大的软件开发和设计空间。目前,XR806开发板代码已经通过XTS认证合入主仓。
      仓库地址:https://gitee.com/moldy-potato-chips/devboard_device_allwinner_xr806

      千行百业加速数字化转型的当下,OpenHarmony将坚持”融合行业需求 夯实关键技术”的重要信念,全志也会持续输出优质产品,并进行OpenHarmony的适配工作,与开放原子开源基金会和众友商共建OpenHarmony繁荣生态,共享共赢新未来。

      发布在 公告
      q1215200171
      budbool
    • XR806开发板驱动6轴MPU6050 陀螺仪+加速度计及数据上传至上位机

      一.开发环境

      • ubuntu16.04虚拟机
      • MPU6050陀螺仪
      • 匿名上位机

      二.软件

      (1).I2C引脚
      使用Xr806硬件I2C,需要在文件夹找到“/home/a/xr806_openharmony/device/xradio/xr806/xr_skylark/project/common/board/xr806_OHOS/borad_config.c"板级配置文件,可以看到共有两个I2C端口可用,i2c0和i2c1,这里是使用i2c0,引脚为A12,A13,复用通道F9。找好端口号,插上MPU6050。
      3756531D-12EC-414d-A435-24D2DA3B0F13.png

      (2).12C协议
      鸿蒙已自带多种I2C协议,MPU6050需要写寄存器地址,必须选用能写HAL_I2C_Master_Transmit_Mem_IT()函数,写寄存器大小设为8位,但是连续写协议,发送数据长度设为1。

      (3).上位机协议

      1:在调试过程中可以将某些标志位、寄存器、变量实时发回上位机,并在DEBUG页面显示。
      2:通讯格式为:0x88 + 0xAD + len + num + DATA + SUM,  len为num与DATA的总长度,num表示要改变哪个显示
            状态,例如num=0x01即是要改变第一个LED,num=0x07即是改变第一个数字输出显示。当要改变LED时,
            DATA只需一字节,DATA=0x00表示关闭LED,大于0x00表示点亮LED;当要改变数字输出时,DATA需要两字
      节,
            表示 一个uint16数字,高字节在前。SUM为从0x88开始到SUM前一字节的和校验,uint8格式。
            例如:发送 0x88 + 0xAD + 0x02 + 0x01 + 0x01 + 0x39    表示点亮第一个LED
                        发送 0x88 + 0xAD + 0x03 + 0x07 + 0x00 + 0x05 + 0x44   表示在第一个数字输出位置显示 5 。
      

      3.源码

      #include <stdio.h>
      #include "ohos_init.h"
      #include "kernel/os/os.h"
      #include "/home/zfy/xr806_openharmony/base/iot_hardware/peripheral/interfaces/kits/iot_gpio.h"                                                           //(8)
      #include "driver/chip/hal_i2c.h"
      static OS_Thread_t g_main_thread,g_main_thread2;
      
      
      #define GPIO_ID_PA21 21
      
      #define I2C_SPEED (200000)
      
      
      
      
      #define    SMPLRT_DIV        0x19    
      #define    CONFIG            0x1A    
      #define    GYRO_CONFIG        0x1B    
      #define    ACCEL_CONFIG    0x1C    
      #define    ACCEL_XOUT_H    0x3B
      #define    ACCEL_XOUT_L    0x3C
      #define    ACCEL_YOUT_H    0x3D
      #define    ACCEL_YOUT_L    0x3E
      #define    ACCEL_ZOUT_H    0x3F
      #define    ACCEL_ZOUT_L    0x40
      #define    TEMP_OUT_H        0x41
      #define    TEMP_OUT_L        0x42
      #define    GYRO_XOUT_H        0x43
      #define    GYRO_XOUT_L        0x44    
      #define    GYRO_YOUT_H        0x45
      #define    GYRO_YOUT_L        0x46
      #define    GYRO_ZOUT_H        0x47
      #define    GYRO_ZOUT_L        0x48
      #define    PWR_MGMT_1        0x6B    
      #define    WHO_AM_I            0x75    
      #define    SlaveAddress    0x68    
      
      unsigned int i2c_id = 0;
      
      void mpu6050_send_data(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz,short p,short r,short y)
      {
           char str_buff[5];
           
           
           unsigned char head_buff[]={0x88,0xAF,0x1C};
           unsigned char end_buff[]={0x00,0x00,0x00,0x00};
           unsigned char check_sum[1]={0};
           unsigned char data[24];
           check_sum[0]+=0x88+0xAF+0x1C;
           
           data[0]=aacx>>8&0xFF;
           data[1]=aacx&0xFF;
           data[2]=aacy>>8&0xFF;
           data[3]=aacy&0xFF;
           data[4]=aacz>>8&0xFF;
           data[5]=aacz&0xFF;
           
           
           data[6]=gyrox>>8&0xFF;
           data[7]=gyrox&0xFF;
           data[8]=gyroy>>8&0xFF;
           data[9]=gyroy&0xFF;
           data[10]=gyroz>>8&0xFF;
           data[11]=gyroz&0xFF;
           
           data[12]=0;
           data[13]=0;
           data[14]=0;
           data[15]=0;
           data[16]=0;
           data[17]=0;
           
           
           data[18]=r>>8&0xFF;
           data[19]=r&0xFF;
           data[20]=p>>8&0xFF;
           data[21]=p;
           data[22]=y>>8&0xFF;
           data[23]=y&0xFF;
           
           
           int i=0;
           for(i=0;i<24;i++){
           check_sum[0]+=data[i]; 
           } 
      
          //  printf("%s",head_buff);
          //  printf("%s",data);
          //  printf("%s",end_buff);
          //  printf("%s",check_sum);
      
          for(int i=0;i<3;i++){ printf("%c",head_buff[i]);}
          for(int i=0;i<24;i++){ printf("%c",data[i]);}
          for(int i=0;i<4;i++){ printf("%c",end_buff[i]);}
          for(int i=0;i<1;i++){ printf("%c",check_sum[i]);}
      
      
          
          //uart_send_str(data,24);
          
           
      }    
      
      short Acc[3],Gyro[3];
      
      void GetData(unsigned char REG_Address,short data[3])
      {
          unsigned char H[1]={0},L[1]={0};
          
          //HAL_I2C_Master_Receive_Mem_IT(i2c_id, SlaveAddress, REG_Address+1, I2C_MEMADDR_SIZE_16BIT, L, 1);
          //return ((int)(H[0]<<8)+L[0]);
          for(int i=0;i<3;i++){
              HAL_I2C_Master_Receive_Mem_IT(i2c_id, SlaveAddress, REG_Address+(i*2), I2C_MEMADDR_SIZE_8BIT, H, 1);
              HAL_I2C_Master_Receive_Mem_IT(i2c_id, SlaveAddress, REG_Address+(i*2+1), I2C_MEMADDR_SIZE_8BIT, L, 1);
            
             data[i]=(( short)(H[0]<<8))|L[0];
          }
      
      }
      
      
      
      
      static void MainThread2(void *arg)                                               
      {
        printf("LED test start\r\n");
        IoTGpioInit(GPIO_ID_PA21);                                                   
        IoTGpioSetDir(GPIO_ID_PA21, IOT_GPIO_DIR_OUT);   
      
      
      
          
          IoTI2cInit(i2c_id,I2C_SPEED);
          const unsigned char data[]={0x00};
          const unsigned char data1[]={0x07};
          const unsigned char data2[]={0x06};
          const unsigned char data3[]={0x18};
          const unsigned char data4[]={0x01};
      
          printf("i2c test start\r\n");
          int a=HAL_I2C_Master_Transmit_Mem_IT(i2c_id, SlaveAddress, PWR_MGMT_1, I2C_MEMADDR_SIZE_8BIT, data, 1);
          HAL_I2C_Master_Transmit_Mem_IT(i2c_id, SlaveAddress, PWR_MGMT_1, I2C_MEMADDR_SIZE_8BIT, data1, 1);
          OS_MSleep(1);
          HAL_I2C_Master_Transmit_Mem_IT(i2c_id, SlaveAddress, SMPLRT_DIV, I2C_MEMADDR_SIZE_8BIT, data2, 1);
          OS_MSleep(1);
          HAL_I2C_Master_Transmit_Mem_IT(i2c_id, SlaveAddress, GYRO_CONFIG, I2C_MEMADDR_SIZE_8BIT, data3, 1);
          OS_MSleep(1);
          HAL_I2C_Master_Transmit_Mem_IT(i2c_id, SlaveAddress, ACCEL_CONFIG, I2C_MEMADDR_SIZE_8BIT, data4, 1);
          OS_MSleep(1);
      
      
        while (1) {
              IoTGpioSetOutputVal(GPIO_ID_PA21, 1); 
              OS_MSleep(10);
              IoTGpioSetOutputVal(GPIO_ID_PA21, 0);    
              OS_MSleep(10);  
              GetData(ACCEL_XOUT_H,Acc);
              GetData(GYRO_XOUT_H,Gyro);
              GetData(GYRO_XOUT_H,Gyro);
              mpu6050_send_data(Acc[0],Acc[1],Acc[2],Gyro[0],Gyro[1],Gyro[2],0,0,0);
      
              
                                          
        }
        
      }
      void LEDMain(void)                                                            
      {
        printf("LED Test Start\n");
      
      
       if (OS_ThreadCreate(&g_main_thread2, "MainThread2", MainThread2, NULL,
                      OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) {
              printf("[ERR] Create MainThread Failed\n");
          }
      }
      
      
      
      
      
      
      
      
      static void MainThread(void *arg)
      {int i=0;
      
          while (1) {
              printf("hello world:%d\n",i);
              LOS_Msleep(1000);
              
              i++;
          }
      }
      
      void HelloTestMain(void)
      {
          printf("Wifi Test Start\n");
      
          if (OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL,
                      OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) {
              printf("[ERR] Create MainThread Failed\n");
          }
      }
      
      
      
      //SYS_RUN(HelloTestMain);
      SYS_RUN(LEDMain);
      

      三、效果

      CF30071D-C03F-4a97-B305-1B891FD1574D.png

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

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 【FAQ】全志D1芯片FAQ汇总(你不知道的和你想知道的的这里都有)

      01、【FAQ】全志D1芯片 如何解决Audiocodec使用S24_LE格式进行录音,软件分析波形异常的问题?
      02、【FAQ】全志D1芯片 如何在 Linux Device Tree 中配置预留内存?
      03、【FAQ】全志D1芯片 如何解决Gstreamer播放1080视频显示异常问题(重影)?
      04、【FAQ】全志D1芯片 如何对D1主频进行调节?
      05、【FAQ】全志D1芯片 如何解决Gstreamer:fb UI旋转(直接修改内核参数)后,sunxifbsink显示异常问题?
      06、【FAQ】全志D1芯片 Tina 如何查看通过 procd init 脚本启动的应用输出到 stdout/stderr 的打印信息?
      07、【FAQ】全志D1芯片 如何移植 rtl8821cu wifi 驱动到 Linux-5.4内核?
      08、【FAQ】全志D1芯片 XR829扫卡失败问题排查
      09、【FAQ】全志D1芯片 mp4(Xvid)视频文件播放花屏问题
      10、【FAQ】全志D1芯片 如何解决在创建视频解码器后,未送入视频帧数据之前,cpu被占满的问题?
      11、【FAQ】全志D1芯片 如何在休眠唤醒过程中通过-sunxi_dump-读写外设寄存器?
      12、【FAQ】全志D1芯片 minigui如何显示鼠标?
      13、【FAQ】全志D1芯片 uart测试用例(支持自发自收,板间收发,数据校验,收发时间统计)
      14、【FAQ】全志D1芯片 如何在tina使用tplayerdemo 进行rtsp拉流说明?
      15、【FAQ】全志全系列芯片 APST平台无法下载或者更新工具
      16、【FAQ】全志 F系列/R系列/V系列 RTOS平台cache操作接口介绍
      17、【FAQ】全志系列芯片如何把flash擦成空片?
      18、【FAQ】持续更新......

      发布在 MR Series
      q1215200171
      budbool
    • 回复: R329语音识别视频教程,从编译到部署,完全可用

      @hu_710774265 其实我也没有😀 只能到sipeed那买 https://item.taobao.com/item.htm?spm=a230r.1.14.24.5d6170a1IJNADK&id=652879327858&ns=1&abbucket=20#detail

      发布在 A Series
      q1215200171
      budbool
    • 回复: R329语音识别视频教程,从编译到部署,完全可用

      @hu_710774265 有吸引到就玩起来😁

      发布在 A Series
      q1215200171
      budbool
    • 回复: 【资料释放】全志XR806开发板全资料释放,连bomlist都给出来了

      @allzhi 已更新,谢谢

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 【XR806开发板试用】TCP通信测试 && Ping 命令测试

      1.工程准备
      由于要使用wifi功能,直接从wlan_demo复制一份出来,然后修改。
      源文件只留下 main.c 就可以了。

      BUILD.gn文件

      import("//device/xradio/xr806/liteos_m/config.gni")
      
      static_library("app_mying") {
         configs = []
      
         sources = [
            "main.c",
         ]
      
         cflags = board_cflags
      
         include_dirs = board_include_dirs
         include_dirs += [
              "//kernel/liteos_m/kernel/arch/include",
              "//utils/native/lite/include",
              "//foundation/communication/wifi_lite/interfaces/wifiservice",
         ]
      }
      

      2. XR806 SDK
      仔细看下xr806工程库的结构,
      xr806的xr_skylark路径下属于芯片原生驱动库!
      该路径下面有各种功能参考示例,如trustzone、net、ping、json等。
      因此,直接参考xr_skylark\include下的内容,来实现一些简单的功能。
      234337DD-F6B5-4426-9972-3A91F9CB9C64.png

      3.实现的功能

      0)连接WiFi;
      根据自己的SSID和PSK修改,代码直接copy原来的。

      1)ping服务器,进行联通性测试;
      ping一下自己的服务器,根据需要进行修改。

      include下面有ping/ping.h文件。很简单的一个结构体(如下所示),看情况就是给个地址,设置一下参数,然后就可以实现ping命令的功能了。

      struct ping_data {
          ip_addr_t sin_addr; /* server addr */
      
          u32_t count;        /* number of ping */
          u32_t data_long;    /* the ping packet data long */
          u32_t interval;     /* Wait interval seconds between sending each packet, default 1s */
          u32_t timeout;      /* Time to wait for a response, in seconds */
          u32_t deadline;     /* Specify a timeout, in seconds, ping thread will stop if timeout */
          u32_t ttl;          /* ttl ping only. Set the IP Time to Live. */
      
          int run_flag;       /* run flag, 0:stop 1:start */
      ![CB84C5B5-489A-4f24-BD4D-67909D582B90.png](/assets/uploads/files/1640308813559-cb84c5b5-489a-4f24-bd4d-67909d582b90.png) };
      
      s32_t ping(struct ping_data *data);
      

      2)作为TCP客户端,连接server,发数据;
      通过TCP连接服务器,发数据。
      设置服务器信息
      【地址】(比如:192.168.1.100)
      【端口号】(比如5679)
      net路径下面有lwip库,借此实现网络通信功能。

      代码里,通过宏定义的方式,将lwip_xxx改成了与linux下的soket API一样的接口。
      参考正常的TCP_Client程序就行了。
      CB84C5B5-489A-4f24-BD4D-67909D582B90.png

      3)读取一下xr_skylark里的cjson版本信息。
      发现有cjson库,然后就随便测试一下。

      4.程序示例

      #include <stdio.h>
      #include <string.h>
      #include <stdlib.h>
      #include "ohos_init.h"
      #include "driver/chip/hal_gpio.h"
      #include "kernel/os/os.h"
      #include "wifi_device.h"
      #include "cjson/cJSON.h"
      #include "net/ping/ping.h"
      #include "net/lwip-2.1.2/lwip/sockets.h"
      #include "net/lwip-2.1.2/lwip/tcp.h"
      #include "net/lwip-2.1.2/lwip/inet.h"
      #include "net/lwip-2.1.2/lwip/ip_addr.h"
      
      #define WIFI_DEVICE_CONNECT_AP_SSID "ChinaNet-111"
      #define WIFI_DEVICE_CONNECT_AP_PSK "111666111"
      
      #define GPIO_OUTPUT_PORT           GPIO_PORT_A
      
      static OS_Thread_t g_main_thread;
      
      static void gpio_output_init(void)
      {
          GPIO_InitParam param;
          param.driving = GPIO_DRIVING_LEVEL_1;
          param.mode = GPIOx_Pn_F1_OUTPUT;
          param.pull = GPIO_PULL_NONE;
          HAL_GPIO_Init(GPIO_OUTPUT_PORT, GPIO_PIN_21, &param);//led灯对应IO
      }
      
      static void gpio_output_ctl(uint8_t level)
      {
          HAL_GPIO_WritePin(GPIO_OUTPUT_PORT, GPIO_PIN_21, level ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
      }
      
      
      void wifi_connect(void)
      {
          const char ssid_want_connect[] = WIFI_DEVICE_CONNECT_AP_SSID;
          const char psk[] = WIFI_DEVICE_CONNECT_AP_PSK;
      
          printf("\n=========== Connect Test Start ===========\n");
      
          if (WIFI_SUCCESS != EnableWifi()) {
              printf("Error: EnableWifi fail.\n");
              return;
          }
          printf("EnableWifi Success.\n");
      
          if (WIFI_STA_ACTIVE == IsWifiActive())
              printf("Wifi is active.\n");
      
          OS_Sleep(1);
      
          if (WIFI_SUCCESS != Scan()) {
              printf("Error: Scan fail.\n");
              return;
          }
          printf("Wifi Scan Success.\n");
      
          OS_Sleep(1);
      
          WifiScanInfo scan_results[30];
          unsigned int scan_num = 30;
      
          if (WIFI_SUCCESS != GetScanInfoList(scan_results, &scan_num)) {
              printf("Error: GetScanInfoList fail.\n");
              return;
          }
      
          WifiDeviceConfig config = { 0 };
          int netId = 0;
      
          int i;
          for (i = 0; i < scan_num; i++) {
              if (0 == strcmp(scan_results[i].ssid, ssid_want_connect)) {
                  memcpy(config.ssid, scan_results[i].ssid,
                         WIFI_MAX_SSID_LEN);
                  memcpy(config.bssid, scan_results[i].bssid,
                         WIFI_MAC_LEN);
                  strcpy(config.preSharedKey, psk);
                  config.securityType = scan_results[i].securityType;
                  config.wapiPskType = WIFI_PSK_TYPE_ASCII;
                  config.freq = scan_results[i].frequency;
                  break;
              }
          }
      
          if (i >= scan_num) {
              printf("Error: No found ssid in scan_results\n");
              return;
          }
          printf("GetScanInfoList Success.\n");
      
          if (WIFI_SUCCESS != AddDeviceConfig(&config, &netId)) {
              printf("Error: AddDeviceConfig Fail\n");
              return;
          }
          printf("AddDeviceConfig Success.\n");
      
          if (WIFI_SUCCESS != ConnectTo(netId)) {
              printf("Error: ConnectTo Fail\n");
              return;
          }
          printf("ConnectTo Success\n");
      
          OS_Sleep(3);
      
          WifiLinkedInfo get_linked_res;
      
          if (WIFI_SUCCESS != GetLinkedInfo(&get_linked_res)) {
              printf("Error: GetLinkedInfo Fail\n");
              return;
          }
          printf("GetLinkedInfo Success.\n");
      
          printf("ssid: %s\n", get_linked_res.ssid);
          printf("bssid: ");
          for (int j = 0; j < WIFI_MAC_LEN; j++) {
              printf("%02X", get_linked_res.bssid[j]);
          }
          printf("\n");
          printf("rssi: %d\n", get_linked_res.rssi);
      
          unsigned char get_mac_res[WIFI_MAC_LEN];
      
          if (WIFI_SUCCESS != GetDeviceMacAddress(get_mac_res)) {
              printf("Error: GetDeviceMacAddress Fail\n");
              return;
          }
          printf("GetDeviceMacAddress Success.\n");
          for (int j = 0; j < WIFI_MAC_LEN - 1; j++) {
              printf("%02X:", get_mac_res[j]);
          }
          printf("%02X\n", get_mac_res[WIFI_MAC_LEN - 1]);
      }
      struct ping_data ping_t;
      //ping命令参数设置
      void ping_init()
      {
          ip_addr_t server_ip;
          inet_aton("129.204.63.27", &server_ip);
          ping_t.sin_addr = server_ip;
          ping_t.count = 0xF;
          ping_t.data_long = 512;
          ping_t.timeout = 30;
          ping_t.run_flag = 1;
      }
      
      //TCP SOCKET
      int s;
      void tcp_test_init()
      {
      //socket create!
          s  = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
      
      //address info!
          struct sockaddr_in server_addr;
      
          memset(&server_addr, 0, sizeof(server_addr));
      
          server_addr.sin_family = AF_INET;
          server_addr.sin_port = htons(5679);
          inet_pton(AF_INET, "192.168.1.100", &server_addr.sin_addr);
      
      //connect!
          if(connect(s,(void *)&server_addr,sizeof(server_addr)) < 0) {
              printf("connect tcp_server failed! \r\n");
          } else {
              printf("connect tcp_server successfuly! \r\n");
          }
      // send data
          send(s, "xr806\n", 7, 0);
      }
      static void MainThread(void *arg)
      {
          gpio_output_init();
          wifi_connect();
          ping_init();
          ping(&ping_t);
      
          tcp_test_init();
          char buf[32];
          int cnt = 0;
          while(1) {
              sprintf(buf,"XR806:%s : %d \r\n",cJSON_Version(), cnt++);
              //向服务器发送数据
              send(s,buf, sizeof(buf), 0);
              printf("%s:Hello XR806 \r\n",__func__);
              
              gpio_output_ctl(1);
              OS_Sleep(1);
              gpio_output_ctl(0);
              OS_Sleep(1);
          }
      }
      
      void WifiTestMain(void)
      {
          printf("Wifi Test Start\r\n");
      
          if (OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL,
                              OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) {
              printf("[ERR] Create MainThread Failed\n");
          }
      }
      
      SYS_RUN(WifiTestMain);
      

      5.结果展示
      通过网络调试工具,建立TCP服务器,接收到了xr806发来的数据。

      D91C2B61-5E2E-4a60-92A2-8D51C581D798.png
      串口打印信息

      [net INF] netif (IPv4) is up
      [net INF] address: 192.168.1.110
      [net INF] gateway: 192.168.1.1
      [net INF] netmask: 255.255.255.0
      [net INF] msg <network IPv6 state>
      GetLinkedInfo Success.
      ssid: ChinaNet-111
      bssid: 5475956E3374
      rssi: 110
      GetDeviceMacAddress Success.
      9C:9E:49:BA:5B:01
      PING 129.204.63.27 520 bytes of data.
      Request timeout for icmp_seq=1
      512 bytes from 129.204.63.27: icmp_seq=2    time=43 ms
      512 bytes from 129.204.63.27: icmp_seq=3    time=43 ms
      512 bytes from 129.204.63.27: icmp_seq=4    time=44 ms
      512 bytes from 129.204.63.27: icmp_seq=5    time=43 ms
      512 bytes from 129.204.63.27: icmp_seq=6    time=45 ms
      512 bytes from 129.204.63.27: icmp_seq=7    time=46 ms
      512 bytes from 129.204.63.27: icmp_seq=8    time=44 ms
      512 bytes from 129.204.63.27: icmp_seq=9    time=44 ms
      512 bytes from 129.204.63.27: icmp_seq=10    time=44 ms
      512 bytes from 129.204.63.27: icmp_seq=11    time=44 ms
      512 bytes from 129.204.63.27: icmp_seq=12    time=44 ms
      512 bytes from 129.204.63.27: icmp_seq=13    time=44 ms
      512 bytes from 129.204.63.27: icmp_seq=14    time=44 ms
      512 bytes from 129.204.63.27: icmp_seq=15    time=43 ms
      
      --- 129.204.63.27 ping statistics ---
      15 packets transmitted, 14 received, 6% packet loss, time 672ms
      rtt min/avg/max/mdev = 43/43/46/3 ms
      connect tcp_server successfuly! 
      MainThread:Hello XR806 
      MainThread:Hello XR806
      

      文章转自极术社区:https://aijishu.com/a/1060000000286996
      作者:Pingyang @Pingyang

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 回复: 【FAQ】全志XR806芯片FAQ汇总(你不知道的和你想知道的的这里都有)

      全志在线官方QQ群:498263967,欢迎每一位小伙伴进来吹水

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 回复: 小巧精湛!基于D1s的全开源芒果派-哪吒MQ正式开售!

      芒果派麻雀到手试玩记录贴

      发布在 MR Series
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      Sipeed Lichee RV 86 Panel 智能家居 中控开发板 支持Linux WAFT

      发布在 公告
      q1215200171
      budbool
    • 回复: 请提供一个WSL能用的mkimage,谢谢

      @cszzlsw 是没有这个的

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 【XR806开发板试用】通过MQTT实现手机远程实现PWM控灯

      一、例程编译、烧录确认
      首先按照全志在线文档平台的点灯教程确保能正常编译、烧录和点灯:https://xr806.docs.aw-ol.com/...
      确保例程没问题后,我们再改造例程,实现我们想要的功能

      二、代码编写
      我们将led工程复制一份改文件夹名为mydemo,目录结构如下

      mydemo
          ├── BUILD.gn
          └── src
          └── main.c
      

      然后BUILD.gn内容增加头文件引用,部分配置如下:

      static_library("app_mydemo") {
      ...
      include_dirs += [
            "//kernel/liteos_m/kernel/arch/include",
            "//base/iot_hardware/peripheral/interfaces/kits",
      
            ".",
            "//utils/native/lite/include",
            "//foundation/communication/wifi_lite/interfaces/wifiservice",
            "//device/xradio/xr806/xr_skylark/project"
         ]
      }
      

      接下来是main.c,内容如下:

      #include <stdio.h>
      #include <string.h>
      #include "ohos_init.h"
      #include "kernel/os/os.h"
      
      #include "iot_gpio.h"
      #include "wifi_device.h"
      #include "common/framework/net_ctrl.h"
      #include "net/mqtt/MQTTClient-C/MQTTClient.h"
      #include "driver/chip/hal_pwm.h"
      
      static OS_Thread_t g_main_thread;
      static OS_Thread_t g_mqtt_thread;
      
      #define PWM_OUTPUT_CHL        PWM_GROUP1_CH2
      #define PWM_OUTPUT_MODE       PWM_CYCLE_MODE
      
      #define WIFI_DEVICE_CONNECT_AP_SSID "ssid"//这里填你家路由器的SSID
      #define WIFI_DEVICE_CONNECT_AP_PSK "pwm"//这里填你家路由器的PWD
      
      
      #define MQTT_DEMO_CLIENT_ID "12345"
      #define MQTT_DEMO_HOST_NAME "broker-cn.emqx.io"//这个是免费调试用的MQTT服务器地址
      #define MQTT_DEMO_PORT      "1883"
      #define MQTT_DEMO_USERNAME  "12345678"
      #define MQTT_DEMO_PASSWORD  "12345678"
      #define MQTT_RESP_TOPIC "/to/master/light" //手机发出来的TOPIC
      #define MQTT_RECV_TOPIC  "/to/slave/light" //设备发出来的TOPIC
      #define MQTT_DEMO_BUF_SIZE (2*1024)
      
      static MQTTPacket_connectData mqtt_demo_connectData = MQTTPacket_connectData_initializer;
      static Client mqtt_demo_client;
      static Network mqtt_demo_network;
      static int max_duty_ratio = 0;
      
      static int mqtt_demo_publish(char *topic, char *msg) ;
      
      static int mqtt_demo_init(void) {
          char *send_buf;
          char *recv_buf;
      
          mqtt_demo_connectData.clientID.cstring = MQTT_DEMO_CLIENT_ID;
          mqtt_demo_connectData.keepAliveInterval = 30; // 30s
          mqtt_demo_connectData.cleansession = 0;
          mqtt_demo_connectData.MQTTVersion = 4; //Version of MQTT 3.1.1
      
          send_buf = malloc(MQTT_DEMO_BUF_SIZE);
          if (send_buf == NULL) {
              printf("no memory\n");
              return -1;
          }
          recv_buf = malloc(MQTT_DEMO_BUF_SIZE);
          if (recv_buf == NULL) {
              free(send_buf);
              printf("no memory\n");
              return -1;
          }
      
          /* init network */
          NewNetwork(&mqtt_demo_network);
          /* init mqtt client object */
          MQTTClient(&mqtt_demo_client, &mqtt_demo_network, 6000,
                     (unsigned char *)send_buf, MQTT_DEMO_BUF_SIZE,
                     (unsigned char *)recv_buf, MQTT_DEMO_BUF_SIZE);
      
          /* set username and password */
          mqtt_demo_connectData.username.cstring = MQTT_DEMO_USERNAME;
          mqtt_demo_connectData.password.cstring = MQTT_DEMO_PASSWORD;
          return 0;
      }
      
      static int mqtt_demo_connect(char *host_name, char *host_port) {
          int ret = -1;
      
          ret = ConnectNetwork(&mqtt_demo_network, host_name, atoi(host_port));
          if (ret != 0) {
              printf("mqtt connect faild, ret:%d, host:%s, port:%s\n", ret, host_name, host_port);
              goto exit;
          }
      
          ret = MQTTConnect(&mqtt_demo_client, &mqtt_demo_connectData);
          if (ret != 0) {
              printf("mqtt connect faild, ret:%d\n", ret);
              mqtt_demo_network.disconnect(&mqtt_demo_network);
              goto exit;
          }
          printf("mqtt connected\n");
      exit:
          return ret;
      }
      
      static void mqtt_demo_msg_cb(MessageData *data) {
          printf("get a message, topic: %.*s, msg: %.*s\n", data->topicName->lenstring.len,
                 data->topicName->lenstring.data, data->message->payloadlen,
                 (char *)data->message->payload);
          if(!strncmp(data->topicName->lenstring.data, "/to/slave/light", 15) && data->message->payloadlen) {
              char *payload = data->message->payload;
              char str[8] = "";
              int max_len = data->message->payloadlen > 3 ? 3 : data->message->payloadlen;
              strncpy(str, payload, max_len);
              int duty = atoi(str);
              HAL_Status status = HAL_PWM_ChSetDutyRatio(PWM_OUTPUT_CHL, duty * max_duty_ratio / 100);
              if (status != HAL_OK)
                  printf("%s(): %d, PWM set duty ratio error\n", __func__, __LINE__);
              
              if(duty) {
                  mqtt_demo_publish(MQTT_RESP_TOPIC, "light on");
              } else {
                  mqtt_demo_publish(MQTT_RESP_TOPIC, "light off");
              }
          } 
      }
      
      static int mqtt_demo_subscribe(char *topic) {
          int ret = -1;
          if (mqtt_demo_client.isconnected) {
              ret = MQTTSubscribe(&mqtt_demo_client, topic, 0, mqtt_demo_msg_cb);
              if (ret != 0)
                  printf("mqtt subscribe faild ret:%d\n", ret);
          }
          return ret;
      }
      
      static int mqtt_demo_unsubscribe(char *topic) {
          int ret = -1;
          if (mqtt_demo_client.isconnected) {
              ret = MQTTUnsubscribe(&mqtt_demo_client, topic);
              if (ret != 0)
                  printf("mqtt unsubscribe faild, ret:%d\n", ret);
          }
          return ret;
      }
      
      static int mqtt_demo_publish(char *topic, char *msg) {
          int ret = -1;
      
          MQTTMessage message;
          memset(&message, 0, sizeof(message));
          message.qos = 0;
          message.retained = 0; /* disable retain the message in server */
          message.payload = msg;
          message.payloadlen = strlen(msg);
          ret = MQTTPublish(&mqtt_demo_client, topic, &message);
          if (ret != 0)
              printf("mqtt publish faild, ret:%d\n", ret);
          return ret;
      }
      
      static int mqtt_demo_disconnect(void) {
          int ret = -1;
      
          if (mqtt_demo_client.isconnected) {
              ret = MQTTDisconnect(&mqtt_demo_client);
              if (ret != 0)
                  printf("mqtt disconnect fail, ret:%d\n", ret);
              mqtt_demo_network.disconnect(&mqtt_demo_network);
          }
          return ret;
      }
      
      static void mqtt_demo_deinit(void) {
          if (mqtt_demo_client.buf) {
              free(mqtt_demo_client.buf);
              mqtt_demo_client.buf = NULL;
          }
          if (mqtt_demo_client.readbuf) {
              free(mqtt_demo_client.readbuf);
              mqtt_demo_client.readbuf = NULL;
          }
      }
      
      static void mqtt_task(void *arg)   {
          int ret;
          int reconnect_times = 0;
      
          mqtt_demo_init();
      
          ret = mqtt_demo_connect(MQTT_DEMO_HOST_NAME, MQTT_DEMO_PORT);
          if (ret != 0)
              goto exit;
      
          ret = mqtt_demo_subscribe(MQTT_RECV_TOPIC);
          if (ret != 0)
              goto exit;
      
          mqtt_demo_publish(MQTT_RESP_TOPIC, "light ready");
      
          while (1) {
              ret = MQTTYield(&mqtt_demo_client, 300);
              if (ret != 0) {
                  printf("mqtt yield err, ret:%d\n", ret);
      reconnect:
                  printf("mqtt reconnect\n");
                  mqtt_demo_disconnect();
                  ret = mqtt_demo_connect(MQTT_DEMO_HOST_NAME, MQTT_DEMO_PORT);
                  if (ret != 0) {
                      reconnect_times++;
                      if (reconnect_times > 5)
                          goto exit;
                      OS_MSleep(5000); //5s
                      goto reconnect;
                  }
              }
          }
      
      exit:
          mqtt_demo_unsubscribe(MQTT_RECV_TOPIC);
          mqtt_demo_disconnect();
          mqtt_demo_deinit();
          OS_ThreadDelete(&g_mqtt_thread);
      }
      
      static void net_cb(uint32_t event, uint32_t data, void *arg) {
          uint16_t type = EVENT_SUBTYPE(event);
          switch (type) {
          case NET_CTRL_MSG_NETWORK_UP:
              printf("NET_CTRL_MSG_NETWORK_UP\n");
              if (!OS_ThreadIsValid(&g_mqtt_thread)) {
                  OS_ThreadCreate(&g_mqtt_thread, "connect_to_server_task",
                                      mqtt_task, (void *)NULL,  OS_THREAD_PRIO_APP, (8 * 1024));
              }
              break;
          case NET_CTRL_MSG_NETWORK_DOWN:
              break;
          default:
              break;
          }
      }
      
      static void MainThread(void *arg)   {
          printf("MainThread start\r\n");
          HAL_Status status = HAL_ERROR;
          PWM_ClkParam clk_param;
          PWM_ChInitParam ch_param;
      
          clk_param.clk = PWM_CLK_HOSC;
          clk_param.div = PWM_SRC_CLK_DIV_1;
      
          status = HAL_PWM_GroupClkCfg(PWM_OUTPUT_CHL, &clk_param);
          if (status != HAL_OK)
              printf("%s(): %d, PWM group clk config error\n", __func__, __LINE__);
      
          ch_param.hz = 1000;
          ch_param.mode = PWM_OUTPUT_MODE;
          ch_param.polarity = PWM_HIGHLEVE;
          max_duty_ratio = HAL_PWM_ChInit(PWM_OUTPUT_CHL, &ch_param);
          if (max_duty_ratio == -1)
              printf("%s(): %d, PWM ch init error\n", __func__, __LINE__);
      
          printf("max_duty_ratio=%d\n", max_duty_ratio);
          status = HAL_PWM_ChSetDutyRatio(PWM_OUTPUT_CHL, 0);
          if (status != HAL_OK)
              printf("%s(): %d, PWM set duty ratio error\n", __func__, __LINE__);
      
          status = HAL_PWM_EnableCh(PWM_OUTPUT_CHL, PWM_OUTPUT_MODE, 1);
          if (status != HAL_OK)
              printf("%s(): %d, PWM ch enable error\n", __func__, __LINE__);
      
          if (WIFI_SUCCESS != EnableWifi()) {
              printf("Error: EnableWifi fail\n");
              return;
          }
      
          OS_Sleep(1);
      
          if (WIFI_SUCCESS != Scan()) {
              printf("Error: Scan fail.\n");
              return;
          }
      
          OS_Sleep(3);//这里为了方便用延时,实际用回调更好,否则3秒可能不够
      
          const char ssid_want_connect[] = WIFI_DEVICE_CONNECT_AP_SSID;
          const char psk[] = WIFI_DEVICE_CONNECT_AP_PSK;
          WifiScanInfo scan_results[30];
          unsigned int scan_num = 30;
      
          if (WIFI_SUCCESS != GetScanInfoList(scan_results, &scan_num)) {
              printf("Error: GetScanInfoList fail.\n");
              return;
          }
      
          WifiDeviceConfig config = { 0 };
          int netId = 0;
      
          int i;
          for (i = 0; i < scan_num; i++) {
              printf("ssid: %s    ", scan_results[i].ssid);
              printf("securityType: %d\n", scan_results[i].securityType);
              if (0 == strcmp(scan_results[i].ssid, ssid_want_connect)) {
                  memcpy(config.ssid, scan_results[i].ssid,
                         WIFI_MAX_SSID_LEN);
                  memcpy(config.bssid, scan_results[i].bssid,
                         WIFI_MAC_LEN);
                  strcpy(config.preSharedKey, psk);
                  config.securityType = scan_results[i].securityType;
                  config.wapiPskType = WIFI_PSK_TYPE_ASCII;
                  config.freq = scan_results[i].frequency;
                  break;
              }
          }
      
          if (i >= scan_num) {
              printf("Error: No found ssid in scan_results\n");
              return;
          }
      
          if (WIFI_SUCCESS != AddDeviceConfig(&config, &netId)) {
              printf("Error: AddDeviceConfig Fail\n");
              return;
          }
          printf("Config Success\n");
      
          if (WIFI_SUCCESS != ConnectTo(netId)) {
              printf("Error: ConnectTo Fail\n");
              return;
          }
          
          observer_base *net_ob;
          net_ob = sys_callback_observer_create(CTRL_MSG_TYPE_NETWORK, NET_CTRL_MSG_ALL, net_cb, NULL);
          if (net_ob == NULL)
              return;
      
          if (sys_ctrl_attach(net_ob) != 0)
              return;
      
          while (1) {
              OS_MSleep(500);
          }
      }
      
      void LEDMain(void) {
          if (OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL, OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) {
              printf("[ERR] Create MainThread Failed\n");
          }
      }
      
      SYS_RUN(LEDMain);
      

      三、配置上层的BUILD.gn,并编译
      部分内容如下:

      group("ohosdemo") {
          deps = [
              #"hello_demo:app_hello",
              #"iot_peripheral:app_peripheral",
              #"wlan_demo:app_WlanTest",
              "mydemo:app_mydemo",
          ]
      }
      

      然后执行hb build -f,编译成功(若编译失败见论坛有解决方案)
      然后烧录到开发板上

      四、运行实例
      烧录完成后,开发板重新上电,输出如下日志

      ====================================================================
          Hello! OpenHarmony!
          System tag : OpenHarmony 1.1.2_LTS
      ====================================================================
          
      use default flash chip mJedec 0x0
      [FD I]: mode: 0x10, freq: 96000000Hz, drv: 0
      [FD I]: jedec: 0x0, suspend_support: 1
      mode select:e
      
      wlan information ===================================================
      firmware:
          version : R0-XR_C07.08.52.65_02.84 May 27 2021 11:41:33-Y02.84 
          buffer  : 8
      driver:
          version : XR_V02.05
      mac address:
          in use        : 1c:98:c9:bc:50:01
          in use        : 1c:98:c9:bc:50:02
      ====================================================================
      
      wlan mode:a
      [VFS INF] LittleFS mount success.
      
      platform information ===============================================
      XR806 SDK v1.2.0  Dec 13 2021 13:06:05
      
      heap space [0x2238d0, 0x24bc00), size 164656
      
      cpu  clock 160000000 Hz
      HF   clock  40000000 Hz
      
      sdk option:
          XIP           : enable
          INT LF OSC    : enable
          SIP flash     : enable
      
      mac address:
          efuse         : 80:74:84:21:38:8e
          in use        : 1c:98:c9:bc:50:01
      ====================================================================
      
      hiview init success.MainThread start
      
      max_duty_ratio=40000
      
      
      console init success
      
      [net INF] no need to switch wlan mode 0
      [net INF] msg <wlan scan success>
      ssid: TP-LINK_A668    securityType: 2
      Config Success
      [net INF] no need to switch wlan mode 0
      en1: Trying to associate with a4:c7:4b:71:f9:84 (SSID='XXXXXX' freq=2462 MHz)
      en1: Associated with a4:c7:4b:71:f9:84
      en1: WPA: Key negotiation completed with a4:c7:4b:71:f9:84 [PTK=CCMP GTK=CCMP]
      en1: CTRL-EVENT-CONNECTED - Connection to a4:c7:4b:71:f9:84 completed [id=0 id_str=]
      [net INF] msg <wlan connected>
      [net INF] netif is link up
      [net INF] start DHCP...
      [net INF] IPv6 addr state change: 0x0 --> 0x1
      [net INF] msg <>
      [net INF] netif (IPv4) is up
      [net INF] address: 192.168.3.48
      [net INF] gateway: 192.168.3.1
      [net INF] netmask: 255.255.255.0
      [net INF] msg <network IPv6 state>
      NET_CTRL_MSG_NETWORK_UP
      WAR drop=1117, fctl=0x00d0.
      mqtt connected
      get a message, topic: /to/slave/light, msg: 0
      

      可以看到,开发板成功连接路由器,并接入了MQTT服务器

      五、手机测试
      本人的手机是Iphone,也不会手机APP开发,于是我们下载了一个叫MQTTTool的第三方APP验证点灯,其界面如下:

      2437004155-61b749d3dd687.png

      Host和Port填对,由于是免费开放的MQTT服务器,其他参数任意,设置好以后点Connect即可连接上MQTT服务器。然后底部切换至Subscribe栏,订阅主题:

      2879423047-61b74a76db2c0.png

      若手机比设备先连接服务器并订阅相关主题,那么你会在订阅栏收到topic为/to/master/light的消息:light ready,这是因为设备连上服务器就会发布该topic。
      接下来是发布主题,我们往/to/slave/light主题发送一个0~100的数字,就会让设备以这个数字为占空比控制LED灯亮灭,如0表示灭灯,50表示50%的占空比驱动LED灯,100表示100%的占空比驱动LED灯。同时设备收到LED控制指令后,若占空比不为0,则发送消息light on,否则发送消息light off
      3483115163-61b74c1527603.jfif

      745186370-61b74c1c9e55a.jfif

      1649520644-61b74d4e8379a.jfif

      部分日志如下:

      WAR drop=1117, fctl=0x00d0.
      mqtt connected
      get a message, topic: /to/slave/light, msg: 0
      [net INF] IPv6 addr state change: 0x0 --> 0x1
      [net INF] msg <>
      get a message, topic: /to/slave/light, msg: 100
      get a message, topic: /to/slave/light, msg: 100
      get a message, topic: /to/slave/light, msg: 50
      

      以上就是一个手机远程给LED进行PWM调光的应用实例

      本帖转自极术社区:https://aijishu.com/a/1060000000284320
      作者:ctspot

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 回复: 开源!教你自制最精致的Pi!

      @iamliubo 👍

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 回复: 小巧精湛!基于D1s的全开源芒果派-哪吒MQ正式开售!

      @theone @mangogeek 想了解更多也可以看看他过去发的帖

      发布在 MR Series
      q1215200171
      budbool
    • 回复: 小巧精湛!基于D1s的全开源芒果派-哪吒MQ正式开售!

      @theone 应该还没有?去问问芒果哥 或者 等芒果哥看到了他会回答你的😀

      发布在 MR Series
      q1215200171
      budbool
    • 小巧精湛!基于D1s的全开源芒果派-哪吒MQ正式开售!

      还记得之前的哪吒新品三连发吗?今天就来为你送上打开第二款新品宝箱的钥匙。

      预告3.png

      没错,这块上线即售空的新板子,就是之前预告过的哪吒新品三连发中的其中一块全新开发板:

      MQ正面DIS.png

      芒果派-哪吒MQ
      (MangoPi-Nezha MQ)

      芒果派-哪吒MQ(MangoPi-Nezha MQ)是芒果派(MangoPi)针对全志D1s设计的小型RISCV-Linux原型板,一体化极简设计,可以应用于屏显类AIoT产品。

      量产版的型号主要有以下两种:

      • MPi-MQ1:基础版,无NAND FLASH,无WiFi
      • MPi-MQ1W:WiFi版,无NAND FLASH,有WiFi

      可以看到两个型号最主要的区别就体现在WiFi模块之上,而WiFi型号的板子早已抢购一空,库存仅剩下基础版(悄悄透露,文末有下一批板子的消息),当然买到基础版的小伙伴也不用担心,基础版本虽然不带WiFi,但WiFi周围器件/ipex等都是齐的,还配备了MPi-MQ-GW2:双网口扩展板(PoP安装)的配件,通过这些都可以自行焊接实现WiFi功能。

      参数配置

      芒果派-哪吒MQ搭载的D1s是全志针对智能解码市场推出的高性价比AIoT芯片。它使用64bit RISC-V架构的阿里平头哥C906处理器,区别于D1芯片,D1s内置了64M DDR2,支持Linux系统,可以支持H.265,、H.264、MPEG-1/2/4、JPEG等全格式视频解码,支持ADC/DAC/I2S/PCM/DMIC/OWA等多种音频接口。

      mmexport1639379778742.png
      芒果派-哪吒MQ底板

      规格参数

      • 主控D1s(D1芯片内置64MB运存)
      • USB-OTG Type-C形式(fel方式刷机、接U盘、键盘、摄像头、usb网卡等)
      • USB-HOST Type-C形式(接U盘、键盘、摄像头、usb网卡等)
      • 22Pin扩展排针 x2(全Pin引出)
      • 可焊接Nand/Nor FLASH
      • TF卡槽
      • 板载基于RTL8189的WiFi
      • 15P通用树莓派DSI FPC排座
      • 40P通用RGB FPC排座(内含4线电阻触摸接口)
      • 6P通用电容触摸FPC排座
      • 板载MIC*1
      • 24Pin DVP接口
      • BOOT按键、复位按键
      • 4x4cm迷你尺寸,4个固定装配脚

      得益于D1s芯片加持,DSI接口的强大功能,也是赋予了麻雀点屏神器的头衔,板载WiFi以及双Type-C的接口也显示出紧跟潮流的设计理念,紧跟潮流的同时也保留了芒果派一贯的优良传统,独立BOOT按键、超高集成度......都是麻雀虽小,五脏俱全的最佳佐证。

      7df8ed97-499d-4c85-9b87-89c6f19cf41b-image.png
      kicad画的PCB渲染图

      秉持着开源的理念,麻雀作为一款全开源的产品,不仅会在近日于官网处开源板子的所有相关参数资源,在硬件方面,设计走的是kicad路线,近期也会上传到github。

      系统适配

      目前系统适配的还是全志官方的Tina Linux,麻雀主要跑Linux+LVGL或QT,当然debian也是可以在麻雀上跑起来的。除了最基本的Tina Linux,芒果派也针对麻雀进行了xboot和RTT-Smart的适配。

      xboot针对麻雀进行了适配,对于裸机感兴趣的可以用xboot。xboot不仅仅是一款功能强大、可移植性强、代码复用率高的嵌入式系统bootloader,而且还是一款SOC片上系统应用软件执行引擎,无需复杂的操作系统,就可以直接执行。

      xboot基本特性

      • 支持文件系统
      • 支持lua虚拟机
      • 支持各种协议栈
      • 支持矢量图形库,矢量字体
      • 支持各种现代GUI控件,以及动效
      • 多平台支持
      • 各种总线驱动,UART,I2C,SPI等等
      • 各种设备驱动,GPIO,PWM,IRQ,CLK,LED,BUZZER,VIBRATOR,WATCHDOG,RNG,FRAMEBUFFER,RTC等
      • 支持用lua编写应用软件,包含高等级API,可直接操作各种硬件抽象接口
      • 应用软件平台无关,一次编写,到处运行

      RTT那边针对麻雀适配了RTT-Smart(RT-Thread Smart),适合于经常使用RTOS的人。RT-Thread Smart 定位于成为一个专业的面向实时应用场合的高性能混合微内核操作系统。填补传统 RTOS 和大型操作系统 Linux 之间的空白,在实时性、成本、安全性、启动速度等方面取得最佳的平衡。

      RT-Thread Smart七大优点

      • 启动速度最快可在几百毫秒以内
      • 抢占式调度内核,任务响应性能相比 Linux 更加优秀
      • 支持POSIX API 规范,极大程度降低 Linux 开源软件的移植成本
      • OS占用内存空间以及Flash空间极小,可最大化节约物料成本
      • 支持Windows下开发应用程序,开发环境更加友好
      • 系统和应用分离,方便应用程序和系统单独发布、单独升级
      • 重大组件和服务运行在用户态,操作系统更加轻量、安全

      芒果派-哪吒MQ Pro

      作为芒果派-哪吒MQ基础款的升级版,除了外观方面保密,其他属性都已悉数公开,芒果派-哪吒MQ Pro正式上线时间也初定在十二月底。

      • 主控D1芯片
      • 512M or 1GB 运存
      • USB-OTG Type-C形式(fel方式刷机、接U盘、键盘、摄像头、usb网卡等)
      • USB-HOST Type-C形式(接U盘、键盘、摄像头、usb网卡等)
      • 40Pin扩展排针
      • TF卡槽
      • 板载基于AP6212/RTL8723的WiFi/BT
      • Mini HDMI接口
      • 15P通用树莓派DSI FPC排座
      • 24Pin DVP接口
      • 列表外观保密

      从参数方面来看,外观保密的原因是进行了大改,在小麻雀开售后,b站也有很多小伙伴留言想直接跑发行版(debian/ubuntu)的,也就是说很多人需要一款rv架构的linux小电脑,那使用D1作为主控,目的就会为了将内存打算做到512~1G,带上HDMI,同时保留小巧的属性。重点实现了一体化设计,简单易用,那样可以实现更广的人群的覆盖。

      芒果派-哪吒MQ上线情况

      已经有不少小伙伴收到了第一批发售的板子,有人点起了灯,有人跑起了LVGL demo,还有人将自己开发的系统移植到了麻雀上,看到这里是不是都后悔自己没能买到第一波的麻雀板子。

      FA665A55-D518-4f35-B3B8-14F6A53E299C.png 63E38483-E028-4173-BB51-AA87C1EB501C.png
      没抢到板子的小伙伴不要着急,下一批的物料已经在准备之中了,预计生产的数量也是远远超出上一次,焊接厂排期也是在今年开工,所以在不久的将来就会有一批全新、大量的板子上架,全志在线也会和芒果派持续合作,输出更小巧精湛,高性价比的板子。

      芒果派 哪吒MQ MangoPi Nezha MQ 麻雀 哪吒mini 全志D1s 开发板:
      https://item.taobao.com/item.htm?id=638644511420
      五寸电阻屏/电容屏:
      https://item.taobao.com/item.htm?id=587925184119
      芒果派 哪吒MQ 文档
      https://mangopi.org/zh/mangopi_mq

      微信公众号推文直通车:https://mp.weixin.qq.com/s/QPhxg84J1BvJJ8ODq4njUw

      发布在 MR Series
      q1215200171
      budbool
    • 【XR806开发板试用】系列之二 - I2C外设使用及控制OLED屏显示

      前言
      XR806硬件上支持SPI,I2C等其他外设接口,且DDR和FLASH,满足常见应用场景的开发,适合开发者进行方案评估、DIY或小规模产品研发使用。本篇文章,将使用到I2C接口,去控制OLED屏幕的显示。

      OLED屏幕规格: 0.96英寸 主控SSD1306 I2C接口 地址 0x3C
      XR806外设:I2C1
      

      创建工程
      参考device/xradio/xr806/ohosdemo目录下的wlan_demo,

      拷贝wlan_demo为xr806_oled,并同步修改ohosdemo和xr806_oled目录下的BUILD.gn。

      主要修改如下:

      1、device/xradio/xr806/ohosdemo/BUILD.gn

      group("ohosdemo") {
       deps = [
           #"hello_demo:app_hello",
           #"iot_peripheral:app_peripheral",
           #"wlan_demo:app_WlanTest",
           "xr806_oled:app_oled", #增加app_oled目标编译
       ]
      }
      

      2、device/xradio/xr806/ohosdemo/xr806_oled/BUILD.gn

      static_library("app_oled") {
         configs = []
      
         sources = [
        "main.c",
         ]
      
         cflags = board_cflags
      
         include_dirs = board_include_dirs
         include_dirs += [
          ".",
          "thirdparty/ssd1306/ssd1306",
          "//utils/native/lite/include",
          "//foundation/communication/wifi_lite/interfaces/wifiservice",
         ]
      
         deps = [
          "thirdparty/ssd1306/ssd1306:oled_ssd1306",
         ]
      }
      

      注意:

      • static_library代表生成静态库(.a)文件,其中包含main.c的静态库必须是app_打头,如app_hello,否则虽然可以编译成功,但无法生效;
      • ~~xr806_oled/BUILD.gn中静态库app_oled的命名,需要和ohosdemo/BUILD.gn中的一致;
      • thirdparty/ssd1306/ssd1306:oled_ssd1306 为依赖的开源库

      工程编译
      创建工程后,如果非首次编译,执行以下命令便可以编译:

      hb build
      

      编译如果遇到以下错误:

      [OHOS ERROR] /*
      [OHOS ERROR]  *
      [OHOS ERROR]  * Automatically generated file; DO NOT EDIT.
      [OHOS ERROR]  * XR806 SDK Configuration
      [OHOS ERROR]  *
      [OHOS ERROR]  */
      [OHOS ERROR] /*
      [OHOS ERROR]  *
      [OHOS ERROR]  * Automatically generated file; DO NOT EDIT.
      [OHOS ERROR]  * XR806 SDK Configuration
      [OHOS ERROR]  *
      [OHOS ERROR]  */
      [OHOS ERROR] {
      [OHOS ERROR]     "magic" : "AWIH",
      [OHOS ERROR]     "version" : "0.5",
      [OHOS ERROR]     "image" : {"max_size": "1532K"},
      [OHOS ERROR]     "section" :[
      [OHOS ERROR]   {"id": "0xa5ff5a00", "bin" :"boot_40M.bin", "cert": "null", "flash_offs": "0K", "sram_offs": "0x00230000", "ep": "0x00230101", "attr":"0x1"},
      [OHOS ERROR]   {"id": "0xa5fe5a01", "bin" :"app.bin", "cert": "null", "flash_offs": "32K", "sram_offs": "0x00201000", "ep": "0x00201101", "attr":"0x1"},
      [OHOS ERROR]   {"id": "0xa5fd5a02", "bin" :"app_xip.bin", "cert": "null", "flash_offs": "99K", "sram_offs": "0xffffffff", "ep": "0xffffffff", "attr":"0x2"},
      [OHOS ERROR]   {"id": "0xa5fa5a05", "bin" :"wlan_bl.bin", "cert": "null", "flash_offs": "1170K", "sram_offs": "0xffffffff", "ep": "0xffffffff", "attr":"0x1"},
      [OHOS ERROR]   {"id": "0xa5f95a06", "bin" :"wlan_fw.bin", "cert": "null", "flash_offs": "1173K", "sram_offs": "0xffffffff", "ep": "0xffffffff", "attr":"0x1"},
      [OHOS ERROR]   {"id": "0xa5f85a07", "bin" :"sys_sdd_40M.bin", "cert": "null", "flash_offs": "1198K", "sram_offs": "0xffffffff", "ep": "0xffffffff", "attr":"0x1"},
      [OHOS ERROR]   {}
      [OHOS ERROR]  ]
      [OHOS ERROR] }
      [OHOS ERROR] 
      [OHOS ERROR] make[2]: *** [../../../../project/project.mk:520:image] 错误 255
      [OHOS ERROR] make[2]: 离开目录“/home/algo/openharmony/xr806/device/xradio/xr806/xr_skylark/project/demo/audio_demo/gcc”
      [OHOS ERROR] make[1]: *** [../../../../project/project.mk:493:__build] 错误 2
      [OHOS ERROR] make[1]: 离开目录“/home/algo/openharmony/xr806/device/xradio/xr806/xr_skylark/project/demo/audio_demo/gcc”
      [OHOS ERROR] make: *** [Makefile:164:build] 错误 2
      [OHOS ERROR] you can check build log in /home/algo/openharmony/xr806/out/xr806/wifi_skylark/build.log
      [OHOS ERROR] /home/algo/.local/bin/ninja -w dupbuild=warn -C /home/algo/openharmony/xr806/out/xr806/wifi_skylark failed, return code is 1
      

      执行以下命令后,再次编译即可:

      cp  device/xradio/xr806/xr_skylark/project/demo/audio_demo/image/xr806/image_auto_cal.cfg  device/xradio/xr806/xr_skylark/project/demo/audio_demo/image/xr806/image.cfg
      

      编译后生成的镜像,便可以烧录验证。

      注:以上基础工程是基于wlan_demo,oled屏幕显示需要使用I2C外设和移植oled库

      库移植
      其实XR806本身自带了OLED主控为SSD1306的驱动(采用的是SPI接口方式),移植基于I2C接口的库也相对简单,可以参考开源库harmonyos-ssd1306,将其中的I2C相关头文件和API替换为XR806 OpenHarmony中的相关头文件和API,编译通过即可。

      其中涉及到BUID.gn的修改如下:

      static_library("oled_ssd1306") {
          sources = [
              "ssd1306.c",
              "ssd1306_fonts.c",
          ]
      
          include_dirs = [
              ".",
              "//kernel/liteos_m/kernel/arch/include",
              "//utils/native/lite/include",
              "//base/iot_hardware/peripheral/interfaces/kits",
          ]
      }
      

      开源库主要修改如下:

      #include "iot_i2c.h"
      #include "iot_errno.h"
      
      /**
       * @brief Defines I2C data transmission attributes.
       */
      typedef struct {
          /** Pointer to the buffer storing data to send */
          unsigned char *sendBuf;
          /** Length of data to send */
          unsigned int  sendLen;
          /** Pointer to the buffer for storing data to receive */
          unsigned char *receiveBuf;
          /** Length of data received */
          unsigned int  receiveLen;
      } IotI2cData;  
      
      
      static uint32_t ssd1306_SendData(uint8_t* data, size_t size)
      {
          uint32_t id = SSD1306_I2C_IDX;
          IotI2cData i2cData = {0};
          i2cData.sendBuf = data;
          i2cData.sendLen = size;
      
          return IoTI2cWrite(id, SSD1306_I2C_ADDR, i2cData.sendBuf, i2cData.sendLen);
      }
      

      ssd1306.h头文件定义SSD1306_I2C_IDX为1

      显示程序
      程序部分参考了上面提到的OLED库,完整的测试程序,可以参考harmonyos-ssd1306里的example.

      /*
       * Copyright (c) 2021-2031, AlgoIdeas
       *
       * SPDX-License-Identifier: Apache-2.0
       *
       * Change Logs:
       * Date           Author       Notes
       * 2020-12-13     AlgoIdeas    the first version
       */
      
      #include <stdio.h>
      #include "ohos_init.h"
      #include "kernel/os/os.h"
      #include "ssd1306.h"
      
      #define OLED_I2C_BAUDRATE       100000
      
      static OS_Thread_t g_main_thread;
      
      
      static void DrawChinese(void)
      {
          const uint32_t W = 12, H = 12, S = 16;
          uint8_t fonts[][24] = {
              {
                  /*-- ID:0,字符:"您",ASCII编码:C4FA,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
                  0x14,0x00,0x24,0x00,0x2F,0xF0,0x71,0x20,0xA5,0x40,0x29,0x20,0x33,0x10,0x20,0x00,
                  0x54,0x40,0x52,0xA0,0x90,0x90,0x0F,0x80,
              },{
                  /*-- ID:1,字符:"好",ASCII编码:BAC3,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
                  0x20,0x00,0x27,0xE0,0x20,0x40,0xF8,0x80,0x48,0x80,0x48,0xA0,0x57,0xF0,0x50,0x80,
                  0x30,0x80,0x28,0x80,0x4A,0x80,0x81,0x00,
              },{
                  /*-- ID:2,字符:"鸿",ASCII编码:BAE8,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
                  0x00,0x40,0x80,0x80,0x5D,0xE0,0x09,0x20,0xC9,0xA0,0x09,0x60,0x29,0x00,0xCD,0xF0,
                  0x58,0x10,0x43,0xD0,0x40,0x10,0x40,0x60,
              },{
                  /*-- ID:3,字符:"蒙",ASCII编码:C3C9,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
                  0x09,0x00,0x7F,0xE0,0x09,0x00,0x7F,0xF0,0x80,0x10,0x7F,0xE0,0x0C,0x40,0x32,0x80,
                  0xC7,0x00,0x0A,0x80,0x32,0x70,0xC6,0x20
              }
          };
      
          ssd1306_Fill(Black);
          for (size_t i = 0; i < sizeof(fonts)/sizeof(fonts[0]); i++) {
              ssd1306_DrawRegion(i * H + 32, 26, W, H, fonts[i], sizeof(fonts[0]), S);
          }
          ssd1306_UpdateScreen();
          sleep(1);
      }
      
      static void MainThread(void *arg)
      {
          IoTI2cInit(SSD1306_I2C_IDX, OLED_I2C_BAUDRATE);
      
          usleep(20*1000);
      
          printf("ssd1306_Init.\n");
          ssd1306_Init();
          ssd1306_Fill(Black);
          ssd1306_SetCursor(22, 27);
          ssd1306_DrawString("Hello XR806!", Font_7x10, White);
      
          uint32_t start = HAL_GetTick();
          ssd1306_UpdateScreen();
          uint32_t end = HAL_GetTick();
          printf("ssd1306_UpdateScreen, time cost: %d ms.\n", end - start);
      
          usleep(2000*1000);
      
          while (1) {
              DrawChinese();
          }
      }
      
      void OledMain(void)
      {
           if (OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL,
                      OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) {
               printf("[ERR] Create MainThread Failed\n");
           }
      }
      
      SYS_RUN(OledMain);
      

      运行效果
      最终OLED显示:您好鸿蒙
      1003546875-61b74f422e829.jfif

      参考资料
      【XR806开发板试用】系列之一 - Linux环境下Ubuntu完全开发流程
      https://xr806.docs.aw-ol.com/
      https://aijishu.com/a/1060000000256653

      本贴转自极术社区:https://aijishu.com/a/1060000000284333
      作者:H2O2_H2O2

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 【XR806开发板试用】Linux环境下Ubuntu完全开发流程

      前言
      为了让极术社区开发者体验搭载安谋科技STAR-MC1处理器的面向IoT领域的全志XR806开发板,极术社区联合全志在线开发者社区共同推出XR806开发板免费试用活动。

      极术社区特准备了200块XR806开发板作为2022年社区新年活动,申请的人数有600多,手快有手慢无,有幸申请到一块XR806开发板。该开发板目前支持鸿蒙L0轻量级设备(OpenHarmony-v1.1.2-LTS),之前没有接触过,值得开发体验一番。

      环境准备
      系统:Ubuntu 20.04.3 LTS
      Python: Python 3.8.10
      编译链:gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2

      串口调试工具:
      CuteCom - http://cutecom.sourceforge.net/

      或在安装好Wine环境下,可以使用在Windows上的串口调试工具,如经典的putty等

      开发流程
      官方参考:https://xr806.docs.aw-ol.com/...,本文将完全在Ubuntu环境下开发,基本流程和官方一致。

      一. 代码下载

      mkdir xr806
      cd xr806
      repo init -u ssh://git@gitee.com/openharmony-sig/manifest.git -b OpenHarmony_1.0.1_release --no-repo-verify -m devboard_xr806.xml
      repo sync -c -j8
      repo forall -c 'git lfs pull'
      

      二. 环境配置

      1.OpenHarmony相关工具
      Ubuntu环境配置可参考OpenHarmony官方:获取源码及Ubuntu编译环境准备,因XR806主要采用gcc编译,环境配置重点关注下安装Python3和安装hb(暂可以不安装llvm)。

      注:在下载完成代码后,可以在项目根目录下,执行以下命令安装OpenHarmony编译系统工具 - hb(也可参考OpenHarmony官方):

      pip3 install build/lite
      

      2.GCC编译链安装
      解压环境准备小节中下载的gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2
      默认解压到~/tools目录

      mkdir -p ~/tools
      tar -jxvf gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 ~/tools
      

      注:~表示你的/home/用户名目录,
      项目编译链配置默认~/tools目录下,可以不用修改编译链路径,当然在也可以解压到其他目录

      三. 固件编译
      请详见官方参考:https://xr806.docs.aw-ol.com/...

      首次编译工程,需要对原生库进行配置,否则无法编译通过,配置步骤如下:

      cd device/xradio/xr806/xr_skylark
      cp project/demo/audio_demo/gcc/defconfig .config
      make menuconfig
      make build_clean
      make lib -j
      cd -
      hb set
      hb build -f
      

      注:首次编译可能会遇到异常,请参考官方固件编译说明

      四. 固件下载
      固件下载请参考:https://xr806.docs.aw-ol.com/...,Ubuntu环境下,与Windows相同,
      编译生成的固件在device/xradio/xr806/xr_skylark/out,名称为xr_system.img

      1.设备识别

      将XR806开发板,插入PC的USB接口,用lsusb命令查看,会多出一个设备,设备标识:ID 10c4:ea60 Silicon Labs CP210x UART Bridge,如下图所示:
      528882338-61b5892c82a8c.png

      algo@algoideas:~/openharmony/xr806$ lsusb 
      Bus 002 Device 002: ID 8087:8000 Intel Corp. 
      Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
      Bus 001 Device 002: ID 8087:8008 Intel Corp. 
      Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
      Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
      Bus 003 Device 006: ID 138a:0017 Validity Sensors, Inc. VFS 5011 fingerprint sensor
      Bus 003 Device 002: ID 1ea7:0064 SHARKOON Technologies GmbH 2.4G Mouse
      Bus 003 Device 008: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
      Bus 003 Device 005: ID 5986:0268 Acer, Inc Integrated Camera
      Bus 003 Device 004: ID 8087:07dc Intel Corp. 
      Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
      algo@algoideas:~/openharmony/xr806$ ls /dev/ttyUSB*
      /dev/ttyUSB0
      

      新增加的设备节点名称为:ttyUSB0

      2.工具配置

      Linux下烧录工具文件位于device/xradio/xr806/xr_skylark/tools下,工具名为phoenixMC,工具配置文件为settings.ini,如下图所示:
      207752238-61b58deee92b1.png
      主要修改:strComDev iBaud 和 strImagePath

      [comm]
      strComDev = /dev/ttyUSB0
      iBaud = 3000000
      
      [log]
      strLogFile = ./log/log.txt
      
      [firmware]
      strImagePath = ../out/xr_system.img
      strEtfImagePath = xr_system_etf.img
      

      3.固件烧录

      执行以下命令便可以烧录:

      cd device/xradio/xr806/xr_skylark/tools
      ./phoenixMC
      

      烧录部分过程如下:
      279596692-61b58e933f609.png

      注:Linux下烧录,固件路径长度有限制,使用路径时,目前使用的是相对路径,或如用其他路径,请拷贝固件到其他路径长度较短的目录下

      五. 串口调试

      打开CuteCom工具,设置好波特率为115200,及相关参数,并点击Open,此时按下开发板的Reset键即可,看到XR806的串口日志输出,当然也可以输入命令进行交互。
      串口设置及XR806日志输出如图所示:
      3623160675-61b5913ab9f35.png

      问题与总结
      作为一名开发者,XR806在Linux环境下Ubuntu开发,整个开发的流程很顺利,本文未涉及到应用程序,仅涉及到固件相关开发,应用开发烧录一致,应用开发将在下一篇文章介绍,或参考官方相关文章。
      Linux环境下开发,主要遇到以下问题:
      Linux下烧录波特率非实际配置的3000000,对比Windows环境下,固件烧录慢很多,烧录提示如下:

      Baud should be one of the values below:
      110 300 600 1200 2400 4800 9600 19200 38400 57600 115200 230400 460800 921600
      

      参考资料:
      https://xr806.docs.aw-ol.com/
      https://aijishu.com/a/1060000000256653

      本贴转自极术社区:https://aijishu.com/a/1060000000282581
      作者:H2O2_H2O2

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      3D图

      D1_86_Panel_7012.png

      D1_86_Panel_7012.pdf
      D1_86_Panel_7012.dxf
      D1_86_Panel_7012(3D Model).STEP

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      86盒位号图

      C952A3BA-8881-463b-A48E-D5EFE7B76071.png

      D1_Case_86_7002_TOP.pdf

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      86盒原理图

      2D89A7C5-2252-47ff-AC94-9E3720B96E75.png BE170746-5288-4b87-9BAA-57629E4628B3.png
      5E52949F-3D05-4fbd-86E5-B253E6C873C4.png
      8754D74D-EE7C-4a64-8DE2-872A3A379BA7.png
      1D3F62B8-F7FB-49e3-9387-FC4FF9FA8729.png
      4DEF8443-B5C1-4765-8C5B-DA5D2E47BE78.png
      E10B8AEF-E854-4e50-AFF6-51BBEAD8D858.png 6D02B7E3-0B1A-464e-8A8B-CFA050F43A22.png 06481E17-C7AE-4e62-BCA2-3D7DF2A4372E.png
      764BB7C1-9496-450b-9CF7-1F26985CC259.png

      D1_86_Panel_7012(Schematic).pdf

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      86盒规格书

      A50036E2-C95A-475a-80FB-FE978B9DFB96.png 1306AD33-249A-4441-B063-C57E8C015102.png C42F7092-EE2C-4d87-A328-746C76352A46.png 4E5F5AC6-4E5C-4fd3-9717-14A45E6AE1D3.png 69D6304B-7AA4-43aa-BFF7-1EBF774FA5F8.png E6CAAA9D-742C-45b5-B1AF-E011D8FDA65F.png FFD64A67-E990-4877-8CA4-9277503F3327.png

      中文版:Sipeed Lichee RV 86 Panel 规格书 V1.0.pdf
      英文版:Sipeed Lichee RV 86 Panel Datasheet V1.0.pdf

      发布在 公告
      q1215200171
      budbool
    • 回复: 【单板仅需99】D1哪吒计算条上线!为智能家居提供高性价比的RISC-V算力

      @wuzhujian https://bbs.aw-ol.com/topic/683/ 资源帖里面找找看

      发布在 MR Series
      q1215200171
      budbool
    • LicheeRV 入门开发一帖通

      目录

      • 板卡系列介绍
      • 开箱教程
      • 上手点灯
      • 外设功能验证
      • Debian镜像体验
      • BSP SDK 开发指南
      • WAFT 开发指南

      1. 板卡系列介绍
      LicheeRV系列是Lichee系列下的RV子系列,主要为RISC-V内核的Linux SBC产品。
      目前有以下几款产品:Nezha CM, HDMI Dock, 86-Panel
      购买地址为:https://item.taobao.com/item.htm?id=663345415205
      交流QQ群为:488268051

      板卡相关开发资料已上传到百度云:

      链接:https://pan.baidu.com/s/1QJTaDw6kkTM4c_GAlmG0hg
      提取码:wbef

      NB20jdpSzAHsjCn6vmnbdvPGPzjN3WsgNV6zlOcS.png

      01GV2mogRbep6UkmNyQDObvBu5eQxncPvq8bNAlc.png

      ax0kjeXJ1nlukfIqVf2vsauhBlwj5zCZQRdqNr4q.png

      2. 开箱教程
      LicheeRV产品默认使用TF卡启动,不管你购买的哪款产品,请先备好tf卡与读卡器。

      烧录软件
      全志镜像的卡烧录工具下载地址:https://dl.sipeed.com/shareURL/LICHEE/D1/SDK/
      下载 PhoenixCard.rar 解压运行其中的主程序即可

      系统镜像
      默认系统镜像已上传到百度盘,会持续更新

      系统镜像分为 Tina与Debian两种,Tina为专用小linux镜像,Debian为桌面级镜像

      板级配置
      在上述百度盘的board目录下为板级配置文件,如果底包(系统镜像)的后缀与实际板卡不符,需要再使用此fex覆盖板级配置来正确显示。

      烧录步骤
      打开烧录软件,按顺序点击下图按键进行烧录对应镜像

      CQe4odVaM6LIFMR043hRj5o4luanrW9htBmSC5h5.png

      如果烧录的镜像后缀与板子实际型号不符,下载对应的 boot_package_XXX.fex 来覆盖板级配置

      覆盖指令为:

      sudo dd if=boot_package_XXX.fex of=/dev/sdX bs=1K seek=16400
      

      前面的镜像烧录,建议使用USB3.0的读卡器烧录,此时烧录100MB的Tina镜像约用时半分钟,烧录4GB的Debian镜像,约用时10分钟。

      开机启动
      将上面烧录好的镜像卡,插入核心板的tf卡槽里,接好系统串口(86 panel板载了USB转串口,可以直接插对应C口),上电启动,可以在串口以115200波特率看到系统启动信息,Tina启动时间约10s,Debian启动时间久些,约2~3分钟。

      BusyBox v1.27.2 () built-in shell (ash)
      
          __  ___     _        __   _   
         /  |/  /__ _(_)_ __  / /  (_)__  __ ____ __
        / /|_/ / _ `/ /\ \ / / /__/ / _ \/ // /\ \ /
       /_/  /_/\_,_/_//_\_\ /____/_/_//_/\_,_//_\_\ 
       ----------------------------------------------
       Maix Linux (Neptune, 5C1C9C53)
       ----------------------------------------------
      

      以上是Tina系统进入系统终端的logo打印,出现该字样说明系统启动成功

      如果你需要使用ssh登录,则默认Tina的用户名密码为 root,tina
      Debian的用户名密码为 sipeed,licheepi

      如果你只购买了LICheRV D1核心板,需要传输大文件的话,可以使用adb进行文件传输,adb push/pull 即可。

      3.点灯教程
      当我们成功进入系统后,就可以进行基础的点灯操作啦!
      (注:该教程不适用于86-panel,因为对应引脚连接了外设,86panel用户可以拆下核心板来操作实验)

      核心板的螺丝固定焊盘旁有一颗LED,查看原理图:https://dl.sipeed.com/shareURL/LICHEE/D1/HDK/Lichee_RV/2_Schematic

      可知该LED连接的是PC1,换算该IO的数字标号为:2*32+1=65,或者查看IO复用情况表:

      cat /sys/kernel/debug/pinctrl/2000000.pinctrl/pinmux-pins
      ...
      pin 64 (PC0): device 2008000.ledc function ledc group PC0
      pin 65 (PC1): UNCLAIMED
      pin 66 (PC2): UNCLAIMED
      pin 67 (PC3): UNCLAIMED
      pin 68 (PC4): UNCLAIMED
      pin 69 (PC5): UNCLAIMED
      pin 70 (PC6): UNCLAIMED
      pin 71 (PC7): UNCLAIMED
      

      我们先导出该GPIO:

      echo 65 > /sys/class/gpio/export
      cd /sys/class/gpio/export/gpio65
      

      然后再将该IO置为输出状态,即可操作其电平:

      echo out>direction
      echo 1 > value  #LED点亮
      echo 0 > value  #LED熄灭
      

      至此我们就成功在RISC-V 64 D1上点灯啦~

      你也可以对 串行RGB LED WS2812 进行花式点灯:

      cd /sys/class/leds/
      	echo 255 > sunxi_led0r/brightness;echo 0 > sunxi_led0g/brightness;echo 0 > sunxi_led0b/brightness;
      	echo 0 > sunxi_led0r/brightness;echo 255 > sunxi_led0g/brightness;echo 0 > sunxi_led0b/brightness;
      	echo 0 > sunxi_led0r/brightness;echo 0 > sunxi_led0g/brightness;echo 255 > sunxi_led0b/brightness;
      

      4. 外设功能验证

      4.1 音频功能

      录音设备查看

      root@MaixLinux:~# arecord -l
      **** List of CAPTURE Hardware Devices ****
      card 0: audiocodec [audiocodec], device 0: SUNXI-CODEC 2030000.codec-0 []
        Subdevices: 1/1
        Subdevice 0: subdevice 0
      card 1: snddmic [snddmic], device 0: 2031000.dmic-dmic-hifi dmic-hifi-0 []
        Subdevices: 1/1
        Subdevice 0: subdevice 0
      card 2: sndhdmi [sndhdmi], device 0: 2034000.daudio-audiohdmi-dai 20340a4.hdmiaudio-0 []
        Subdevices: 1/1
        Subdevice 0: subdevice 0
      

      播放设备查看

      root@MaixLinux:~# aplay -l
      **** List of PLAYBACK Hardware Devices ****
      card 0: audiocodec [audiocodec], device 0: SUNXI-CODEC 2030000.codec-0 []
        Subdevices: 1/1
        Subdevice 0: subdevice 0
      card 2: sndhdmi [sndhdmi], device 0: 2034000.daudio-audiohdmi-dai 20340a4.hdmiaudio-0 []
        Subdevices: 1/1
        Subdevice 0: subdevice 0
      

      录放音测试:

      arecord -D hw:1,0 -f S16_LE -t wav -d 3 t.wav 
      	aplay -D hw:0,0 t.wav
      

      另外可以使用alsamixer 进行音量调整

      4.2 USB功能
      默认内核支持外挂U盘的驱动,插上U盘后可以使用 fdisk -l 查看到新增的 /dev/sda
      如果U盘没有被格式化,可以使用mkfs.vfat指令来格式化U盘,再使用mount指令挂载
      默认Tina固件里的 /dev/mmcblk0p8 分区即可使用上述方式格式化后挂载,来提升可用空间

      4.3 有线网络
      LicheeRV-86 Panel 支持百兆网络,使用套餐附送的网线尾线接上网线后,执行以下指令来连接有线网络

      ifconfig eth0 up
      udhcpc -ieth0
      

      4.4 无线网络
      LicheeRV 底板默认使用XR829或者RTL8723BS wifi模块,可以使用以下指令进行联网操作:

      先配置热点信息:

      vim /etc/wifi/wpa_supplicant.conf
      	network={  
      		ssid="Sipeed_2.4G"  
      		psk="XXXX"  
      	} 
      配置完成后重启
      

      ,ifconfig wlan0 up; udhcpc -iwlan0 即可连上对应的wifi。
      连上网络后,你就可以使用ssh远程登录板卡,或者使用scp来进行文件传输啦~

      4.5 屏显触摸
      LicheeRV系列支持以下显示屏:

      SPI屏		1.14寸屏(TODO)
      RGB屏		4.3寸 480x272;5.0寸 800x480;
      RGB+SPI屏	4.0寸 480x480(st7701s); 4.0寸 720x720(nv3052c)
      MIPI屏		8.0寸 1280x720(ILI9881C)
      

      Tina下可以通过以下指令测试屏幕显示:
      fbviewer xxx.jpg
      如果需要调试屏幕驱动,可以使用以下指令查看屏幕驱动信息:

      cat /sys/class/disp/disp/attr/sys
      
      screen 0:
      de_rate 300000000 hz, ref_fps:60
      mgr0: 480x480 fmt[rgb] cs[0x204] range[full] eotf[0x4] bits[8bits] err[0] force_sync[0] unblank direct_show[false] iommu[1]
      dmabuf: cache[0] cache max[0] umap skip[0] overflow[0]
      	lcd output	backlight( 50)	fps:59.5	esd level(0)	freq(60)	pos(0)	reset(0)	 480x 480
      	err:0	skip:184	irq:230715	vsync:0	vsync_skip:0
         BUF    enable ch[1] lyr[0] z[16] prem[N] a[globl 255] fmt[  0] fb[ 480, 480; 480, 480; 480, 480] crop[   0,   0, 480, 480] frame[   0,   0, 480, 480] addr[ffe00000,       0,       0] flags[0x       0] trd[0,0]
      

      屏幕彩条测试:echo 1 > /sys/class/disp/disp/attr/colorbar

      如果你购买的是86面板套餐,可以使用 ts_test进行触摸测试
      (注意触摸驱动有瑕疵,ts_test测试时松开后,光标会不动,但是终端仍会正常打印信息)

      4.6 视频播放
      最终我们可以尝试在LicheeRV上播放BadApple啦~
      Tina镜像中内置了ffmpeg软件包,ffmpeg是强大的多媒体库,可以用于录屏或者播放
      录屏指令:ffmpeg -f fbdev -framerate 10 -i /dev/fb0 record.avi
      播放指令(分别是扬声器播放音频和hdmi播放音频):

      ffmpeg -i /mnt/UDISK/badapple_640480_xvid.mp4 -pix_fmt bgra -f fbdev /dev/fb0 -f alsa hw:0,0  
      ffmpeg -i /mnt/UDISK/badapple_640480_xvid.mp4 -pix_fmt bgra -f fbdev /dev/fb0 -f alsa hw:2,0
      

      这里由于是CPU软解,所以测试最高分辨率约为720x540, 再高会变卡

      4.7 麦克风阵列
      如果你使用的是dock板,那么还可以外接麦克风阵列版进行声场成像演示:
      直接执行debian系统下内置的micarr_0609指令即可
      有麦克风阵列相关的二次开发需求,可以联系support@sipeed.com

      5. Debian镜像体验
      对于只接触过桌面级系统的开发者,推荐使用Debian镜像,可在上面的网盘里下载
      LicheeRV_Debian_86_480p 为 480p的86盒板卡的debian镜像
      LicheeRV_Debian_hdmi 为 dock的hdmi输出的debian镜像
      如果是其他板卡或者屏幕,请自行使用对应的fex覆盖板级配置。
      烧录完成后,插卡启动,稍等2分钟左右,屏幕上就会显示登录界面

      z8QlbfdC11GLaT5dis9epd1DdfbRPpRsa6XEi2AU.png

      输入用户名 sipeed,密码 licheepi,即可进入桌面 (使用USB HOST口外接键鼠输入)

      2uBMvAjSuX8VLL3kVVKmBCUIxqOPJgVyYsl7MTge.png

      进入桌面后可以进行一些基础操作

      jtKDz9H3AvMrfmLCSwQW3QR8sRXQEDjAJFMG9KaI.png

      接下来让我们尝试在Debian下跑一下Hello World:

      vuluuJDdW5sJm2dSy60HmqUvpYJ6YJMuIinX3Y0N.png

      另有720P高清屏的效果对比,有米的同学可以考虑入手:

      77KuMcmppgJn44doDQMYBBi8pPDRdKwkXm9HPit6.png

      E1qugpwslyoHbknndO5KDqv3tjclx3GUWM5QDzN4.png

      6.BSP SDK 开发指南
      为了方便用户自行开发,矽速整理发布了 LicheeRV 的bsp开发docker镜像,大家使用该镜像可以快速开始D1的系统级开发。
      在网盘中下载对应的docker文件后,解压到tar文件,
      docker import licheerv_d1_compile.tar licheerv_d1_compile:lastest
      然后即可run该容器,用户名为nihao,密码为sipeed123
      进入容器后的基础编译操作为:

      cd ~/sdk/tina-d1-open_new/
      source build/envsetup.sh
      lunch   //选1
      make menuconfig //去掉里面的 alsa-plugin选项,否则编译不过
      make -j96 #按实际核数编译
      pack  # 打包
      

      SDK内置了一些版型的dts,你可以自行选择编辑:
      device/config/chips/d1/configs/nezha/board_xxx.dts

      其他SDK的开发说明,可以参见全志开发平台上下载的相关文档
      https://open.allwinnertech.com/
      也可以加全志交流QQ群:498263967

      如果需要自己下载SDK开发,参考全志在线相关网页:https://d1.docs.aw-ol.com/en/

      7.WAFT 开发指南
      TODO

      转载自Sipeed社区:https://bbs.sipeed.com/thread/1300

      发布在 MR Series
      q1215200171
      budbool
    • 回复: 兄弟们,MangoPi-麻雀MQ已成功量产

      买买买买买买😁

      发布在 MR Series
      q1215200171
      budbool
    • 回复: 【单板仅需99】D1哪吒计算条上线!为智能家居提供高性价比的RISC-V算力

      淘宝已上线,Sipeed Lichee RV 86 Panel 智能家居 中控开发板 支持Linux WAFT
      https://item.taobao.com/item.htm?id=663345415205
      你的86 @jordonwu

      发布在 MR Series
      q1215200171
      budbool
    • 【FAQ】Wi-Fi/BT MAC地址定制

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

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

      f0b99d68a48d47fb86bbcd973ef20647.jfif

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

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

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

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

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

      使用

      内核空间

      Linux-4.9

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

      Linux-5.4

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

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

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

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

      linux-5.4下主要节点如下:

      console:/ # ls -l /sys/class/addr_mgt/
      total 0
      -rw-r--r-- 1 bluetooth net_bt_admin 4096 2020-12-22 19:33 addr_bt
      -rw-r--r-- 1 root      root         4096 2020-12-23 13:10 addr_eth
      -rw-r--r-- 1 root      root         4096 2020-12-23 13:10 addr_wifi
      -r--r--r-- 1 root      root         4096 2020-12-23 13:10 summary
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志D1芯片 XR829扫卡失败问题排查

      【问题背景】
      硬件:D1 + Wi-Fi模组(XR829)
      软件:melis-v3.0
      说明:该FAQ旨在记录

      【问题简述】
      WiFi初始化指令执行后无法扫描到WiFi模组,即扫卡失败

      【问题分析】
      1、首先排查硬件问题,其次再找软件bug
      (1)同样的模组在跑其它软件时,可以正常工作;排除模组的硬件问题
      (2)定位软件bug,扫卡失败发生WiFi初始化阶段1

      2、解软件bug
      WiFi模组引脚图:
      92e5cd3275ac494c9c2c994f2f6f734b.jfif
      (1)WiFi初始化时会对模组进行上电
      可能时上电时序不对导致扫卡失败,检查REG_ON引脚时序
      REG_ON:执行WiFi初始化指令后,引脚时序应该是10ms高电平-》20ms低电平-》高电平
      (2)上电时序没有问题的话,检查sdio驱动问题,因为扫卡是通过是sdio下发cmd5
      使用其它sdio设备,看其是否可以正常工作;使用sd卡测试,可以正常工作,说明不是sdio的驱动问题

      检查指令引脚是否发出cmd5——SDIO CMD:在扫卡阶段检查该引脚是否有cmd5命令输入

      cmd5命令格式如下:
      860be038437041a48b05a796c65c8b41.jpg

      检查扫卡频率是否正常——SDIO CLK:在扫卡阶段,该引脚应该是输入4KHZ、50%占空比的方波。

      3、在检查这两个大方向后还是无法排查问题
      (1)和正常模组对比差异点
      最后发现LPO引脚输入24MHZ时钟,而正常模组为高电平;将该引脚修改为高电平,可以正常扫到卡。

      【解决方法】
      LPO引脚正常情况下是输入32.768KHZ的震荡信号作为低功耗时使用,故输入32.768KHZ时钟;测试可以正常扫到卡。
      执行wifi初始化指令后,设置LPO输入32KHZ、50%占空比的方波

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志D1芯片 如何移植 rtl8821cu wifi 驱动到 Linux-5.4内核?

      问题背景
      移植 Linux-4.9 或之前的内核版本下的 wifi 驱动到 Linux-5.4 内核版本时会出现编译和运行错误,
      该 FAQ 主要用于帮助开发人员解决驱动移植出现的问题。

      问题分析
      移植到 Linux-5.4 内核版本时出现如下编译错误:

      WARNING: module 8821cu uses symbol kernel_read from namespace VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver, but does not import it.
      

      出现该 WANRING 的原因是内核版本升级后文件系统存在差异,驱动调用了 kernel_read()和 kernel_write() 函数,需要进行 import VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver 处理。

      移植到 Linux-5.4 内核版本时运行的错误:

      04e7d843b1934a02af9d0335885f837c.jfif
      出现该问题的原因是 Linux-5.3 及以后版本 cfg80211.h 里结构体 wiphy_vendor_command 新增了变量 policy 和 maxattr。

      解决方案

      出现编译错误时解决方案如下:

      diff --git a/drivers/net/wireless/rtl8821cu/os_dep/linux/os_intfs.c b/drivers/net/wireless/rtl8821cu/os_dep/linux/os_intfs.c
      index c4b515763ac8..466a3b27f521 100644
      --- a/drivers/net/wireless/rtl8821cu/os_dep/linux/os_intfs.c
      +++ b/drivers/net/wireless/rtl8821cu/os_dep/linux/os_intfs.c
      @@ -28,6 +28,8 @@ MODULE_LICENSE("GPL");
       MODULE_DESCRIPTION("Realtek Wireless Lan Driver");
       MODULE_AUTHOR("Realtek Semiconductor Corp.");
       MODULE_VERSION(DRIVERVERSION);
      +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
      

      出现运行错误时解决方案为遍历驱动里所有使用 wiphy_vendor_command 结构体并修改如下:

      diff --git a/drivers/net/wireless/rtl8821cu/os_dep/linux/rtw_cfgvendor.c b/drivers/net/wireless/rtl8821cu/os_dep/linux/rtw_cfgvendor.c
      index 6bac27d37766..09e24dcc9480 100644
      --- a/drivers/net/wireless/rtl8821cu/os_dep/linux/rtw_cfgvendor.c
      +++ b/drivers/net/wireless/rtl8821cu/os_dep/linux/rtw_cfgvendor.c
      @@ -1756,6 +1756,11 @@ static const struct wiphy_vendor_command rtw_vendor_cmds[] = {
                      },
                      .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
                      .doit = rtw_cfgvendor_gscan_get_capabilities
      +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
      +               ,
      +               .policy = VENDOR_CMD_RAW_DATA,
      +               .maxattr = 1
      +#endif
              },
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志D1芯片 Tina 如何查看通过 procd init 脚本启动的应用输出到 stdout/stderr 的打印信息?

      问题描述

      当我们使用 procd init 脚本让某个应用程序实现开机自启时,会发现应用程序中原本通过 printf/fprintf 等输出到 stdout/stderr 的打印信息都无法从串口或 adb shell 中看到了。

      这些打印默认是输出到什么地方?我们可以如何看到这些打印?

      原因

      一般情况下,当用户在终端中执行命令来运行某个应用程序时,stdin/stdout/stderr 就确定下来是在当前终端,因此应用程序的打印信息自然能从当前终端中显示出来。

      而如果该应用程序是通过 procd init 脚本进行开机自启,它会被认为是一个守护进程(daemon)。守护进程是随系统自启的,它们有可能在用户登录终端之前就已经开始运行了,也无法得知用户是从哪个终端登录,因此也就无法将打印信息输出到用户所在的终端。

      解决方法

      一般来说,要获取守护进程的打印,需要通过 syslog 之类记录系统整体日志的方法。procd init 脚本也提供了方法将应用程序的打印重定向到 syslog 中。

      下面是一个简单的 procd init 脚本例子,它会启动应用程序 /usr/bin/foobar,但我们默认没法看到 foobar 输出到 stdout/stderr 的打印:

      #!/bin/sh /etc/rc.common
      
      START=50
      
      USE_PROCD=1
      
      start_service() {
          procd_open_instance
          procd_set_param command /usr/bin/foobar
          procd_close_instance
      }
      

      通过增加“procd_set_param stdout 1”和“procd_set_param stderr 1”两个参数,可将其输出到 stdout/stderr 的内容重定向到 syslog:

      #!/bin/sh /etc/rc.common
      
      START=50
      
      USE_PROCD=1
      
      start_service() {
          procd_open_instance
          procd_set_param command /usr/bin/foobar
          procd_set_param stdout 1    # 将其 stdout 的内容重定向到 syslog
          procd_set_param stderr 1    # 将其 stderr 的内容重定向到 syslog
          procd_close_instance
      }
      

      如此设置后,就可以从 syslog 中看到 foobar 应用程序输出的打印。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志D1芯片 如何解决Gstreamer:fb UI旋转(直接修改内核参数)后,sunxifbsink显示异常问题?

      1、问题背景
      客户在使用D1做项目开发时,通过直接修改内核参数的方法来旋转fb以达到旋转UI的目的(如下图所示),但此修改会导致sunxifbsink中获取到的视频层信息也随之改变,影响显示效果。

      ce3f57bc2d514a7cafcd38d3ea429022.jfif

      2、解决方法
      需要重置视频层的分辨率为屏幕物理分辨率,改动如下图所示:

      a025bb29f21e4b57b29ab03d568e3a04.jfif

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志D1芯片 如何对D1主频进行调节?

      【问题背景】
      在D1项目开发的过程中,有时候需要调节CPU主频,以对一些场景、功耗或性能进行测试,故对主频的调节方法进行介绍,方便大家后面调主频

      【适用场景】
      硬件:D1芯片平台 软件:Tina系统

      【基本操作】

      1.在烧了Tina固件的D1开发板上可以看到调频相关节点:

      3d6597a2851b4d15a77c03c25fda9b7b.jfif

      2.在系统启动log中,可以看到默认频率,一般是1G

      a43c9ff24fe14f42936d96ae38578486.jfif

      3.查看内核文件发现SDK提供了RV的调频代码,看来可以将调频模块加载起来

      65f0ecc9398b49f097c885c8a2935ca5.jfif
      4.打开内核相关配置:make ARCH=riscv menuconfig,选择:

      CPU Power Management  --->
          CPU Frequency scaling  --->
              ARCH RISCV Allwinner nvmem based SUN50I CPUFreq driver
      

      如图:
      75dd751c9626447aa13489e8173b056d.jfif

      c2b088f4cb8d4003868a242949adee54.jfif

      5b280e91402b4dbea7d4d1bbbfdc4112.jfif

      5.查找调频相关的dts中频率表的配置,只有1008M,可以进行超频修改,比如改到1.3G

      6d8b3309eb614d89b2168e3ecdea5104.jfif

      6.重新编译打包烧写,可以跑到1.3G

      9d0e670b2be242c482b87ce2b7aae769.jfif

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志D1芯片 如何解决Gstreamer播放1080视频显示异常问题(重影)?

      1、问题描述
      Gstreamer升级后测试发现,在播放1080P视频时,画面会出现重影现象。

      2、问题分析
      通过抓取图像数据以及对log分析,怀疑与VE的数据对齐有关,经验证确实如此。在解码的时候,VE会做16位对齐,所以1080P解码出来的数据除了需要将frame buffer的宽高设置给显示外,还需要做crop处理。而造成重影现象的原因就是在做crop处理前未将frame buffer的真实宽高设置给显示。

      3、解决方法
      在omx层第二次设置输出状态时,图像宽高为对齐后的宽高,sunxifbsink做crop处理;见附件。

      将附件中的0008 patch放在tina/package/multimedia/gst1-omx/patches目录下,然后用附件中的gst-plugins-aw-1.8.2.tar.x替换dl目录下的同名文件。

      gst-plugins-aw-1.8.2.tar.xz
      0008-Solve-the-ghosting-problem-of-sunxifbsink-display-du.patch

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志D1芯片 如何在 Linux Device Tree 中配置预留内存?

      前言

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

      memreserve

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

      /memreserve/ 0x40000000 0x00100000;
      

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

      reserved-memory

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

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

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

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

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

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

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

      通过 DMA API 来使用

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

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

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

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

      给 CMA 预留内存

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

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

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

      • compatible 需要为“shared-dma-pool”
      • 没有定义“no-map”属性
      • 定义了“reusable”属性
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志D1芯片 如何解决Audiocodec使用S24_LE格式进行录音,软件分析波形异常的问题?

      问题背景

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

      问题描述

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

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

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

      3cddc50a8f214d7380305433df378993.jfif

      问题分析

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

      4570bdb36f594591b6ec4c71310e5fe7.jfif

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

      5c2c17d228f944fd8a4a6e8d1924e778.jfif

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

      6972b81f741b4bf9829ecb814f5dbb7a.jfif

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

      8b502f06666046368fafccf0d13eee46.jfif

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

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

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

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

      S32_LE的wav文件信息:

      b782fd998a1a42bfafb6a46a3362d79b.jfif

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

      5de38b0c26a346a2bd0cc517b1cb6485.jfif

      S24_LE的wav文件信息:

      561fc954670c4a7e8f5c122acd788689.jfif

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

      a185f006bee4483ebb53b3835c4053dc.jfif

      解决方案

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

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

      1、问题背景
      客户使用F133进行一体广告机项目开发过程中,测试到附件中的片源《少女时代OhMVFullHD1080(播放花屏).mp4》播放时会出现花屏现象。但在之前的C800相同项目中该片源测试正常。

      2、问题描述
      出错第一帧标号为17(标号从0开始),如下图所示:

      da9c3adc58f84f8eb9b1e7d5cb3d0ec4.jfif

      抓取该帧花屏图像,现象如下:

      3d51e88c16464edf8ba651a6cf3c4a0b.jfif

      花掉的图像帧数据如下:

      7db8c1e56dfc4ca2a4210e43e89395db.jfif

      3、问题分析
      (1)关掉cache,花屏现象仍旧,排除漏刷cache影响;
      (2)64位系统(tina/melis)播放均花屏,32位系统正常;
      (3)寄存器对比,未发现异常;
      (4)在FbmRequestBuffer中将请求到的buffer清零,图像仍会花掉,但是花屏现象如下:
      aa75881faf5e4df188b7155423c7be2c.jfif

      3611d291672040c18324116b11f523d2.jfif

      推测在视频播放的过程中,该部分未有数据写出,仍然保留该buffer中上一帧的数据。(未修改代码前出错第一帧下半部分之所以是黑色的,是因为该视频前面的12帧均为黑色图像帧,所以该buffer中残留有上一帧的数据)

      daf70c99de2f4e0b83f821cf7c086999.jfif

      最后,通过添加打印发现,正常情况(R528平台),在未解码完一帧时,会通过检查同步标记函数而进入下一个packet的解码 ,但是现在异常(F133/D1)情况下跑到了else里面,导致一帧图像没有解码完,就解下一帧了。 正好前面抓图的现象也是第一帧出错的图像,下半部分是前面图像的数据残余。

      经分析,该问题的根本原因是在64位编译器中,i>>32 都等于i;而在32位编译器中,i>>32 都等于0。所以此发现也正好解释了之前的测试结果 “64位系统(tina/melis)播放均花屏,32位系统正常”。

      4、解决办法
      对出现右移32位的情况做判断,即return (rbit-n)<0?0:((rbit-n)>=32?0:(ld->bit_a & (0xFFFFFFFF >> (ld->bitcnt))) >> (rbit-n));

      对应的库文件见附件。
      library.7z

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片FAQ汇总(你不知道的和你想知道的的这里都有)

      01、【FAQ】全志XR806芯片 系统异常重启如何解决?
      02、【FAQ】全志XR806芯片 如何更换打印log口?
      03、【FAQ】全志XR806芯片 为什么开机时候串口以及部分gpio会有电平跳变?
      04、【FAQ】全志XR806芯片 mac地址要如何存放以及如何获取?
      05、【FAQ】全志XR806芯片 固件烧录完成后,程序不是预期烧录程序或者甚至无法启动如何解决?
      06、【FAQ】全志XR806芯片 如何使用timer命令行命令?
      07、【FAQ】全志XR806芯片 如何修改中断优先级?
      08、【FAQ】全志XR806芯片 如何设置AP模式默认IP地址、子网掩码、网关?
      09、【FAQ】全志XR806芯片 低功耗蓝牙BLE断开连接错误码和分析?
      10、【FAQ】全志XR806芯片 select引发崩溃如何解决?
      11、【FAQ】全志XR806芯片 如何打开 LwIP 调试信息?
      12、【FAQ】全志XR806芯片 执行扫描动作时,偶尔会扫描不到目标的AP如何解决?
      13、【FAQ】全志XR806芯片 如何解决编译错误undefined reference to?
      14、【FAQ】全志XR806芯片 standby模式下gpio的电平状态是如何变化?
      15、【FAQ】全志XR806芯片 如何清除扫描列表缓存?
      16、【FAQ】全志XR806芯片 RTC时钟不能跑、有时候时间不准是什么原因?
      17、【FAQ】全志XR806芯片 如何使用watchpoint功能?
      18、【FAQ】全志XR806芯片getsockopt、setsockopt失败如何解决?
      19、【FAQ】全志XR806芯片 串口修改波特率后与目标波特率不匹配如何解决?
      20、【FAQ】全志XR806芯片 Xradio Skylark 中的无线网络回调事件含义
      21、【FAQ】全志XR806芯片 如何使用phoenixMC软件把应用固件与etf固件合并在一起?
      22、【FAQ】全志XR806芯片 RF参数是如何保存的?
      23、【FAQ】全志XR806芯片 汇编代码调试技巧
      24、【FAQ】全志XR806芯片 如何解决第三方静态库函数符号重复?
      25、【FAQ】全志XR806芯片 如何创建自定义状态回调函数?
      26、【FAQ】全志XR806芯片 如何获取ap的rssi值?
      27、【FAQ】全志XR806芯片 XR806如何添加本地音频到flash?
      28、【FAQ】全志XR806芯片 XR MCU的外设驱动为什么修改无效?
      29、【FAQ】全志XR系列 XRMCU如何播放xip中的音频?
      30、【FAQ】全志XR系列 XRMCU如何修改录音编码器的输入数据?
      31、【FAQ】全志XR系列 如何调试wifi频偏问题?
      32、【FAQ】全志XR系列 如何统计XRMCU的内存使用情况
      33、【FAQ】全志XR系列 设置音频结构体HttpStreamBufferConfig成员有什么意义?
      34、【FAQ】全志全系列芯片 APST平台无法下载或者更新工具
      35、【FAQ】全志XR806 Freertos+XRMCU+ADC采样频率偏低
      36、【FAQ】全志XR806 Freertos + XRMCU +ADC采样数值不准
      37、【FAQ】全志系列芯片如何把flash擦成空片?
      38、持续更新....

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 XR MCU的外设驱动为什么修改无效?

      1.问题背景
      为了节省更多的flash空间,在xr872/xr808/xr806芯片上把大部分的驱动都已经做了rom化处理,即出厂的时候已经把外设驱动都集成到rom当中,因此默认sdk中驱动的代码是不能修改的。而客户有时候调试需要在驱动层添加一些打印信息或者修改外设驱动的配置,此时则需要舍弃rom化的驱动,自己在源代码上添加相应的驱动了。

      2.问题描述
      XR MCU的外设驱动为什么修改无效。

      3.解决办法

      • 先舍弃rom化驱动的代码:在lib\xradio_v2目录下的rom_symbol.ld文件,删除所要修改的模块的驱动相关的函数。注,xr806的rom_symbol.ld文件在lib\xradio_v3文件夹。
      • 在src\driver\chip这个目录相应的外设模组上的源代码文件填上所需的函数,一般情况下把src\rom\rom_bin\src\driver\chip相关模组的函数移植过去即可,因为该目录下的驱动只提供客户查看,并没有编译到sdk镜像里面,真正编译到镜像的是src\driver\chip里面的函数。
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 XR806如何添加本地音频到flash?

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

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

      问题分析

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

      解决方法

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

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

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

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

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

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

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

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

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

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

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 如何获取ap的rssi值?

      1.问题背景
      在网络设备上,很多开发者要把当前的网络质量反馈到用户上,以便用户了解当前网络环境,当网速慢或联网失败时做出及时的网络环境调整。

      2.问题描述
      如何获取目标ap的信号强度。

      3.解决办法
      (1)当连接到ap时获取当前ap的信号强度值,通过以下方式来获取rssi和dbm的值:

      ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_GET_SIGNAL, (int)(&signal));
      	printf("signal = %d! noise = %d!\r\n", (signal.noise + (signal.rssi/2)), signal.noise);
      

      (2)获取附近ap的rssi值和dbm值,可以通过扫描结果来获取,其中获取ap信息结构体wlan_sta_ap里面的rssi成员代表rssi值,level代表dbm值。

      wlan_ssid_t    ssid;
      		uint8_t        bssid[6];
      		uint8_t        channel;
      		uint16_t       beacon_int;
      		int            freq;
      		int            rssi;     /* unit is 0.5db */
      		int            level;    /* signal level, unit is dbm */
      		int            wpa_flags;
      		int            wpa_cipher;
      		int            wpa_key_mgmt;
      		int            wpa2_cipher;
      		int            wpa2_key_mgmt;
      	} wlan_sta_ap_t;
      

      注意:获取的信号强度信息时需要进行一次扫描动作才能刷新缓存结果,所以获取信息之前需要调用wlan_ap_scan_once()函数扫描,并且等待扫描成功后,信号强度信息才会刷新。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 如何创建自定义状态回调函数?

      问题背景
      XR_MCU的SDK中,audio,wlan,Fs等模块被引用时,已经根据状态,设置好了回调函数,但是有客户不清楚如何利用SDK自身资源,创建自己应用模块的状态回调函数。

      问题描述
      如何创建自定义状态回调函数。

      问题分析
      状态回调函数依赖于SDK的framework框架,且已经为用户预留了自定义回调函数的框架,audio,bt,fs,net的状态回调框架都是完全公开的,参照编写即可。

      解决方法

      1 添加自定义状态回调类型
      在project\common\framework\sys_ctrl\sys_ctrl.h文件中,修改ctrl_msg_type结构体,在CTRL_MSG_TYPE_USER后添加自定义类型,如CTRL_MSG_TYPE_TEST。

      typedef enum ctrl_msg_type{
      	CTRL_MSG_TYPE_SYSTEM = 0,
      	CTRL_MSG_TYPE_NETWORK,
      	CTRL_MSG_TYPE_VKEY,
      	CTRL_MSG_TYPE_VOLUME,
      	CTRL_MSG_TYPE_SDCARD,
      	CTRL_MSG_TYPE_FS,
      	CTRL_MSG_TYPE_AUDIO,
      	CTRL_MSG_TYPE_HANDLER,
      
      	/* message defined by user starts from CTRL_MSG_TYPE_USER */
      	CTRL_MSG_TYPE_USER = 0x100,
              CTRL_MSG_TYPE_TEST, //自主添加的回调函数
      } ctrl_msg_type;
      

      2 创建回调函数
      在.h文件中添加状态类型

      enum test_status {
      	TEST_MSG_STATE_FIRSR,        //状态1
      	TEST_MSG_STATE_SECOND,        //状态2
      	TEST_MSG_STATE_UNDEFINE,
      };
      

      在.c文件中添加实体函数

      /* 处理状态变化 */
      static void test_ctrl_msg_process(uint32_t event, uint32_t data, void *arg)
      {
      	switch (EVENT_SUBTYPE(event)) {
      	case TEST_MSG_STATE_FIRSR:
      		test_act_first(data);
      		break;
      	case TEST_MSG_STATE_SECOND:
      		test_act_second(data);
      		break;
      	default:
      		break;
      	}
      }
      
      /* 创建回调函数 */
      int test_init(void)
      {
      	observer_base *base = sys_callback_observer_create(CTRL_MSG_TYPE_TEST,    //监控event类型
      	                                                   0xFFFF,                //监控类型可分类,可参考fs_ctrl.h    
      	                                                   test_ctrl_msg_process, //回调函数
      	                                                   NULL);
      	if (base == NULL) {
      		printf("create fail\n");
      		return -1;
      	}
              /* 挂载到观察链表 */
      	if (sys_ctrl_attach(base) != 0) {
      		printf("attach fail\n");
      		return -1;
      	}
      }
      

      3 发送状态
      当线程中状态发生变化时,通过project\common\framework\sys_ctrl\sys_ctrl.h中定义的API,会调用步骤2中设置好的回调函数。
      常规用法

      /* 实体 */
      int sys_event_send(uint16_t type, uint16_t subtype, uint32_t data, uint32_t wait_ms);
      /* 例,其中wait_ms为队列等待超时时间,队列深度默认为6 */
      sys_event_send(CTRL_MSG_TYPE_TEST,TEST_MSG_STATE_FIRSR,0,0);
      

      特殊用法,发送完成后自动释放数据

      /* 实体 */
      int sys_event_send_with_free(uint16_t type, uint16_t subtype, void *data, uint32_t wait_ms);
      /* 例,其中data是希望传输到回调函数的数据,使用该API能在传输完成后释放内存 */
      struct STtest *testdata = malloc(sizeof(*testdata));
      memset(testdata,0,sizeof(*testdata);
      testdata = dataget(testdata) //数据赋值
      sys_event_send_with_free(CTRL_MSG_TYPE_TEST,TEST_MSG_STATE_FIRSR,testdata ,0);//发送完成后会自动释放数据
      

      特殊用法,自定义销毁方式

      /* 实体 */
      int sys_event_send_with_destruct(uint16_t type, uint16_t subtype, void *data, void (*destruct)(event_msg *), uint32_t wait_ms)
      

      该API和sys_event_send_with_free差异点为,sys_event_send_with_free执行完回调后,会固定执行free(data),但是sys_event_send_with_destruct在执行完回调后,继续执行destruct函数,destruct函数由用户自主编写,可以选择销毁data,也可以选择特殊处理。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 如何解决第三方静态库函数符号重复?

      1.问题背景
      联合开发中,由于软件保密,合作方仅提供.a静态库。但可能出现合作方提供的.a静态库和自身的.a静态库冲突,导致镜像合成失败,且可能因为合作方的各种缘故不方便修改静态库。

      2.问题描述
      程序编译过程中没有出错,但是在ld链接过程中提示错误:multiple definition of。

      3.问题分析
      1 对于在程序中可以修改的重复定义,直接修改程序即可。
      2 multiple definition of的函数都在保密的.a库文件中,重复函数众多,且无法轻易更改程序。由于.a静态文件是由.o可执行文件打包而来,可以先对.a静态库解包,删除掉重复定义的.o可执行文件后重新打包即可。

      4.解决方法
      1 拆包.a静态库。

      ar -x libtarget.a
      

      2 删除多余的.o文件。
      3 重新打包静态库。

      ar crv libtarget.a *.o
      

      4 重新编译。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 汇编代码调试技巧

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

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

      3.问题分析

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

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

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 RF参数是如何保存的?

      1.问题背景
      客户在量产中,由于各个产品一致性不太一样,很多时候需要在出厂时对每个产品进行RF参数的校准才能确保RF性能达到最佳。那么校准后,相关的参数保存在什么地方?

      2.问题描述
      XR系列MCU的RF参数是如何保存的?

      3.解决办法
      目前出厂校准的RF参数主要包括有频偏和发射功率。XR系列MCU获取这两个参数的主要途径有两个:镜像打包时的sdd文件和efuse。而获取来源是遵循以下原则:
      1、MCU启动后,会读取efsue上RF参数区域的数据,如果是合法数据,则采用efuse上的参数,而sdd文件的参数会无效。
      2、MCU启动后,如果efsue上RF参数区域的数据不是合法数据,则采用sdd文件上的参数。如果在软件代码上写入频偏,代码流程上参考project\example\efpg这个示例写入efuse。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 如何使用phoenixMC软件把应用固件与etf固件合并在一起?

      1.问题背景
      在客户量产中,出厂的板子rf参数不太可能做到完全一致,所以需要etf固件来校准rf参数。但是如果烧录完etf固件又再一遍烧录应用固件生产起来就比较麻烦。把两个固件合并在一起的话可以减少生产工序,提高生产效率。

      2.问题描述
      如何使用phoenixMC软件把应用固件与etf固件合并在一起?

      3.解决办法

      3.1使用方法:
      1、打开phoenixMC.exe,点击设置按钮。

      fd29a84ae50b4aae95a0c0ed8d08cacf.jfif

      2、点击合并固件,并依次选择应用固件和etf固件。

      111fa2eba9ca46e0b6c82c4d5f2656a6.jfif

      3、选择完成后,固件会在etf固件的目录下生产新的combineImage.cimg文件,此文件即是两者合并的文件。

      a0ad08b9200640d8b0cf41704de5c1a0.jfif

      e6e7555db2054710b81d7f8003cbe725.jfif

      3.2注意事项:

      • 如果应用固件支持ota升级,合并文件一定要先选择应用固件后再选择etf固件,因为etf固件不支持ota功能。
      • 合并后固件flash layout为:app1->应用固件,app2->etf固件。
      • 固件进行一次ota升级后,etf固件将会被升级后的应用固件覆盖,即app2的区域装载固件不是etf固件,而是新的etf固件。
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 Xradio Skylark 中的无线网络回调事件含义

      1. 问题背景
      部分客户在使用 WLAN 时,不清楚各回调事件的含义,不利于上层应用逻辑开发。

      2. 问题描述
      无线网络各个事件的代表的含义是什么?

      3. 问题分析
      首先看一下无线网卡处于 Station 模式下连接 AP 的过程:

      • Station 发起扫描,扫描附近的 AP
      • Station 选中指定的 AP,发起认证(Authentication)、关联(Association)
      • (可选) 如果是 WPA/WPA2 加密方式,则 AP 发起四次握手协商密钥
      • Station 发起 DHCP 获取 IP 地址

      到这里网络通路已经可以正常运行,上层应用数据包可以发出去了。

      Station 模式断开连接过程:

      • Station 向 AP 发送断开连接请求 (Disassociation)

      以上是正常断开连接过程。除此之外的异常断开连接还有 Station 掉电、重启、发送 DHCP 释放报文等。

      4. 解决办法
      使用 sys_callback_observer_create 创建类型为 CTRL_MSG_TYPE_NETWORK 的事件观察器后,当网络状态发生变化或底层完成相应的任务后,会触发对应的事件回调。创建方法如下:

      ```
      

      observer_base *ob = sys_callback_observer_create(
      CTRL_MSG_TYPE_NETWORK,
      NET_CTRL_MSG_ALL,
      net_ctrl_msg_process,
      NULL
      );

      CTRL_MSG_TYPE_NETWORK 类型的事件目前有以下几种:
      
      

      NET_CTRL_MSG_WLAN_CONNECTED /* 连接成功事件。代表 Station 关联或四次握手完成后(如果 WPA/WPA2 加密,则是四次握手完成后) /
      NET_CTRL_MSG_WLAN_DISCONNECTED /
      断开连接事件。代表 Station 请求断开连接成功后 /
      NET_CTRL_MSG_WLAN_SCAN_SUCCESS /
      扫描完成事件。代表 Station 完成一次扫描 /
      NET_CTRL_MSG_WLAN_SCAN_FAILED /
      扫描失败事件。代表 Station 扫描操作失败 /
      NET_CTRL_MSG_WLAN_4WAY_HANDSHAKE_FAILED /
      四次握手失败事件。代表 WPA/WPA2 四次握手过程失败 /
      NET_CTRL_MSG_WLAN_CONNECT_FAILED /
      连接失败时间。代表 Station 在认证/关联阶段失败 /
      NET_CTRL_MSG_CONNECTION_LOSS /
      连接丢失事件。代表 Station 当前连接丢失,可能是 AP 修改了配置重启、掉电之类的,导致 Station 无法扫描到 /
      NET_CTRL_MSG_NETWORK_UP /
      网络启动完成事件。代表已经获取到 IP 地址(DHCP 完成),网卡已经可以正常工作,通过协议栈收发网络中的数据包 /
      NET_CTRL_MSG_NETWORK_DOWN /
      网络关闭事件。代表已经发送 DHCP 释放报文,而且网卡已经关闭 /
      NET_CTRL_MSG_NETWORK_IPV6_STATE /
      IPv6 地址状态事件。代表 IPv6 地址状态发生了变化 */
      NET_CTRL_MSG_ALL = ALL_SUBTYPE
      };

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 串口修改波特率后与目标波特率不匹配如何解决?

      1、问题背景
      有客户反应,XR系列MCU在修改完串口波特率后,打印输出的是乱码,通过仪器抓波形发现输出的波特率与设置不一致。

      2. 问题描述
      串口修改波特率后与目标波特率不匹配。

      3. 问题分析
      XR系列MCU的波特率理论计算是baund=apb_freq/(16*div),其中apb_freq是APB总线时钟频率,div是分频系数,div计算结果采用去尾法会产生误差。板级文件board_config.h 中BOARD_APBS_CLK_SRC以及BOARD_APBS_CLK_FACTOR可配置APB时钟总线频率。实际应用中,串口误码率建议小于5%,从计算公式得知波特率会出现不是百分百的匹配的情况,但是波特率在允许的误差范围内是可以正常使用的。

      4.解决方法
      通过调整BOARD_APBS_CLK_SRC以及BOARD_APBS_CLK_FACTOR、或者cpu主频来匹配相应的波特率,但是要注意同一个分频值可能出现不能同时兼容所有波特率的情况。下图是主频和分频计算出波特率的示例:
      8690e4e9f6224101bdda453d4f7ec9dd.jfif

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 getsockopt、setsockopt失败如何解决?

      1. 问题背景
      调用 setsockopt 设置 socket 属性失败,或者 getsockopt 获取 socket 属性失败。

      2. 问题描述
      调用 setsockopt、getsockopt 时返回 -1,且 errno 为 ENOPROTOOPT(92)。

      3. 问题分析
      LwIP 当前版本有部分 socket 属性的设置/获取是暂时没有支持的,操作这些属性会返回 errno = ENOPROTOOPT 的错误码。

      4. 解决办法
      以 SDK 中 lwip-2.0.3 为例。可以通过打开文件 include/net/lwip-2.0.3/lwip/sockets.h 查看目前版本 LwIP 支持哪些 socket 属性的设置/获取。

      #define SO_DEBUG       0x0001 /* Unimplemented: turn on debugging info recording */
      #define SO_ACCEPTCONN  0x0002 /* socket has had listen() */
      #define SO_DONTROUTE   0x0010 /* Unimplemented: just use interface addresses */
      #define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */
      #define SO_LINGER      0x0080 /* linger on close if data present */
      #define SO_DONTLINGER  ((int)(~SO_LINGER))
      #define SO_OOBINLINE   0x0100 /* Unimplemented: leave received OOB data in line */
      #define SO_REUSEPORT   0x0200 /* Unimplemented: allow local address & port reuse */
      #define SO_SNDBUF      0x1001 /* Unimplemented: send buffer size */
      #define SO_RCVBUF      0x1002 /* receive buffer size */
      #define SO_SNDLOWAT    0x1003 /* Unimplemented: send low-water mark */
      #define SO_RCVLOWAT    0x1004 /* Unimplemented: receive low-water mark */
      #define SO_SNDTIMEO    0x1005 /* send timeout */
      #define SO_RCVTIMEO    0x1006 /* receive timeout */
      #define SO_ERROR       0x1007 /* get error status and clear */
      #define SO_TYPE        0x1008 /* get socket type */
      #define SO_CONTIMEO    0x1009 /* Unimplemented: connect timeout */
      #define SO_NO_CHECK    0x100a /* don't create UDP checksum */
      

      如上所示,若该属性后的注释有 Unimplemented 标识,则未支持。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 如何使用watchpoint功能?

      1.问题背景
      watchpoint,一般用来观察某个变量/内存地址的状态(也可以是表达式),如可以监控该变量/内存值是否被程序读/写情况。

      2.问题描述
      在程序运行异常的时候,可以借助watchpoint来进行辅助调试。

      3.问题分析
      在XR MCU SDK中,支持了watchpoint功能,通过使能指定宏以及调用指定函数来使用该功能。

      4.解决办法
      (1)使能watchpoint的宏开关:export __CONFIG_WATCHPOINT:=y
      (2)调用watchpoint_add函数添加观察点
      以下是代码使用示例:

      #include <debug/watchpoint.h>
      static int watchpoint_test_value;
      static struct watchpoint wp;
      static enum cmd_status cmd_watchpoint_value_init(char *cmd)
      {
          int ret;
          watchpoint_test_value = 1;
          wp.address = (unsigned int)&watchpoint_test_value;
          wp.length = sizeof(watchpoint_test_value);
          wp.rw = DWT_WRITE;
          ret = watchpoint_add(&wp);
          if (ret) {
              printf("watchpoint_add fail.\n");
          }
          return CMD_STATUS_OK;
      }
      static enum cmd_status cmd_watchpoint_value_change(char *cmd)
      {
          watchpoint_test_value = 0;
          return CMD_STATUS_OK;
      }
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 RTC时钟不能跑、有时候时间不准是什么原因?

      1、问题背景
      有客户反应,XR系列MCU在跑rtc模块时,读取时间一直是同一个值,或者出现时间与现实时间相比不准确。

      2. 问题描述
      RTC时钟不能跑、有时候时间不准是什么原因。

      3.解决方法
      (1)、先确定RTC使用的时钟源是内部震荡还是外部晶振。并且通过修改板级文件board_config.h中BOARD_LOSC_EXTERNAL这个宏定义来匹配相关配置(0是使用内部震荡作为震荡源,1是使用外部晶振),如果配置是外部晶振,但是却没有外接外部32.768khz晶振的话,RTC是跑不起来的。
      #define BOARD_LOSC_EXTERNAL 0 /* 0: inter 32k, 1: external 32k */

      (2)、使用内部震荡的话,由于是rc震荡产生时钟,所以受到温度漂移影响很大,所以客户如果需要精度高的计时,建议使用外部晶振来作为震荡源。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 如何清除扫描列表缓存?

      问题背景
      XR MCU平台发起扫描后,会对扫描结果进行缓存一段时间。

      问题描述
      Wi-Fi设备发起扫描,获取扫描结果。当关闭掉目标路由器后,再次进行扫描获取的扫描结果会依旧包含已关闭的路由器SSID。

      问题分析
      由于实现机制,会对扫描结果进行一定时间缓存,导致已关闭的路由,仍然能扫描到。只要下次发起扫描时,对缓存进行清除,就可以解决该问题。

      解决办法
      调用一下函数即可清除缓存:

      int wlan_sta_bss_flush(int age);
      

      如移除30s内未更新的AP节点为例:

      wlan_sta_bss_flush(30);
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 standby模式下gpio的电平状态是如何变化?

      1.问题背景
      客户在做低功耗设计时经常会使用GPIO外接一些硬件外设,这些外设在芯片的管脚在休眠时候如果跟GPIO有压差就会产生漏电流。我们如何保证休眠时的GPIO的电平状态呢。

      2.问题描述
      客户提问:XR808/XR809/XR871/XR872和XR806在standby模式下芯片的gpio电平状态如何保持的。

      3.解决办法
      XR808/XR809/XR871/XR872在芯片进入standby模式后,如果属于wakeup IO的管脚电平状态处于高阻抗,要保持电平的话,需要调用HAL_Wakeup_SetIOHold才可以把wakeup io固定在某种电平状态。但是不属于wakeup IO的管脚进入休眠是不受控制的,仍然为高阻态。而XR806所有的GPIO都可以通过hold功能来保持原来的电平。
      在硬件设计的时候,如果要休眠保持电平就选wakupio做普通io用。具体哪些管脚属于wakeup IO请在相关芯片的PIN_Multiplexing文档查询。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 如何解决编译错误undefined reference to?

      1.问题背景
      把SDK默认的Freertos切换为其他RTOS后,部分用户反馈,工程中已经定义某个函数,但是在编译最后依旧会报错undefined reference to(找不到某个函数)。

      2.问题描述
      工程编译过程中没有报错,但是在最后连接过程时会提示错误undefined reference to"",找不到特定函数。

      3.问题分析
      编译过程中没有报错,在最后连接时才报错,说明编译时引用了某个头文件,指明该函数需要用其他库实现。

      4.解决方法
      1)首先使用nm命令检查该函数所在的.a静态库,确认该静态库中是否已经包含了该函数,如果没有该函数,则检查该函数的编译是不是需要使能某些宏。

      2)如果已经确认了静态库中已经包含了该函数,说明在gcc链接过程中被忽略了,则可以尝试使用以下三种方法。

      • 把该静态库的顺序提前,如first.a中调用了second.a中的某个函数,但是编译时却报错找不到second.a的某个函数,尝试调换两个静态库的顺序。

      • 使用-Wl,–start-group和-Wl,–end-group修饰该静态库,代表该静态库不会只检索一次,而是多次来回检索,防止遗漏。缺点如果修饰的静态库太多,会导致编译速度变慢。

      • 使用-Wl,–whole-archive和-Wl,–no-whole-archive修饰静态库,代表该静态库的所有函数都不会被忽略,强制链接。缺点是如果该静态库中存在多余的函数,会浪费flash。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 执行扫描动作时,偶尔会扫描不到目标的AP如何解决?

      1、问题背景
      有客户反应,XR系列MCU在连接进行扫描附近AP时,扫描不出所需要的AP,但第二次或者第三次就能扫描出来了。

      2. 问题描述
      当mcu执行扫描动作时,扫描不出所需要的ap时,可以通过哪些方法来改善这种情况。

      3. 问题分析

      • 增加扫描结果的缓存
        如果附近网络环境复杂,AP数量太多时,扫描达到缓存上限值就会忽略掉一些ap数。此时可以通过增加扫描结果的缓存来让目标AP显示出来。具体方法可通过net sta scan result_num指令来查询当前AP的上限值(默认是20个),设置上限则通过net sta bss max count 和net sta scan result 指令来实现(num代表实际所需的AP数量)。函数实现在cmd_wlan.c里面查询相关指令接口。

      • 增加信道停留时间
        同一个信道的信道停留时间也有限,如果附近的AP都挤在同一个的信道,扫描这个信道的时间超时了也会忽略掉一些AP的信息。所以有时候也需要通过增加信道停留时间的方式来改善扫不出目标AP的情况。具体方法可通过以下代码来实现:

      param.num_probes = num_probes;
      param.probe_delay = probe_delay;
      param.min_dwell = min_dwell;
      param.max_dwell = max_dwell;
      ret = wlan_ext_request(g_wlan_netif, WLAN_EXT_CMD_SET_SCAN_PARAM, (int)(&param));
      
      其中几个参数的典型值是:n=2 d=100 min=100 max=125 n
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 如何打开 LwIP 调试信息?

      1. 问题背景
      出现网络问题时,常常需要打开 LwIP 内部打印信息调试、查看协议栈运行状态,以获取更多的有效信息。

      2. 问题描述
      如何打开 LwIP 调试信息?

      3. 问题分析
      LwIP 内部调试信息有两类:
      (1) LWIP_DEBUG,可以显示协议栈内部各层运行流程,收发通路信息等。
      (2) LWIP_STATS,可以显示协议栈内部各种资源使用情况,包括内存、队列、信号量等。

      4. 解决办法

      (1) 打开 LWIP_DEBUG 的方式
      文件 include/net/lwip-x.x.x/arch/cc.h 中使能 DEBUG:

      /* Debug on/off */
      #define LWIP_DEBUG
      

      文件 include/net/lwip-2.0.3/lwipopts.h 中

      设置调试等级,使能全局调试信息:

      #define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_ALL
      #define LWIP_DBG_TYPES_ON               LWIP_DBG_ON
      

      根据需要打开相应类别的调试信息,如 socket 相关调试信息:

      #define SOCKETS_DEBUG                   LWIP_DBG_ON
      

      (2) 打开 LWIP_STATS 的方式
      文件 include/net/lwip-2.0.3/lwipopts.h 中

      使能 LWIP_STATS:

      #define LWIP_STATS                     1
      #define LWIP_STATS_DISPLAY             1
      

      根据需要打开相应类别的统计信息(默认已打开),如协议栈堆内存使用信息:

      #define MEM_STATS                       ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0))
      

      最后自行调用相应统计函数,就可以显示当前协议栈统计信息:

      LINK_STATS_DISPLAY();      // 链路层统计信息
      ETHARP_STATS_DISPLAY();    // ARP层统计信息
      IPFRAG_STATS_DISPLAY();    // IP层分片统计信息
      IP_STATS_DISPLAY();        // IP层统计信息
      IGMP_STATS_DISPLAY();      // IGMP协议统计信息
      ICMP_STATS_DISPLAY();      // ICMP协议统计信息
      UDP_STATS_DISPLAY();       // UDP层统计信息
      TCP_STATS_DISPLAY();       // TCP层统计信息
      MEM_STATS_DISPLAY();       // 堆内存使用统计信息
      MEMP_STATS_DISPLAY(i);     // 内存池i的使用统计信息
      SYS_STATS_DISPLAY();       // 系统统计信息,包括队列(mbox)、信号量、锁
      stats_display();           // 打印上面所有信息
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 select引发崩溃如何解决?

      1. 问题背景
      lwip-1.4.1 版本使用 select 函数后引发崩溃。
      内部报错:sock != NULL at line 1296 in src/api/sockets.c

      2. 问题描述
      在多线程同时使用 lwip-1.4.1 版本的 select 函数,可能产生崩溃问题。

      3. 问题分析
      lwip-1.4.1 中 lwip_select 函数获取 sock 结构时,未对空指针进行处理,从而引发崩溃。多线程操作同个 socket 的场景下易复现该问题。
      该 bug 在 lwip 后续版本中进行了修复。

      4. 解决办法

      方法 (1): 使用 lwip-2.0.3
      因为 lwip-2.0.3 中已修复该 bug,切换使用即可。
      xradio_skylark_sdk 中切换使用 lwip-2.0.3 的方法:在本地工程的 gcc/localconfig.mk 内部导出 __CONFIG_LWIP_V1 为 n。如下所示:

      export __CONFIG_LWIP_V1 := n
      

      方法 (2): 合入 lwip 修复成果至 lwip-1.4.1
      lwip 开源代码获取方式:

      git clone https://git.savannah.gnu.org/git/lwip.git
      

      该 bug 在提交 5ceaed291f2c1320d36f9501fadd51923fa1c556 中修复,查看修改的代码:

      git show 5ceaed291f2c1320d36f9501fadd51923fa1c556
      

      修改内容如下所示:

      commit 5ceaed291f2c1320d36f9501fadd51923fa1c556
      Author: sg <goldsimon@gmx.de>
      Date:   Sat Jan 17 21:02:58 2015 +0100
      
          fixed bug #43361 select() crashes with stale FDs
      
      diff --git a/CHANGELOG b/CHANGELOG
      index 2c9aebbb..3bf40441 100644
      --- a/CHANGELOG
      +++ b/CHANGELOG
      @@ -152,6 +152,9 @@ HISTORY
      
         ++ Bugfixes:
      
      +  2015-01-17: Simon Goldschmidt
      +  * sockets.c: fixed bug #43361 select() crashes with stale FDs
      +
         2015-01-17: Simon Goldschmidt
         * sockets.c/.h, memp_std.h: fixed bug #40788 "lwip_setsockopt_internal() crashes"
           by rewriting set/getsockopt functions to combine checks with the actual code
      diff --git a/src/api/sockets.c b/src/api/sockets.c
      index 3369c6d1..4109cee4 100644
      --- a/src/api/sockets.c
      +++ b/src/api/sockets.c
      @@ -1209,6 +1209,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
         u32_t msectimeout;
         struct lwip_select_cb select_cb;
         int i;
      +  int maxfdp2;
         SYS_ARCH_DECL_PROTECT(lev);
      
         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
      @@ -1266,47 +1267,69 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
           SYS_ARCH_UNPROTECT(lev);
      
           /* Increase select_waiting for each socket we are interested in */
      -    for(i = 0; i < maxfdp1; i++) {
      +    maxfdp2 = maxfdp1;
      +    for (i = 0; i < maxfdp1; i++) {
             if ((readset && FD_ISSET(i, readset)) ||
                 (writeset && FD_ISSET(i, writeset)) ||
                 (exceptset && FD_ISSET(i, exceptset))) {
      -        struct lwip_sock *sock = tryget_socket(i);
      -        LWIP_ASSERT("sock != NULL", sock != NULL);
      +        struct lwip_sock *sock;
               SYS_ARCH_PROTECT(lev);
      -        sock->select_waiting++;
      -        LWIP_ASSERT("sock->select_waiting overflow", sock->select_waiting > 0);
      +        sock = tryget_socket(i);
      +        if (sock != NULL) {
      +          sock->select_waiting++;
      +          LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
      +        } else {
      +          /* Not a valid socket */
      +          nready = -1;
      +          maxfdp2 = i;
      +          SYS_ARCH_UNPROTECT(lev);
      +          break;
      +        }
               SYS_ARCH_UNPROTECT(lev);
             }
           }
      
      -    /* Call lwip_selscan again: there could have been events between
      -       the last scan (without us on the list) and putting us on the list! */
      -    nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
      -    if (!nready) {
      -      /* Still none ready, just wait to be woken */
      -      if (timeout == 0) {
      -        /* Wait forever */
      -        msectimeout = 0;
      -      } else {
      -        msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
      -        if (msectimeout == 0) {
      -          /* Wait 1ms at least (0 means wait forever) */
      -          msectimeout = 1;
      +    if (nready >= 0) {
      +      /* Call lwip_selscan again: there could have been events between
      +         the last scan (without us on the list) and putting us on the list! */
      +      nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
      +      if (!nready) {
      +        /* Still none ready, just wait to be woken */
      +        if (timeout == 0) {
      +          /* Wait forever */
      +          msectimeout = 0;
      +        } else {
      +          msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
      +          if (msectimeout == 0) {
      +            /* Wait 1ms at least (0 means wait forever) */
      +            msectimeout = 1;
      +          }
               }
      -      }
      
      -      waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout);
      +        waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout);
      +      }
           }
      -    /* Increase select_waiting for each socket we are interested in */
      -    for(i = 0; i < maxfdp1; i++) {
      +
      +    /* Decrease select_waiting for each socket we are interested in */
      +    for (i = 0; i < maxfdp2; i++) {
             if ((readset && FD_ISSET(i, readset)) ||
                 (writeset && FD_ISSET(i, writeset)) ||
                 (exceptset && FD_ISSET(i, exceptset))) {
      -        struct lwip_sock *sock = tryget_socket(i);
      -        LWIP_ASSERT("sock != NULL", sock != NULL);
      +        struct lwip_sock *sock;
               SYS_ARCH_PROTECT(lev);
      -        LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
      -        sock->select_waiting--;
      +        sock = tryget_socket(i);
      +        if (sock != NULL) {
      +          /* @todo: what if this is a new socket (reallocated?) in this case,
      +             select_waiting-- would be wrong (a global 'sockalloc' counter,
      +             stored per socket could help) */
      +          LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
      +          if (sock->select_waiting > 0) {
      +            sock->select_waiting--;
      +          }
      +        } else {
      +          /* Not a valid socket */
      +          nready = -1;
      +        }
               SYS_ARCH_UNPROTECT(lev);
             }
           }
      @@ -1330,6 +1353,12 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
           sys_sem_free(&select_cb.sem);
       #endif /* LWIP_NETCONN_SEM_PER_THREAD */
      
      +    if (nready < 0) {
      +      /* This happens when a socket got closed while waiting */
      +      set_errno(EBADF);
      +      return -1;
      +    }
      +
           if (waitres == SYS_ARCH_TIMEOUT) {
             /* Timeout */
             LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 低功耗蓝牙BLE断开连接错误码和分析?

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

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

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

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 如何设置AP模式默认IP地址、子网掩码、网关?

      1. 问题背景
      特殊需求想要修改 AP 模式使用的 IP 地址、子网掩码、网关。

      2. 问题描述
      xradio_skylark_sdk 中如何设置 AP 模式默认 IP 地址、子网掩码、网关?

      3. 问题分析
      目前 SDK 中使用都是使用静态的方法去配置 AP 模式的 IP 地址、掩码、网关以及 DHCP 的地址池范围。若要修改,则需要到指定文件中修改。注意:若修改了 AP 的 IP 地址,需要确保 DHCP 分配的地址池与 AP 的 IP 地址是同一子网段下。

      4. 解决办法

      (1) 修改 AP 模式的 IP 地址的方法
      在 project/common/framework/sysinfo.c 的 int sysinfo_default(void) 函数内部进行修改:

      /* netif AP */
      IP4_ADDR(&g_sysinfo.netif_ap_param.ip_addr, 192, 168, 51, 1);
      IP4_ADDR(&g_sysinfo.netif_ap_param.net_mask, 255, 255, 255, 0);
      IP4_ADDR(&g_sysinfo.netif_ap_param.gateway, 192, 168, 51, 1);
      

      (2) 修改 DHCP 地址池范围的方法
      在 src/net/udhcp-0.9.8/dhcpd_cfg.h 进行修改:

      #define DHCPD_ADDR_START         "192.168.51.100"
      #define DHCPD_ADDR_END           "192.168.51.104"
      #define DHCPD_INTERFACE          "en1"
      #define DHCPD_OPTION             ""
      #define DHCPD_OPT                ""
      #define DHCPD_REMAIN             "yes"
      #define DHCPD_MAX_LEASES         "5"
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 如何修改中断优先级?

      1.问题背景
      XR809/XR871/XR808/XR872上如何修改中断的优先级。

      2.问题描述
      很多模块都会使用到中断,但中断的优先级在模块的初始化或者在使能中断时就设定了,那么如何修改中断的优先级呢?

      3.解决办法

      3.1 中断是如何设定优先级的
      中断的优先级是在下面这个函数设定的,每个带中断的模块都会调用到这个函数
      HAL_NVIC_ConfigExtIRQ(GPADC_IRQn, GPADC_IRQHandler, NVIC_PERIPH_PRIO_DEFAULT);(第二个参数代表的是优先级)
      这个HAL_NVIC_ConfigExtIRQ会调用到HAL_NVIC_SetPriority函数
      HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)函数的2个参数分别是中断类型以及中断优先级。
      最终是HAL_NVIC_SetPriority进行了中断优先级的设定的。

      3.2如何设定中断优先级
      (1).本来修改模块的优先级通过修改这个模块的HAL_NVIC_ConfigExtIRQ函数即可,但大部分模块的初始化函数都已经rom化了,直接修改rom化的初始化函数是无法生效的。

      (2).所以首先我们需要找到模块中哪里调用了HAL_NVIC_ConfigExtIRQ函数,然后在应用层代码中添加HAL_NVIC_SetPriority函数重新设定优先级
      例如:
      GPIO模块在HAL_GPIO_EnableIRQ模块中调用到了HAL_NVIC_ConfigExtIRQ函数,那么需在上层应用代码中再次调用HAL_NVIC_SetPriority
      函数来进行重新设定中断的优先级

      HAL_GPIO_EnableIRQ        --->   这个接口里面的代码已经rom化,不能进行优先级设定
      HAL_NVIC_SetPriority      --->   重新设定优先级,覆盖HAL_GPIO_EnableIRQ函数里设定的默认值
      

      ADC模块在HAL_ADC_Init模块中调用到了HAL_NVIC_ConfigExtIRQ函数,那么需在上层应用代码中再次调用HAL_NVIC_SetPriority
      函数来进行重新设定中断的优先级

      HAL_ADC_Init              --->   这个接口里面的代码已经rom化,不能进行优先级设定
      HAL_NVIC_SetPriority      --->   重新设定优先级,覆盖HAL_ADC_Init函数里设定的默认值
      

      (3).需要注意HAL_NVIC_SetPriority函数的2个参数

      void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
      IRQn_Type IRQn     --->   中断类型,在应用层需要根据具体的模块进行填写,例如GPIO需要填GPIOA_IRQn/GPIOB_IRQn,ADC需要填GPADC_IRQn
      uint32_t priority  --->   优先级,根据具体所需进行填写,数字越小优先级越低
      
      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 如何使用timer命令行命令?

      1.问题背景
      XR809/XR871/XR808/XR872上timer如何使用

      2.问题描述
      timer模块在芯片中只是一个小模块,在发布文档中没有专门的文档进行说明,只有代码用例,部分客户看代码后会对timer里的一些参数云里雾里的

      3.解决办法
      下面会从几个方面帮助客户去了解以及测试timer模块。

      3.1如何在固件中添加测试timer测试用的命令行命令:

      (1).project/XXX/command.c文件中添加timer命令如下:

      --- a/platforms/xr806/xr806-os/project/tuya/command.c
      +++ b/platforms/xr806/xr806-os/project/tuya/command.c
      @@ -181,6 +181,7 @@ static const struct cmd_data g_main_cmds[] = {
      +       { "timer",  cmd_timer_exec },
              { "sysinfo",cmd_sysinfo_exec, CMD_DESC("system information command") },
              { "help",   cmd_main_help_exec, CMD_DESC(CMD_HELP_DESC) },
      

      (2).添加完成后编译烧录固件在命令行中输入help命令可以看到timer命令被编译进固件中了:

      [*] net      : network command
      [*] rf       : radio frequency command
      [*] drv      : driver command
      [*] echo     : echo command
      [*] mem      : memory command
      [*] heap     : heap use information command
      [*] thread   : thread information command
      [*] upgrade  : upgrade command
      [*] reboot   : reboot command
      [*] ota      : over the airtechnology upgrade commands
      [*] etf      : etf command
      [*] pm       : power management command
      [*] efpg     : efpg command
      [*] flash    : flash control command
      [*] lmac     : low mac command
      [*] timer
      [*] sysinfo  : system information command
      [*] ble
      [*] help     : print this message and quit
      

      (3)timer命令的源码在project/common/cmd/cmd_timer.c,用户可以对该源码进行修改测试,也可以参考该文件的timer接口进行应用开发。

      3.2timer命令如何使用

      (1)timer命令行命令支持下面几个子命令:

      timer config i=X m=X s=X d=X p=X   -->  配置timer的参数,参数后面说明
      timer deconfig i=X                 -->  取消当前timer的配置参数
      timer start i=X                    -->  启动对应的timer(支持2个timer 0/1)
      timer stop i=X                     -->  停止对应的timer
      timer pause i=X                    -->  暂停对应的timer
      timer continue i=X                 -->  继续对应的timer
      Timer value i=X                    -->  获取对应timer的值(该值是剩余多少定时时间,需计算)
      

      (2)timer命令行参数说明:

      参数i:0/1  -->  控制的是哪个timer,806支持2个timer,0/1
      参数m:repeat/once  -->  定时模式,repeat:循环定时模式,once:一次定时模式
      参数s:LF/HF  -->  时钟源,LF:低频32k晶振,HF:高频晶振,该晶振为外部所接晶振,例如如果接的是40M,HF就是40M,接的是26M,HF就是26M
      参数d:1/2/4/8/16/32/64/128  -->  分频系数
      参数p:                    -->  定时period值,该值需要用户根据时钟源,分频系数,定时时间进行计算:
                                      需要用到的计算公式如下:
                                      interval = period / ( clk-src / clk-div )
                                      period = interval * ( clk-src / clk-div )
      

      (3)公式参数说明:

      参数interval:需要定时的值(例如5s,0.5s)
      参数clk-src:时钟源(例如40M,26M)
      参数clk-div:分频系数(分频系数的选择影响精度和定时时间长短范围)
      参数period:根据定时值,时钟源,分频系数计算出来的值,该值会写到timer寄存器中,timer模块
                  就是根据这个值进行定时的。
      
      例子:例如需要定时5s,板子外接时钟源是26M,分频系数选4,那么根据公式可以计算出period的值应该需要填32,500,000
      

      4.timer命令实操说明说明

      timer config i=1 m=once s=HF d=4 p=32500000    -- 1
      <ACK> 200 OK
      timer start i=2                                -- 2
      <ACK> 200 OK
      timer value i=1                                -- 3
      <ACK> 200 value=19462685
      timer value i=1                                -- 4
      <ACK> 200 value=4617179
      timer value i=1                                -- 5
      <ACK> 200 value=0
      
      (1).配置timer 1,模式设定once模式,时钟源选HF(26M),分频选4,因为想定时5s,因此算出p值需要填写32500000
      (2).启动定时器1
      (3).第一次获取period值19462685,根据公式interval = period / ( clk-src / clk-div )
          可以算出剩余时间interval = 19462685 / (26000000 / 4) = 2.994s
      (4).同上可以算出第二次剩余时间 interval = 4617179 / (26000000/4) = 0.71s
      (5).第3次获取值时因为已经超过5s,所以获取到的值为0
      

      想设定其他分频和时间可根据公式以及需要设定的分频时间算出period值填到对应的函数接口即可。

      其他命令相对简单,因此不再进行实操显示

      注意:
      如果遇到timer测试定时时间与现实实际实际不符,可以从下面一些方向进行排查:
      (1).计算晶振与实际晶振部分(例如:计算时使用26M,但实际板子接的时40M)
      (2).重复计算一下period值,period值填写错误也会导致定时时间不准确

      附件timer_pparam.xlsx:timer_param.xlsx
      附件是26M参数的时间,分频,period值的参考表,其他频率的晶振也可以参考该表算出period值。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 固件烧录完成后,程序不是预期烧录程序或者甚至无法启动如何解决?

      1.问题背景
      872平台上烧录成功后,程序运行没有改变,还是原来的程序,有时候甚至烧录成功后系统无法启动。

      2.问题描述
      烧录固件完成后,提示烧录成功,断上电后,程序跑的还是原来的程序,没有烧录成功,同时还出现概率性提示烧录成功后无法启动现象。

      3.问题分析
      程序跑的还是原来的,同时还出现烧录成功后无法启动。如果img没有问题,那么大概率就是程序根本没有烧录到flash中。所以在烧录flash前,勾选上"写入后进行校验"。

      5dbd36c9abfb459ab101a808932b0c51.jfif

      勾选上写入校验后,发现,烧录异常,无法进行写入。

      938df70d787b4b2dae81ce32887762b2.jfif

      4.解决办法
      根本原因还是在于固件没有写入

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 mac地址要如何存放以及如何获取?

      1.问题背景
      XR809/XR871/XR808/XR872上的mac地址改如何存放,还有获取的方式是怎样。

      2.问题描述
      客户使用中XR809/XR871/XR808/XR872中,可能不了解mac地址的存放以及获取方式。

      3.解决办法

      3.1 MAC地址存放在什么地方的
      根据prj_config.h里面的#define PRJCONF_MAC_ADDR_SOURCE 来决定
      1、SYSINFO_MAC_ADDR_FLASH是sysinfo里面的一个缓冲区。
      2、SYSINFO_MAC_ADDR_CHIPID是根据chipid来随机生成,有小概率重复。
      3、SYSINFO_MAC_ADDR_EFUSE写进efuse里面的mac地址。
      注:MAC地址的第一个字节必须为偶数,可参考mac地址规则

      3.2 MAC地址怎么获取
      如mac地址存放在flash,使用控制台指令:sysinfo get mac
      如mac地址存放在efuse,使用控制台指令:efpg get mac

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 为什么开机时候串口以及部分gpio会有电平跳变?

      1.问题背景
      客户在测试时,发现开机的一瞬间串口以及部分gpio会有电平跳变,这个电平跳变的来源是哪里的,是否能消除掉的。

      2.问题描述
      客户设备在开机的时候PB2上的LED会闪烁一下,使用示波器抓有一段5毫秒左右的脉冲。

      3.解决办法
      由于XR系列MCU最开始运行的是固化在ROM里面的brom代码,会执行下列操作:
      1、PB2、PB3管脚会反初始化后再初始化成输入功能GPIO,用于检测是否进入烧录模式,导致PB2、PB3管脚会有跳变。
      2、UART0会初始化,用于与烧录工具通信,导致UART0的TX、RX管脚有跳变。
      3、如果该型号的MCU的flash是外挂的话,那么操作flash相关的管脚也会有跳变,包括hold管脚与wp管脚。
      从跳变原因来看,这几个管脚是来自brom的操作,已经固化到芯片上,所以是不能消除的,所以硬件设计的时候需要注意。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 如何更换打印log口?

      1.问题背景
      XR809/XR871/XR808/XR872/XR806 上如何把log口uart0更换为uart1或uart2。

      2.问题描述
      我司SDK发布时镜像log默认由uart0输出,有些客户的产品需要把log从非uart0口输出(例如从uart1或uart2输出)。

      3.解决办法

      3.1 修改board_config.c文件,配置对应uart口的ping脚
      例如:(下面的代码只做事例讲解,实际代码不同平台可能会不一样,请根据原理图和数据手册进行修改):
      (1).添加对应uart的脚

      static const GPIO_PinMuxParam g_pinmux_uart2[] = {
          { GPIO_PORT_B, GPIO_PIN_14, { GPIOB_P14_F3_UART2_TX,  GPIO_DRIVING_LEVEL_1, GPIO_PULL_UP } }, /* TX */
          { GPIO_PORT_B, GPIO_PIN_15, { GPIOB_P15_F3_UART2_RX,  GPIO_DRIVING_LEVEL_1, GPIO_PULL_UP } }, /* RX */
      

      (2).确保board_config.c中board_get_pinmux_info函数已有对应的uart口的初始化代码(有些版本可能没有uart2的初始化代码,需要自行添加)

      case HAL_DEV_MAJOR_UART:
          if (minor == UART0_ID) {
              info[0].pinmux = g_pinmux_uart0;
              info[0].count = HAL_ARRAY_SIZE(g_pinmux_uart0);
          } else if (minor == UART1_ID) {
              info[0].pinmux = g_pinmux_uart1;
              info[0].count = HAL_ARRAY_SIZE(g_pinmux_uart1);
          } else if (minor == UART2_ID) {
              info[0].pinmux = g_pinmux_uart2;
              info[0].count = HAL_ARRAY_SIZE(g_pinmux_uart2);
          } else {
              ret = HAL_INVALID;
          }
          break;
      

      3.2 修改board_config.h文件配置log从那个uart输出
      例如:把log从uart0修改为从uart2输出

      #define BOARD_MAIN_UART_ID      UART0_ID  --改为-->  #define BOARD_MAIN_UART_ID      UART2_ID
      

      注意点:
      不同芯片不同方案会有不同的board_config.c和board_config.h文件,确保修改的文件是你所需要的方案

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志XR806芯片 系统异常重启如何解决?

      1. 问题背景
      产品在做稳定性测试,发现设备异常重启

      2. 问题描述
      用户应用在做长运压测,发现设备长运2~3天后会异常重启,log中未发现有代码奔溃现象。

      3. 问题分析
      系统重启,需要判断重启原因,系统中的重启原因有如下:

      typedef enum {
          SYS_POWERON             = 0,    //硬件上电启动
          SYS_WATCHDOG_CHIP_RST   = 1,    //看门狗复位重启,包含整个系统
          SYS_WATCHDOG_CPU_RST    = 2,    //看门狗复位重启,仅CPU
          SYS_REBOOT              = 6,    //执行reboot命令重启
          SYS_CPU_RST             = 7,    //cpu异常复位启动
          SYS_NVIC_RST            = 8,    //中断异常重启
      }SystemStartupState;
      

      在系统阶段就可以插桩代码,判断重启原因,下面是示例代码:

      const char* startup_state_str[] = {"powerOn", "wdgSocRst", "wdgCpuRst", "sleep",
          "standby", "hibernation", "reboot", "cpuRst","nvicRst"};
      printf("startup state: %s\n", startup_state_str[SysGetStartupState()]);
      

      通过插桩代码,就可以明确重启原因,导致看门狗喂狗不及时而重启。

      4. 解决办法
      (1)插桩代码,判断重启原因。
      (2)如果是看门狗重启,大部分情况下看门狗重启都是由于代码执行异常卡死,解决该问题,就先把看门狗关掉,接上JTAG等调试工具,程序执行异常,就会block住(不会重启),就可以利用jtag判断代码执行位置,进而找出异常点。

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 【FAQ】全志R329芯片FAQ汇总(你不知道的和你想知道的的这里都有)

      01、【FAQ】全志R329 Tina中如何使用adb/串口密码登录?
      02、【FAQ】全志R329 Tina中使用如何使用perf分析CPU使用率?
      03、【FAQ】全志R329以太网模块初始化失败如何解决?
      04、【FAQ】全志R329以太网网络不通或丢包严重怎么解决?
      05、【FAQ】全志R329以太网常用调试命令和排查手段
      06、【FAQ】全志R329以太网使能报No phy found或Initialize hardware error怎么解决
      07、【FAQ】全志R系列Tina系统Wi-Fi联网失败排查思路
      08、【FAQ】全志R系列Tina-Linux4.9部分平台唤醒源配置
      09、【FAQ】全志R系列休眠唤醒使用和框架介绍
      10、【FAQ】全志R329 Tina下如何使用硬件Watchdog?
      11、【FAQ】全志R系列启动频率的修改方法
      12、【FAQ】全志R329如何查看和修改sdio的频率?
      13、【FAQ】全志R329如何进行coredump的配置与调试?
      14、【FAQ】全志R系列如何进行Tina根文件系统定制?
      15、【FAQ】全志R系列Tina内核配置不生效如何解决?
      16、【FAQ】全志R329如何在DragonSN烧写mac地址?
      18、【FAQ】全志R系列如何解决wpa_supplicant服务启动问题?
      19、【FAQ】全志R329如何进行WiFi驱动收发帧打印控制?
      20、【FAQ】全志R329如何解决Tina删除内核根目录.config后一直编译失败的问题?
      21、【FAQ】全志R329如何于Tina下支持多用户?
      22、【FAQ】全志R系列Wi-Fi唤醒问题排查思路
      23、【FAQ】全志R329如何解决Tina双系统安全固件启动失败问题?
      24、【FAQ】全志R329如何通过wpa_cli手动调试wifi station?
      25、【FAQ】全志R329如何实现Tina secureboot 打包分离模式支持?
      26、【FAQ】全志R329如何解决在线mp3流媒体seek异常?
      27、【FAQ】全志R系列wpa_supplicant和wpa_cli简介
      28、【FAQ】全志R系列Tina 如何使用 NFS?
      29、【FAQ】全志R329如何在平台修改uboot阶段CPU频率?
      30、【FAQ】全志R329Tina下如何判断是安全固件?
      31、【FAQ】全志R329如何将I2C时钟频率变成800kHz?
      32、【FAQ】全志R系列如何在Tina下使用bootchartd来分析rootfs启动时间?
      33、【FAQ】全志R329如何通过uboot修改设备树属性?
      34、【FAQ】全志R329如何解决RTL驱动hostap启动失败的问题?
      35、【FAQ】全志R329如何解决无法将wlan0加到br-lan这个网桥上面的问题?
      36、【FAQ】全志R329如何解决蓝牙设备断开慢的问题?
      37、【FAQ】全志R329如何利用wpa_cli设置国家代码?
      38、【FAQ】全志R329Tina网络adb的使用
      39、【FAQ】全志R329如何解决在Audiocodec使用S24_LE格式进行录音时产生的软件分析波形异常问题?
      40、【FAQ】全志R系列如何解决gpio-keys驱动在系统启动上报两次input事件?
      41、【FAQ】全志R329以太网常用调试说明
      42、【FAQ】全志R329如何在Linux Device Tree中配置预留内存?
      43、【FAQ】全志R329如何正确查看XRADIO相关版本信息?
      44、【FAQ】全志R329如何解决调用Bluez mainloop_add_fd函数失败的问题?
      45、【FAQ】全志R329蓝牙设备类型分类与过滤方法
      46、【FAQ】全志R329一些正常的I2C报错
      47、【FAQ】全志R329如何关闭HT40?
      48、【FAQ】全志R329 XRADIO如何查看发射功率和频偏?
      49、【FAQ】全志R329如何在WiFi Softap模式添加自定义Vendor IE?
      50、【FAQ】全志R329如何解决蓝牙播放无声(snd_pcm_open error: Out of memory)?
      51、【FAQ】全志R329 多台设备的adb device id相同,无法指定设备,如何指定设备的adb device id?
      52、【FAQ】全志R329如何解决Tina中package下新增软件包目录很深导致检测不到问题
      53、【FAQ】全志R329如何使用DMIC的高通滤波寄存器滤掉低频噪声?
      54、【FAQ】全志R329如何解决Tina双系统uboot校验rootfs失败的问题?
      55、【FAQ】全志R329如何在Tina安全应用程序调试?
      56、【FAQ】全志R329在dtbo中如何配置gpio?
      57、【FAQ】全志R329 LRADC电压设置、识别精度、识别误差、应用等相关知识
      58、【FAQ】全志R329如何设置蓝牙自动重连时间或关闭自动重连?
      59、【FAQ】全志R系列 Tina 如何查看通过 procd init 脚本启动的应用输出到 stdout/stderr 的打印信息?
      60、【FAQ】全志R329如何在Tina在不烧写secure bit下开发OPTEE安全应用?
      61、【FAQ】全志R329 MiniGUI如何获取和设置BITMAP像素点?
      62、【FAQ】全志R329如何判断Tina安全启动boot分区证书与boot分区数据是匹配与否?
      63、【FAQ】全志R329Tina安全启动校验linux/rootfs失败直接重启如何解决?
      64、【FAQ】全志R329Tina下几种安全存储实现有何区别
      65、【FAQ】全志R329 Tina下为何有些optee的demo只有NA源码没有TA源码?
      66、【FAQ】全志R329Tina中TA下有哪些加解密接口?
      67、【FAQ】全志R329Tina下无法选中libcedarx如何解决?
      68、【FAQ】全志R系列在Tina下如何确认方案的optee版本信息
      69、【FAQ】全志R系列在Tina下如何设置optee-secure-storage默认保存路径
      70、【FAQ】全志R329如何使用audiocodec如何减少snd_pcm_open的耗时
      71、【FAQ】全志R329如何进入monitor模式
      72、【FAQ】全志R329如何进行Tina Linux蓝牙低功耗默认连接参数修改
      73、【FAQ】全志R329在Tina如何在蓝牙已连接情况下拒绝其他耳机回连
      74、【FAQ】全志全系列芯片 APST平台无法下载或者更新工具
      75、【FAQ】全志 F系列/R系列/V系列 RTOS平台cache操作接口介绍
      76、【FAQ】全志系列芯片如何把flash擦成空片?
      77、【FAQ】持续更新中......

      发布在 A Series
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      软解跑1080P

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      720P四寸
      720P四寸1.jpg
      720P四寸2.jpg

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      480P 四寸
      480P四寸1.jpg
      480P四寸2.jpg

      发布在 公告
      q1215200171
      budbool
    • R329语音识别视频教程,从编译到部署,完全可用

      R329语音识别 视频教程, 从编译到部署,完全可用
      R329语音识别之前发布了一个简单版本, 今天终于出了一个详细的版本, 可以自行在 R329上实现编译
      获取到语音识别的结果用于其他的DIY项目
      手把手教会如何编译, 以及在哪修改源码更改功能

      视频地址: https://www.bilibili.com/video/BV1Rq4y1B7WH?spm_id_from=333.999.0.0
      项目地址: https://github.com/7758258abc/r329_speed
      下载Maix-Speech-master的地址: https://github.com/sipeed/Maix-Speech

      原文链接:https://bbs.sipeed.com/thread/1296

      enxegIUmXvwB6in26G2sqHS7qp2axDYvVLldRWgM.png

      发布在 A Series
      q1215200171
      budbool
    • 回复: 【366期开放夜】自制一款低成本的RISC-V 64单板机(基于全志D1s)

      蹲直播回放的小伙伴看过来:https://www.bilibili.com/video/BV1CQ4y1e7km?spm_id_from=333.999.0.0

      发布在 MR Series
      q1215200171
      budbool
    • 回复: 【366期开放夜】自制一款低成本的RISC-V 64单板机(基于全志D1s)

      @zibon 0.PNG 作者的github

      发布在 MR Series
      q1215200171
      budbool
    • 回复: RISC-V SoC + AI | 在全志 D1「哪吒」开发板上,跑个 ncnn 神经网络推理框架的 demo

      @abb12 再换个版本试试?

      发布在 MR Series
      q1215200171
      budbool
    • RISC-V SoC + AI | 在全志 D1「哪吒」开发板上,跑个 ncnn 神经网络推理框架的 demo

      引言

      D1 是全志科技首款基于 RISC-V 指令集的 SoC,主核是来自阿里平头哥的 64 位的 玄铁 C906。「哪吒」开发板 是全志在线基于全志科技 D1 芯片定制的 AIoT 开发板,是目前还比较罕见的使用 RISC-V SoC 且可运行 GNU/Linux 操作系统的可量产开发板。

      ncnn 是腾讯优图实验室推出的一个为移动端极致优化的高性能神经网络前向计算框架,是目前同样也比较罕见的为 RISC-V 架构做过适配和优化的神经网络框架。

      本文 是一份教程,步骤骑着步骤 (step by step) 地展示了如何在一块全新的全志 D1「哪吒」开发板上,跑个 ncnn 神经网络推理框架的 demo。

      本文的完成参考了以下材料,非常感谢 nihui、BedRock 等开发者们在互联网上的分享!
      [1] D1 哪吒 - 在线文档
      [2] nihui: 在全志d1开发板上玩ncnn
      [3] 腾讯优图ncnn新版本适配国产CPU,全志D1加持最高速度提升70倍!

      目录

      1. 引言
      2. 必要的材料
      3. 上电!
      4. 重刷固件
      5. 安装并配置交叉编译工具链
      6. 编译 ncnn,并准备 demo 程序
      7. 使用 ADB 传输文件
      8. 运行 demo

      1、必要的材料

      • 「哪吒」开发板
      • Type-C USB 线
      • USB 转 TTL 转换器
      • 安装有 GNU/Linux 或较新版本的 Windows 10 / 11 的可联网电脑
        (本文以 Windows 10 的电脑为例来展示)

      2、上电

      取出哪吒和 USB 转 TTL 转换器,先把转换器按下图所示接上 DEBUG 端口,再将转换器插入电脑的 USB 口。如果电脑没有识别到串口,可能是因为没有安装转换器的驱动程序,可以在 这里 下载。

      dqs12WnDI7.png

      在使用开发板自带的固件时,DEBUG 端口会在开发板上电后通过 115200 波特率的 UART 串口来提供一个 Shell,我们可以使用 PuTTY、MobaXterm 或者其它类似的终端模拟器访问这个串口来在 Shell 中操作开发板。(如果使用 PuTTY,可以参考下图来设置)

      yTczpA98AF.png

      启动终端模拟器后,暂时只能看到个黑框,因为开发板还没上电。

      找出 Type-C USB 线,将开发板的 OTG 接口与电脑相连即可上电(虽然连 POWER 也可以,但是后边一直需要使用这个 OTG 接口,所以推荐连接它)。上电后可发现,开发板上的灯亮了,而且终端模拟器中开始一条条地冒出各种提示了!大概 10 ~ 20 秒后,根据一行按下回车的提示,在终端模拟器中按下回车,即可进入如下图所示的界面,然后就可以执行各种 GNU/Linux 命令了。

      EYGkrTrrMD.png

      3、重刷固件

      新开封的开发板里边自带的固件是基于 Open v1.0 版本的 D1 Tina SDK 编译的,在运行 ncnn 程序时会发生非法指令错误 (参考 这里),根据全志在线开发者论坛中网友 BedRock 的评论,我们可将固件更新为基于 Open v1.01 版本的 SDK 编译的固件再进行后续的步骤。

      如果想自己编译固件或者修改固件,可以参考 D1 文档中的 “Tina SDK版本” 部分 下载 SDK。当然,如果只想先跑个 ncnn 玩玩看的话,我们可以直接在 “固件下载” 选择一款全志原厂为我们准备好的固件,比如我可以选择 D1哪吒HDMI测试固件20210804(开机HDMI就有小企鹅启动logo) (名字有点长) 为例。这个固件估计是为展示 HDMI 输出功能而设计的,我们给开发板用 HDMI 线接上个屏幕就能看到个小企鹅,但是因为它是基于 v1.01 SDK 编译的,所以我们刚好也能用它来跑 ncnn 的 demo。

      下载好 .img 固件文件后,参考 D1 文档中 “编译与烧写” 的 “烧写” 部分 ,下载 全志USB驱动,使用管理员权限运行 install.bat 安装驱动,再安装烧写软件进行操作,即可将固件烧写进开发板。比如,在 Windows 电脑中我们要下载 PhoenixSuit 软件来烧写固件。要注意的是,在烧写软件中要选择 “全盘擦除升级”,如下图所示,否则无法成功烧写。

      SPrmQRsskU.png

      烧写成功后,重新上电即可。

      4、安装并配置交叉编译工具链

      注意:第 4 节和第 5 节的操作需要在 GNU/Linux 操作系统下进行。如果你的电脑装有 GNU/Linux 操作系统、或者可使用虚拟机,可直接在 GNU/Linux 操作系统中进行操作。如果你的电脑装的是较新版本的 Windows 10 / 11,也可以上网搜索相关教程安装并配置个 WSL (Windows Subsystem Linux),然后在 WSL 中进行操作。

      在平头哥芯片开放社区的 “资源下载” 页面,我们可以在 “工具链-900系列” 中找到 V2.0.1 版本的 riscv64-linux-x86_64-20210512.tar.gz,下载它到电脑里,放到 <自己想放的路径>,解压它

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

      解压完成后,使用 vim 或者其它文本编辑器,打开 ~/.bashrc,在结尾添加工具链的路径至环境变量,即下列内容

      # My PATH
      export RISCV_ROOT_PATH=/<自己想放的路径>/riscv64-linux-x86_64-20210512
      

      保存并关闭编辑器,然后使用 source 命令刷新 Shell 环境:

      source ~/.bashrc
      

      就安装并配置好交叉编译工具链了。

      5、编译 ncnn,并准备 demo 程序

      在 GitHub 上下载 2021 年 7 月 20 日 Release 的 ncnn 的源代码(Source code)到电脑里,比如 ncnn-20210720.tar.gz,解压,然后进入 ncnn-20210720 目录,准备并开始编译

      mkdir build-c906
      cd build-c906
      cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/c906.toolchain.cmake -DCMAKE_BUILD_TYPE=relwithdebinfo -DNCNN_OPENMP=OFF -DNCNN_THREADS=OFF -DNCNN_RUNTIME_CPU=OFF -DNCNN_RVV=ON -DNCNN_SIMPLEOCV=ON -DNCNN_BUILD_EXAMPLES=ON ..
      make -j32
      

      编译大概需要几分钟,完成后,可在 build-c906 目录中找到编译好的所有文件。

      我们可先尝试两个 demo,分别为:

      ① 使用 benchncnn 做基准测试
      ② 使用 NanoDet 模型对一张自己的图片做目标检测(NanoDet 是个可在移动端超快运行的超轻量目标检测模型)

      为了方便后续将文件传输进开发板,我们可先在电脑上创建 benchncnn_demo 和 nanodet_demo 两个文件夹,将 ① 和 ② 所需的文件分别都放进去准备好。

      对于 ①,我们把 ncnn 目录中的 build-c906/benchmark/benchncnn 和 benchmark/*.param 复制进去即完成准备。

      对于 ②,我们需要把 ncnn 目录中的 build-c906/examples/nanodet 复制进去,在 ncnn-assets中下载 nanodet_m.bin 和 nanodet_m.param 两个文件放进去,再放入一张你想检测的图片即可。

      即,两个目录的结构分别是类似这样的:

      benchncnn_demo/
      ├ benchncnn
      ├ alexnet.param
      ├ blazeface.param
      └ <一大堆其它模型的 param>
      
      nanodet_demo/
      ├ nanodet
      ├ nanodet_m.bin
      ├ nanodet_m.param
      └ <你想检测的图片>
      

      6. 使用 ADB 传输文件

      ADB 是 Android Debug Bridge,原本为 Android 设计,全志给 Tina Linux 也做了适配,所以我们可以使用 ADB 来调试 Tina Linux 的设备。参考 D1 文档中的 “研发生产工具” 部分 可以下载,下载完成后,将其路径加入环境变量即可使用。

      我们在跑这两个 demo 时,可能暂时只需要用到以下几个命令,如果需要使用其它功能也可上网搜索相关教程。

      检查设备与电脑的连接情况,可以使用

      adb devices
      

      adb push 可以把电脑上的文件或文件夹传给开发板,使用语法如下

      adb push <电脑上的文件路径> <开发板上的目标路径>
      

      adb pull 可以把开发板上的文件或文件夹传给电脑,使用语法如下

      adb pull <开发板上的文件路径> <电脑上的目标路径>
      

      要注意的是,开发板上的路径都需要填写绝对路径。

      7、运行 demo

      把第 5 节所示的类似 benchncnn_demo 和 nanodet_demo 的文件夹通过 adb push 命令传进开发板,在开发板上进入 benchncnn_demo 目录,再输入

      ./benchncnn 4 1 0 -1 0
      

      可开始做基准测试。如果成功运行即可慢慢看到类似下图这样的提示,展示了当前平台运行 ncnn 使用各种模型推理一帧所需的毫秒耗时。

      zY277yF0dK.png

      (如果不想等测试慢慢跑完,也可以按 Ctrl + C 停止运行)

      在开发板上进入 nanodet_demo 目录,再输入

      ./nanodet <你想检测的图片>
      

      即可使用 NanoDet 对这张图片目标检测。运行完成后,可在命令行中看到文字版的检测结果,也可以使用 adb pull 把生成的 image.png 图片文件传给电脑再打开查看,上边会画好边界框、类别和置信度。比如这是它检测出的南京市长 江大桥上边的车车车车。

      DvWduiFyik.png

      到了这里,我们就成功在一块运行 GNU/Linux 系统的 RISC-V 开发板上跑了个神经网络框架的 demo,如果想进行后续的实验或研发,可以了解有关 D1 哪吒 和 ncnn 的更多内容。

      B站视频讲解:https://www.bilibili.com/video/BV1wQ4y1B7VU
      本文来源:https://verimake.com/topics/275

      发布在 MR Series
      q1215200171
      budbool
    • 回复: 【366期开放夜】自制一款低成本的RISC-V 64单板机(基于全志D1s)

      开始啦~有空来看 https://live.bilibili.com/21864541?spm_id_from=333.999.space_home.strengthen_live_card.click

      发布在 MR Series
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      @jordonwu ✔

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      音乐播放器

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      QQ图片20211201124955.png QQ图片20211201124941.jpg

      发布在 公告
      q1215200171
      budbool
    • 【366期开放夜】自制一款低成本的RISC-V 64单板机(基于全志D1s)

      微信图片_20211201114020.jpg
      本周开放夜嘉宾Young将为我们带来一个最低成本的RISC-V单板机分享。

      有哪些特征?

      门槛高么?

      可以拿来做些什么?

      我也可以设计、制作一个吗?

      我们的嘉宾将为您解答。

      嘉宾介绍

      Young

      Young,电子科技大学通信工程专业大四学生。

      既是从前端到操作系统均有涉猎的软件开发者,也是一名硬件hacker。自接触到嵌入式Linux以来深深被这个领域吸引,从ARM、MIPS到RISC-V架构的平台均有接触过。

      RISC-V是什么?

      RISC-V是一个基于精简指令集(RISC)原则的开源指令集架构(ISA),V表示为第五代。第五代的问世受到了大量创客们的广泛关注,但它的硬件却不易获得。

      自制的RISC-V是什么样子的?

      微信图片_20211201114036.jpg

      芯片

      全志科技D1s是系统级封装(SIP)采用了阿里平头官方C906,具有单RISC-V 64内核@1.008G和64MB DDR2。

      单板机介绍

      在一个紧凑的56*56毫米的2层板上,引出全部IO,包括模拟外围设备

      配有标准接口,包括USB、micro SD、LCD、Line-in和耳机

      为自制优化布局,适合在加热台上焊接

      微信图片_20211201114039.jpg
      微信图片_20211201114041.jpg

      拿来运行Linux妥妥的!

      微信图片_20211201114045.jpg

      我们可以获得的体验感与现在的发行版别无二致,甚至可以安装任何我们想要的东西。

      本次开放夜我们将采用线上分享

      也欢迎大家来到线下一起交流讨论!

      博云路111号 B1

      期待的小伙伴们准备好加入我们!

      活动时间:12月2日 19:30 - 21:00

      我们不见不散!

      线上观看直播入口

      微信图片_20211201114731.jpg

      发布在 MR Series
      q1215200171
      budbool
    • 【小白自制Linux开发板】Debian文件系统制作,以及WIFI配置、交换分区配置

      该片文章将完整记录一个Debian的最小文件系统的生成,以及自定义配置WIFI组件、网络组件和交换分区配置

      本文章参考:
      https://whycan.com/t_4236.html
      http://www.leux.cn/doc/debootstrap.html(该网站在备案中,可能暂时无法查看了)
      帖子整理完成。

      1. 制作Debian系统
      构建debian文件系统,作为记录,最小rootfs在180MB左右。

      1.1 配置构建环境
      安装构建文件系统的工具,一个是用来chroot,一个是用来构建文件系统

      sudo apt install qemu-user-static -y
      sudo apt install debootstrap -y
      mkdir rootfs
      

      构建文件系统之前,你要知道你想要构建哪个版本的文件系统,
      我从 https://www.debian.org/mirror/list.zh-cn.html 这里,
      选择了我访问速度快的源,并且该源有armel。

      armhf (支持硬件浮点)
      armel (软浮点)

      我看华为源挺快的,就用这个了mirrors.huaweicloud.com
      然后就是debian的版本,我尝试一下最新的,buster

      sudo debootstrap --foreign --verbose --arch=armel  buster rootfs http://mirrors.huaweicloud.com/debian/
      

      构建完成之后,需要chroot进去修改密码等配置

      cd rootfs
      sudo mount --bind /dev dev/
      sudo mount --bind /sys sys/
      sudo mount --bind /proc proc/
      sudo mount --bind /dev/pts dev/pts/
      cd ..
      sudo cp /usr/bin/qemu-arm-static rootfs/usr/bin/
      sudo chmod +x rootfs/usr/bin/qemu-arm-static
      sudo LC_ALL=C LANGUAGE=C LANG=C chroot rootfs /debootstrap/debootstrap --second-stage --verbose
      sudo LC_ALL=C LANGUAGE=C LANG=C chroot rootfs
      

      最后一条命令chroot完成,
      此时可以先apt-get等给你的文件系统安装你需要的软件包

      为了提高下载速度,我们首先修改源

      vi /etc/apt/sources.list
      

      改为(注意要换其他源用http方式可以访问的,要不然还得处理https的内容):

      deb http://mirrors.huaweicloud.com/debian buster main
      

      改完以后执行:

      apt-get update
      

      使源生效

      安装网络相关的库

      apt-get install wpasupplicant #安装WIFI配置相关的组件
      apt-get install net-tools     #安装网络基础组件、如使用ifconfig等
      apt-get install udhcpc        #当wifi连接成功后,需要用这个组件去获取IP地址
      

      其他组件

      apt-get install wireless-tools 
      apt install sudo vim openssh-server htop
      apt install pciutils usbutils acpi
      

      1.2 配置账号
      修改root登录密码的方式如下

      passwd root
      

      添加用户

      groupadd <用户组>
      useradd -m -g <用户组> -s /bin/bash <用户名>
      passwd <用户名>
      

      1.3 新增账号sudo配置
      对于出现

      <用户名> is not in the sudoers file.  This incident will be reported.
      

      切换到超级用户:

      $ su
      

      打开/etc/sudoers文件:

      # vi /etc/sudoers
      

      修改文件内容

      1.png

      保存退出

      修改主机名,否则将会以当前编译的系统的主机名进行设置(如:笔者为Ubuntu,相当的尴尬)

      HOSTNAME=<你的主机名>
      echo $HOSTNAME > /etc/hostname
      echo $HOSTNAME > /proc/sys/kernel/hostname
      sed -i '/localhost/s/$/\t'"$HOSTNAME"'/g' /etc/hosts
      

      1.4 配置时区
      修改系统默认时区

      cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
      

      1.5 配置SSH
      如果要使用SSH服务,并且允许SSH客户端以root方式登录需要进行一下设置。

      vi rootfs/etc/ssh/sshd_config
      

      添加

      PermitRootLogin yes
      

      1.6 rootfs打包
      当所有的内容制作完成,就可以清理缓存,打包之后就可以替换你的文件系统了

      apt-cache clean #删除安装包 
      exit  #退出chroot
      rm rootfs/usr/bin/qemu-arm-static
      

      卸载刚在挂载的文件夹。

      cd rootfs
      sudo umount   dev/pts/
      sudo umount   dev/
      sudo umount   sys/
      sudo umount   proc/
      sudo umount   dev/pts/
      

      打包文件。

      # cd rootfs  #进到文件系统目录,如果已经在该文件夹下,可以忽略
      tar cvf ../rootfs.tar .    #要注意那个.  代表当前目录
      

      生成的rootfs.tar任意解压到文件系统即可

      2. 使用wpa_supplicant连接wifi

      创建配置文件

      vi /etc/wpa_supplicant.conf
      

      输入内容:

      network={
        ssid="我的热点"
        psk="我的密码"
      }
      

      然后执行命令

      wpa_supplicant -B -d -i wlan0 -c /etc/wpa_supplicant.conf
      

      示例如下

      root@dika-pc:~# wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf
      Successfully initialized wpa_supplicant
      rfkill: Cannot open RFKILL control device
      root@dika-pc:~# [  444.817608] wlan0: authenticate with e4:67:1e:02:33:c0
      [  444.843208] wlan0: send auth to e4:67:1e:02:33:c0 (try 1/3)
      [  444.900867] wlan0: authenticated
      [  444.935561] wlan0: associate with e4:67:1e:02:33:c0 (try 1/3)
      [  444.986874] wlan0: RX AssocResp from e4:67:1e:02:33:c0 (capab=0x411 status=0 aid=4)
      [  445.033483] wlan0: associated
      [  446.047125] IPv6: ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready
      ^C
      

      执行dhcp命名,获取IP地址

      root@dika-pc:~# udhcpc -i wlan0
      udhcpc: started, v1.30.1
      udhcpc: sending discover
      udhcpc: sending select for 172.16.1.106
      udhcpc: lease of 172.16.1.106 obtained, lease time 43200
      root@dika-pc:~# ping www.dika.ren
      PING www.dika.ren (149.129.80.46) 56(84) bytes of data.
      64 bytes from 149.129.80.46: icmp_seq=3 ttl=45 time=217 ms
      64 bytes from 149.129.80.46: icmp_seq=4 ttl=45 time=417 ms
      64 bytes from 149.129.80.46: icmp_seq=5 ttl=45 time=102 ms
      64 bytes from 149.129.80.46: icmp_seq=6 ttl=45 time=108 ms
      ^C
      --- www.dika.ren ping statistics ---
      6 packets transmitted, 4 received, 33.3333% packet loss, time 346ms
      rtt min/avg/max/mdev = 102.009/211.020/417.367/127.586 ms
      

      3. 增加swap分区

      在使用一些软件的过程中,会遇到系统崩溃,尤其是使用 apt-get install 的时候,所以需要加入swap分区,可以简单理解为虚拟内存。

      使用

      free
      

      查看当前swap大小,
      使用如下命令创建你想要添加swap分区的大小

      dd if=/dev/zero of=/swap1 bs=1M count=512  #改成你要设置的SWAP大小,512就是512MB
      

      设置swap分区文件

      mkswap /swap1
      

      激活swap分区

      swapon /swap1
      

      此时使用free命令就能看到创建好的swap分区,但这只是临时性的, 重启会失效,需要配置一下,下次开机时候要开swap

      vi /etc/fstab
      

      操作,在最后一行添加

      /swap1 swap swap defaults 0 0
      

      展示
      开始进入Debian

      2.png

      使用我们自定义的pi账户登录

      3.png

      使用命令查看Swap分区

      4.png

      以上内容来自 WhyCan Forum哇酷开发者社区
      小白自制Linux开发板(F1C200s)整理系列,持续更新中
      作者:twzy

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      @jordonwu 编译和烧写的内容都已经在D1的在线文档里公布了 https://d1.docs.aw-ol.com/study/study_4compile/
      这部分帖子的内容是从sipeed那边搬运过来的😊

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      Lichee_RV_7001_3D.step

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      尺寸图

      96B2DA58-1E08-4e35-A1F7-B8D6BD7285D7.png

      Lichee_RV_7001-Blue(Dimension Drawing).pdf
      Lichee_RV_7001(Dimension Drawing).pdf

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      昨天晚上本来准备睡觉发现D1的核心板居然上架了,立刻上车了一个,那么问题来了,我是想买来点手里的MIPI带鱼屏,看了下资料,官方的核心板很明显是考虑到内嵌设计的,本体只有用户指示灯和SPI屏的接口,倒是底下放了两个M2的金手指来引出IO,MIPI的差分对也在金手指上,想用的话就得自己画个底板了,两个M2金手指的相对间距在外围尺寸图里看不出来,找了找有3D模型,我是在模型里测的,最后糊了个空板,周围有几个朋友一起买的,他们拿去之后转了下格式后丢给我一起备份了,尺寸我看了下应该是没什么问题了,就在这一起放出来吧。

      注意:压缩包里一共有三个版本,kicad的是5.99,阿狸狗是17.2,用某d的那个朋友说无所谓啥版本都能兼容。。

      空板如图。一边的座子标了那几个电源脚,画板的时候记得别放反了~

      Sc2EiUUoh1YMmNPFJNTBhGKgnTCei4nQOdm1OpJG.jpg

      PS:铜柱我用的是个小尺寸的,如果自己有更合适的话可以换掉;我打算用是4.2mm高度的B-KEY座子,算了下核心板下面除去背面的器件还有大概1.5mm空隙,可以塞小芯片和比较薄的wifi模块。

      文件放在下面了,有需要的小伙伴可以自取~

      ubvQeRQQP5kDREO6NpKoQW5n9fHvnKd19RZQgjlG.zip

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      哪吒计算条(LicheeRV-Nezha Compute Module)位号图

      lQLPDhrqZwrZHqnNAlvNBBWw4oqXxgTBZw0BrUmyJIB0AA_1045_603.png

      lQLPDhrqZxA2aUTNAmPNBCywVqgnru4ExaIBrUm67AA4AA_1068_611.png

      Lichee_RV_7001(TOP-Designator Drawing).pdf
      Lichee_RV_7001(Bottom-Designator Drawing).pdf

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      哪吒计算条(LicheeRV-Nezha Compute Module)原理图
      lQLPDhrqYyR4ZdbNAuTNBCawCGPdHII46J8BrUNN2gBmAA_1062_740.png

      lQLPDhrqYynVsP7NAt3NBCWwVLkykRSg0H4BrUNW3IBMAA_1061_733.png

      lQLPDhrqYy6aY6nNAuDNBDGwz7AgL9FZkZ0BrUNeIUB4AA_1073_736.png

      lQLPDhrqYzP3rv7NAtvNBCuwZhZqJu2RwJ0BrUNnZoBmAA_1067_731.png

      lQLPDhrqYzlU-jfNAtrNBCmwRPaheJBwWLgBrUNweQBMAA_1065_730.png

      lQLPDhrqYz6yRPHNAtzNBCewVMtcxVYlsLYBrUN5WYB4AA_1063_732.png

      lQLPDhrqY0QPj5jNAuPNBCiwjQBoCm8YouUBrUOCPoBmAA_1064_739.png

      lQLPDhrqY0oFcHnNAtzNBCiw1qziuvO8FTUBrUOMAcBMAA_1064_732.png

      lQLPDhrqY09iuf7NAt7NBCiwazyTkFuqNaABrUOUWkB4AA_1064_734.png
      lQLPDhrqY1L2QPDNAuXNBDCwHSESLlSjrxQBrUOaKsBmAQ_1072_741.png

      lQLPDhrqY1aJyUHNAurNBDGwr37gTNRvKvkBrUOgoABMAA_1073_746.png

      lQLPDhrqY1tOfVHNAuDNBCmwuTKEVvhFZtQBrUOoZkB4AA_1065_736.png

      lQLPDhrqY2ATMPXNAuLNBCewfpDiCdO9i7MBrUOwBsBmAA_1063_738.png

      Lichee_RV_7001_Schematic.pdf

      发布在 公告
      q1215200171
      budbool
    • 回复: 【资料释放】D1哪吒计算条资源汇总(持续更新)

      哪吒计算条(LicheeRV-Nezha Compute Module)规格书

      lQLPDhrqX6qSrMjNAyrNAr-wy6LfLlL6WAYBrT2bj8BkAA_703_810.png

      lQLPDhrqX7VNQ23NAzLNArCwd_cNKrPGA1oBrT2t-EASAA_688_818.png

      lQLPDhrqX77WqfXNAjvNAqSwKaPVZtkL5yEBrT29CUBMAA_676_571.png

      lQLPDhrqX8aWTgfNAyTNArKwxxjCTUaP92gBrT3Jc4BkAA_690_804.png

      lQLPDhrqX80kxlnNAlPNArSwMp9ykXifRWkBrT3UmgASAQ_692_595.png

      lQLPDhrqX9MaprvNAlTNArCwfHG0rShBZFYBrT3eCMBMAA_688_596.png

      lQLPDhrqX9kQiCvNApnNArCwi87cfvPgzkgBrT3oIkBkAA_688_665.png

      中文版:Sipeed Lichee RV 规格书 V1.1.pdf
      英文版:Sipeed Lichee RV Datasheet V1.1.pdf

      发布在 公告
      q1215200171
      budbool
    • 【资料释放】D1哪吒计算条资源汇总(持续更新)

      计算条ps.png

      D1哪吒计算条发布贴:【单板仅需99】D1哪吒计算条上线!为智能家居提供高性价比的RISC-V算力

      购买链接:淘宝D1哪吒计算条直通车

      发布在 公告
      q1215200171
      budbool
    • 回复: 【单板仅需99】D1哪吒计算条上线!为智能家居提供高性价比的RISC-V算力

      @jordonwu 官方Tina Linux编译烧写文档见:https://d1.docs.aw-ol.com/study/study_4compile/
      板子由合作伙伴Sipeed推出,更多相关参数可到Sipeed社区了解

      发布在 MR Series
      q1215200171
      budbool
    • 回复: 「免费申请」基于安谋科技STAR-C1的全志XR806 IoT开发板试用活动

      PS.如果已有XR806开发板,也可以参与发文,极术社区同样有好礼相赠

      开发过程中,遇到任何问题,欢迎访问全志在线开发者社区发帖咨询及加入XR806活动交流群,有任何问题也可以直接在微信群里咨询。
      3173972048-619f343a242b8.png

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 【小白自制Linux开发板】 二. u-boot移植

      上一篇: 【小白自制Linux开发板】 一. 瞎抄原理图与乱画PCB中我们做了一个小型而没用的开发板,用的是Licheepi Nano的镜像,那从本篇开始我们开始自己构建它的灵魂吧。

      我们都知道,PC在启动的时候,首先是进入BIOS,再根据BIOS中配置信息引导后续的启动操作系统,比如配置Windows启动。

      而对于嵌入式linux中,并没有BIOS,这时候就需要一种类似引导程序来处理。于是就有了BootLoader。

      BootLoader是一段小程序,可以把它想象成PC机linux上的GRUB/LILO引导程序,可以直接从flash或TF卡中运行,来装载内核。它可以初始化硬件设备,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统做好准备。

      1. 嵌入式开发板的启动过程

      一个嵌入式系统从软件角度来看分为三个层次:

      • 引导加载程序
        包括固化在芯片中的boot程序(可选)和BootLoader两大部分,对于固化的boot程序。主要是芯片通过外围电路连接的实际情况选择读入程序的位置,比如:通过TF卡或是SPI以及其他方式启动,至于优先顺序这就要具体看芯片的数据手册,个人没做过具体测试。

      • linux内核
        特定于嵌入式平台的定制内核

      • 文件系统
        包括了系统命令和应用程序

      01.png

      BootLoader启动过程可分为单阶段和多阶段(stage1、stage2),其中stage1完成初始化硬件,如CPU寄存器、内存控制器,为stage2准备内存空间。一般stage1是可以直接在nor flash中运行的,并将stage2复制到内存RAM中,设置堆栈,然后跳转到stage2(从这也可以看出stage2是在RAM中运行的,与stage1不同)

      Boot Parameters 顾名思义,就是配置了要启动内核的参数,包含要加载系统内核相关文件的位置,要加载到内存中的位置,定位到文件系统的位置,相关输入输出的呈现等一系列参数。

      kernel 在存放在bootloader之后,对于SoC来说,代码都需要在RAM中运行,这里与MCU不一样的地方就是引入了MMU(内存管理单元)。对于MCU而言,由于其执行速度低,因此运行代码都在ROM中直接运行,而对于Flash而言,其读取速度远不及RAM的速度,因此对于运行速度非常快的SoC而言,所有的代码都需要在RAM中运行。但是这里有一个问题,RAM掉电数据将会丢失,故代码保存不可能放在RAM中,当前所有的嵌入式设备而言,代码保存都是放在ROM中,因此在SoC中运行代码需要将代码搬运到RAM中然后再执行。

      Root Filesystem 由于其执行过程需要对ROM进行读写操作,因此可以不用搬运到RAM中,但是实际过程中内核启动后会产生一个虚拟的文件系统,该文件系统是挂在根文件系统的关键所在,这里不详细讲解。整体来说,大致的过程为,嵌入式设备上电后将执行bootloader,对硬件进行硬件和堆栈初始化,然后搬运内核到RAM中并启动内核,紧接着挂载根文件系统。

      2. 环境配置与参考项目

      系统:Ubuntu 16

      编辑器:VSCode

      参考项目:Lichee-Pi Nano

      地址:https://wiki.sipeed.com/soft/Lichee/zh/Nano-Doc-Backup/index.html

      1.png

      Lichee-Pi Nano

      需要注意的是一定要选择Nano版本,因为我们开发板使用的主控芯片和Nano的主控是一致的,所以后续我们要编译U-boot,内核都可以参考(bai piao)这里面的配置。

      主控芯片:F1c100s/F1c200s,100s内置32MB DDR1内存,200s内置64MB DDR1内存,200s贵一点,他们都是QFN88封装。

      ARM926ejs内核,主频默认408MHz,据了解做产品出货的一般在600M左右。

      带有100M的SPI接口2个,SDIO接口1个,USB OTG接口,还有CSI摄像头接口,LCD RGB显示屏接口,音频接口,I2C I2S UART PWM等等。

      还有就是他们不支持硬件浮点,所以浮点运算使用软浮点方式。

      2.png
      F1c100s/F1c200s芯片功能

      3.交叉编译器

      我们通过PC版的Linux自带的gcc编译的程序只能在当前系统架构下的cpu架构(x86)下运行,如果我们想要编写的程序在嵌入式Linux下运行,那么就需要用到对应的编译器。

      我们做的开发板主控芯片F1C200S,内核为ARM9,其架构使用的是ARMv5架构,所以我们也要选用对应的编译器,同样,这样的编译器很多,这里我们使用最常用的arm-linux-gnueabi- ,因为交叉编译器F1C200S必须高于6.0版本,这里我们使用7.2版本

      下载完成后解压文件:

      tar -vxjf gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabi.tar.xz
      

      然后在/usr/local目录下新建arm-linux-gcc目录

      sudo mkdir /usr/local/arm-linux-gcc
      

      进入解压目录下:

      cd gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabi/
      

      将该目录下的所有文件复制到新建的目录下

      sudo cp -rd * /usr/local/arm-linux-gcc/
      

      最后需要添加该工具链的环境变量使其可以在任何目录下执行,打开/etc/profile文件

      sudo nano /etc/profile
      

      在文件末尾添加以下内容

      PATH=$PATH:/usr/local/arm-linux-gcc/bin
      

      添加完毕,使路径生效

      source /etc/profile
      

      接下来在终端输入:

      arm-linux-
      

      然后连按两次Tab键,如图在表示成功:

      3.png

      如果没有出现,则进行下面操作,安装必要的动态链接库

      sudo apt-get install lib32ncurses5 lib32z1
      

      至此,我们完成了编译工具的配置。

      4. 编译U-boot

      当Arm开发板上电以后第一个要加载到内存并运行的程序就是BootLoader,BootLoader的同类型程序很多,如U-boot、X-boot、Rt-Thread,这里我们依然选中最常用的U-boot作为目标(因为其他的我也不会呀),

      最新版本的uboot几乎包含当前主流的SoC芯片,前面提到本开发板使用的芯片和licheePI nano相同,大部分硬件也是兼容的,为了快速移植该部分,这里采用licheePI nano的u-boot来进行移植。在终端输入如下命令克隆u-boot:

      git clone https://github.com/Lichee-Pi/u-boot.git -b nano-v2018.01
      

      克隆完毕文件会保存在当前目录下,进入该目录,

      cd u-boot
      

      在该文件夹下有很多分支,我们可以查看所有分支,使用如下命令:

      git branch -a
      

      现在我们使用的是nano开发板,所以将当前分支切换到nano分支,命令如下:

      git checkout nano-v2018.01u-boot
      

      4.png

      切换到Nano分支

      默认的没有指定交叉工具链和架构,因此在编译之前需要指定交叉工具链和芯片架构,u-boot的交叉编译器在u-boot 的根目录下中的Makefile文件中定义了。打开文件找到CROSS_COMPILE变量,修改为如下:

      ARCH=arm
      CROSS_COMPILE=arm-linux-gnueabi-
      

      5.png

      配制交叉编译环境

      这样我们就能使用我们指定的编译器来编译u-boot了。

      在u-boot项目的config目录下存在对多种板子的配置描述文件,由于每个板子的外设不同,因此编译之前必须要对u-boot进行配置。然而配置是一件比较繁琐的事情,特别是像u-boot这种比较复杂的项目而言,初学者几乎无法完成。幸运的是对于大部分开发板而言,config目录下有其配置好的默认配置文件。进入config目录中,然后执行ls查看当前所有的配置文件

      cd config
      ls
      

      6.png

      查看配制文件

      找到licheepi_nano_defconfig 和 licheepi_nano_spiflash_defconfig,前者表示为TF卡启动,后者表示从SPI 设备启动,因为我们做的小板只有从TF卡启动,所以我们需要使用 licheepi_nano_defconfig 。

      现在回到上级目录,然后执行

      make licheepi_nano_defconfig
      cd ..
      make make licheepi_nano_defconfig
      

      这样我们把licheepi_nano_defconfig 作为默认配置项。

      接下来我们就可以用图形界面进行配置了,执行

      make menuconfig
      

      此时出现图形配置选项,如下图所示

      7.png

      u-boot Menuconfig配制,注意红框中的配置,我们后续要用到。

      至此我们的u-boot环境配置就完成了,但是我们还有个问题要解决:如何让u-boot引导系统

      我们在PC端安装Windows系统的时候往往需要选择启动顺序,比如需要优先通过光驱或u盘启动等。

      同样在u-boot中也需要这样的配置,当然u-boot比PC配置稍微复杂一丢丢。我们前面提到Linux嵌入式系统结构分布中有个Boot Parameters 部分,这部分就是做引导配置的,那怎么配置呢,总体来说可以分为两部分:

      • bootcmd,主要用于描述控制Linux内核文件以及其他描述文件加载到内存中位置以及启动Linux内核系统等

      • bootargs,用于配制文件系统、串口信息等。

      bootcmd

      在最开始提到过,内核一般不在flash中运行,这样就需要将内核搬运到内存中,这个过程需要u-boot来完成。对于mmc (TF卡)而言,在u-boot有专门的命令load mmc,该命令可以将mmc中的代码从flash搬运到指定的地址处。

      当u-boot中环境变量bootdelay计数到0时,此时uboot就会开始执行bootcmd中的命令。

      bootdelay这个环境变量是一个计数器,当u-boot主体运行完毕后,此时bootdelay该变量的值将会开始递减,递减时间为1s,当递减到0时,此时u-boot将会跳转到bootcmd处开始执行bootcmd命令,(你可以简单理解为PC启动后有一两秒时间等待,你可以可以通过F8或Enter键打断进入Bios设置的过程,这个等待时间就由u-boot中的bootdelay来控制)。

      下面我们需要记住这句指令,这就是我们当前制作的开发板需要用到的bootcmd全部内容

      load mmc 0:1 0x80008000 zImage;load mmc 0:1 0x80c08000 suniv-f1c100s-licheepi-nano.dtb;bootz 0x80008000 - 0x80c08000;
      

      如果你需要详细了解这句话那就接着往下看,如果不需要则可以跳到 下面的u-boot参数配置环节

      对于上面命令,我们根据分号拆分为3部分:

      1> load mmc 0:1 0x80008000 zImage;
      2> load mmc 0:1 0x80c08000 suniv-f1c100s-licheepi-nano.dtb;
      3> bootz 0x80008000 - 0x80c08000;
      

      其中两个 load mmc 命令、一个bootz 命令。

      先看第一条:

      load mmc 0:1 0x80008000 zImage
      

      load mmc有三个参数:第一个参数是mmc(TF卡)分区,第二个参数是内存中目标地址,第三个参数是源文件。

      即上面的命令意思是将mmc的0:1 分区中的zImage复制到内存中的0x80008000地址处。这里的zimage就是Linux内核,后续会提到该文件编译,0:1这个可以这样理解0表示TF卡(TF卡属于mmc存储器的一种),1这表示TF卡的第一个分区(boot分区)后面会提到。

      而对于内存位置 0x80008000 地址位置,将其理解为默认值就行了。这样完成了zImage的加载。

      下面分析第二条命令:

      load mmc 0:1 0x80c08000 suniv-f1c100s-licheepi-nano.dtb
      

      有了上面的加载zImage的说明,可以很轻松的理解上面的命令意思是将mmc的0:1分区中的suniv-f1c100s-licheepi-nano.dtb文件加载到内存中的0x80c08000地址处。对于suniv-f1c100s-licheepi-nano.dtb 这个文件,叫做设备树文件,简单来说就是当前开发板上面所有外设备描述文件,这部分将会在后续内核编译部分进行详细说明。

      对于第三条命令:

      bootz 0x80008000 - 0x80c08000
      

      的意思是告诉内核镜像的起始地址为0x80008000,加载的设备树地址为0x80c08000。这里是告诉cpu从这里开始启动Linux, bootz命令的格式是:bootz空格0x80008000空格-空格0x80c08000,注意-左右有空格。

      除了bootz 命令外,有些系统里面还可能存在一个叫做bootm命令,这是是对没有使用设备树内核的镜像启动命令,早期版本的内核没有引入设备树,因此对于早期的内核一般使用的是bootm,其命令格式为bootm内核地址,比如bootm x0x30008000,意思是从0x30008000开始启动内核,启动内核的过程其实是将pc指针指向该地址,这样处理器就会从该地址处运行代码。

      这里我们就完成了bootcmd的说明,接下来我们看另外一个参数。

      bootargs

      bootargs也是u-boot环境变量中一个非常重要的变量,上面已经讲解了内核的启动可以通过bootcmd来完成,那接下来内核启动完毕后必须挂在根文件系统(rootfs)。但是内核并不知道根文件系统的具体位置,我们必须要告诉根文件的位置后内核才能将其挂载,这时就需要有bootargs变量。该变量的作用是告诉内核根文件系统的位置和属性以及必要的配置,

      console=ttyS0,115200 panic=5 rootwait root=/dev/mmcblk0p2 earlyprintk rw
      同上面分析的方法一样,我们依然将这部分命令拆成几部分来说明。这里需要说明的是,这部分配置信息是由u-boot 直接按照参数字符串方式提供给Linux内核,然后由Linux内核进行执行的,这也说明里为什么格式与bootcmd配置方式不一致。

      **console=ttyS0,115200 **表示终端为ttyS0即串口0,波特率为115200;

      panic=5 字面意思是恐慌,即linux内核恐慌,其实就是linux不知道怎么执行了,此时内核就需要做一些相关的处理,这里的5表示超时时间,当Linux卡住5秒后仍未成功就会执行Linux恐慌异常的一些操作。

      rootwait 该参数是告诉内核挂在文件系统之前需要先加载相关驱动,这样做的目的是防止因mmc驱动还未加载就开始挂载驱动而导致文件系统挂载失败,所以一般bootargs中都要加上这个参数。

      root=/dev/mmcblk0p2 表示根文件系统的位置在mmc的0:2分区处,/dev是设备文件夹,内核在加载mmc中的时候就会在根文件系统中生成mmcblk0p2设备文件,这个设备文件其实就是mmc的0:2分区(这里对应TF卡的第二个分区:rootfs),这样内核对文件系统的读写操作方式本质上就是读写/dev/mmcblk0p2该设备文件。

      earlyprintk 参数是指在内核加载的过程中打印输出信息,这样内核在加载的时候终端就会输出相应的启动信息。rw表示文件系统的操作属性,此处rw表示可读可写。

      5.u-boot参数配置

      make menuconfig
      

      选中 Enable boot arguments 按空格选中,下面会显示:() Boot arguments

      然后选中Boot arguments ,按回车,进入配置窗口,接下来上面解释过的bootargs 参数信息:

      console=ttyS0,115200 panic=5 rootwait root=/dev/mmcblk0p2 earlyprintk rw
      

      8.png

      配置bootargs信息

      然后按Tab键选中<OK>,保存并进入主菜单。

      同理配置:Enable a default value for bootcmd 按空格选中,下面会显示:() bootcmd value 配置项,

      选中bootcmd value 进入配置界面,输入bootcmd命令:

      load mmc 0:1 0x80008000 zImage;load mmc 0:1 0x80c08000 suniv-f1c100s-licheepi-nano.dtb;bootz 0x80008000 - 0x80c08000;
      

      9.png

      配置bootcmd参数

      按Tab键选中<OK>,保存并进入主菜单。

      6.u-boot编译与烧录

      先保存图形配置界面后推出界面,在终端执行make -j4即可对整个u-boot进行编译。

      10.png

      编译u-boot

      make -j4后面的-j4表示4个核心进行编译,若电脑的处理器是2核心,请使用make -j2进行编译。

      编译完成后会在当前目录生成u-boot-sunxi-with-spl.bin烧录文件。

      11.png

      根目录下找到 u-boot-sunxi-with-spl.bin 文件

      该文件就是我们最终要烧录的二进制文件。

      在当前目录下会有一个隐藏的文件.config,该文件是u-boot编译后根据各个选项产生的配置文件,这个配置文件记录了所有配置选项的宏开关,编译的时候是根据最终的.config文件来进行编译的,当然编译前是需要有脚本解析.config文件然后进行相应的编译。

      烧录到TF卡

      只要将u-boot-sunxi-with-spl.bin烧录到tf卡的8k偏移处地址就可以了,烧录步骤如下:使用dd命令进行块搬移:

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

      该命令中:

      • if 文件名:输入文件名,缺省为标准输入。即指定源文件。< if=input file >
      • of 文件名:输出文件名,缺省为标准输出。即指定目的文件。< of=output file >
      • bs bytes:同时设置读入/输出的块大小为bytes个字节。
      • seek blocks:从输出文件开头跳过blocks个块后再开始复制。

      这里的输出文件(of)为主机电脑的/dev/sdb文件,也就是TF卡,这里也体现了Linux一切皆文件的思想。

      /dev/sdb 这个可以用gparted 软件查看,该软件可以直接用命令安装即可:

      sudo apt-get install gparted
      

      此时在Ubuntu下面可以看到如下软件:

      12.png

      安装好GParted软件

      打开软件

      13.png

      GParted

      在右上角可以看到两个硬盘,/dev/sda 为本地硬盘,/dev/sdb 是我们将要写数据的TF(当然这只是墨云自己的配置使然,具体情况请根据实际情况而定),因此这里的of=/dev/sdb 烧录到8k偏移地址处是指绝对地址,这个绝对地址指的是TF卡的物理地址。这8K的值是由F1C200S 中固化的启动代码决定的,所以照抄即可。

      14.png

      烧写u-boot

      然后我们正常退出TF卡,然后插入我们自制的开发板,通过USB线连接电脑,

      15.png

      连接开发板

      打开电脑中的命令行工具,我这里使用Xshell,

      打开Xshell,新建连接:

      16.png

      配置名称 ,协议选择Serial

      17.png

      配置串口

      通过下拉选中com端口,波特率为115200,其他默认即可,点击确定,然后双击主界面左侧会话管理中的刚建立的会话,此时进入连接状态。

      因为在你插入USB通电的时候开发板就已经启动了,所以当你打开串口连接的时候可能未必会看到信息,所以按一下重启键,就可以看到如下的输出信息了,这就是我们的u-boot,执行到u-bbot计数完成后会产生错误,那是因为我们还没有进行系统内核的移植,所以默认就会进入u-boot命令模式。

      18.png

      启动信息

      输入pri命令打印环境变量的所有值,可以找到已经配置的bootcmd 和bootargs

      19.png

      pri命令结果

      至此完成了u-boot移植的全部内容,对于u-boot的移植方法,在后续移植Linux内核和文件系统时都会用到,都是大同小异的,所以有了本篇的说明,之后操作将会非常简单。

      而关于u-boot的内容事实上非常的复杂繁琐,有兴趣的可以自行去了解到,毕竟作为一个小白的我初衷只是先让小板先跑起来

      参考资料
      Lite200 (lishanwen) -- https://lishanwen.cn/index.php/2021/07/03/lite200/

      全志F1C200S F1C100S 介绍 ( 迪卡魏曼依奇君 ) https://blog.csdn.net/tunqimai9331/article/details/95938903

      荔枝派Nano 全流程指南 (矽速科技) https://wiki.sipeed.com/soft/Lichee/zh/Nano-Doc-Backup/index.html

      以上内容来自 WhyCan Forum哇酷开发者社区
      小白自制Linux开发板(F1C200s)整理系列,持续更新中
      作者:twzy

      发布在 其它全志芯片讨论区
      q1215200171
      budbool
    • 回复: 「免费申请」基于安谋科技STAR-C1的全志XR806 IoT开发板试用活动

      全志XR806在线文档 https://xr806.docs.aw-ol.com/

      发布在 Wireless & Analog Series
      q1215200171
      budbool
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 4 / 6