0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

OpenHarmony源码剖析之ACE(JavaScript运行环境初始化)

OpenAtom OpenHarmony 来源:51CTO 作者:张亮亮 2021-11-18 10:40 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

张亮亮

深圳开鸿数字产业发展有限公司

简介

JS UI 框架引擎ACE全称 Ability Cross-platform Environment,是 OpenHarmony 标准系统上的UI框架。ACE:结合了 OpenHarmony 系统的基础组件 Ability,开源 jsframework 框架,开源 js 引擎 quickjs,开源跨平台 UI 框架 flutter,开源渲染引擎 skia 以及各种平台能力 API 等共同构筑了 OpenHarmony 标准系统 javacript 应用开发的基础。

1.1 OpenHarmony 架构图

9b9230c6-47d2-11ec-b939-dac502259ad0.png

1.2 ACE UI框架引擎图

9cadf030-47d2-11ec-b939-dac502259ad0.png

1.3 ACE 主要构成

1. JavaScript前端框架

目前 OpenHarmony 标准系统采用主流的类 Web 范式,对开源的 Weex 框架中的 jsframework 做定制化,采用 ts 开发,主要包括编程模型 MVVM、组件、API、页面路由以及事件处理。

2. JavaScript引擎

目前 OpenHarmony 标准系统使用的是开源 quickjs 引擎,提供 JS 语言运行时和执行上下文,提供 js 的解析和 jsframework 的加载。

3. 中间转换层

中间转换层也就是 JS 桥接层,实现前端开发框架到 UI 后端引擎和 JS 引擎的对接。

4. 声明式UI后端引擎

C++构建的UI后端引擎,包括 UI 组件、布局视图、动画事件、自绘制选软管线。

5. 渲染引擎

目前 OpenHarmony 标准系统复用了开源跨平台 UI 框架 flutter 引擎提供基础的图形渲染能力。

6. 平台适配层

目前 OpenHarmony 标准系统的适配层完成了 OpenHarmony 平台和 IDE 的 previewer 的适配,将平台依赖聚焦到平台相关的画布、通用线程以及事件处理机制等少数接口上,为跨平台提供相应的基础设施,实现跨平台一致化的 UI 渲染。

7. 能力扩展层

为扩展 ACE 能力提供的插件机制,平台其他子系统可以利用插件机制开发相关能力的 js 接口,为应用层提供相应的能力支持。通过 napi 提供引擎无关的插件实现机制,保证接口的 ABI 兼容性。

基础知识

2.1 代码结构
/foundation/ace/ace_engine├── adapter                       # 平台适配目录│   ├── common|   ├── ohos                      # ohos平台适配目录│   └── preview                   # IDE preview平台适配目录├── frameworks                    # 框架代码│   ├── base                      # 基础库│   ├── bridge                    # 前后端对接层│   └── core                      # 声明式UI后端引擎目录/third_party/jsframework          # JavaScript前端框架/third_party/quickjs              # JavaScript引擎/third_party/flutter#flutterengine提供跨平台自渲染引擎

2.2 ACE框架类图

9ce025a0-47d2-11ec-b939-dac502259ad0.png

(点击图片查看高清大图) 2.3 线程模型

ACE JS 应用启动时会创建一系列线程,形成独立的线程模型,以实现高性能的渲染流程。

Platform线程:当前平台的主线程,也就是应用的主线程,主要负责平台层的交互、应用生命周期以及窗口环境的创建。

JS线程:JS 前端框架的执行线程,应用的 JS 逻辑以及应用 UI 界面的解析构建都在该线程执行。

UI线程:引擎的核心线程,组件树的构建以及整个渲染管线的核心逻辑都在该线程:包括渲染树的构建、布局、绘制以及动画调度。

GPU线程:现代的渲染引擎,为了充分发挥硬件性能,都支持 GPU 硬件加速,在该线程上,会通过系统的窗口句柄,创建 GPU 加速的 OpenGL 环境,负责将整个渲染树的内容光栅化,直接将每一帧的内容渲染合成到该窗口的 Surface 上并送显。

