单片机/MCU论坛
直播中

HonestQiao

8年用户 520经验值
擅长:嵌入式技术
私信 关注
[文章]

【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台

这次非常有幸,能够得到深圳风火轮youyeetoo X1的体验机会,感谢电子发烧友和风火轮。

在申请youyeetoo X1之前,已经通过风火轮的官方WiKi做过了一下了解,官方的介绍简介给力:
image.png
经过了解,更增添了我对youyeetoo X1的兴趣。

详细的WiKi网址:youyeetoo X1 | 风火轮Wiki ,感兴趣的同学可以前往了解。

一、开箱

玩板子最开心的事情,就是开箱了。
拆开寄过来的箱子,一共有三个部分:
image.png

分别是主机(SBC)、屏幕、NFC板。

打开后,内容不少:
image.png

核心看一下主机:
image.png

image.png

以及屏幕:
image.png

主机的正反面,都接口丰富,通过官方WiKi可以了解到:
接口图-正面(中文).jpg

接口图_背面(1).jpg

具体的硬件参数,有一长溜,我就不贴了,可以从官方WiKi了解。

套件中的屏幕,是一块7寸MIPI屏幕,具体介绍如下:
image.png

二、配件

在官方WiKi上,列出了可用的配件:
image.png

因为提前做过了解,所以我给youyeetoo X1准备了不少基础配件,具体如下图:
image.png

分别为:

  • 绿联USB HUB
  • 8欧小音箱
  • 翼联(EDUP)EP-1696S,RTL8832AU WiFi6双频无线网卡
  • EDUP EP-N1572无线网卡,RTL8192CU
  • EC20 4G Cat
  • RTL8852BE WIFI6E 5G双频内置无线网卡
  • USB蓝牙
  • RTC电池
  • 512G M.2 SSD
  • 64G U盘
  • 256G SD卡
  • PWLink2 Lite调试器:Arm版和RISC-V版
  • USB鼠标
  • 蓝牙键盘
  • 积木版屏幕支架

另外,还有USB摄像头,没有在上面一起列出。
此外,在项目中用到的模块配件,在后续更新中,会陆续更新上来。

三、开机

将开发板、屏幕,以及主要配件连接好,就可以连上电源开始使用了。

默认情况下,可以直接连接HDMI,然后按照官方说明,刷BIOS,以便开启MIPI屏幕。
在我实际测试过程中,HDMI和MIPI屏幕,是可以同时使用的。
另外,官方WiKi也提供了进行系统安装的指导。

我第一时间刷了BIOS,装了系统,所以下面展示直接使用情况。

连接后,整体如下:
image.png

image.png

进入Windows10系统后,首先了解具体系统情况:
Snipaste_2024-01-28_23-48-23.png

Snipaste_2024-01-28_23-48-42.png
然后进行系统更新。

更新完系统,一切准备妥当,那就跑分好了。
使用鲁大师进行了评测,具体情况如下:
综合评分:
Snipaste_2024-01-27_23-25-46.png
AI评分:
Snipaste_2024-01-28_23-45-58.png
Snipaste_2024-01-28_23-45-58.png

四、项目计划

要进行的项目,是作为一个探索型的项目,将在youyeetoo X1硬件和系统平台上,结合AI大模型、AI Agent技术和IoT硬件,构建一个少儿AI智能STEAM积木平台。
使用的少儿可以通过智能积木搭建的方式,来完成STEAM创意的初步构建,然后通过自然语言对话进行沟通,最终通过AI大模型来完成最终的创意,并进行实时的动画展现。

具体的实现过程,将会在更新的过程中,逐步进行分享。

回帖(31)

HonestQiao

2024-2-25 19:38:00
启用WSL(Windows Subsystem for Linux)

在Windows10及后续系统,能够直接在Windows环境中,使用WSL享受Linux系统服务了。
下面为具体的安装使用过程。

一、Ubuntu系统安装
通常情况下,打开cmd.exe,使用wsl --install,既可以进行默认提供的Ubuntu系统的安装。
但是,可能会遇到下面的错误:

此时,需要下载更新包:https://github.com/microsoft/WSL/releases ,然后进行安装:


安装完成后,重新使用wsl --install安装即可。建议安装更新后,重启系统再进行安装。

如果安装过程中,出现如下的错误:

那是因为无法直接访问 raw.githubusercontent.com 这个网址,需要使用科学的创新的上网方式来解决。
解决后,就能够正常安装了:

成功安装过程中,会提示设置用户名和密码,最终将会进入Ubuntu系统。

二、安装WindowsTerminal
在上面的界面中,会出现乱码,不要换,不要怕,那只是因为cmd.exe的内码导致的。
默认的cmd.exe也不好用,第一时间安装 WindowsTerminal 好了。
下载地址:https://github.com/microsoft/terminal/releases
下载后,直接点击安装即可:


安装完成,第一次打开时,会提示是否使用其做为默认的Windows 终端,果断选择:


三、进入Ubuntu系统
在WindowsTerminal中,使用wsl命令进入Ubuntu系统后,就可以用常见的Linux命令了。

四、文件共享
在WSL的Ubuntu系统中,可以直接访问Windows下面的文件:


Windows系统的C盘,会直接挂接到Ubuntu系统的/mnt/c路径下,可以直接当做本地路径使用即可。


现在,就能够方便的在Windows环境中,使用Ubuntu Linux系统了。
1 举报
  • Darber: 啥?!现在微软居然搞出这种引狼入室的事情?
    话说回来,github太烦了,可以修改git地址么,我要用gitee~~~

电子破烂人

