- 2024-11-24
-
发表了主题帖:
HomeAssistant添加HACS插件接入米家
本帖最后由 maskmoo 于 2024-11-24 18:05 编辑
1 FTP安装
安装文件传输工具Samba或者FTP。由于网络原因Samba始终安装不上 ,我这里采用FTP工具。
点击设置->加载项商店 搜索FTP进行安装
安装完成后需要修改配置文件,应为后面安装hacs插件需要放到config目录下。所以配置文件中config对应的权限需要打开。 调整完配置后重启FTP。
本地连接后可以正常查看到配置文件中描述的目录。
2 下载HACS源码
Release 2.0.1 · hacs/integration · GitHub
将解压后的文件全部放到config/custom_components/hacs目录下。
3 重启HA
4 添加HACS集成
进入到设备与服务界面,点击右下角添加集成。
搜索hacs
根据提示信息进行验证后便完成了安装。
5 绑定米家设备
在HACS界面搜索xiaomi, 进入Xiaomi Miot 插件页面点击右下角的Download。
然后需要重启一下HA
重启后再到集成界面添加小米插件(与添加HACSf方式相同)。
最终可以在主页面中查看到添加的设备。
Ref:
homeassistant安装HACS报could_not_register解决方案-CSDN博客
home assistant 安装hacs的正确方法 - 知乎 (zhihu.com)
HACS更新后怎么添加代理从而顺畅下载 - 『HomeAssistant』综合讨论区 - 『瀚思彼岸』» 智能家居技术论坛 - Powered by Discuz! (hassbian.com)
- 2024-11-03
-
发表了主题帖:
《Cmake构建实战》5 onnxruntime手写识别实践(libpng引用失败)
本帖最后由 maskmoo 于 2024-11-3 20:02 编辑
1 工程设计
设计目标
实现包括手写数字识别库以及一个识别命令行工具,识别库能够被C语言等其他编程语言所调用。
目录结构
├─cli
├─cmake
├─include
├─models
└─src
└─CMakeList.txt
接口设计
初始化手写数字识别库 NUM_RECOGNIZER_EXPORT void num_recognizer_init();
识别器创建 NUM_RECOGNIZER_EXPORT void num_recognizer_create(const char *model_path, Recognizer **out_recognizer);
析构识别器 NUM_RECOGNIZER_EXPORT void num_recognizer_delete(Recognizer *recognizer);
识别图片 NUM_RECOGNIZER_EXPORT int num_recognizer_recognize_png(Recognizer *recognizer, const char *png_path, int *result);
2 安装依赖库
第3方库的依赖主要包含有libpng,zlib以及onnxruntime。
onnxruntime安装:
《Cmake构建实战》4 onnxruntime的查找模块实践
zlib安装
Release zlib 1.3.1 · madler/zlib · GitHub
cd zlib
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --config Release
#需要管理员权限 默认安装路径 C:\Program Files(x86)\zlib
cmake --install .
libpng安装
需要先安装zib
Release v1.6.40 · pnggroup/libpng · GitHub
cd libpng
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --config Release
#需要管理员权限 默认安装路径 C:\Program Files(x86)\libpng
cmake --install .
Cmake导入脚本
#[=======================================================================[.rst:
Findlibpng
-------
Finds the libpng library.(查找libpng库)
Imported Targets(导入目标)
^^^^^^^^^^^^^^^^^^^^^^^^^^
This module provides the following imported targets, if found(若查找成功,该模块会创建如下导入目标):
``png_shared``
The libpng shared library(libpng动态库)
``png_static``
The libpng static library(libpng静态库)
Result Variables(结果变量)
^^^^^^^^^^^^^^^^^^^^^^^^^^
This will define the following variables(该模块会定义如下变量):
``libpng_FOUND``
True if the system has the libpng library.(若成功查找libpng库,则为真值)
``libpng_INCLUDE_DIRS``
Include directories needed to use libpng.(作为使用要求的libpng的头文件目录)
``libpng_LIBRARIES``
Libraries needed to link to libpng shared library.(作为使用要求的libpng的动态链接库文件路径)
Cache Variables(缓存变量)
^^^^^^^^^^^^^^^^^^^^^^^^^
The following cache variables may also be set(该模块会定义如下缓存变量):
``libpng_INCLUDE_DIR``
The directory containing ``png.h``.(``png.h``所在目录)
#]=======================================================================]
# 调用libpng库自带的配置文件来查找软件包,其自带配置文件会创建两个导入库目标:
# 1. 动态库导入目标``png_shared``
# 2. 静态库导入目标``png_static``
find_package(libpng CONFIG CONFIGS libpng16.cmake)
# 若成功查找,为两个库目标补上缺失的头文件目录属性
if(libpng_FOUND)
# 获取png动态库导入目标对应动态库文件的路径,首先尝试其IMPORTED_LOCATION属性
get_target_property(libpng_LIBRARY png_shared IMPORTED_LOCATION)
# 若未能获得动态库文件路径,再尝试其IMPORTED_LOCATION_RELEASE属性
if(NOT libpng_LIBRARY)
get_target_property(libpng_LIBRARY png_shared IMPORTED_LOCATION_RELEASE)
endif()
# 根据png动态库的路径,设置libpng的根目录
set(_png_root "${libpng_LIBRARY}/../..")
# 查找png.h头文件所在目录的路径
find_path(libpng_INCLUDE_DIR png.h
HINTS ${_png_root}
PATH_SUFFIXES include)
# 为png和png_static导入库目标设置头文件目录属性
target_include_directories(png_shared INTERFACE ${libpng_INCLUDE_DIR})
target_include_directories(png_static INTERFACE ${libpng_INCLUDE_DIR})
endif()
include(FindPackageHandleStandardArgs)
# 检查变量是否有效以及配置文件是否成功执行
find_package_handle_standard_args(libpng
REQUIRED_VARS libpng_LIBRARY libpng_INCLUDE_DIR
CONFIG_MODE)
# 若一切成功,设置结果变量
if(libpng_FOUND)
set(libpng_INCLUDE_DIRS ${libpng_INCLUDE_DIR})
set(libpng_LIBRARIES ${libpng_LIBRARY})
endif()
构建和运行
cd ch011
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
cmake --build . --config Debug
最终编译失败,提示找不到png_shared。但是查看安装目录也可以看到目标png_shared的IMPORTED_LOCATION_RELEASE属性。有了解错误原因的大佬帮忙指导一下。
-
发表了主题帖:
《Cmake构建实战》4 onnxruntime的查找模块实践
本帖最后由 maskmoo 于 2024-11-3 18:21 编辑
1 onnxruntime模块配置
onnxruntime是微软开发的一个机器学习推理和训练的加速库。onnxruntime本身并没有提供用于导入依赖的Cmake配置文件,因此需要自行实现一个用于查找onnxruntime的查找模块Findonnxruntime.cmake。查找模块主要完成对onnxruntime库的头文件/库文件的路径和库版本号等参数的查找。
首先下载onnxruntime预编译包,Releases · microsoft/onnxruntime (github.com),我这里选择的是onnxruntime-win-x64-1.20.0版本。
解压文件,可以发现库文件夹中主要包含头文件include目录和库文件lib两个文件夹组成.
查找脚本编写,查找脚本将环境变量onnxruntime_ROOT作为候选路径,通过find_path find_library以及find_file命令分别查找头文件和库文件的路径以及库版本信息。
最用采用FindPackageHandleStandardArgs模块来进行检查。
find_path(onnxruntime_INCLUDE_DIR onnxruntim e_c_api.h
HINTS ENV onnxruntime_ROOT
PATH_SUFFIXES include)
find_library(onnxruntime_LIBRARY
NAMES onnxruntime
HINTS ENV onnxruntime_ROOT
PATH_SUFFIXES lib)
find_file(onnxruntime_VERSION_FILE VERSION_NUMBER
HINTS ENV onnxruntime_ROOT)
if(onnxruntime_VERSION_FILE)
file(STRINGS ${onnxruntime_VERSION_FILE} onnxruntime_VERSION LIMIT_COUNT 1)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(onnxruntime
REQUIRED_VARS onnxruntime_LIBRARY onnxruntime_INCLUDE_DIR
VERSION_VAR onnxruntime_VERSION
)
if(onnxruntime_FOUND)
set(onnxruntime_INCLUDE_DIRS ${onnxruntime_INCLUDE_DIR})
set(onnxruntime_LIBRARIES ${onnxruntime_LIBRARY})
add_library(onnxruntime::onnxruntime SHARED IMPORTED)
target_include_directories(onnxruntime::onnxruntime INTERFACE ${onnxruntime_INCLUDE_DIRS})
if(WIN32)
set_target_properties(onnxruntime::onnxruntime PROPERTIES
IMPORTED_IMPLIB "${onnxruntime_LIBRARY}")
else()
set_target_properties(onnxruntime::onnxruntime PROPERTIES
IMPORTED_LOCATION "${onnxruntime_LIBRARY}")
endif()
endif()
2 在目录程序CmakeList.txt文件中引用配置
首先向set(CMAKE_MODULE_PATH 插入当前目录,方便寻找当前文件夹下的脚本文件。以及设置onnxruntime_ROOT目录;最终通过find_package命令真正开始查找onnxruntime库。
cmake_minimum_required(VERSION 3.20)
project(find-onnxruntime)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR};${CMAKE_MODULE_PATH}")
set(CMAKE_CXX_STANDARD 11) # 设置C++标准为11
set(onnx_version 1.20.0) # 根据下载的版本进行设置,本例使用1.10.0版本
# 请下载onnxruntime库的压缩包,并解压至该目录中
if("$ENV{ }" STREQUAL "")
if(WIN32)
set(ENV{onnxruntime_ROOT} "${CMAKE_CURRENT_LIST_DIR}/onnxruntime-win-x64-${onnx_version}")
elseif(APPLE)
set(ENV{onnxruntime_ROOT} "${CMAKE_CURRENT_LIST_DIR}/onnxruntime-osx-universal2-${onnx_version}")
else()
set(ENV{onnxruntime_ROOT} "${CMAKE_CURRENT_LIST_DIR}/onnxruntime-linux-x64-${onnx_version}")
endif()
endif()
find_package(onnxruntime 1.20) # 指定依赖的最小版本
add_executable(main main.cpp)
target_link_libraries(main onnxruntime::onnxruntime)
target_compile_definitions(main PRIVATE ORT_NO_EXCEPTIONS)
添加主程序引用onnxruntime库中的函数,用来测试证明onnxruntime库已经被成功链接到主程序中了。
#include <onnxruntime_cxx_api.h>
int main() {
Ort::Env env;
Ort::Session session(env, ORT_TSTR(""), Ort::SessionOptions(nullptr));
return 0;
}
3 配置测试
执行配置命令行,可以发现已经可以查找到onnxruntime库。
mkdir build
cd build
cmake ..
执行cmake --build . 命令进行编译,编译完成后将onnxruntime.dll拷贝到Findonnxruntime\build\Debug下执行main.exe,执行结果输出了一条错误信息,表明onnxruntime库已经被成功链接到主程序中了。
- 2024-10-20
-
发表了主题帖:
《Cmake构建实战》3 Cmake基础语法学习
本帖最后由 maskmoo 于 2024-10-20 21:45 编辑
第3章主要描述Cmake的基本使用语法,结合书中的实例整理如下
CMake程序
cmake的文件类型包括CMakeList.txt文件和扩展名为.cmake的文件。其中CMakeList.txt是用于组织构建项目源文件的目录结构,.cmake文件可以作为脚本和模块两种类型。
目录(CMakeList.txt) 脚本(<script>.cmake) 模块 (<module>.cmake)
注释
主要分为单行注释和多行注释,其中多行注释本质上是单行注释+括号参数的组成形式
#单行注释
#[=[多行注释 ]=]
命令调用
message if for等
命令参数
引号参数
#包含换行
message("CMake
你好!")
#不包含换行
message("\
CMake\
您好!\
")
非引号参数
message("x;y;z") # 引号参数
message(x y z) # 多个非引号参数
message(x;y;z) # 非引号参数
变量引用
set(var_a 您好)
set(var_b a)
message(${var_${var_b}})
转义字符
cmake_minimum_required(VERSION 3.20)
set("a?b" "变量a?b")
# \? 转义为 ?
message(${a\?b})
message(今天是几号\?)
# \n 转义为换行符,\t 转义为制表符,\! 转义为 !
message(回答:\n\t今天是1号\!)
set("a;b" "变量a;b")
# 非引号参数中 \; 转义为 ;,且不分隔变量
message(x;y\;z)
# 引号参数中 \; 不转义
message("x;y\;z")
# 变量引用中 \; 转义为 ;
message("${a\;b}")
括号参数
message([==[
abc
def
]==])
message([===[abc
def
]===])
message([===[
随便写终止方括号并不会导致文本结束,
因此右边这两个括号]]也会包括在原始文本中。
下一行中最后的括号也是原始文本的一部分,
因为等号的数量与起始括号不匹配。]==]
]===])
变量
预定义变量
message("CMake命令行:${CMAKE_COMMAND}")
message("OS:${CMAKE_HOST_SYSTEM_NAME}")
定义普通变量
需要注意的是变量的作用域
function(f)
set(a "我是修改后的a")
set(b "我是b")
set(c "我是c" PARENT_SCOPE)
endfunction()
set(a "我是a")
f()
message("a: ${a}")
message("b: ${b}")
message("c: ${c}")
缓存变量
cmake_minimum_required(VERSION 3.20)
project(Notepad)
set(path_to_notepad "" CACHE FILEPATH "Path to notepad.exe")
# 下面的命令将会用记事本打开同一目录中的in.txt
execute_process(COMMAND "cmd" "/c"
${path_to_notepad} ${CMAKE_CURRENT_LIST_DIR}/in.txt)
环境变量
message("main \$ENV{PATH}: $ENV{PATH}")
列表
定义列表变量
include(print_list.cmake)
set(a "a;b;c")
set(b a;b;c)
set(c a b c)
print_list(a) # 输出:a | b | c
print_list(b) # 输出:a | b | c
print_list(c) # 输出:a | b | c
控制结构
if while foreach break continue
条件语法
常量条件
变量条件
cmake_minimum_required(VERSION 3.20)
set(on "OFF")
if(on)
message("ON")
else()
message("OFF")
endif()
if(${on})
message("ON")
else()
message("OFF")
endif()
字符串条件
if(ABC)
else()
message("ABC不是一个已定义的变量,因此条件为假")
endif()
set(a "XYZ")
set(b "0")
set(c "a-NOTFOUND")
if(a)
message("a是一个变量,其值非假值常量,因此条件为真")
endif()
if(b)
else()
message("b是一个变量,其值为假值常量,因此条件为假")
endif()
if(c)
else()
message("c是一个变量,其值为假值常量,因此条件为假")
endif()
逻辑运算
cmake_minimum_required(VERSION 3.20)
if(NOT OFF)
message("NOT OFF为真")
endif()
if(ON AND YES)
message("ON AND YES为真")
endif()
if(TRUE AND NOTFOUND)
else()
message("TRUE AND NOTFOUND为假")
endif()
if(A-NOTFOUND OR YES)
message("A-NOTFOUND OR YES为真")
endif()
单参数条件
set(a 1)
if(DEFINED a)
message("DEFINED a为真")
endif()
if(CACHE{b})
else()
message("CACHE{b}为假")
endif()
if(COMMAND set)
message("COMMAND set为真")
endif()
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/逻辑运算.cmake")
message("EXISTS \"${CMAKE_CURRENT_LIST_DIR}/逻辑运算.cmake\"为真")
endif()
双参数条件
cmake_minimum_required(VERSION 3.20)
set(a 10)
set(b "abc")
set(list 1;10;100)
if(11 GREATER a)
message("11 GREATER a为真")
endif()
if(1 LESS 2)
message("1 LESS 2为真")
endif()
if(b STRLESS "b")
message("b LESS \"b\"为真")
endif()
if(1.2.3 VERSION_LESS 1.10.1)
message("1.2.3 LESS 1.10.1为真")
endif()
if(abc MATCHES a..)
message("abc MATCHES a..为真")
endif()
if(ab MATCHES a..)
else()
message("ab MATCHES a..为假")
endif()
if(a IN_LIST list)
message("a IN_LIST list为真")
endif()
括号和条件优先级
cmake_minimum_required(VERSION 3.20)
if(NOT TRUE AND FALSE OR TRUE)
message("NOT FALSE AND TRUE OR FALSE为真")
endif()
if(NOT (TRUE AND (FALSE OR TRUE)))
else()
message("NOT FALSE AND TRUE OR FALSE为假")
endif()
变量展开
cmake_minimum_required(VERSION 3.20)
set(A FALSE)
set(B "A")
if(B)
message("B为真")
endif()
if(${B})
else()
message("\${B}为假")
endif()
while(NOT ${B})
message("NOT \${B}为真")
break()
endwhile()
命令定义
宏定义
macro(my_macro a b)
set(result "参数a: ${a}, 参数b: ${b}")
endmacro()
my_macro(x y)
message("${result}") # 输出:参数a: x, 参数b: y
MY_macro(A;B)
message("${result}") # 输出:参数a: A, 参数b: B
MY_MACRO(你 好)
message("${result}") # 输出:参数a: 你, 参数b: 好
函数定义
function(my_func a b)
set(result "参数a: ${a}, 参数b: ${b}" PARENT_SCOPE)
endfunction()
my_func(x y)
message("${result}") # 输出:参数a: x, 参数b: y
MY_func(A;B)
message("${result}") # 输出:参数a: A, 参数b: B
MY_FUNC(你 好)
message("${result}") # 输出:参数a: 你, 参数b: 好
参数访问
macro(my_macro p)
message("ARGC: ${ARGC}")
message("ARGV: ${ARGV}")
message("ARGN: ${ARGN}")
message("ARGV0: ${ARGV0}, ARGV1: ${ARGV1}")
endmacro()
function(my_func p)
message("ARGC: ${ARGC}")
message("ARGV: ${ARGV}")
message("ARGN: ${ARGN}")
message("ARGV0: ${ARGV0}, ARGV1: ${ARGV1}")
endfunction()
my_macro(x y z)
my_func(x y z)
参数的设计与解析
function(my_copy_func)
message("ARGN: ${ARGN}")
set(options OVERWRITE MOVE)
set(oneValueArgs DESTINATION)
set(multiValueArgs PATHS)
cmake_parse_arguments(
my
"${options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
)
message("OVERWRITE:\t${my_OVERWRITE}")
message("MOVE:\t\t${my_MOVE}")
message("DESTINATION:\t${my_DESTINATION}")
message("PATHS: \t\t${my_PATHS}")
message("---")
endfunction()
my_copy_func(DESTINATION ".." PATHS "1.txt" "2.txt" OVERWRITE)
my_copy_func(MOVE DESTINATION "../.." PATHS "3.txt" "4.txt")
my_copy_func(DESTINATION "../folder;name" PATHS 1.txt;2.txt)
宏和函数参数的区别
macro(my_macro p)
message("-- my_macro --")
if(p)
message("p为真")
endif()
set(i 1)
message("ARGV i: ${ARGV${i}}")
endmacro()
function(my_func p)
message("-- my_func --")
if(p)
message("p为真")
endif()
set(i 1)
message("ARGV i: ${ARGV${i}}")
endfunction(my_func)
my_macro(ON x)
my_func(ON x)
-
发表了主题帖:
《Cmake构建实战》2 随书资料分享
《Cmake构建实战》这本书出版社是提供了包含示例代码在内的随书资料,需要按照前言后面关于资源与支持部分的章节指引来进行下载。
资料中主要包含思维导图个随书源代码以及一份有关面试的电子书。
思维导图部分整理了本身的章节组成结构(不知道为什么只有前3章)。
程序员面试手册-电子书
随书源代码,与书中的章节一一对应。
├─.vscode
├─ch001
│ ├─Makefile
│ ├─动态库
│ ├─多源程序
│ ├─头文件库
│ ├─按需编译
│ ├─无需传递
│ │ ├─liba
│ │ └─libb
│ ├─漫长等待
│ ├─链接Boost
│ ├─间接引用
│ │ ├─liba
│ │ └─libb
│ └─静态库
├─ch002
├─ch003
│ ├─列表
│ ├─变量
│ │ ├─环境变量
│ │ └─缓存变量
│ │ └─匹配
│ ├─命令参数
│ ├─命令定义
│ ├─条件语法
│ └─遍历循环
├─ch004
│ ├─cmake_language
│ │ └─延迟调用
│ │ └─子目录
│ ├─cmake_path
│ ├─configure_file
│ ├─execute_process
│ ├─file
│ │ ├─归档文件
│ │ │ └─dir
│ │ ├─拷贝文件
│ │ ├─生成文件
│ │ └─遍历路径
│ │ └─a
│ │ └─b
│ ├─get_filename_component
│ ├─include
│ ├─list
│ ├─message
│ │ └─Warning
│ ├─separate_arguments
│ ├─string
│ │ └─字符串模板
│ └─variable_watch
├─ch005
├─ch006
│ ├─Cache
│ ├─mylib
│ └─使用mylib
├─ch007
│ ├─cache
│ ├─target_link_libraries
│ ├─一般库
│ ├─全局属性
│ ├─别名目标
│ ├─可执行文件
│ ├─可执行文件导入目标
│ ├─库导入目标
│ ├─接口库
│ │ └─include
│ ├─无需传递
│ ├─源文件属性
│ │ ├─a
│ │ └─b
│ ├─目录属性
│ │ ├─a
│ │ └─b
│ ├─目标属性
│ │ ├─include
│ │ └─liba
│ │ ├─include
│ │ └─src
│ ├─目标文件库
│ ├─自定义构建目标
│ ├─自定义构建规则
│ │ ├─响应构建事件
│ │ └─自定义依赖清单
│ └─间接引用
├─ch008
│ ├─GENEX_EVAL
│ ├─LINK_ONLY
│ ├─TARGET_GENEX_EVAL
│ ├─关系比较
│ ├─当前编程语言
│ ├─条件表达式
│ ├─构建模式与源文件
│ ├─目标属性
│ ├─输出表达式
│ └─逻辑运算
├─ch009
│ ├─CheckCompilerFlag
│ ├─CheckIncludeFiles
│ ├─CheckIPOSupported
│ ├─CheckPrototypeDefinition
│ ├─CheckSourceCompiles
│ ├─CheckSourceRuns
│ ├─CheckStructHasMember
│ ├─CheckSymbolExists
│ ├─CMakePrintHelpers
│ ├─CMakePrintSystemInformation
│ ├─CMakePushCheckState
│ │ └─b
│ ├─FindBoost
│ ├─Findonnxruntime
│ ├─FindThreads
│ ├─find_file
│ │ ├─a
│ │ │ └─b
│ │ └─b
│ │ └─a
│ ├─find_library
│ │ ├─dir1
│ │ └─dir2
│ ├─find_path
│ │ ├─a
│ │ │ └─b
│ │ └─b
│ │ └─a
│ ├─find_program
│ ├─GenerateExportHeader
│ └─查找要求变量
├─ch010
│ ├─同时兼容
│ └─最低版本
└─ch011
├─cli
├─cmake
├─include
├─models
└─src
- 2024-09-29
-
发表了主题帖:
《Cmake构建实战》1 构建之旅与Cmake安装
本帖最后由 maskmoo 于 2024-9-28 23:07 编辑
《CMake构建实战:项目开发卷》的前两章的内容:
第1章 构建之旅
1.1 单源文件程序:您好,世界
1.2 构建多源程序
1.3 构建静态库
1.4 构建动态库
1.5 引用第三方库
1.6 旅行笔记
第2章 CMake简介
2.1 为什么使用CMake
2.2 安装CMake
2.3 您好,CMake!
其中第一章构建之旅介绍了C /C++程序的构建基础,如何构建一个最简单的程序,"Hello, World!"等内容,阅读这部分可以了解到编译和运行程序的基本流程。并有助于理解和感受Cmake和传统Makefile等配置工具的相似和不同之处。
第二章主要是介绍了Cmake的特性,为什么选择CMake以及如何安装它。阅读这部分可以对Cmake的灵活性和强大的跨平台支持等特性有了个基本了解。
Cmake安装:
Windows平台安装包下载Download CMake , 书中是以3..20版本为示范,Cmake是向后兼容的设计,说以选择最新版本应该没什么问题。
详细安装流程:
勾选加入系统环境变量,方便后面进行调用。
安装路径选择默认目录
安装完成
测试在Terminal中是否可以查到安装版本信息
Hello Cmake!
通过message函数(类似C中的printf)实现输出一行文本。
message(Hello Cmake!)
关于Cmake的一些链接:
官方CMake Tutorial — CMake 3.30.4 Documentation
CMake菜谱(CMake Cookbook中文版)》
awesome-cmake: A curated list of awesome CMake resources, scripts, modules and examples.
- 2024-09-08
-
发表了主题帖:
【2024 DigiKey 创意大赛】Raspberry Pi5 部署HA系统
本帖最后由 maskmoo 于 2024-9-8 21:47 编辑
HA是HomeAssistant的简称,Home Assistant是一个开源的智能家居系统软件,能接入各种平台的智能设备,打破不同设备厂商之间的壁垒,即使是不支持联网的传统家电,也可以通过 DIY 一些传感器和开关将其整合到 HA 中;也可以通过编定制自动化场景,满足特定需求进而实现万物互联。
HA在Raspberry Pi5上的安装:
将安装到Raspberry Pi5上主要有两种安装方式,一种是在通用系统的基础之上手动对HA软件进行安装 ,另一种是直接安装HassOS 系统。两种方式各有优缺点,我这里主要为了使用HA就选择了第二种方式。
官网安装说明Raspberry Pi - Home Assistant (home-assistant.io)
硬件准备:一个 5V5A 电源,还要32GB 以上的 microSD 卡+读卡器来安装系统。 再准备一根网线用来访问HA。
可以通过Raspberry Pi Imager软件以在线方式进行安装,如果网络环境有问题也可以下载 Home Assistant 映像并使用 Balena Etcher 或其他烧录软件对SD卡进行镜像烧录。
1 打开 Raspberry Pi Imager 软件并选择 Raspberry Pi 设备
2 选择系统镜像类别, 这里选择基于Raspberry Pi5的 Home Assistant 操作系统.。
接下来选择插入计算机的SD卡,然后选择选择下一步等待 Home Assistant 操作系统写入 SD 卡。最后烧写完成弹出SD卡。
访问HOME ASSISTANT
将烧写完镜像的SD卡插入树莓派,用网线连接到路由器,连接电源开机,等待几分钟打开浏览器输入 homeassistant.local:8123 如果一切正常的话就能进入HomeAssistant。
在这个过程可能会遇到一些问题,如果一段时间后打开浏览器还是没反应可以外接一个显示器看下屏幕上的错误提示。我这里遇到的问题是网页能打开,但是会报一些克隆github相关仓库异常等问题导致不能正常进入主页面,这个是因为初始化阶段会在线下载一些资源,由于国内网络环境访问GitHub不稳定的原因造成的。我这里在确认PC能正常访问Github的时候尝试重新启动了树莓派解决的。
最终可以看到如下登录界面:
登录后界面:
概览:智能家居控制面板,也叫做仪表盘,可自定义卡片布局,是打开 HA 网页后看到的首页。
能源:监控家庭能源消耗情况,统计电力数据。
地图:可显示地理信息,如家、公司和家庭成员的位置信息。
日志:系统中各个实体的状态变化记录,如太阳升起和降落、灯的打开和闭合。
历史:以图像的形式显示各实体在某个时间段的状态信息。
媒体浏览器:将视频、音频和图像文件放在媒体目录中,就能在浏览器或支持的媒体播放器上浏览和播放这些文件。
开发者工具:包括实体状态、服务调用、显示模板以及事件触发的调试和开发。
配置:HA 配置页面,HA 所有可配置项基本可以在该页面找到。之前版本里的 Supervisor 菜单也移到了该界面。
通知:系统消息通知,如当系统检测到网络中存在可接入设备,会进行通知。
用户中心:用户自定义配置,以用户为单位进行配置,如系统语言、系统主题等。
- 2024-09-01
-
回复了主题帖:
读书入围名单: 《CMake构建实战:项目开发卷》
个人信息无误,确认可以完成阅读分享计划
- 2024-08-17
-
发表了主题帖:
【2024 DigiKey 创意大赛】物料开箱
本帖最后由 maskmoo 于 2024-8-17 19:23 编辑
感谢DigiKey,EEworld组织此次活动,很高兴能够入围参加这次活动。本次比赛想通过在Raspberry Pi 5上部署Home Assistant系统,并将室内环境采集单元,家居控制等单元结合起来实现一个定制化的智能家居系统。
本次购买的物料清单如下:
树莓派5 是一个4GB的版本,用来部署HA。只有一个裸板,后面还需要购买电源扇热等其他配件。
NRF52840-DONGLE是一款小型、低成本的 USB Dongle,支持蓝牙 5.4、蓝牙Mesh网络、Thread、Zigbee、802.15.4、ANT 和 2.4 GHz 专有协议。本次计划使用这个模快在树莓派构建上多协议网关。
ESP32-C6是与传感器搭配组成环境采集单元并最终接入到HA系统。
- 2024-08-04
-
发表了主题帖:
正点原子i.MX93开发板】eIQ图像分类测试
本帖最后由 maskmoo 于 2024-8-4 19:40 编辑
NXP 提供了一部分学习机器学习的例程(NXP 将其称为 eIQ Demos),默认存放在/usr/bin/eiq-examples-git目录。
其中dms为人脸关键点例程,face_recognition是人脸识别例程,gesture_detection是手势识别例程,image_classification图像分类例程,object_detection目标检测例程。
测试前需要将预先训练好的模型传到开发板上,模型在【正点原子】DLIMX93开发板资料(A盘)-基础资料\01、程序源码\06、AI例程源码\01、例程源码\03、eIQ Demos\models.zip
解压到/usr/bin/eiq-examples-git目录
cd /usr/bin/eiq-examples-git
unzip models.zip
CPU进行推理
进到/usr/bin/eiq-examples-git/image_classification 下的目录,执行以下命令测试模型
python3 label_image.py -i grace_hopper.bmp
其中grace_hopper.bmp 是用于测试推理的图片,label_image.py 是用于图像分类推理的python程序,labels.txt 是类别标签。
推理结果显示87.84%的概率为军装。
测试图片如下所示:
Python代码如下,这段代码是用于使用TensorFlow Lite(TFLite)模型对图像进行分类的脚本,并输出结果和推理时间。其主要步骤包括:
导入必要的库:加载处理图像、命令行参数、数组操作和TFLite解释器的库。
定义加载标签的函数:从指定的标签文件中读取标签。
解析命令行参数:获取图像文件、模型文件、标签文件、委托路径、输入均值和标准差,以及线程数。
加载并初始化模型:根据是否提供委托路径,加载TFLite模型并分配张量。
获取输入和输出细节:获取模型的输入和输出张量信息,检查输入数据类型。
预处理图像:调整图像大小并进行必要的归一化处理。
执行模型推理:设置输入张量数据并调用模型进行推理,获取输出数据。
处理和显示结果:找出概率最高的前五个分类,加载标签文件并输出分类结果和推理时间。
python 代码里指定了模型的路径以及标签文件,如果需要更换别的模型,需要修改 python 代码里的路径和模型以及标签文件。
# Copyright 2018 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""label_image for tflite."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import time
import numpy as np
from PIL import Image
import tflite_runtime.interpreter as tflite
def load_labels(filename):
with open(filename, 'r') as f:
return [line.strip() for line in f.readlines()]
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
'-i',
'--image',
default='grace_hopper.bmp',
help='image to be classified')
parser.add_argument(
'-m',
'--model_file',
default='../models/mobilenet_v1_1.0_224_quant.tflite',
help='.tflite model to be executed')
parser.add_argument(
'-l',
'--label_file',
default='labels.txt',
help='name of file containing labels')
parser.add_argument(
'-d',
'--delegate',
default='',
help='delegate path')
parser.add_argument(
'--input_mean',
default=127.5, type=float,
help='input_mean')
parser.add_argument(
'--input_std',
default=127.5, type=float,
help='input standard deviation')
parser.add_argument(
'--num_threads', default=None, type=int, help='number of threads')
args = parser.parse_args()
if(args.delegate):
ext_delegate = [tflite.load_delegate(args.delegate)]
interpreter = tflite.Interpreter(model_path=args.model_file, experimental_delegates=ext_delegate)
else:
interpreter = tflite.Interpreter(model_path=args.model_file)
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
# check the type of the input tensor
floating_model = input_details[0]['dtype'] == np.float32
# NxHxWxC, H:1, W:2
height = input_details[0]['shape'][1]
width = input_details[0]['shape'][2]
img = Image.open(args.image).resize((width, height))
# add N dim
input_data = np.expand_dims(img, axis=0)
if floating_model:
input_data = (np.float32(input_data) - args.input_mean) / args.input_std
interpreter.set_tensor(input_details[0]['index'], input_data)
start_time = time.time()
interpreter.invoke()
stop_time = time.time()
output_data = interpreter.get_tensor(output_details[0]['index'])
results = np.squeeze(output_data)
top_k = results.argsort()[-5:][::-1]
labels = load_labels(args.label_file)
for i in top_k:
if floating_model:
print('{:08.6f}: {}'.format(float(results[i]), labels[i]))
else:
print('{:08.6f}: {}'.format(float(results[i] / 255.0), labels[i]))
print('time: {:.3f}ms'.format((stop_time - start_time) * 1000))
NPU进行推理
默认情况下使用的CPU进行推理,如果想使用IMX93的NPU进行推理,则需要通过 vela 工具将模型编译成可以使 NPU 进行推理的 vela 模型并且调用推理脚本是使用通过-d 来指定委托(使用npu 的推理动态库/usr/lib/libethosu_delegate.so)。
vela 工具编译模型
使用 vela 工具编译 models 目录下 mobilenet_v1_1.0_224_quant.tflite 模型,并使用--output-dir 参数指定 vela_models 目录
mkdir vela_models
vela models/mobilenet_v1_1.0_224_quant.tflite --output-dir vela_models/
编译完成进入到 vela_models 目录可以看到生成的 mobilenet_v1_1.0_224_quant_vela.tflite 模型和 mobilenet_v1_1.0_224_quant_summary_internal-default.csv 性能评估两个文件,mo
bilenet_v1_1.0_224_quant_vela.tflite 就是我们要用于推理的 vela 模型。
执行 python 脚本,-m 指定编译后的vela_models 目录下的 mobilenet_v1_1.0_224_quant_vela.tflite 模型文件,通过-d 来指定 npu 的推理动态库/usr/lib/libethosu_delegate.so作为委托。
python3 label_image.py -i grace_hopper.bmp -m ../vela_models/mobilenet_v1_1.0_224_quant_vela.tflite -d /usr/lib/libethosu_delegate.so
从推理结果可以发现NPU的推理时间推理时间只有 4ms 左右,与前面的 CPU 推理时间的 64ms 相比大大缩短。
-
发表了主题帖:
正点原子i.MX93开发板】Buildroot构建
本帖最后由 maskmoo 于 2024-8-4 11:45 编辑
Linux的构建过程通常有Busybox Buildroot 和 Yocto几种方式,其中Yocto由于功能更加强大,学习曲线会更陡峭,需要更多的学习和配置工作。Busybox 也比较简单易
用,但是它的构建过程需要手动编写Makefile。 相对来说Buildroot更加轻量化和简单易用,能够更容易地进行系统构建和定制化。
本文在freescale_imx93evk_defconfig的官方配置的基础上,进行buildroot文件系统的编译。
buildroot 编译依赖软件安装
sudo apt-get install gcc g++
sudo apt-get install lsb-core lib32stdc++6 libncurses-dev
配置 defconfig 文件
make freescale_imx93evk_defconfig
执行完配置命令后会在当前目录下生成.config 隐藏文件,这个配置文件作用是让 buildroot 知道它要编译什么,同时make menuconfig指令也会根据这个.config 来进行图形化选择菜单。
然后执行 make 指令开始编译。
网络问题解决
buildroot编译过程中需要下载大量软件,由于国内网络环境原因,国外很多软件下载速度较慢或者访问不了,需要使用国内开源的镜像源加速下载。
buildroot加速下载 - goodboyyd - 博客园 (cnblogs.com)
GitHub访问有问题,这里把指定的Kernel(github.com)离线下载后copy到builtroot目录,然后对配置选项进行修改(之前是指定GitHub地址,这里修改成本地路径)
使用 Buildroot 的内部机制将本地压缩包复制到 Buildroot 的dl下载目录,以避免 wget 尝试下载。
Buildroot 会从dl目录中查找源代码包,首先复制内核压缩包到 Buildroot 的下载目录
这样,Buildroot会使用本地复制到dl目录的内核压缩包,而不会尝试通过网络下载(后面也遇到了几个模块下载有问题也都是通过这种方式解决的)。
编译完成得到的文件存放在 buildroot 源码的 output/images 目录下
文件系统打包
rootfs相关的文件是文件系统固件,可以使用 zstd 工具将 rootfs.tar 打包成 rootfs.tar.zst 格式,并替换到开发板出厂烧录固件包 ATK-IMX93-firmware/filesystem 目录,然后使用 sudo uuu alientek-imx93-emmc.uuu 烧写。
sudo apt-get update && sudo apt-get install zstd
zstd -c rootfs.tar -o rootfs.tar.zst
uuu烧写问题解决
最先按照原子的01【正点原子】ATK-DLIMX93快速体验手册V1.0文档中的烧录说明进行操作,总是异常失败。
原因是在烧写完 fsl-image-mfgtool-initramfs-imx_mfgtools.cpio.zst.u-boot 后,开发板会重启一次系统这时候的USB设备时需要驱动的。Github上说Win7是需要手动安装WinUSB驱动,Win10会自动安装,不清楚我的电脑为啥没有自动安装,使用Zadig安装完驱动后就正常了。
启动测试
烧录完成后切换启动模式,登陆用户名为 roo默认没有密码。可以看到编译出来的buildroot 文件系统正常启动。默认的配置是比较精简的系统,可以在此基础上按照需求进行定制化配置。
- 2024-07-26
-
回复了主题帖:
【正点原子i.MX93开发板】异构核间通讯--3 Windows环境下调试M33
Jacktang 发表于 2024-7-13 09:23
mingw32安装看着挺麻烦的
1下载工具链+2解压+3配置环境变量
- 2024-07-24
-
发表了主题帖:
正点原子i.MX93开发板】异构核间通讯--5 异核GPIO实验
本帖最后由 maskmoo 于 2024-7-21 21:07 编辑
异核GPIO实验是采用RPMSG的异构核间通讯来实现在A55核心下发控制命令传给M33核心进行控制执行的操作。
1 修改设备树
修改内核设备树文件 imx93-11x11-atk.dts。关闭linux对LED驱动的调用,即将LED的节点内的 status 属性赋值为 disabled。
imx93-11x11-atk.dts 文件的路径在/arch/arm64/boot/dts/freescale/imx93-11x11-atk.dts
修改完成后,需要重新编译设备树,并将生成的 imx93-11x11-atk.dtb 文件替换到Linux内核中。
cp imx93-11x11-atk.dtb /run/media/mmcblk0p1/
2 程序定制修改
LED0 是接在了GPIO_IO04上面,因此需要修改修改引脚复用(默认SDK文件已经修改好了)。
3 编译M33核固件
进入 01_rpmsg_rtos_tty_led 项目 工程文件夹,执行 build_all.sh 脚本构建 Cortex-M33 固件文件。
4 加载M33核固件
cd /lib/firmware
modprobe imx_rpmsg_tty
./load_remoteproc.sh rpmsg_rtos_led_imxcm33.elf
5 控制测试
Cortex-A55 终端执行以下指令控制板载 LED 灯。
Cortex-A55 终端执行以下指令点亮板载 LED 灯
echo "ON" > /dev/ttyRPMSG<num>
Cortex-A55 终端执行以下指令熄灭板载 LED 灯
echo "OFF" > /dev/ttyRPMSG<num>
在A55控制过程中,Cortex-M33 终端会打印相关消息,同时被控的红色LED也正常亮灭。
[localvideo]d2e7d360111aa024919d32732220f89e[/localvideo]
- 2024-07-21
-
发表了主题帖:
正点原子i.MX93开发板】异构核间通讯--4 实验前准备工作
本帖最后由 maskmoo 于 2024-7-21 21:06 编辑
Linux 系统要启动需要通过 bootloader 程序引导,也就说芯片上电以后先运行一段 bootloader 程序。这段 bootloader 程序会先初始化 DDR 等外设,然后将 Linux 内核从 flash(NAND,
NOR FLASH,SD,EMMC 等)拷贝到 DDR 中,最后启动 Linux 内核。
通过 M33 固件来测试异核通信例程时,需要提前修改 uboot 的 bootargs 变量,否则可能出现 M33 核启动后无法接收 A55 核指令的问题和。
启动开发板时,在串口打印信息界面可以看到 uboot 启动相关的信息,需要在 uboot 倒计时结束前按下回车键,停留在 uboot 命令行,才能在 uboot 命令行中进行 uboot 命令的操作。
1 修改 uboot 启动参数
在 uboot 下我们可以将开发板虚拟成一个 U 盘,可以选择将 EMMC 虚拟成 U 盘以后就可以直接在电脑上向开发板拷贝文件了。uboot 提供的 ums 命令是来完成此功能。
使用 Type C 线将电脑的 USB 接口和开发板的 USB_OTG 接口连接起来。在 uboot中,使用以下指令将 EMMC 虚拟成 U 盘。
ums 0 mmc 0
当 EMMC 成功挂载后,在显示的U盘中找到挂载显示的 extlinux.conf 文件。
修改 extlinux.conf 配置文件,添加 clk_ignore_unused 参数
确认clk_ignore_unused 参数是否成功传参到内核中,在开发板成功进入到文件系统后,使用如下指令查看。
cat /proc/cmdline
2 修改异核通信缓冲区大小
修改 Cortex-A55 异核通信单次接收数据包的总大小
异核通信例程SDK已经将所有异核通信例程中的异核通信缓冲区大小修改为 1024 字节。为了确保异核通信不出现问题,还需将 Linux 内核的异核通信缓冲区大小同样修改为 1024 字节。
在内核源码kernel-6.1.55/drivers/rpmsg 目录的 virtio_rpmsg_bus.c 文件。修改宏定义变量 MAX_RPMSG_BUF_SIZE 的大小为 1024。这个值代表单次接收数据包的总大小 。
修改 Cortex-A55 异核通信缓冲池大小
在 kernel-6.1.55/arch/arm64/boot/dts/freescale 目录下找到 imx93-11x11-atk.dts 文件。定位到 vdevbuffer 节点,修改 reg 属性的第四个参数为 0x20000。出厂设备中值reg 属性的第四个参数是 0x10000,对应 512 字节的缓冲区大小,将其调整为0x20000 就能对应1024 字节的缓冲区大小,按以上方法即可计算出其它缓冲区大小对应的 reg 属性第四个参数的值
测试验证
使用 imx_rpmsg_tty.ko 进行测试,检验异核通信缓冲区大小修改是否完成。
将宏定义 MSG 的值改为以下内容,数据大小大于默认的512字节。修改完后重新编译内核模块文件并将新的内核模块文件替换到核心板中。
修改Cortex-M33 SDK 驱动源码
主要是 rpmsg_config.h 的 RL_BUFFER_PAYLOAD_SIZE 变量大小修改为 1008和 main_remote.c 下的 app_buff 字符串数组大小,将其修改为1024 即可,这个数值代表异核通信缓冲区总大小。SDK源码默认这两处都已经修改完成,因此这里只需要重新编译文件,将生成的 elf 文件放到开发板的/lib/firmware 文件夹路径下即可。
分别将调整后的内核镜像设备树更新到对应目录,然后重启开发板。
打开 M33 和 A55 的串口终端,接着拨码 A55 EMMC 模式启动开发板,进入/lib/firmware文件夹,使用以下指令进行测试
modprobe imx_rpmsg_tty
./load_remoteproc.sh rpmsg_buffer_test.elf
第一次测试发现现象不符合预期,检查发现时更改后的imx_rpmsg_tty模块没有更新到开发板。
更新imx_rpmsg_tty模块
最终测试成功
检验修改成功后记得将内核源码中的 imx_rpmsg_tty.c 文件里宏定义 MSG 的值改回“helloworld!”再进行接下来的例程测试,否则建立异核通信通道后无法完整初始化硬件,容易出现
一些与测试现象不相符的内容。
-
发表了主题帖:
【正点原子i.MX93开发板】固件更新实践
本帖最后由 maskmoo 于 2024-7-21 00:01 编辑
【正点原子i.MX93开发板】PC与开发板文件传输测试
【正点原子i.MX93开发板】出厂Linux系统源码编译实践
在前面文件传输和源码编译的基础上,这次将编译生成的镜像固件替换到开发板系统上更新,进行调试验证。
对于不同的镜像、文件,需要拷贝到开发板文件系统对应的路径也不同,这里列举常用的镜像、文件在开发板上的路径。
1 flash.bin(U-Boot)更新
对BootLoader进行更新主要有两种方法,分别是使用UUU脚本更新和使用dd指令更新。我这里使用的dd命令进行更新。
更新前确认系统启动的Uboot版本信息
然后将先前编译好的flash.bin文件拷贝到开发板home目录下,准备进行 flash.bin 烧写。 烧录前要执行下面的指令,先使能 emmc 启动分区。
echo 0 > /sys/block/mmcblk0boot0/force_ro
当前目录下的 flash.bin 烧写至 emmc的启动分区
dd if=flash.bin of=/dev/mmcblk0boot0
烧写完成后,关闭烧写的启动分区
echo 1 > /sys/block/mmcblk0boot0/force_ro
最后执行以下指令使能启动分区
mmc bootpart enable 1 1 /dev/mmcblk0
重启开发板查看 U-Boot 的打印信息,从打印的编译实践信息可以看到flash.bin已经成功更新。
2 内核镜像/设备树/内核模块更新
在调试验证阶段,只需要将需要验证的镜像文件替换到对应的路径下即可。对应文件在系统的路径为/run/media/mmcblk0p1。
更新前确认系统内核启动的版本信息
更新内核镜像
重启开发板观察内核启动信息,通过编译实践可以确认内核已经成功更新。
驱动模块路径位于系统的/lib/modules/6.1.55,同样进行替换即可。
如果最终确认完镜像功能后,可以将对应的镜像文件替换到基础资料\08、系统镜像\ATK-DLIMX93 出厂系统固件烧录包\boot,使用正点原子提供的 alientek-
imx93-emmc.uuu或alientek-imx93-sd.uuu进行烧写。针对这部分具体操作可以参照【正点原子】DLIMX93开发板资料(A盘)-基础资料\10、用户手册\06【正点原子】ATK-DLIMX93固件更新参考文档V1.0.pdf。
3 更新文件系统
文件系统的更新如果直接在运行中的系统上操作可能会遇到诸多问题,可能存在文件系统的一致性和数据损坏的风险。为了安全和有效地打包整个文件系统,原子的文档中提供了从TF卡启动和UUU工具烧录更新两种方式,目前笔者暂时没有文件系统更新需求,所以这部分没有具体实操,有更新需求的小伙伴可以参照【正点原子】DLIMX93开发板资料(A盘)-基础资料\10、用户手册\06【正点原子】ATK-DLIMX93固件更新参考文档V1.0.pdf 文档的第5章。
- 2024-07-18
-
发表了主题帖:
【正点原子i.MX93开发板】PC与开发板文件传输测试
本帖最后由 maskmoo 于 2024-7-18 22:52 编辑
玩转开发板,少不了要在PC与开发板之间进行文件互传等操作,原子的文档中介绍了几种可以将 Ubuntu 虚拟机里的文件传输到开发板上的方法,根据传输介质的类型分为 U 盘/TF 卡传输和网络传输,本文主要采用有线网络和WindTerm软件进行SSH连接和文件传输功能实现。
1 网络测试
在开箱测评中对开发板进行了简单的网络测试,将网线插入到任一网口处,确保网线能上网,开发板出厂系统将根据本地网络环境自动获取到上网 IP 地址(出厂系统支持 DHCP),输入 ifconfig 命令查看获取到的网络 IP。Ping一下,检查网络能否上网。
2 SSH连接
SSH(Secure Shell)是一种网络安全协议,通过加密和认证机制实现安全的访问和文件传输等业务。IMX93开发板出厂系统配置了 SSH 协议,使用WindTerm通过 SSH 协议登陆。
用户名为root,开发板默认没有 ssh 登录密码。登陆进去后界面如下图。
3 文件传输
界面左边的目录栏的资源管理器界面,可以方便地实现 Windows 和开发板的文件传输。
还可以通过SCP命令进行文件传输,scp(secure copy)是 linux 系统下基于 ssh 登陆进行安全的远程文件拷贝命令。
从本地复制文件到远程:
scp local_file remote_username@remote_ip:remote_folder
从本地复制文件夹到远程:
scp -r local_file_dir remote_username@remote_ip:remote_folder
推测上面资源管理器的功能应该也是通过SCP实现的
参考文档:
【正点原子】DLIMX93开发板资料(A盘)-基础资料\10、用户手册\07【正点原子】ATK-DLIMX93文件传输参考手册V1.0.pdf
【正点原子】DLIMX93开发板资料(A盘)-基础资料\10、用户手册\08【正点原子】Linux开发板网络环境搭建手册V1.0.pdf
【正点原子】DLIMX93开发板资料(A盘)-基础资料\10、用户手册\09【正点原子】ATK-DLIMX93出厂系统TFTP搭建手册V1.0.pdf
【正点原子】DLIMX93开发板资料(A盘)-基础资料\10、用户手册\10【正点原子】ATK-DLIMX93出厂系统NFS搭建手册V1.0.pdf
- 2024-07-16
-
发表了主题帖:
【正点原子i.MX93开发板】出厂Linux系统源码编译实践
本帖最后由 maskmoo 于 2024-7-16 00:02 编辑
如果想对系统部分参数进行调整或者针对特定功能进行二次开发则需要对开发板的出厂源码进行修改和重新编译,本文参照【正点原子】DLIMX93开发板资料(A盘)-基础资料\10、用户手册\06【正点原子】ATK-DLIMX93固件更新参考文档V1.0.pdf 进行编译环境搭建和源码和Uboot的编译实践。
1 安装 ARM 交叉编译工具链
网盘资料路径:IMX93 开发板\开发板光盘 A 盘-基础资料\05、开发工具\01、交叉编译器
fsl-imx-xwayland-glibc-x86_64-imx-image-full-armv8a-imx93evk-toolchain-6.1-mickledore.sh工具链是由基于 NXP 官方 yocto 文件系统生成的交叉编译工具链,主要是用作编译文件系统相关的命令和程序(包含 Qt 和 AI 相关程序)。
修改脚本的权限
chmod u+x fsl-imx-xwayland-glibc-x86_64-imx-image-full-armv8a-imx93evk-toolchain-6.1-mickledore.sh
安装交叉编译工具链
默认安装到/opt/fsl-imx-xwayland/6.1-mickledore 这个目录
./fsl-imx-xwayland-glibc-x86_64-imx-image-full-armv8a-imx93evk-toolchain-6.1-mickledore.sh
安装完的工具链目录大小为 24GB,此工具链包含 Qt、AI 等相关库,需要提前准备好足够的空间。
确认工具链自带的 GCC 版本来验证是否安装成功
source /opt/fsl-imx-xwayland/6.1-mickledore/environment-setup-armv8a-poky-linux
aarch64-poky-linux-gcc --version
2 正点原子出厂系统源码编译及镜像构建
出厂系统源码位于网盘资料路径:IMX93 开发板\开发板光盘 A 盘-基础资料\01、程序源码\01、正点原子 Linux 出厂系统源码
提前在ubuntu20.04 环境中安装以下工具,避免编译时提示缺少工具库
sudo apt-get install make gcc libssl-dev g++ git libncurses5-dev libncursesw5-dev libyaml-dev
sudo apt-get install u-boot-tools python3-pyelftools device-tree-compiler bison flex expect
U-Boot编译
在编译 uboot 前需要安装一下库
sudo apt-get install bison flex
解压源码
tar -xjf uboot-2023.04-v1.0.tar.bz2
使用正点原子提供的一键编译脚本 build.sh。此脚本中包含了使能交叉编译器、编译 U-Boot 源码、打包 flash.bin 等操作。
其中 flash.bin 文件就是可以烧写到开发板的固件,由 imx-mkimage 工具生成,包括u-boot.bin、u-boot-spl.bin、bl31.bin、tee.bin 等文件。
内核源码及模块编译
解压linux-6.1.55-v1.0.tar.bz2 内核源码
tar -xjf linux-6.1.55-v1.0.tar.bz2
其中适配于 ATK-DLIMX93 开发板硬件资源的 Linux内核源码设备树路径为 arch/arm64/boot/dts/freescale/dts/,设备树文件为 imx93-11x11-atk.dts
同样使用一键编译脚本 build.sh进行编译
最终编译生成的内核 Image 镜像和设备树文件,个设备树兼容正点原子的多款屏幕。
- 2024-07-09
-
发表了主题帖:
【正点原子i.MX93开发板】异构核间通讯--3 Windows环境下调试M33
本帖最后由 maskmoo 于 2024-7-7 23:34 编辑
M33 的SDK是以Cmake进行构建的,同时看官方SDK中的编译脚本也有适配Windows的bat文件,所以本篇就尝试在Windows平台对IMX93的M33核心进行开发和调试。
1 windows编译工具链安装
官网下载windows版本编译器
配置环境变量
查看tools/armgcc.cmake文件可知Cmake会从环境变量ARMGCC_DIR中查找编译器的目录。
解压gcc-arm-none-eabi-9-2019-q4-major-win32到本地并配置环境变量。
mingw32安装
尝试调用\SDK_1_0_0_ATK-DLIMX93\SDK_1_0_0_ATK-DLIMX93\boards\atk-dlimx93\00_demo_example\01_hello_world\armgcc\build_debug.bat进行编译
出现错误提示找不到mingw32-make,通过查看bat脚本内容可以编译过程是通过Cmake先生成Make File文件,然后再通过make进行编译。
if exist CMakeFiles (RD /s /Q CMakeFiles)
if exist Makefile (DEL /s /Q /F Makefile)
if exist cmake_install.cmake (DEL /s /Q /F cmake_install.cmake)
if exist CMakeCache.txt (DEL /s /Q /F CMakeCache.txt)
cmake -DCMAKE_TOOLCHAIN_FILE="../../../../../tools/cmake_toolchain_files/armgcc.cmake" -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=debug .
mingw32-make -j 2> build_log.txt
因此还需要安装mingw32工具链。这里我直接使用之前下载过的x86_64-8.1.0-release-posix-seh-rt_v6-rev0版本。解压并配置到path环境变量中。这里主要使用的是make工具,gcc的版本就不关系了。
编译测试
再次执行build_debug.bat脚本进行编译,可以看到已经可以正常编译了,输出文件在debug目录。
2 Windows环境调试
Jlink驱动和补丁安装
这部分操作跟Ubuntu的安装方式类似,可以参照上一篇文章【正点原子i.MX93开发板】异构核间通讯--2 Ubuntu环境下使用GDB调试M33 进行,主要差别就是对应软件都切换到windows平台的。
测试Jlink连接
使用JLinkGDBServer
运行J-Link GDB Server V7.52d GUI程序,进行相关参数配置后点击OK启动。
这部分跟Ubuntu的操作类似,启动GDB调试程序并加载测试。
- 2024-07-07
-
发表了主题帖:
【正点原子i.MX93开发板】异构核间通讯--2 Ubuntu环境下使用GDB调试M33
本帖最后由 maskmoo 于 2024-7-7 20:41 编辑
【正点原子i.MX93开发板】异构核间通讯--1 搭建M33-SDK编译环境
前面在Ubuntu环境下完成了M33 SDK环境的搭建,并成功完成demo程序的编译。这次就以上次编译出的elf文件为基础使用GDB来进行M33的调试。
1 JLink调试软件安装
需要注意的是某宝上的部分Jlink调试器会对驱动版本有限制,这个要跟商家进行确认根据自己的情况进行选择。我这里使用的7.52d的版本。
首先去Segger的官网下载对应版本驱动软件。
然后拷贝到ubuntu中,使用以下指令进行安装
sudo dpkg -i JLink_Linux_V752d_x86_64.deb
2 IMX93设备补丁安装
为了使Jlink能正常识别IMAX93,还需要进行Patch补丁的安装。(使用的补丁在资料盘 【正点原子】DLIMX93开发板资料(A盘)-基础资料\05、开发工具\02、异核通信开发工具\SDK_MX93_3RDPARTY_PATCH.zip)
首先解压补丁文件
unzip SDK_MX93_3RDPARTY_PATCH.zip
cd SDK_MX93_3RDPARTY_PATCH/
unzip JLink.zip
然后进入SDK_MX93_3RDPARTY_PATCH/JLink 文件夹,使用以下指令为 JLink 软件安装补丁。
这块需要注意如果使用的是7.54以上的版本可以按照原子的文档描述进行安装,如果要是像我这样使用的版本在7.54以下的情况则需要手动在原有驱动设备描述文件JLinkDevices.xml的文件上增加IMX93相关的信息,不能直接替换。
这里主要分两步首先是 JLinkDevices.xml的修改,拷贝补丁文件中的这部分信息到驱动文件中
第二件事情是把Jlink链接脚本文件放到上一把的信息中描述的指定路径
3 硬件连接
将 SW2 拨码开关全部往下拨,使用 JTAG 接口, 将 JLink 仿真器接到开发板 JTAG接口,将开发板拨码到 M33 的 EMMC 模式启动。
4 测试Jlink与M33的连接情况
首先我们试一下Jlink的默认连接方式能不能正常连接到内核
默认方式看来是不行的,那么这次测试指定刚刚安装的补丁设备(IMX93)
这块一开始在设备列表里找不到IMX94
后来检查补丁安装过程,最终发现问题出在修改XML文件。一开始写错位了一行,以下是修改后的。
修改后保存,在此启动JlinkExe进行connect测试,这次就可以正常在设备列表里找到IMX93系列设备了。我们选择MIMX9352_M33设备。
最终正常连接并设别到Cortex-M33核心,黄色的Log信息表明有调用我们安装的连接脚本。
5 使用 JLinkGDBServer
在 ubuntu 下打开终端,输入以下指令启动 J-Link GDB Server 应用
JLinkGDBServer -jlinkscriptfile /opt/SEGGER/JLink/Devices/NXP/iMX93/NXP_iMX93_Connect_CortexM33.JLinkScript
回到上篇文章编译生成的 hello_world.elf目录,在终端输入以下指令启动 M33 GDB 调试。
arm-none-eabi-gdb hello_world.elf
接着连接 GDB 服务器,加载程序。
target remote localhost:2331
monitor reset
monitor halt
监测M33 UART可以看到打印信息
关于Ubuntu环境下使用GDB调试M33的记录就到这里了,本篇文章记录了在 Ubuntu 环境下在正点原子 i.MX93 开发板上进行 GDB 调试的过程。包括下载并安装适用于 JLink 7.52d 版本的调试软件。通过修改 JLink 驱动文件添加对 IMX93 的支持。将 JLink 仿真器接到开发板的 JTAG 接口,并设置开发板的启动模式。最后,启动 J-Link GDB 服务器并使用 GDB 加载和调试编译出的 M33 程序,成功连接并调试 Cortex-M33 。
部分步骤的详细信息可以查阅原子资料盘【正点原子】DLIMX93开发板资料(A盘)-基础资料\10、用户手册\15【正点原子】ATK-DLIMX93使用GDB调试M33手册V1.0.pdf 文档
- 2024-07-06
-
回复了主题帖:
【正点原子i.MX93开发板】异构核间通讯--1 搭建M33-SDK编译环境
吾妻思萌 发表于 2024-7-1 07:10
异构是个啥啊?没接触过~
异构是不同架构的核心组成的Soc。 比如Contex-A55和 Contex-M33 ,如果要是两个A55就是同构了