IO线程:主要为了异步的文件 IO 读写,同时该线程会创建一个离屏的 GL 环境,这个环境和 GPU 线程的 GL 环境是同一个共享组,可以共享资源,图片资源解码的内容可直接在该线程上传生成 GPU 纹理,实现更高效的图片渲染。

Javascript运行环境初始化

3.1 时序图

9d28c008-47d2-11ec-b939-dac502259ad0.png

(点击图片查看高清大图)

3.2 源码解析

1.OnStart()

  • AceAbility继承自Ability,当应用启动时首先应用程序框架会调用AceAbility的生命周期函数OnStart();

  • 通过Ability的api获取Hap包的路径,通过读取配置文件manifest.json获取应用程序配置的前端的类型;

  • 当前我们只关注JS前端,目前支持的前端类型包括enum class FrontendType { JSON, JS, JS_CARD, DECLARATIVE_JS };

  • 根据前端类型调用ACE核心聚合类AceContainer的静态方法CreateContainer,这个类是ACE框架平台适配层的核心类,接下来的前端核心类和JS引擎的创建都是在其中完成的。

//foundationaceace_engineadapterpreviewentranceace_ability.cppvoid AceAbility::OnStart(const Want& want){    ...        //获取打包的js bundle文件,取出配置文件,获取前端类型    auto packagePathStr = GetBundleCodePath();    auto moduleInfo = GetHapModuleInfo();    if (moduleInfo != nullptr) {        packagePathStr += "/" + moduleInfo->name + "/";    }    FrontendType frontendType = GetFrontendTypeFromManifest(packagePathStr);
    // create container    //创建AceContainer:内部初始化时创建了js线程,load了js engine,创建了JsFrontend    Platform::CreateContainer(        abilityId_, frontendType, this,        std::make_unique([this]() {            TerminateAbility();        }));    ...    ...
    //运行page    Platform::RunPage(        abilityId_, Platform::GetContainer(abilityId_)->GeneratePageId(),        parsedPageUrl, want.GetStringParam(START_PARAMS_KEY));
    ...}
2. CreateContainer
  • 在AceContainer::CreateContainer中,首先创建了AceContainer对象;

  • 在构造函数中创建了FlutterTaskerExecutor对象用于多线程的任务管理;

  • 此处主要关注JS线程的创建和初始化,在InitJsThread()中创建了JS线程并获取保存了jsRunner_用于JS任务的派发;

//foundationaceace_engineadapterpreviewentranceace_container.cppvoid AceContainer::CreateContainer(int32_t instanceId, FrontendType type, AceAbility* aceAbility,    std::unique_ptr callback){    auto aceContainer = AceType::MakeRefPtr(instanceId, type, aceAbility, std::move(callback));    AceEngine::Get().AddContainer(instanceId, aceContainer);    auto front = aceContainer->GetFrontend();    if (front) {        front->UpdateState(Frontend::ON_CREATE);        front->SetJsMessageDispatcher(aceContainer);    }}
AceContainer::AceContainer(int32_t instanceId, FrontendType type, AceAbility* aceAbility,    std::unique_ptr callback) : instanceId_(instanceId), type_(type), aceAbility_(aceAbility){    ACE_DCHECK(callback);    //创建和初始化FlutterTaskerExecutor用于封装管理Flutter ACE中涉及的多个线程:platform,UI,JS,GPU,IO,统一post任务到各线程执行    auto flutterTaskExecutor = Referenced::MakeRefPtr();    //初始化platform线程,将flutter platform线程的TaskerRunner适配到ohos平台主线程的EventRunner    flutterTaskExecutor->InitPlatformThread();    //初始化JS线程,这个线程用于解析JS,不归flutter管理,因此是单独在ACE里使用的    flutterTaskExecutor->InitJsThread();    //taskExector_封装了所有线程任务调度的接口,因此会传给Frontend用于JS前端解析任务和PipelineContext后端渲染UI和GPU IO相关    taskExecutor_ = flutterTaskExecutor;    if (type_ != FrontendType::DECLARATIVE_JS) {        //zll:初始化前端        InitializeFrontend();    }
    platformEventCallback_ = std::move(callback);}