2024-2-25 19:56:34
不太理解,这个板子为啥要给一个NFC的天线?一般WIN开发板也没有这部分的功能啊
难道是给外挂IC卡用的么,官方有没有类似的历程?
1 举报
  • HonestQiao: 官方有实例,可以和手机通信:https://wiki.youyeetoo.cn/zh/x1/linux/nfc_driver

HonestQiao

2024-2-26 20:22:30
Python操控GPIO

在Linux系统上,可以用GPIOD来操控GPIO,Windows上面,一般用WinIO来进行操作。
风火轮官方提供的C#实例中,封装了inpoutx64,来进行操作。


我使用Python开发,使用pywinio即可。
首先,使用安装Python3.11,然后使用pip install pywinio安装该模块。


安装完成后,就可以测试是否正常。
直接在cmd.exe中运行python,进入交互模式,然后运行下面的代码:
  1. import pywinio
  2. pywinio.WinIO()
开始使用的时候,可能会遇到下面的问题:


  • 没有权限:需要使用管理员权限打开cmd.exe,然后测试
  • 签名存在问题:需要使用 BCDEDIT /SET TESTSIGNING ON 命令设置测试模式,重启后,再继续测试



能够正常调用后,就可以开始编写代码了。


在官方提供的C#代码的IOApp.cs中,有对应的代码可供参考:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace IO测试
  6. {
  7.     ///
  8.     /// WINIO 应用
  9.     ///
  10.     public class IOApp:WinIOV2
  11.     {
  12.         ///
  13.         /// 写IO
  14.         ///
  15.         ///
  16.         ///
  17.         ///
  18.         public bool SetValToIO(UInt64 PhysAddr, UInt32 PhysVal)
  19.         {            
  20.             return SetPhysLong(PhysAddr, PhysVal);
  21.         }
  22.         ///
  23.         /// 读IO
  24.         ///
  25.         ///
  26.         ///
  27.         ///
  28.         public unsafe bool GetValFromIO(UInt64 PhysAddr, ref UInt32 PhysVal)
  29.         {
  30.             return GetPhysLong(PhysAddr, ref PhysVal);         
  31.         }
  32.         ///
  33.         /// LED控制
  34.         ///
  35.         ///
  36.         ///
  37.         ///
  38.         public bool Led_Ctrl00(byte addr, byte ctrlCode)
  39.         {
  40.             if (idOK())
  41.             {
  42.                 //进入模式
  43.                 SetPortVal(0x2E, 0x87, 1);
  44.                 SetPortVal(0x2E, 0x01, 1);
  45.                 SetPortVal(0x2E, 0x55, 1);
  46.                 SetPortVal(0x2E, 0x55, 1);
  47.                 //选择设备
  48.                 SetPortVal(0x2E, 0x07, 1);
  49.                 SetPortVal(0x2F, 0x07, 1);
  50.                 //控制LED
  51.                 SetPortVal(0x2E, addr, 1);
  52.                 SetPortVal(0x2F, ctrlCode, 1);
  53.                 //退出模式
  54.                 SetPortVal(0x2E, 0x02, 1);
  55.                 SetPortVal(0x2F, 0x02, 1);
  56.                 return true;
  57.             }
  58.             return false;
  59.         }
  60.         ///
  61.         /// 控制红色LED:亮/灭
  62.         ///
  63.         ///
  64.         ///
  65.         public bool Led_Ctrl_Red(bool isOn)
  66.         {
  67.             byte ctrlVal = 0X02;
  68.             if (isOn)
  69.             {
  70.                 ctrlVal = 0X00;
  71.             }
  72.             return Led_Ctrl00(0XB1, ctrlVal);
  73.         }
  74.         ///
  75.         /// 红LED闪烁
  76.         ///
  77.         ///
  78.         ///
  79.         public bool Led_Ctrl_Red_Flash(bool isOn)
  80.         {
  81.             byte ctrlVal = 0X00;
  82.             if (isOn)
  83.             {
  84.                 ctrlVal = 0X11;
  85.             }
  86.             return Led_Ctrl00(0XF8, ctrlVal);
  87.         }
  88.         ///
  89.         /// 绿LED:亮灭
  90.         ///
  91.         ///
  92.         ///
  93.         public bool Led_Ctrl_Green(bool isOn)
  94.         {
  95.             byte ctrlVal = 0X40;
  96.             if (isOn)
  97.             {
  98.                 ctrlVal = 0X00;
  99.             }
  100.             return Led_Ctrl00(0XC2, ctrlVal);
  101.         }
  102.         ///
  103.         /// 绿LED闪烁
  104.         ///
  105.         ///
  106.         ///
  107.         public bool Led_Ctrl_Green_Flash(bool isOn)
  108.         {
  109.             byte ctrlVal = 0X00;
  110.             if (isOn)
  111.             {
  112.                 ctrlVal = 0X1E;
  113.             }
  114.             return Led_Ctrl00(0XF8, ctrlVal);
  115.         }
  116.         ///
  117.         /// 获取控制码
  118.         ///
  119.         ///
  120.         ///
  121.         public byte Get_Led_Ctrl_Status(byte addr)
  122.         {
  123.             UInt32 ctrlCode = 0;
  124.             if (idOK())
  125.             {
  126.                 //进入模式
  127.                 SetPortVal(0x2E, 0x87, 1);
  128.                 SetPortVal(0x2E, 0x01, 1);
  129.                 SetPortVal(0x2E, 0x55, 1);
  130.                 SetPortVal(0x2E, 0x55, 1);
  131.                 //选择设备
  132.                 SetPortVal(0x2E, 0x07, 1);
  133.                 SetPortVal(0x2F, 0x07, 1);
  134.                 //读取状态
  135.                 SetPortVal(0x2E, addr, 1);
  136.                 GetPortVal(0x2F, ref ctrlCode, 1);
  137.                 //退出模式
  138.                 SetPortVal(0x2E, 0x02, 1);
  139.                 SetPortVal(0x2F, 0x02, 1);
  140.               
  141.             }
  142.             return (byte)(ctrlCode&0XFF);
  143.         }
  144.     }
  145. }

