<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zephyr设备初始化机制交互式解析</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- Chosen Palette: Soft Tech -->
<!-- Application Structure Plan: The application is designed around a central, interactive, vertical flowchart representing the Zephyr boot sequence. This visual anchor (hub) allows users to immediately form a mental model of the process. Instead of a linear report, content is organized into thematic sections (spokes) that are revealed dynamically when a user clicks on a corresponding stage in the flowchart. This hub-and-spoke model promotes non-linear exploration, which is ideal for a technical audience that may want to quickly jump to specific topics like initialization priorities or dependency issues. Key data points, such as initialization priorities, are visualized using a bar chart to make abstract numbers tangible. This structure was chosen to transform a dense, text-based report into an engaging and intuitive learning tool, prioritizing user understanding and exploration over simply reproducing the source document's layout. -->
<!-- Visualization & Content Choices:
- Report Info: Zephyr Boot Sequence -> Goal: Organize/Change -> Viz: Vertical HTML/CSS flowchart -> Interaction: Click to navigate to content sections -> Justification: Provides a high-level map and acts as the main navigation, guiding the user's journey.
- Report Info: DEVICE_DEFINE macro -> Goal: Inform/Organize -> Viz: Code block + HTML table -> Interaction: Click button to toggle table visibility -> Justification: Clearly separates code from its explanation, reducing initial clutter.
- Report Info: Initialization Levels -> Goal: Compare/Inform -> Viz: HTML table -> Interaction: Highlight active level based on flowchart selection -> Justification: Table is ideal for comparison; highlighting adds context.
- Report Info: Initialization Priorities -> Goal: Compare/Relationships -> Viz: Chart.js Bar Chart -> Interaction: Highlight specific driver priority -> Justification: A chart visualizes relative numerical order far more effectively than text, making priority conflicts easier to understand.
- Report Info: Dependency/Future Issues -> Goal: Organize/Inform -> Viz: Interactive accordion cards -> Interaction: Click to expand/collapse -> Justification: Breaks down complex problems into digestible chunks, encouraging engagement without overwhelming the user.
- Library/Method: Chart.js for canvas-based charts, Vanilla JS for all interactions (toggles, navigation), Tailwind CSS for layout and styling. -->
<!-- CONFIRMATION: NO SVG graphics used. NO Mermaid JS used. -->
<style>
body {
font-family: 'Inter', 'Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif';
}
.nav-link.active {
background-color: #e0f2fe; /* sky-100 */
color: #0c4a6e; /* sky-900 */
font-weight: 600;
border-left-color: #0ea5e9; /* sky-500 */
}
.content-section {
display: none;
}
.content-section.active {
display: block;
}
.flow-line {
width: 2px;
background-color: #cbd5e1; /* slate-300 */
height: 1.5rem;
margin-left: calc(0.75rem - 1px);
}
.flow-dot {
width: 0.75rem;
height: 0.75rem;
background-color: #94a3b8; /* slate-400 */
border-radius: 9999px;
}
.nav-link.active .flow-dot {
background-color: #0ea5e9; /* sky-500 */
}
.accordion-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
</style>
</head>
<body class="bg-slate-50 text-slate-700">
<main class="container mx-auto p-4 md:p-8">
<header class="text-center mb-10">
<h1 class="text-3xl md:text-4xl font-bold text-slate-900 mb-2">Zephyr设备初始化机制交互式解析</h1>
<p class="text-lg text-slate-600">一份将复杂的技术报告转化为可探索体验的交互式应用</p>
</header>
<div class="flex flex-col md:flex-row gap-8">
<!-- Sticky Navigation -->
<aside class="md:w-1/4 lg:w-1/5 md:sticky top-8 self-start">
<h2 class="text-lg font-semibold text-slate-800 mb-4">系统启动流程</h2>
<nav id="boot-sequence-nav" class="flex flex-col items-start">
<!-- Nav items will be dynamically generated here -->
</nav>
</aside>
<!-- Content Panel -->
<div id="content-panel" class="md:w-3/4 lg:w-4/5 min-h-screen">
<!-- Content sections will be dynamically generated here -->
</div>
</div>
</main>
<footer class="text-center p-6 mt-12 border-t border-slate-200">
<p class="text-sm text-slate-500">基于 Zephyr RTOS 设备模型报告构建 | 旨在促进理解与探索</p>
</footer>
<script>
document.addEventListener('DOMContentLoaded', () => {
const navContainer = document.getElementById('boot-sequence-nav');
const contentContainer = document.getElementById('content-panel');
const contentData = [
{
id: 'intro',
title: '报告引言',
content: `
<h3 class="text-2xl font-bold text-slate-800 mb-4">深入理解Zephyr的自动化设备初始化</h3>
<p class="mb-4 text-slate-600 leading-relaxed">在像Zephyr这样的实时操作系统中,确保所有硬件设备在主应用程序开始前都已正确初始化是至关重要的。本应用的源报告深入探讨了Zephyr的设备模型,特别是<code>DEVICE_DEFINE</code>宏如何将一个设备(如DSP)的初始化函数(例如<code>dsp_acts_init</code>)无缝集成到系统启动流程中。这个过程是高度自动化的,旨在简化开发,但其背后依赖于一个由初始化级别、优先级和“链接器魔法”构成的复杂系统。</p>
<p class="mb-6 text-slate-600 leading-relaxed">本交互式应用旨在揭开这一过程的神秘面纱。您可以通过左侧的启动流程图进行导航,逐步探索从设备定义到内核调用其初始化函数的完整路径。我们将通过可视化的方式,帮助您理解其中的关键概念、潜在的依赖问题以及Zephyr社区为应对这些挑战而提出的未来演进方向。</p>
<div class="bg-sky-50 border-l-4 border-sky-400 p-4 rounded-r-lg">
<p class="text-sky-800"><strong>如何使用:</strong> 点击左侧“系统启动流程”中的任意阶段,右侧将显示对应的详细解析。请从“设备定义”开始您的探索之旅!</p>
</div>
`
},
{
id: 'device-define',
title: '1. 设备定义: DEVICE_DEFINE',
content: `
<h3 class="text-2xl font-bold text-slate-800 mb-4">一切的起点:<code>DEVICE_DEFINE</code> 宏</h3>
<p class="mb-4 text-slate-600 leading-relaxed">在Zephyr中,一个设备驱动程序的生命周期始于<code>DEVICE_DEFINE</code>宏。这个宏是Zephyr设备模型的核心,它在编译时静态地创建一个设备实例,并将其初始化函数注册到系统的启动序列中。这使得内核能够在启动时自动发现并初始化所有已定义的设备,而无需开发者手动调用任何初始化代码。</p>
<p class="mb-6 text-slate-600 leading-relaxed">下面是源报告中分析的<code>dsp_acts</code>设备的定义示例。这个宏的每个参数都扮演着至关重要的角色,共同构成了设备在系统中的完整画像。</p>
<div class="bg-gray-900 rounded-lg p-4 my-6 text-white text-sm font-mono overflow-x-auto">
<pre><code>DEVICE_DEFINE(dsp_acts, CONFIG_DSP_NAME,
dsp_acts_init, NULL, &dsp_data, &dsp_acts_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &dsp_drv_api);</code></pre>
</div>
<div id="param-table-container" class="border border-slate-200 rounded-lg p-6">
<h4 class="text-xl font-semibold text-slate-800 mb-4">参数详解</h4>
<p class="mb-4 text-slate-600">下表详细解释了<code>DEVICE_DEFINE</code>宏的每个参数及其在<code>dsp_acts</code>示例中的具体值,这些参数共同决定了设备的身份、行为和初始化时机。</p>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead class="bg-slate-100">
<tr>
<th class="p-3 font-semibold text-slate-700 border-b border-slate-200">参数</th>
<th class="p-3 font-semibold text-slate-700 border-b border-slate-200">描述</th>
<th class="p-3 font-semibold text-slate-700 border-b border-slate-200"><code>dsp_acts</code> 示例值</th>
</tr>
</thead>
<tbody>
<tr class="hover:bg-slate-50">
<td class="p-3 border-b border-slate-200 font-mono text-sky-700">init_fn</td>
<td class="p-3 border-b border-slate-200">设备初始化函数指针,由内核在启动时调用。</td>
<td class="p-3 border-b border-slate-200 font-mono">dsp_acts_init</td>
</tr>
<tr class="hover:bg-slate-50">
<td class="p-3 border-b border-slate-200 font-mono text-sky-700">data</td>
<td class="p-3 border-b border-slate-200">指向设备运行时可变数据结构体的指针(存-在RAM中)。</td>
<td class="p-3 border-b border-slate-200 font-mono">&dsp_data</td>
</tr>
<tr class="hover:bg-slate-50">
<td class="p-3 border-b border-slate-200 font-mono text-sky-700">config</td>
<td class="p-3 border-b border-slate-200">指向设备只读配置数据结构体的指针(存在ROM中)。</td>
<td class="p-3 border-b border-slate-200 font-mono">&dsp_acts_config</td>
</tr>
<tr class="hover:bg-slate-50">
<td class="p-3 border-b border-slate-200 font-mono text-sky-700">level</td>
<td class="p-3 border-b border-slate-200">初始化发生的系统级别。</td>
<td class="p-3 border-b border-slate-200 font-mono">POST_KERNEL</td>
</tr>
<tr class="hover:bg-slate-50">
<td class="p-3 border-b border-slate-200 font-mono text-sky-700">prio</td>
<td class="p-3 border-b border-slate-200">在指定级别内的初始化优先级 (0-99)。</td>
<td class="p-3 border-b border-slate-200 font-mono">CONFIG_KERNEL_INIT_PRIORITY_DEVICE</td>
</tr>
<tr class="hover:bg-slate-50">
<td class="p-3 border-b border-slate-200 font-mono text-sky-700">api</td>
<td class="p-3 border-b border-slate-200">指向设备API函数指针集合的指针,提供抽象接口。</td>
<td class="p-3 border-b border-slate-200 font-mono">&dsp_drv_api</td>
</tr>
</tbody>
</table>
</div>
</div>
`
},
{
id: 'init-levels',
title: '2. 初始化级别 (Level)',
content: `
<h3 class="text-2xl font-bold text-slate-800 mb-4">时机至关重要:初始化级别</h3>
<p class="mb-4 text-slate-600 leading-relaxed">Zephyr的启动过程被划分为几个明确的阶段或“级别”。<code>DEVICE_DEFINE</code>宏中的<code>level</code>参数决定了设备的初始化函数将在哪个阶段被执行。这是一个粗粒度的排序机制,确保了系统资源按逻辑顺序准备就绪。</p>
<p class="mb-6 text-slate-600 leading-relaxed"><code>dsp_acts</code>设备被配置在<code>POST_KERNEL</code>级别进行初始化。这是一个非常关键的选择,因为它意味着初始化将在Zephyr内核完全启动、所有内核服务(如线程、信号量、内存管理)都可用之后进行。这为驱动程序提供了安全使用内核功能的保障。</p>
<div class="overflow-x-auto border border-slate-200 rounded-lg p-6">
<h4 class="text-xl font-semibold text-slate-800 mb-4">Zephyr 系统初始化级别详解</h4>
<table class="w-full text-left border-collapse">
<thead class="bg-slate-100">
<tr>
<th class="p-3 font-semibold text-slate-700 border-b border-slate-200">级别</th>
<th class="p-3 font-semibold text-slate-700 border-b border-slate-200">描述</th>
<th class="p-3 font-semibold text-slate-700 border-b border-slate-200">典型用途</th>
</tr>
</thead>
<tbody>
<tr class="hover:bg-slate-50">
<td class="p-3 border-b border-slate-200 font-mono">EARLY</td>
<td class="p-3 border-b border-slate-200">极早期,在C代码环境准备好后立即执行。</td>
<td class="p-3 border-b border-slate-200">SoC或架构特定的底层初始化。</td>
</tr>
<tr class="hover:bg-slate-50">
<td class="p-3 border-b border-slate-200 font-mono">PRE_KERNEL_1 / 2</td>
<td class="p-3 border-b border-slate-200">内核服务可用之前。</td>
<td class="p-3 border-b border-slate-200">不依赖内核服务的早期驱动初始化。</td>
</tr>
<tr class="bg-sky-100 font-semibold text-sky-900">
<td class="p-3 border-b border-slate-200 font-mono">POST_KERNEL</td>
<td class="p-3 border-b border-slate-200">内核已启动并活跃,所有内核原语可用。</td>
<td class="p-3 border-b border-slate-200">大部分设备驱动和系统服务(如本例的DSP、蓝牙栈)。</td>
</tr>
<tr class="hover:bg-slate-50">
<td class="p-3 border-b border-slate-200 font-mono">APPLICATION</td>
<td class="p-3 border-b border-slate-200">在<code>main()</code>函数执行之前。</td>
<td class="p-3 border-b border-slate-200">应用程序特定的初始化。</td>
</tr>
</tbody>
</table>
</div>
`
},
{
id: 'priority',
title: '3. 初始化优先级 (Priority)',
content: `
<h3 class="text-2xl font-bold text-slate-800 mb-4">精细控制:初始化优先级</h3>
<p class="mb-4 text-slate-600 leading-relaxed">在同一个初始化级别内,可能存在数十个设备和系统服务需要初始化。为了管理它们之间的顺序,特别是处理依赖关系,Zephyr引入了优先级(priority)机制。这是一个从0到99的数字,数字越小,优先级越高,越早被执行。</p>
<p class="mb-6 text-slate-600 leading-relaxed"><code>dsp_acts</code>设备的优先级被设置为<code>CONFIG_KERNEL_INIT_PRIORITY_DEVICE</code>,这是一个Kconfig选项,默认值通常为50。这个选择决定了它在<code>POST_KERNEL</code>级别中与其他设备(如PINMUX、I2C控制器等)的相对初始化顺序。正确的优先级设置对于避免“鸡生蛋,蛋生鸡”式的依赖问题至关重要。</p>
<div class="border border-slate-200 rounded-lg p-6">
<h4 class="text-xl font-semibold text-slate-800 mb-4">POST_KERNEL 级别内常见优先级对比</h4>
<p class="mb-4 text-slate-600">下图通过一个条形图直观地展示了<code>POST_KERNEL</code>级别中一些常见驱动的初始化优先级。您可以看到,像PINMUX(引脚复用)这样的基础服务通常具有更高的优先级(数值更小),以确保它们在依赖它们的设备(如我们的DSP)之前准备就M就绪。</p>
<div class="chart-container relative h-96 max-h-[400px] w-full max-w-3xl mx-auto">
<canvas id="priorityChart"></canvas>
</div>
</div>
`
},
{
id: 'linker-magic',
title: '4. 链接器魔法与调用',
content: `
<h3 class="text-2xl font-bold text-slate-800 mb-4">幕后英雄:链接器</h3>
<p class="mb-4 text-slate-600 leading-relaxed">我们已经定义了设备、级别和优先级,但系统究竟是如何找到并按正确顺序调用<code>dsp_acts_init</code>函数的呢?答案在于“链接器魔法”。当编译器处理<code>DEVICE_DEFINE</code>宏时,它会生成一个包含初始化函数指针和设备信息的小结构体(<code>init_entry</code>)。</p>
<p class="mb-6 text-slate-600 leading-relaxed">然后,链接器脚本会将所有这些<code>init_entry</code>结构体收集起来,并将它们放入一个特殊的内存区域(链接器章节)。最关键的是,链接器会根据每个入口的初始化级别和优先级对它们进行排序。这样,在最终的固件镜像中,就形成了一个预先排好序的初始化函数指针数组。</p>
<div class="bg-slate-100 rounded-lg p-6">
<h4 class="text-xl font-semibold text-slate-800 mb-4">最终调用路径</h4>
<ol class="list-decimal list-inside space-y-3 text-slate-700">
<li><strong>定义与注册:</strong> <code>DEVICE_DEFINE</code> 创建一个包含 <code>dsp_acts_init</code> 函数指针的 <code>init_entry</code>。</li>
<li><strong>收集与排序:</strong> 链接器将这个 <code>init_entry</code> 和其他所有入口放入一个特定内存段,并根据级别和优先级排序。</li>
<li><strong>内核遍历:</strong> 系统启动时,内核中的一个函数(如 <code>z_sys_init_runlevel</code>)会遍历这个排好序的数组。</li>
<li><strong>执行调用:</strong> 当遍历到 <code>dsp_acts</code> 对应的入口时,内核会调用 <code>dsp_acts_init</code> 函数,并将指向 <code>dsp_acts</code> 设备实例的指针作为参数传入。</li>
</ol>
</div>
`
},
{
id: 'dependencies',
title: '5. 依赖问题与演进',
content: `
<h3 class="text-2xl font-bold text-slate-800 mb-4">挑战与未来:依赖管理</h3>
<p class="mb-6 text-slate-600 leading-relaxed">尽管Zephyr的初始化系统很强大,但它并非完美无缺。当前基于优先级的依赖管理机制将保证正确顺序的责任完全交给了开发者。如果依赖关系复杂或未被完全理解,就很容易导致难以调试的运行时错误。源报告中强调了几个关键挑战以及社区正在探索的解决方案。</p>
<div class="space-y-4 accordion-container">
<div class="accordion-item border border-slate-200 rounded-lg">
<button class="accordion-header w-full flex justify-between items-center p-4 text-left font-semibold text-slate-800 bg-slate-100 hover:bg-slate-200 transition-colors">
<span>挑战:隐式依赖与优先级冲突</span>
<svg class="w-5 h-5 transform transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
</button>
<div class="accordion-content">
<div class="p-4 border-t border-slate-200 text-slate-600">
<p><strong>问题:</strong> 系统本身不追踪设备间的依赖关系。例如,一个EEPROM驱动可能依赖I2C总线,但如果I2C驱动的初始化优先级(数字更大)低于EEPROM驱动,EEPROM在尝试获取I2C总线句柄时将失败,导致系统故障。</p>
<p class="mt-2"><strong>影响:</strong> 这种手动管理方式是脆弱的,特别是在大型、复杂的项目中,依赖关系可能跨越多个子系统,使得正确的优先级设置变得异常困难。</p>
</div>
</div>
</div>
<div class="accordion-item border border-slate-200 rounded-lg">
<button class="accordion-header w-full flex justify-between items-center p-4 text-left font-semibold text-slate-800 bg-slate-100 hover:bg-slate-200 transition-colors">
<span>演进方向一:延迟初始化 (Deferred Init)</span>
<svg class="w-5 h-5 transform transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
</button>
<div class="accordion-content">
<div class="p-4 border-t border-slate-200 text-slate-600">
<p><strong>方案:</strong> 允许某些设备在启动时不自动初始化。应用程序可以在运行时,当条件成熟时(例如,电源已稳定、所需资源已可用),手动调用其初始化函数。</p>
<p class="mt-2"><strong>优势:</strong> 这对于需要动态电源管理的设备或共享资源的场景非常有用,提供了更大的灵活性,避免了在不适宜的时候强制初始化。</p>
</div>
</div>
</div>
<div class="accordion-item border border-slate-200 rounded-lg">
<button class="accordion-header w-full flex justify-between items-center p-4 text-left font-semibold text-slate-800 bg-slate-100 hover:bg-slate-200 transition-colors">
<span>演进方向二:利用Devicetree序数</span>
<svg class="w-5 h-5 transform transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
</button>
<div class="accordion-content">
<div class="p-4 border-t border-slate-200 text-slate-600">
<p><strong>方案:</strong> 探索使用设备树(Devicetree)来更明确地声明设备间的依赖关系。构建系统可以解析这些依赖,并自动生成正确的初始化顺序,而不是依赖开发者手动设置的数字优先级。</p>
<p class="mt-2"><strong>优势:</strong> 将依赖管理从命令式(手动设置优先级)转变为声明式(声明依赖关系),这是一种更健壮、更不易出错的方法,可以大大提高系统的可靠性和可维护性。</p>
</div>
</div>
</div>
</div>
`
},
{
id: 'summary',
title: '6. 总结与最佳实践',
content: `
<h3 class="text-2xl font-bold text-slate-800 mb-4">总结与关键启示</h3>
<p class="mb-6 text-slate-600 leading-relaxed">通过本次交互式探索,我们揭示了Zephyr RTOS中<code>dsp_acts_init</code>函数的完整调用路径:它始于<code>DEVICE_DEFINE</code>的静态注册,经过初始化级别和优先级的分类,由链接器进行编译时排序,最终在系统启动过程中被内核按预定顺序精确调用。这个自动化机制是Zephyr高效和可预测性的关键。</p>
<div class="bg-sky-50 border-l-4 border-sky-400 p-6 rounded-r-lg">
<h4 class="text-xl font-semibold text-sky-900 mb-3">开发者最佳实践</h4>
<ul class="list-disc list-inside space-y-2 text-sky-800">
<li><strong>深入理解级别与优先级:</strong> 仔细选择初始化级别和优先级,确保所有依赖项(如时钟、PINMUX、总线控制器)都已就绪。</li>
<li><strong>显式管理依赖:</strong> 在文档或代码注释中明确记录驱动的依赖关系。在复杂的系统中,优先考虑使用设备树来声明依赖,而不是仅仅依赖优先级数字。</li>
<li><strong>拥抱未来机制:</strong> 关注Zephyr社区关于延迟初始化和设备树序数等新机制的进展,并适时采用它们来构建更健壮、更灵活的系统。</li>
<li><strong>利用日志与调试:</strong> 当遇到初始化问题时,善用日志系统在初始化函数中打印关键信息,这是定位优先级冲突或资源未就绪问题的最有效方法。</li>
</ul>
</div>
`
},
];
let activeLink = null;
let priorityChartInstance = null;
// Generate Nav and Content
contentData.forEach((item, index) => {
// Create Nav Link
const navItemContainer = document.createElement('div');
navItemContainer.className = 'flex items-center w-full';
const navLink = document.createElement('a');
navLink.href = `#${item.id}`;
navLink.id = `nav-${item.id}`;
navLink.className = 'nav-link flex-grow pl-4 pr-2 py-2 border-l-4 border-transparent hover:bg-slate-100 transition-colors rounded-r-md';
navLink.innerHTML = `<span class="text-slate-700">${item.title}</span>`;
navLink.addEventListener('click', (e) => {
e.preventDefault();
setActiveSection(item.id);
// Smooth scroll for better UX on mobile where content is below
document.getElementById(item.id).scrollIntoView({ behavior: 'smooth', block: 'start' });
});
const dot = document.createElement('div');
dot.className = 'flow-dot -ml-1.5 z-10';
navItemContainer.appendChild(dot);
navItemContainer.appendChild(navLink);
navContainer.appendChild(navItemContainer);
if (index < contentData.length - 1) {
const line = document.createElement('div');
line.className = 'flow-line';
navContainer.appendChild(line);
}
// Create Content Section
const section = document.createElement('section');
section.id = item.id;
section.className = 'content-section';
section.innerHTML = item.content;
contentContainer.appendChild(section);
});
// Accordion Logic
document.querySelectorAll('.accordion-header').forEach(button => {
button.addEventListener('click', () => {
const content = button.nextElementSibling;
const icon = button.querySelector('svg');
button.parentElement.classList.toggle('open');
icon.classList.toggle('rotate-180');
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
});
function setActiveSection(id) {
if (activeLink) {
activeLink.classList.remove('active');
}
document.querySelectorAll('.content-section').forEach(section => {
section.classList.remove('active');
});
document.querySelectorAll('.nav-link').forEach(link => {
link.classList.remove('active');
});
const newActiveSection = document.getElementById(id);
const newActiveLink = document.getElementById(`nav-${id}`);
if (newActiveSection && newActiveLink) {
newActiveSection.classList.add('active');
newActiveLink.classList.add('active');
activeLink = newActiveLink;
if (id === 'priority') {
renderPriorityChart();
}
}
}
function renderPriorityChart() {
const ctx = document.getElementById('priorityChart');
if (!ctx) return;
if (priorityChartInstance) {
priorityChartInstance.destroy();
}
const data = {
labels: ['PINMUX', 'CLOCK_CONTROL', 'DSP (本例)', 'I2C Controller', 'Sensor Driver'],
datasets: [{
label: 'POST_KERNEL 初始化优先级 (值越小越高)',
data: [45, 48, 50, 60, 80],
backgroundColor: [
'rgba(56, 189, 248, 0.6)', // sky-400
'rgba(56, 189, 248, 0.6)',
'rgba(251, 146, 60, 0.7)', // orange-400
'rgba(165, 180, 252, 0.6)', // indigo-300
'rgba(165, 180, 252, 0.6)',
],
borderColor: [
'rgba(14, 165, 233, 1)',
'rgba(14, 165, 233, 1)',
'rgba(249, 115, 22, 1)',
'rgba(99, 102, 241, 1)',
'rgba(99, 102, 241, 1)',
],
borderWidth: 1
}]
};
priorityChartInstance = new Chart(ctx, {
type: 'bar',
data: data,
options: {
indexAxis: 'y',
maintainAspectRatio: false,
responsive: true,
plugins: {
legend: {
display: false
},
title: {
display: true,
text: '常见驱动的初始化优先级对比',
font: {
size: 16
},
color: '#334155'
},
tooltip: {
callbacks: {
label: function(context) {
return ` 优先级: ${context.raw} (数值越小, 越早执行)`;
}
}
}
},
scales: {
x: {
beginAtZero: true,
title: {
display: true,
text: '优先级数值'
}
}
}
}
});
}
// Set initial state
setActiveSection('intro');
});
</script>
</body>
</html>