void FlutterTaskExecutor::InitJsThread(bool newThread){    //创建并初始化JS线程,获取保存js线程的TaskRunner    //JS线程是ACE平台特有,不通过flutter创建管理    if (newThread) {        jsThread_ = std::make_unique(GenJsThreadName());        jsRunner_ = jsThread_->GetTaskRunner();    } else {        jsRunner_ = uiRunner_;    }}

3. JsFrontend

  • 完成JS线程的初始化后,如果前端类型不是DECLARATIVE_JS,会调用InitializeFrontend()对前端进行初始化。

  • 首先创建前端对象,Frontend::Create定义在js_frontend.cpp中,创建的是JsFrontend实例;

  • 然后通过JsEngineLoader::Get()动态加载QjsEngineLoader;

  • 再通过QjsEngineLoader创建QjsEngine并设置给JsFrontend;最后对JsFrontend对象做初始化;

  • JsFrontend是ACE框架从后端进入前端的唯一入口,AceAbility、AceContainer和JsFrontend是一一对应的关系;

//foundationaceace_engineadapterpreviewentranceace_container.cppvoid AceContainer::InitializeFrontend(){    if (type_ == FrontendType::JS) {        //目前Frontend::Create定义在js_frontend.cpp中,创建的是JsFrontend实例        frontend_ = Frontend::Create();        auto jsFrontend = AceType::DynamicCast(frontend_);        //创建并初始化js engine,此处是通过dlopen加载的qjs engine管理对象        jsFrontend->SetJsEngine(Framework::Get().CreateJsEngine(instanceId_));        ...    } else if (type_ == FrontendType::DECLARATIVE_JS) {        ...    } else {        ...    }    ACE_DCHECK(frontend_);    //初始化前端和js engine    frontend_->Initialize(type_, taskExecutor_);}
4. QjsEngine
  • 接下来我们继续分析一下JS引擎管理对象的创建;

  • 首先通过dlopen动态加载libace_engine_qjs.z.so通过入口函数创建获取QjsEngineLoader单例对象;

  • 然后通过QjsEngineLoader::CreateJsEngine()创建QjsEngine;

//foundationaceace_engineframeworksridgejs_frontendenginecommonjs_engine_loader.cpp//"libace_engine_qjs.z.so"动态库的入口,在qjs_engine_loader.cpp中定义constexpr char JS_ENGINE_ENTRY[] = "OHOS_ACE_GetJsEngineLoader";constexpr char QUICK_JS_ENGINE_SHARED_LIB[] = "libace_engine_qjs.z.so";...const char* GetSharedLibrary(){    return QUICK_JS_ENGINE_SHARED_LIB;}JsEngineLoader& GetJsEngineLoader(const char* sharedLibrary){    void* handle = dlopen(sharedLibrary, RTLD_LAZY);    ...    //    auto loader = reinterpret_cast(entry());    ...
    return *loader;}...//通过加载动态链接库的形式获取qjs桥接模块的入口函数并创建QjsEngineLoaderJsEngineLoader& JsEngineLoader::Get(){    static JsEngineLoader& instance = GetJsEngineLoader(GetSharedLibrary());    return instance;}
//foundationaceace_engineframeworksridgejs_frontendenginequickjsqjs_engine_loader.cppRefPtr QjsEngineLoader::CreateJsEngine(int32_t instanceId) const{    return AceType::MakeRefPtr(instanceId);}
5. JS线程
  • 在完成了QjsEngine的创建并设置给JsFrontend后,调用JsFrontend::Initialize();

  • 这里主要完成了FrontendDelegateImpl对象的创建和初始化将对JS引擎的相关操作委派给这个对象;

  • 以及Post JS引擎初始化的任务到JS线程的TaskRunner的message queue;

//foundationaceace_engineframeworksridgejs_frontendjs_frontend.cppbool JsFrontend::Initialize(FrontendType type, const RefPtr& taskExecutor){    LOGI("JsFrontend initialize begin.");    type_ = type;    ACE_DCHECK(type_ == FrontendType::JS);    //创建并初始化FrontendDelegate对象,具体实现为FrontendDelegateImpl    InitializeFrontendDelegate(taskExecutor);    //在JS线程初始化js engine,真正的启动JS引擎运行时并创建上下文    taskExecutor->PostTask(        [weakEngine = WeakPtr(jsEngine_), delegate = delegate_] {            auto jsEngine = weakEngine.Upgrade();            if (!jsEngine) {                return;            }            jsEngine->Initialize(delegate);        },        TaskExecutor::JS);
    LOGI("JsFrontend initialize end.");    return true;}