参考改代码,编写对应的Python代码:
  1. import pywinio
  2. import time
  3. import atexit
  4. g_winio = None
  5. def get_winio():
  6.     global g_winio
  7.     if g_winio is None:
  8.             g_winio = pywinio.WinIO()
  9.             def __clear_winio():
  10.                     global g_winio
  11.                     g_winio = None
  12.             atexit.register(__clear_winio)
  13.     return g_winio
  14. def SetPortVal(wPortAddr, dwPortVal, bSize):
  15.     winio = get_winio()
  16.     if bSize == 1:
  17.         winio.set_port_byte( wPortAddr, dwPortVal)
  18.     elif bSize == 2:
  19.         winio.set_port_word( wPortAddr, dwPortVal)
  20.     elif bSize == 4:
  21.         winio.set_port_dword( wPortAddr, dwPortVal)
  22. def Led_Ctrl00(addr, ctrlCode):
  23.     #//进入模式
  24.     SetPortVal(0x2E, 0x87, 1)
  25.     SetPortVal(0x2E, 0x01, 1)
  26.     SetPortVal(0x2E, 0x55, 1)
  27.     SetPortVal(0x2E, 0x55, 1)
  28.     #//选择设备
  29.     SetPortVal(0x2E, 0x07, 1)
  30.     SetPortVal(0x2F, 0x07, 1)
  31.     #//控制LED
  32.     SetPortVal(0x2E, addr, 1)
  33.     SetPortVal(0x2F, ctrlCode, 1)
  34.     #//退出模式
  35.     SetPortVal(0x2E, 0x02, 1)
  36.     SetPortVal(0x2F, 0x02, 1)
  37. #///
  38. #/// 控制红色LED:亮/灭
  39. #///
  40. #///
  41. #///
  42. def Led_Ctrl_Red(isOn):
  43.     ctrlVal = 0X02
  44.     if isOn:
  45.         ctrlVal = 0X00
  46.     return Led_Ctrl00(0XB1, ctrlVal)
  47. #///
  48. #/// 红LED闪烁
  49. #///
  50. #///
  51. #///
  52. def Led_Ctrl_Red_Flash(isOn):
  53.     ctrlVal = 0X00
  54.     if isOn:
  55.         ctrlVal = 0X11
  56.     return Led_Ctrl00(0XF8, ctrlVal)
  57. #///
  58. #/// 绿LED:亮灭
  59. #///
  60. #///
  61. #///
  62. def Led_Ctrl_Green(isOn):
  63.     ctrlVal = 0X40
  64.     if isOn:
  65.         ctrlVal = 0X00
  66.     return Led_Ctrl00(0XC2, ctrlVal)
  67. #///
  68. #/// 绿LED闪烁
  69. #///
  70. #///
  71. #///
  72. def Led_Ctrl_Green_Flash(isOn):
  73.     ctrlVal = 0X00
  74.     if isOn:
  75.         ctrlVal = 0X1E
  76.     return Led_Ctrl00(0XF8, ctrlVal)
  77. winio = pywinio.WinIO()
  78. status = True
  79. while True:
  80.     print("LED Red: ", status)
  81.     Led_Ctrl_Red(status)
  82.     Led_Ctrl_Green(not status)
  83.     status = not status
  84.     time.sleep(0.2)


运行上述代码,正常情况下,输出如下:


具体效果如下:
14.gif

进一步的,可以参考上述代码,就能实现GPIO的输入输出控制了。

1 举报
  • Darber: 说到权限那个,我突然想起以前我在一个Linux 5G模块上遇到的问题,我想问个问题,可以用C命令,实现权限修改么?
    我不是说我不知道system这种命令,我意思是,可以么?

HonestQiao

2024-2-28 11:09:50
为了方便使用和测试,我专门购置了移远EC20 4G LTE模块,买到后,发现还需要一个转接卡才能正常使用,于是又购置了USB转接卡,并配置了专用天线。

相关的设备如下:


其中包括:

  • 移远EC20 4G LTE模块
  • 迷你minipcie转USB(移远EC20)
  • 射频线
  • 专用天线
  • 4G nano卡 + 转接卡


其中的EC20模块和USB转接卡具体如下:




天线配置了两个,实际使用时,小的天线很好用,就没有用长的了。

将EC20模块插到USB转接卡上,并接线天线,插上卡:


最后,直接连接到USB即可:



接好USB后,无需再安装驱动,系统会自动识别,在设备管理器里面可以看到:


然后USB转接卡上的蓝灯会闪烁。
当它快闪的时候,表示正在联网。慢闪的时候,表示联网失败。很长时间闪一下,说明联网成功。
后续会根据网络使用情况,闪烁方式不同。

点击系统任务栏的网络图标,关闭Wlan/WiFi,开启手机网络,等待连接成功:

需要注意的是,如果不装天线,上面会显示Mobile正在准备,无法联网。

可以鼠标右键查看网络属性,查看当前的状态:


并查看流量的具体使用情况:

建议设置一个流量上线,以免用超了。当然,流量多的可以不用设置了。


网络连上了,就可以打开浏览器上网测试效果了。
使用测速网站进行测速,效果还不错:



现在,这个4G上网卡就可以正常使用了,非常的方便。

1 举报
  • Darber: 眼光不错,EC20确实不错,我老东家的

HonestQiao

2024-3-1 20:43:21
为了提供更好的性能,按照官方资料的指导,购置了SSD,安装使用后,性能大幅提升。


一、选购的SSD:


M.2,NGFF2280,512G


二、SSD安装

直接怼上去,上好螺丝即可。

三、系统安装
使用官方提供的Windows 11安装包:
解压到U盘,然后检查安装方式是否为SSD(1):

安装完成后,成功进入Windows11系统


查看当前挂载的磁盘:


四、读写性能测试:
首先测一下,原有的EMMC:
读写性能有点惨不忍睹。

然后测一测刚装的SSD:
现在,读写性能,全面上升!!!

经过几天的使用,完全正常,日常使用非常的流畅。

1 举报
  • Darber: 话说,这是啥牌子的SSD?

HonestQiao

2024-3-2 14:18:38
不带线网卡模块使用


一、了解不带线网卡模块
我之前准备的配件中,有不带线网卡模块和USB不带线网卡:


不带线网卡模块的具体型号为RTL 8852BE,接口是NGFF M2:
46381708780060_.pic.jpg

其支持能力爆棚:
iShot_2024-03-02_13.28.29.png

二、安装不带线网卡模块

在开发板上的安装位置如下:
46561709356065_.pic.jpg


这个不带线网卡模块上,要连接两根天线,是IPEX4接口的:
46531709356059_.pic.jpg

IPEX4接口比IPEX1接口要小很多,常用于内置不带线网卡模块使用。

连接好不带线信号接受配件,就可以安装到开发板上使用了:
46541709356061_.pic.jpg

三、使用不带线网卡模块
在初次安装好不带线网卡模块后,发现了一个奇怪的问题。
不管是在Windows10,还是在Windows11中,系统会整体不定时的卡顿,就是什么都操作不了。
将不带线网卡模块取下来以后,则系统完全正常。
已经准备好,退回去让厂家测验检查了。

不过,这个时侯,我做了一个小动作。
我看了下系统事件中的记录,发现了一个小秘密:
iShot_2024-03-01_10.35.41.png
iShot_2024-03-01_10.22.53.png

原来装上不带线网卡模块后,板子自带的有线网卡处于"嫉妒"心理,开始罢工。
它一旦罢工,系统就会重置它,从而导致系统整体卡顿。


于是,我尝试着,将板子的有线网卡禁用:
Snipaste_2024-03-01_10-27-24.png

然后,世界进入到大家开开心心过大年状态,系统能够正常使用了。

再然后,我又把板子的有线网卡给启用:
iShot_2024-03-01_10.17.03.png

系统依然正常,再次重启,也没有发现之前的问题了。
真是奇异啊!

现在,可以好好看看不带线网卡模块的信息了:
设备管理器中的信息:
Snipaste_2024-03-01_10-11-51.png

连接到WiFi:
Snipaste_2024-03-01_10-14-19.png

连接信息:
iShot_2024-03-01_10.17.54.png

另外,这个不带线网卡模块,还支持蓝牙:

Snipaste_2024-03-02_14-07-04.png

可以很方便的连接我的多个蓝牙设备:
Snipaste_2024-03-02_14-11-53.png

四、驱动更新
默认情况下,蓝牙可能不好使,可以从如下地址下载驱动:
http://www.wlan-wwan.com/2022/05/22/realtek-rtl8852bewuxianlanyamokuaiqudongjiguigeshu/
iShot_2024-03-02_14.13.45.png

安装后重启电脑,就好使了。


现在,不用外接USB不带线网卡和蓝牙模块了,联网非常的方便了。


1 举报
  • Darber: 话说,啥叫不带线网卡?是说PCIE接口的网卡么

HonestQiao

2024-3-3 19:15:26
在 youyeetoo X1 上 部署 Stable Diffusion


一、openvino了解
在youyeetoo X1支持OpenVINO。OpenVINO™ 是一个用于优化和部署人工智能(AI)推理的开源工具平台。 它可以 提高计算机视觉、自动语音识别、自然语言处理和其他常见任务的深度学习性能。使用经过TensorFlow、PyTorch 等流行框架训练的模型。

在youyeetoo X1上部署Stable Diffusion,并应用OpenVINO支持,目前已有不少选择,可以用openvino_notebooks或者fastsdcpu。我部署了fastsdcpu进行测试,他提供了一个完整的Windows环境测试Stable Diffusion的工具包。

二、部署fastsdcpu
1. 安装Python
首先,安装Python3.11,可以从 https://www.python.org/downloads/ 下载对应的版本进行安装:



安装后,打开命令行工具,查看是否可以正常使用:


2. 安装virtualenv
  1. mkdir SDXL
  2. cd SDXL
  3. pip install virtualenv
  4. virtualenv env
  5. env\Scripts\activate
最终,进入如下的环境,表示安装成功:

3. 安装git
在使用Stable Diffusion的过程中,经常需要通过git下载文件,所以要先安装git。
在Windows11上,已经提供了系统内置的包管理工具,用于安装常见的工具包。
通过下面的命令,即可直接安装:
  1. winget install Git.Git
安装后,检查是否可以正常使用:

4. 安装fastsdcpu工具包
首先使用下面的命令获取:
  1. git clone https://github.com/rupeshs/fastsdcpu.git