6. jsframework
  • 在JS线程执行QjsEngine对象的初始化,初始化JS运行环境;

  • 初始化JS引擎运行时上下文和初始化JavaScript框架层jsframework;

//foundationaceace_engineframeworksridgejs_frontendenginequickjsqjs_engine.cppbool QjsEngine::Initialize(const RefPtr& delegate){    ACE_SCOPED_TRACE("QjsEngine::Initialize");    LOGI("Initialize");
    JSRuntime* runtime = nullptr;    JSContext* context = nullptr;
    // put JS_NewContext as early as possible to make stack_top in context    // closer to the top stack frame pointer of JS thread.    runtime = JS_NewRuntime();    if (runtime != nullptr) {        context = JS_NewContext(runtime);    }
    ...
    engineInstance_ = AceType::MakeRefPtr(delegate, instanceId_);    return engineInstance_->InitJsEnv(runtime, context);}
bool QjsEngineInstance::InitJsEnv(JSRuntime* runtime, JSContext* context){    ...    context_ = context;    //1.初始化js运行时,上下文    if (!InitJsContext(context_, MAX_STACK_SIZE, instanceId_, this)) {        LOGE("Qjs cannot allocate JS context");        EventReport::JS_ENGINE_INIT_ERR);        JS_FreeRuntime(runtime_);        return false;    }    ...    //2.加载JS Framework,初始化JS前端框架    //加载jsframework,js_framework和js_framework_size是quickjs编译器编译jsframework的ts生成的c文件    //quickjs通过JS_ReadObject读取生成的cbytecode,并通过JS_EvalFunction(ctx, obj)执行相应的函数    //在这里最终调用的函数是jsframework/runtime/preparation/index.ts中的initFramework()函数    JSValue retVal = LoadJsFramework(GetQjsContext(), js_framework, js_framework_size, instanceId_);    bool result = JS_IsException(retVal) ? false : true;    if (context) {        JS_FreeValue(context, retVal);    }    ...
    return result;}
7. ACE模块
  • 初始化JS引擎运行时上下文是在InitJsContext完成;

  • 其中初始化Ace模块并将模块导入JS运行时上下文中,为jsframework框架层提供了ACE功能相关的接口;

  • jsframework可以通过调用ACE模块的接口完成Page上Dom元素到后端声明式UI元素节点的创建;

  • 同时往JS运行时上下文全局对象挂载了日志打印的函数用于对接平台日志打印功能;