然后,使用下面的命令,进行支持库和数据文件的安装:
  1. cd fastsdcpu
  2. .\install.bat
安装完成后,就可以启动进行测试。

三. 使用Stable Diffusion
1. 启动
部署完成后,启动包括WEB模式和桌面程序模式,用下面的命令可以启动:
  1. # 启动web环境
  2. .\start-webui.bat

在不同的模型和设置下,首次进行生成时,可能会需要从huggingface下载模型包大,大小和时间不等,可能要下载数G,下载时间从几分钟到数十分钟时。

2. WEB模式
启动WEB模式,界面如下:

可以输入Prompt进行测试,测试过程中,命令行会输出进度信息:


生成的过程中,CPU风扇呼呼呼的转,系统资源拉满:

生成成功后,命令行会提示:

此时可以查看生成的图片:

3. 桌面模式
启动桌面程序模式,界面如下:

4. 配置和openvino支持
可以在桌面模式的配置中,启用openvino支持:

然后再次进行生成。

不过,fastsdcpu提示了:

咱们得板子内存只有8G,而且系统本身还要占用,所以,开启了openvino支持,跑的很不顺,有时候内存不足,有的时候生成的莫名其妙的。



并且生成时,需要的时间大大变长,生成一次,可能需要15分钟或者半个小时。


在配置界面,如果开启了Tiny Auto Encoder配置,则生成的速度,会变快一些。

四、总结
经过使用测试,在youyeetoo X1 上是可以部署运行Stable Diffusion的,但是受限于内存只有8G大小,实际生成过程需要较长的时间,且不能生成过于复杂的图片。
另外,在使用的过程中,应该把其他所有的程序,应用,全部都关闭掉,以免消耗内存。

2 举报
  • Darber: 突然想起来,这个可以扩展内存么?
  • Darber: 看来,要搞智能语音,必须搞CPU

jf_50393217

2024-3-3 19:19:26
牛逼的板子,文章也很棒棒
1 举报

大菠萝Alpha

2024-3-3 19:50:49
板子很赞,帮主写的很好,羡慕
1 举报

xusiwei1236

2024-3-3 20:18:00
乔帮主配件准备的有点多呀,差不多这板子能接的各种外设,你都来了一个
1 举报

HonestQiao

2024-3-4 10:56:14
LLAMA大模型部署测试

在Windows系统上,可以通过ollama来部署大模型进行测试。

1. 安装ollama
https://ollama.com/download 下载Windows版本,然后安装即可:


2. 检查是否正常运行
新开命令行窗口,运行:
  1. # 直接运行
  2. ollama
  3. # 查看版本
  4. ollama --version
运行结果如下:

3. 测试llama2-chinese
首先,下载一个llama2-chinese试一下:
  1. ollama pull llama2-chinese


下载完成后,运行下面的命令进行测试:

不过,实际运行的速度,非常的不理想:


跑了1个小时,都没有生成完。
忍无可忍,ctrl+V了。

4. 测试llama2
同样的,首先下载:
  1. ollama pull llama2

然后运行测试:【中式英文,别笑】
  1. ollama run llama2 "why the sky is blue"

这速度,比中文的要快,但是还是很慢:

5. 总结
看来,受限于CPU和内存,运行大模型,还是非常吃力的。
不过,ollama目前能够直接用的大模型还很有限,后续将会试一试其他的大模型方案,例如llama.cpp等。
1 举报
  • dianzi: 在本地跑大模型还是太难为N5105了

cszzlsw

2024-3-4 14:04:06
不错啊不错啊,可惜没有时间玩板,不然我也申请了!
举报

淡化浅出

2024-3-4 14:24:39
来了来了,楼主太厉害了,必须膜拜一下
举报

ALSET

2024-3-4 14:59:59
不错,写的很详细,收藏后面仔细看看。
举报

大菠萝Alpha

2024-3-6 08:19:20
上个docker,WSL2…
1 举报

HonestQiao

2024-3-8 09:35:10
Windows驱动开发【遇到问题,待官方解答】


参考官方资料,进行驱动开发部分,做 新设备加入到系统 时,出现问题。
官方指导步骤:


实际操作结果:
第1步:从注册表缓存中读取BIOS配置,并保存到DSDT0000.bin文件


第2步:反编译DSDT0000.bin文件,生成DSDT0000.dsl (ASL CODE文件)


第3步:修改DSDT0000.dsl 文件,添加新设备到改文件中
不修改,直接跳过

第4步:编译修改好的DSDT0000.dsl,会生成DSDT0000.aml文件





在第4步的时候,未能达到官方指导资料的结果,导致无法进一步进行添加设备的操作。
待官方解答。


1 举报
  • HonestQiao: 经过官方人员的指导,问题得以解决。
    导出的dsl文件,本身就不是正确的,需要按照上面给出的错误信息,挨个进行排查,去掉有问题的部分,然后重新执行指令即可。

    正确执行后,结果如下:
    PS C:\\Users\\HonestQiao\\Projects\\i2c\\bios> iasl.exe -ve .\\DSDT0000.dsl

    Intel ACPI Component Architecture
    ASL+ Optimizing Compiler/Disassembler version 20230628
    Copyright (c) 2000 - 2023 Intel Corporation

    ASL Input:     ./DSDT0000.dsl - 2117765 bytes  32942 keywords      0 source lines
    AML Output:    ./DSDT0000.aml -  281036 bytes  28230 opcodes    4712 named objects

    Compilation successful. 0 Errors, 136 Warnings, 527 Remarks, 488 Optimizations
    PS C:\\Users\\HonestQiao\\Projects\\i2c\\bios>