//foundationaceace_engineframeworksridgejs_frontendenginequickjsqjs_engine.cpp//ace模块向js context暴露的函数,(js函数名,参数个数,对应的C函数)const JSCFunctionListEntry JS_ACE_FUNCS[] = {    JS_CFUNC_DEF_CPP("domCreateBody", 5, JsDomCreateBody),    JS_CFUNC_DEF_CPP("domAddElement", 9, JsDomAddElement),    JS_CFUNC_DEF_CPP("updateElementAttrs", 3, JsUpdateElementAttrs),    JS_CFUNC_DEF_CPP("updateElementStyles", 3, JsUpdateElementStyles),    JS_CFUNC_DEF_CPP("onCreateFinish", 0, JsOnCreateFinish),    JS_CFUNC_DEF_CPP("onUpdateFinish", 0, JsOnUpdateFinish),    JS_CFUNC_DEF_CPP("removeElement", 2, JsRemoveElement),    JS_CFUNC_DEF_CPP("callNative", 1, JsCallNative),    JS_CFUNC_DEF_CPP("callComponent", 3, JsCallComponent),    JS_CFUNC_DEF_CPP("loadIntl", 0, JsLoadIntl),    JS_CFUNC_DEF_CPP("loadLocaleData", 0, JsLoadLocaleData),#ifdef ENABLE_JS_DEBUG    JS_CFUNC_DEF_CPP("compileAndRunBundle", 4, JsCompileAndRunBundle),#endif};...
bool InitJsContext(JSContext* ctx, size_t maxStackSize, int32_t instanceId, const QjsEngineInstance* qjsEngineInstance){    ...        //将ace模块注入到上下文中,使得jsframework可以通过注册的接口调用ace的相关功能    // Inject ace native functions module    InitAceModules(ctx);
    JSValue globalObj, perfUtil;    globalObj = JS_GetGlobalObject(ctx);    perfUtil = JS_NewObject(ctx);
    InitJsConsoleObject(ctx, globalObj);
    JS_SetPropertyStr(ctx, perfUtil, "printlog", JS_NewCFunction(ctx, JsPerfPrint, "printlog", 0));    JS_SetPropertyStr(ctx, perfUtil, "sleep", JS_NewCFunction(ctx, JsPerfSleep, "sleep", 1));    JS_SetPropertyStr(ctx, perfUtil, "begin", JS_NewCFunction(ctx, JsPerfBegin, "begin", 1));    JS_SetPropertyStr(ctx, perfUtil, "end", JS_NewCFunction(ctx, JsPerfEnd, "end", 1));    JS_SetPropertyStr(ctx, globalObj, "perfutil", perfUtil);
    ...
    JSValue hiView;    hiView = JS_NewObject(ctx);    JS_SetPropertyStr(ctx, hiView, "report", JS_NewCFunction(ctx, JSHiViewReport, "report", 2));    JS_SetPropertyStr(ctx, globalObj, "hiView", hiView);
    JSValue i18nPluralRules;    i18nPluralRules = JS_NewObject(ctx);    JS_SetPropertyStr(ctx, i18nPluralRules, "select", JS_NewCFunction(ctx, JsPluralRulesFormat, "select", 1));    JS_SetPropertyStr(ctx, globalObj, "i18nPluralRules", i18nPluralRules);        //将ace模块导入到cxt指定的js 上下文中    const char* str = "import * as ace from 'ace';
"                      "var global = globalThis;
"                      "global.ace = ace;
"#ifdef ENABLE_JS_DEBUG                      "global.compileAndRunBundle = ace.compileAndRunBundle;
"#endif                      "global.callNative = ace.callNative;
";
    if (JS_CALL_FAIL == CallEvalBuf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE, instanceId)) {        LOGW("Qjs created JS context but failed to init Ace modules!");    }
    JS_FreeValue(ctx, globalObj);    return true;}

8. 初始化完成

  • 完成JS运行时上下文初始化之后,紧接着加载初始化jsframework,为JS应用程序提供javascript应用框架;

  • 这个地方使用quickjs的运行bytecode的方法,在编译时通过qjsc(quickjs编译器)将jsframework编译成c文件;

  • c文件的内容就是一个bytecode的组数和数组大小,指定了jsframework的入口函数;

  • 在这里对应jsframework/runtime/preparation/index.ts 中的initFramework()完成jsframework的初始化;

  • jsframework初始化完成的工作主要包括挂载到js运行时上下文全局对象上提供给native调用的jsframework函数,注册到jsframework的ACE提供的模块及其中的方法和jsframework提供的与native一一对应的组件及其方法;

//foundationaceace_engineframeworksridgejs_frontendenginequickjsqjs_engine.cppJSValue LoadJsFramework(JSContext* ctx, const uint8_t buf[], const uint32_t bufSize, int32_t instanceId){    ACE_SCOPED_TRACE("LoadJsFramework");
    LOGI("Qjs loading JS framework");    //等同于调用jsframework/runtime/preparation/index.ts 中的initFramework()    JSValue ret = CallReadObject(ctx, buf, bufSize, true, instanceId);    if (JS_IsException(ret)) {        LOGD("Qjs loading JSFramework failed!");        QjsUtils::JsStdDumpErrorAce(ctx, JsErrorType::LOAD_JS_FRAMEWORK_ERROR, instanceId);    }
    return ret;}