挽你何用

2024-3-8 17:33:25
大佬牛呀,文章太棒了
1 举报

HonestQiao

2024-3-13 12:47:46
添加I2C设备,并进行I2C接口测试

在youyeetoo X1的官方资料中,提供了Windows驱动开发以及I2C接口的指导,并提供了I2C接口的测试工具。
根据指导,可以进行自己的I2C设备的开发,以及通讯测试。

一、清理系统现有的测试设备
在系统设备管理中,将下面的设备删除,并勾选删除驱动:



清理后,结果如下:

这4个未知设备,2个是NFC使用,1个是SPI使用,还有一个是I2C3使用。

二、添加新的设备和驱动
我后面需要连接SHT30进行测试,其I2C地址为0x44,参考官方资料,进行如下的操作:
1. 生成dsl文件:
  1. asl.exe /tab=DSDT /c
  2. iasl.exe -ve .\DSDT0000.bin
  3. iasl.exe -ve .\DSDT0000.dsl
2. 修改dsl文件,去掉多余的信息,并修改对应的I2C3的配置:
将默认的0x50,修改为0x40
3. 生成aml文件:
  1. iasl.exe -ve .\DSDT0000.dsl
4. 将设备信息写入注册表:
  1. asl.exe /loadtable DSDT0000.aml
然后重启电脑,注册表中就会存在对应的设备信息了

5. 修改官方提供的驱动配置:

6. 安装驱动:


安装完成后,重启电脑,再查看设备管理器,就能够看到设备区东正确安装了:

从上图可以看到,0x44的设备,已经成功安装驱动。

三、不挂I2C设备测试
再不挂接I2C设备的情况下,打开I2C测试工具,可以连接I2C端口:

但是读取会失败:

写入也会失败:

需要注意的是,如果挂接了设备,但I2C设备的地址不是0x44,则出现的错误信息,和上面的完全一样。

四、挂接I2C设备测试
1. I2C从设备制作
为了方便测试,我用硬禾的12指神探,做了一个I2C从设备,方便进行I2C通讯的测试。

这个I2C从设备,内部有256个寄存器,地址为0x00~0xFF,设备初始化的时候,所有的寄存器设置为0x00,读取的时候,每次返回的数据宽度为4位8bits数据。

2. 连接I2C从设备到开发板
实际连到开发板上进行测试的时候,还挂接了一个逻辑分析仪,以便分析通讯的数据:


3. 默认读取测试:
默认情况下,从I2C从设备去读数据,返回的为 00 00 00 00

在I2C从设备的调试输出窗口,也能看到当前的I2C请求为从地址为0x00的寄存器读取数据,以及实际返回的数据。

4. 写入数据测试:
点击写入数据,会成功写入:

在I2C从设备的调试输出窗口,也能看到当前的I2C请求向0x00的寄存器写入数据,以及实际写入的数据。

5. 读取写入后的数据:
再次点击读取,就能够读取到前面写入的数据了:

五、逻辑分析仪分析通讯
写入数据的时候,逻辑分析仪抓取到的数据结果如下:
可以看到,操作的I2C设备地址为0x44,向寄存器地址0x00开始写入了12 34 56 78 90 AB CD EF 8位8bits数据。

读取数据的时候,逻辑分析仪抓取到的数据结果如下:
可以看到,操作的I2C设备地址为0x44,先向I2C从设备发送读数据的命令,然后过了一段时间后,I2C从设备开始返回数据
12 34 56 78,一共4位8bits数据。

通过以上的步骤,就能够完成I2C设备的正常通讯了,后续就可以在此基础上,操作I2C通讯,来完成具体传感器设备的数据读取了。
举报

HonestQiao

2024-3-13 22:50:11
移植驱动读取SHT30温湿度传感器数据

在我的项目中,会涉及到接入多个传感器设备,并进行自动识别,然后结合AIGC大模型,进行特定情景的生成。
在上一部分,已经测试过I2C设备的读写操作了,在此基础上,进行SHT30温湿度传感器的数据读取。

一、硬件了解
有一点,我最近才注意到:


怪不得我测试SHT30的时候,温度数据偏高。
但是手头暂时没做4.7K的电阻,需要采购。暂时智能硬着头皮先上了。

SHT30如下:


二、I2CPython驱动移植
在官方提供的I2C测试程序中,有关于串口数据读取的实例,参考改示例,编写python调用DLL接口的入口文件:
  1. import ctypes, sys
  2. spbdll = ctypes.WinDLL("64" in sys.version and "SPBDLL.dll" or "SPBDLL.dll")
  3. def __DllFunc(name, ret, args):
  4.     func = spbdll[name]
  5.     func.restype = ret
  6.     func.argtype = args
  7.     return func
  8. # //-----连接设备驱动---
  9. SPBDLL_ConnetDev = __DllFunc("SPBDLL_ConnetDev", ctypes.c_void_p, (ctypes.c_char_p))
  10. SPBDLL_isOK = __DllFunc("SPBDLL_isOK", ctypes.c_bool, (ctypes.c_void_p))
  11. SPBDLL_ReleaseDev = __DllFunc("SPBDLL_ReleaseDev", ctypes.c_void_p, (ctypes.c_void_p))
  12. # //----I2C----
  13. SPBDLL_I2C_Read = __DllFunc("SPBDLL_I2C_Read", ctypes.c_int, (ctypes.c_void_p, ctypes.c_uint16, ctypes.c_buffer, ctypes.c_int32))
  14. SPBDLL_I2C_Write = __DllFunc("SPBDLL_I2C_Write", ctypes.c_int, (ctypes.c_void_p, ctypes.c_uint16, ctypes.c_buffer, ctypes.c_int32))
  15. SPBDLL_I2C_Read_RegAddr8bit = __DllFunc("SPBDLL_I2C_Read_RegAddr8bit", ctypes.c_int, (ctypes.c_void_p, ctypes.c_uint8, ctypes.c_buffer, ctypes.c_int32))
  16. SPBDLL_I2C_Write_RegAddr8bit = __DllFunc("SPBDLL_I2C_Write_RegAddr8bit", ctypes.c_int, (ctypes.c_void_p, ctypes.c_uint8, ctypes.c_buffer, ctypes.c_int32))