//third_partyjsframework
untimepreparationinit.tsexport function initFramework(): void {  for (const serviceName in i18n) {    service.register(serviceName, i18n[serviceName]);  }  for (const serviceName in dpi) {    service.register(serviceName, dpi[serviceName]);  }  //jsframework提供的可供Ace native在QjsEngine对象中调用的TS方法  const globalMethods: GlobalInterface = {    'createInstance': globalApi.createInstance,    'registerModules': globalApi.registerModules,    'appDestroy': globalApi.appDestroy,    'appError': globalApi.appError,    'destroyInstance': globalApi.destroyInstance,    'getRoot': globalApi.getRoot,    'callJS': globalApi.callJS  };  //注册modules,这些modules是ACE module提供的,调用这些模块的方法,会通过调用注册到qjs_engine的ace模块中的callNative方法  //会最终通过ace module的callNative调用到qjs_engine中的JsCallNative-->JsHandleModule-->然后调用对应的native方法  // registerModules and registerComponents  ModulesInfo.forEach(modules => {    globalMethods['registerModules'](modules);  });    //注册components组件,对组件方法的调用,最终会通过ace module的callComponent调用到qjs_engine中的JsCallComponent  ComponentsInfo.forEach((name) => {    if (name && name.type && name.methods) {      NativeElementClassFactory.createNativeElementClass(        name.type,        name.methods      );    }  });  //全局方法,这些方法可以被Qjs engine通过JS_GetPropertyStr(ctx, globalObj, "methodNamge")获取并调用,从而实现了从native到js的调用  for (const methodName in globalMethods) {    global[methodName] = (...args: any) => {      const res: any = globalMethods[methodName](...args);      if (res instanceof Error) {        Log.error(res.toString());      }      return res;    };  }}

总结

以上内容首先对 OpenHarmony 标准系统上 JS UI 框架引擎 ACE 的逻辑架构及相关模块进行了简单的介绍,给出了 ACE 架构中相关模块涉及的部分类的类图,结合本次重点分析的 Javascript 运行环境初始化的时序图详细分析了 Javascript 运行环境初始化的整个流程。

本文首发自:https://harmonyos.51cto.com/posts/7908
编辑:jq


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JS
    JS
    +关注

    关注

    0

    文章

    80

    浏览量

    19147
  • ui
    ui
    +关注

    关注

    0

    文章

    211

    浏览量

    22511
  • OpenHarmony
    +关注

    关注

    33

    文章

    3990

    浏览量

    21495

原文标题:OpenHarmony源码解析之ACE(JavaScript运行环境初始化)

文章出处:【微信号:gh_e4f28cfa3159,微信公众号:OpenAtom OpenHarmony】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    如何使用.mem文件初始化ROM并从PS-APU读取内容

    本篇博文旨在演示如何使用 .mem 文件来初始化 ROM 并从 PS-APU 读取内容。
    的头像 发表于 05-30 09:35 81次阅读
    如何使用.mem文件<b class='flag-5'>初始化</b>ROM并从PS-APU读取内容

    ELF-RV112B RKNN模型加载与运行初始化

    ELF-RV112B RKNN模型加载与运行初始化
    的头像 发表于 04-03 16:08 252次阅读
    ELF-RV112B RKNN模型加载与<b class='flag-5'>运行</b>时<b class='flag-5'>初始化</b>

    PC强实时运动控制(一):C#的EtherCAT总线初始化(下)

    通过使用配置工具导出ZAR文件进行EtherCAT总线初始化
    的头像 发表于 02-05 10:00 2866次阅读
    PC强实时运动控制(一):C#的EtherCAT总线<b class='flag-5'>初始化</b>(下)

    MCU工程初始化,到底该不该交给工具?

    背景 工程初始化重复性高,但出错成本大。工程师常问:交给工具是不是会丢失掌控? 工具可做的事 时钟树、引脚复用、外设配置 工程生成、代码模板套用 参数校验和约束检查 工程师仍需做的事 特殊业务逻辑
    的头像 发表于 01-29 10:18 311次阅读
    MCU工程<b class='flag-5'>初始化</b>,到底该不该交给工具?

    EtherCAT总线初始化步骤

    EtherCAT(Ethernet for Control Automation Technology)是一种高性能的工业以太网通信协议,广泛应用于工业自动领域。其初始化过程是确保系统稳定运行
    的头像 发表于 12-22 10:10 1173次阅读
    EtherCAT总线<b class='flag-5'>初始化</b>步骤

    瀚海微SD NAND TF卡硬件识别与初始化类问题探讨

    在瀚海微SD NAND/TF卡的实际应用中,硬件识别与初始化是保障设备正常运行的首要环节,该环节出现故障会直接导致存储卡无法投入使用,尤其在工业控制、车载设备等关键场景中,可能引发设备停机、数据丢失
    的头像 发表于 11-18 09:58 933次阅读
    瀚海微SD NAND  TF卡硬件识别与<b class='flag-5'>初始化</b>类问题探讨

    串口通信基石:Air8000下Modbus RTU串口初始化详解!

    串口初始化是Modbus RTU通信稳定可靠的关键起点。本篇深入剖析Air8000开发板串口参数配置、初始化代码实现及调试要点,结合master_rtu示例,分享实际操作中的经验与避坑指南,让您
    的头像 发表于 10-28 16:33 1866次阅读
    串口通信基石:Air8000下Modbus RTU串口<b class='flag-5'>初始化</b>详解!

    NVMe高速传输摆脱XDMA设计33:初始化功能验证与分析

    本文主要交流NVMe设计思路,在本博客已给出相关博文五十多篇,希望对初学者有一定作用 初始化功能主要实现 PCIe 链路设备的初始化配置和 NVMe 初始化配置。 复杂的PCIe 事务交互与设备行为
    发表于 10-08 08:02

    GraniStudio:IO初始化以及IO资源配置例程

    1.文件运行 导入工程 双击运行桌面GraniStudio.exe。 通过引导界面导入IO初始化以及IO资源配置例程,点击导入按钮。 打开IO初始化以及IO资源配置例程所在路径,选中I
    的头像 发表于 08-22 17:34 1147次阅读
    GraniStudio:IO<b class='flag-5'>初始化</b>以及IO资源配置例程

    GraniStudio:初始化例程

    1.文件运行 导入工程 双击运行桌面GraniStudio.exe。 通过引导界面导入初始化例程,点击导入按钮。 打开初始化例程所在路径,选中初始化
    的头像 发表于 08-22 16:45 1127次阅读
    GraniStudio:<b class='flag-5'>初始化</b>例程

    MCU外设初始化:为什么参数配置必须优先于使能

    在微控制器领域,初始化参数配置阶段至关重要。此时,虽无电源驱动,但微控制器在使能信号到来前,借初始化参数配置这一精细步骤,开启关键准备进程。初始化参数配置如同物理坐标锚定、逻辑指令部署、内在秩序预设
    的头像 发表于 08-13 10:38 1066次阅读

    定义IO初始化结构体

    由上述IOPORT相关功能的枚举类型我们可以知道,在对IOPORT模块进行初始化时需要根据情况配置它们。因此我们定义一个IOPORT初始化的结构体类型IOPORT_Init_t,它的成员包括了由上述所有枚举类型所声明的变量,因此该结构体类型的变量可以包含IOPORT的相关
    的头像 发表于 07-16 16:26 1688次阅读

    NVMe高速传输摆脱XDMA设计七:系统初始化

    直接采用PCIe实现NVMe功能,它的系统初始化流程主要分为链路训练、PCIe 初始化和 NVMe 初始化, 分别实现 PCIe链路连接、 PCIe 设备枚举配置和 NVMe 设备配置功能。 其中链
    发表于 07-04 09:14

    IM系列设备过载故障:界面初始化终止的诊断流程与修复指南

    当 IM 系列设备出现过载故障导致界面初始化终止时,通常表现为设备启动后操作界面无显示、指示灯异常闪烁或初始化进度条停滞不前,同时可能伴随设备运行异响或异常发热。初步判断时,可观察设备是否有错
    的头像 发表于 06-28 09:47 1486次阅读

    IM 系列设备过载保护机制下界面初始化中断的底层逻辑与解决方案

    一、过载保护机制与界面初始化的关联基础 IM 系列设备的过载保护机制是保障设备安全运行的核心功能,其通过传感器实时采集设备运行参数,如电流、电压、温度、系统资源占用率等。一旦这些参数超出预设阈值
    的头像 发表于 06-27 09:58 763次阅读