然后,在编写I2C操作的封装文件:

  1. import SPBDLL as SPBDLL
  2. class SpbDllCtrl:
  3.     lpDev = None
  4.     def __init__(self):
  5.         self.lpDev = None
  6.         pass
  7.     # ///
  8.     # /// 连接设备驱动
  9.     # ///
  10.     # /// 驱动名称,在asl和inf中对应的名称
  11.     # ///
  12.     def ConnetDev(self, devName):
  13.         self.lpDev = SPBDLL.SPBDLL_ConnetDev(devName)
  14.         return not self.lpDev == None
  15.     # ///
  16.     # /// 连接设备是否成功
  17.     # ///
  18.     # ///
  19.     def isOK(self):
  20.         if not self.lpDev == None:
  21.             return 1 == SPBDLL.SPBDLL_isOK(self.lpDev)
  22.         return False
  23.     # ///
  24.     # /// 释放设备
  25.     # ///
  26.     def ReleaseDev(self):
  27.         if not self.lpDev == None:
  28.             SPBDLL.SPBDLL_ReleaseDev(self.lpDev)
  29.             self.lpDev = None
  30.     # ///
  31.     # /// 设置中断回调 def fn(fn_Context);需要在asl中配置了IO中断,这里设置才有意义
  32.     # ///
  33.     # /// 回调函数
  34.     # /// 参数
  35.     def SetInterruptCallBack(self, fn, fn_Context):
  36.         if not self.lpDev == None:
  37.             SPBDLL.SPBDLL_SetInterruptCallBack(self.lpDev, fn, fn_Context)
  38.     # //----I2C----
  39.     # ///
  40.     # /// I2C读寄存器内容
  41.     # ///
  42.     # /// 寄存器地址,2字节的地址
  43.     # /// 接收数据
  44.     # /// 计划读取长度
  45.     # ///
  46.     def I2C_Read(self, regAddr, pData, len):
  47.         if not self.lpDev == None:
  48.             return 0 == SPBDLL.SPBDLL_I2C_Read(self.lpDev, regAddr, pData, len)
  49.         return False
  50.     # ///
  51.     # /// I2C写数据到寄存器中
  52.     # ///
  53.     # /// 寄存器地址,2字节的地址
  54.     # /// 数据
  55.     # /// 数据长度
  56.     # ///
  57.     def I2C_Write(self, regAddr, pData, len):
  58.         if not self.lpDev == None:
  59.             return 0 == SPBDLL.SPBDLL_I2C_Write(self.lpDev, regAddr, pData, len)
  60.         return False
  61.     # ///
  62.     # /// I2C读寄存器内容
  63.     # ///
  64.     # /// 寄存器地址,1字节的地址
  65.     # /// 接收数据
  66.     # /// 计划读取长度
  67.     # ///
  68.     def I2C_Read_RegAddr8bit(self, regAddr, pData, len):
  69.         if not self.lpDev == None:
  70.             return 0 == SPBDLL.SPBDLL_I2C_Read_RegAddr8bit(self.lpDev, regAddr, pData, len)
  71.         return False
  72.     # ///
  73.     # /// I2C写数据到寄存器中
  74.     # ///
  75.     # /// 寄存器地址,1字节的地址
  76.     # /// 数据
  77.     # /// 数据长度
  78.     # ///
  79.     def I2C_Write_RegAddr8bit(self, regAddr, pData, len):
  80.         if not self.lpDev == None:
  81.             return 0 == SPBDLL.SPBDLL_I2C_Write_RegAddr8bit(self.lpDev, regAddr, pData, len)
  82.         return False

通过以上的入口文件和操作封装,就可以在python程序中,进行I2C接口的操作了。

下面编写一个简单的,与之前的RP2040做的I2C从设备沟通的程序,讲一个计数器的值通过I2C写入到从设备,然后读取该值:
  1. from SpbDllCtrl import *
  2. import time
  3. import atexit
  4. # 数组转HEX字符串
  5. to_hex=lambda ary : " ".join(["%02X" % i for i in ary])
  6. devName = "I2C30001"
  7. I2CCtrl = None
  8. def __clear_i2c():
  9.     global I2CCtrl
  10.     if not I2CCtrl == None:
  11.         print("Clear I2C device")
  12.         I2CCtrl.ReleaseDev()
  13.     I2CCtrl = None
  14. atexit.register(__clear_i2c)
  15. I2CCtrl = SpbDllCtrl()
  16. I2CCtrl.ConnetDev(devName)
  17. if not I2CCtrl.isOK():
  18.     print("I2C device is not connected")
  19. else:
  20.     print("I2C device is connected")
  21. rbuf = bytes(4)
  22. r_len = 4
  23. bRet = I2CCtrl.I2C_Read_RegAddr8bit(0x00, rbuf, r_len);
  24. if not bRet:
  25.     print("Read error")
  26. else:
  27.     print("Read data: ", to_hex(rbuf))
  28. counter = 0
  29. while True:
  30.     counter += 1
  31.     if counter > 0xffff:
  32.         break
  33.     hexstr= "%08X" % counter
  34.     rbuf = bytes(bytearray.fromhex(hexstr))
  35.     bRet = I2CCtrl.I2C_Write_RegAddr8bit(0x00, rbuf, r_len);
  36.     if not bRet:
  37.         print("Write error")
  38.     else:
  39.         print("Write data: ", to_hex(rbuf))
  40.     time.sleep(0.1)
  41.     rbuf = bytes(4)
  42.     r_len = 4
  43.     bRet = I2CCtrl.I2C_Read_RegAddr8bit(0x00, rbuf, r_len);
  44.     if not bRet:
  45.         print("Read error")
  46.     else:
  47.         print("Read data: ", to_hex(rbuf))
  48.     time.sleep(1)
  49. # I2CCtrl.ReleaseDev()
运行上述代码,最终结果如下:



从结果中可以看到,python程序将计数器数值写入到从设备,从设备收到并记录。
然后,python程序从从设备读取寄存器的值,就是之前写入的值。

三、SHT30驱动移植
在上一步,已经做好了I2C设备的数据读写了,在此基础上,根据SHT30的数据手册,就可以编写对应的驱动程序了。
为了保持和micropython中的程序一致,我编写了一个伪装接口:
  1. from SpbDllCtrl import *
  2. # 数组转HEX字符串
  3. to_hex=lambda ary : " ".join(["%02X" % i for i in ary])
  4. class I2C:
  5.     def __init__(self, devname):
  6.         self.devname = devname
  7.         self.I2CCtrl = SpbDllCtrl()
  8.         self.I2CCtrl.ConnetDev(self.devname)
  9.         if not self.I2CCtrl.isOK():
  10.             print("I2C device is not connected")
  11.             raise Exception("连接失败")
  12.         else:
  13.             print("I2C device is connected")
  14.     def write_byte_data(self, i2c_address, register_address, value):
  15.         if self.I2CCtrl.isOK():
  16.             rbuf = bytes(bytearray([value]))
  17.             r_len = len(rbuf)
  18.             bRet = self.I2CCtrl.I2C_Write_RegAddr8bit(register_address, rbuf, r_len);
  19.             if not bRet:
  20.                 print("Write error")
  21.                 raise Exception("写入错误")
  22.                 return False
  23.             else:
  24.                 print("Write data: ", to_hex(rbuf))
  25.                 return True
  26.     def write_i2c_block_data(self, i2c_address, register_address, values):
  27.         if self.I2CCtrl.isOK():
  28.             rbuf = bytes(values)
  29.             r_len = len(rbuf)
  30.             bRet = self.I2CCtrl.I2C_Write_RegAddr8bit(register_address, rbuf, r_len);
  31.             if not bRet:
  32.                 print("Write error")
  33.                 raise Exception("写入错误")
  34.                 return False
  35.             else:
  36.                 print("Write data: ", to_hex(rbuf))
  37.                 return True
  38.     def read_byte_data(self, i2c_address, register_address):
  39.         if self.I2CCtrl.isOK():
  40.             r_len = 1
  41.             rbuf = bytes(r_len)
  42.             bRet = self.I2CCtrl.I2C_Read_RegAddr8bit(register_address, rbuf, r_len)
  43.             if not bRet:
  44.                 print("Read error")
  45.                 raise Exception("读取错误")
  46.                 return None
  47.             else:
  48.                 print("Read data: ", to_hex(rbuf))
  49.                 return rbuf
  50.         else:
  51.             return None
  52.     def read_i2c_block_data(self, i2c_address, register_address, block_width):
  53.         if self.I2CCtrl.isOK():
  54.             r_len = block_width
  55.             rbuf = bytes(r_len)
  56.             bRet = self.I2CCtrl.I2C_Read_RegAddr8bit(register_address, rbuf, r_len)
  57.             if not bRet:
  58.                 print("Read error")
  59.                 raise Exception("读取错误")
  60.                 return None
  61.             else:
  62.                 print("Read data: ", to_hex(rbuf))
  63.                 return rbuf
  64.         else:
  65.             return None
然后,编写实际读取SHT30数据的程序:

  1. import smbusx as smbus
  2. import time
  3. i2c = smbus.I2C("I2C30001")
  4. addr=0x44
  5. i2c.write_byte_data(addr,0x30,0xa2)
  6. time.sleep(0.5)
  7. while True:
  8.     i2c.write_byte_data(addr,0x2c,0x10)
  9.     data = i2c.read_i2c_block_data(addr,0x00,6)
  10.     if data == None:
  11.         raise Exception("读取错误")
  12.     else:
  13.         rawT = ((data[0]) << 8) | (data[1])
  14.         rawR = ((data[3]) << 8) | (data[4])
  15.         temp = -45 + rawT * 175 / 65535
  16.         RH = 100 * rawR / 65535
  17.         print (str(temp) +"C", str(RH) +"%")
  18.     time.sleep(1)
使用RP2040 I2C从设备的时候,读取和返回结果如下:


因为没有实际测量,所以显示的为-45℃。

四、实际硬件数据读取
首先,连接SHT30,务必需要注意第一部分的说明,要上拉电阻。
连接后,具体如下:


实际读取的结果如下:


现在,可以在python程序中,通过I2C接口,读取SHT30的数据了。
在后续的开发中,还会将读取到的数据,融合到AIGC大模型中,进行实际场景的生成和展示。

1 举报

更多回帖

×
20
完善资料,
赚取积分