TI 18xx MPU寄存器配置实战:从原理到调试的嵌入式内存保护指南
1. 从手册到实战TI 18xx MPU寄存器配置的深度解析如果你正在基于TI的18xx系列处理器开发嵌入式系统尤其是涉及复杂数据传输或实时多任务处理的应用那么内存保护单元MPU的配置绝对是你绕不开的一环。手册里那一堆以TPTCxWRMPUENDADDx和TPTCxRDMPUSTADDx命名的寄存器看起来枯燥且令人望而生畏但它们恰恰是守护你系统稳定运行的“门神”。我经历过不止一次因为MPU配置不当导致的诡异宕机——数据被意外覆盖、DMA传输跑到未知区域、甚至整个内核挂起。这些寄存器不是摆设而是你从“代码能跑”到“系统可靠”必须跨越的鸿沟。今天我们不照本宣科而是结合我踩过的坑和实际项目经验把这些寄存器掰开揉碎了讲清楚让你不仅知道怎么配更明白为什么要这么配以及配错了会怎样。2. MPU在TPTC中的核心作用与架构设计2.1 为什么TPTC需要独立的MPU在深入寄存器之前我们必须先理解TPTC传输端口控制器在18xx系统中的角色。TPTC通常负责高速、高带宽的数据搬运比如连接DSP核心、DMA控制器与外部存储器或外设。你可以把它想象成一个高度专业化的“数据快递中心”。问题在于这个“快递中心”的“搬运工”读写引擎能力太强如果不对其访问权限加以限制它可能会把包裹数据送到错误的地址或者从禁止的区域取走东西导致系统崩溃。因此TI为TPTC的写端口WR数据写入内存的方向和读端口RD从内存读取数据的方向分别配备了独立的MPU。这是一种非常精细化的设计。试想一个场景某个内存区域只允许DSP核心写入计算结果但禁止DMA控制器读取。如果没有端口级MPU这个策略很难实施。而TPTC的MPU允许你为读和写分别定义不同的地址保护区域实现了更灵活的数据流向控制。2.2 MPU寄存器组概览与寻址逻辑从你提供的资料可以看出TPTC0和TPTC1的MPU寄存器布局是完全对称的。每个TPTC实例的每个端口读/写都支持6个独立的内存保护区域Region 0 - Region 5。这是理解所有寄存器的基础。这些寄存器主要分为三大类地址范围寄存器定义每个区域的边界包括起始地址STADD和结束地址ENDADD。使能与有效位配置寄存器集中管理区域的开关TPTCMPUVALIDCFG和整个MPU模块的使能TPTCMPUENCFG。错误状态寄存器当发生违规访问时记录触发错误的地址TPTCxWRMPUERRADD,TPTCxRDMPUERRADD。寄存器的偏移地址Offset呈现明显的规律性。例如TPTC0写端口的区域4结束地址寄存器TPTC0WRMPUENDADD4的偏移是134h而区域5的TPTC0WRMPUENDADD5就是138h相差4h即4字节一个32位寄存器的宽度。这种规律性对于编写驱动代码非常友好你可以通过基地址加偏移量的方式用循环或宏来高效地访问这些寄存器。注意手册中寄存器描述里的“R/W”表示可读写“R”表示只读。对于TPTCMPUENCFG寄存器中的ERRCLR错误清除位其访问类型标注为特殊“wspecial access type”这意味着向该位写1会产生一个清除错误标志的脉冲写0无效。这是一个关键细节在清除错误状态时必须注意。3. 核心寄存器功能详解与配置策略3.1 地址范围寄存器划定安全边界TPTCxWRMPUSTADDx和TPTCxWRMPUENDADDx以及对应的RD版本是MPU配置的核心。它们都是32位寄存器直接存储地址值。地址对齐要求这是第一个容易踩坑的地方。MPU区域地址通常有对齐要求比如要求起始和结束地址按一定字节如4KB、1KB对齐。手册可能不会在每个寄存器描述中重复强调但在系统内存映射或MPU章节的开头一定有说明。不满足对齐要求的配置是无效的可能导致MPU行为不可预测。在配置前务必确认处理器的具体对齐约束。例如如果要求4KB对齐那么你配置的地址值必须是0x10004096的整数倍。区域大小与重叠结束地址必须大于起始地址。区域大小就是ENDADD - STADD 1。MPU的6个区域是独立且可以重叠的。重叠时访问权限如何判定这取决于具体的硬件实现通常是区域编号优先例如编号小的区域设置优先或最精确匹配优先即地址落入的最小区域优先。TI 18xx的TPTC MPU通常采用后者。这意味着你可以设置一个大范围的“默认”区域如Region 0覆盖整个DDR再用小范围的Region 1-5来定义具有特殊权限的特定段如某个关键的数据缓冲区。当访问发生时MPU硬件会并行检查所有使能的区域并应用最精确匹配即地址落入的、范围最小的那个区域的规则。3.2 有效位与全局使能寄存器开关的艺术TPTCMPUVALIDCFG和TPTCMPUENCFG这两个寄存器是配置流程的“总闸”。TPTCMPUVALIDCFG偏移 214h这个寄存器将四个端口的区域使能位集中在一起。每个端口TPTC0_WR, TPTC0_RD, TPTC1_WR, TPTC1_RD占用一个字节8位但只使用低6位Bit[5:0]分别对应Region 0到Region 5。将某位置1即表示该区域配置生效。一个重要的实践是先配置好所有的地址范围寄存器最后再统一设置VALIDCFG。这可以避免在配置过程中出现“半生效”的区域导致意外的访问拦截。TPTCMPUENCFG偏移 218h这是MPU模块的顶层开关。低4位Bit[3:0]分别使能四个端口的MPU功能。Bit[7:4]则是四个端口对应的错误清除位ERRCLR。这里有一个关键操作顺序配置所有地址范围和有效位。将TPTCMPUENCFG的使能位如TPTC0WRMPUEN置1开启MPU保护。当系统触发MPU错误可通过中断或状态寄存器查询后在服务程序中先读取TPTCxWRMPUERRADD定位错误地址分析原因然后向对应的ERRCLR位写1来清除错误标志系统才能恢复正常传输。实操心得在系统初始化阶段我习惯将所有MPU相关寄存器地址、有效位、使能位全部清零然后按需逐个配置。这能确保系统从一个确定的、无保护的状态开始启动避免残留配置引起的问题。尤其是在进行热复位或局部复位后不要假设寄存器的状态会保持一定要重新初始化。4. 实战配置流程与代码示例假设我们需要为TPTC0的写端口配置两个内存保护区域Region 0保护一块位于DDR中的关键数据缓冲区地址范围0x8000_0000到0x8000_3FFF16KB。Region 1保护一段外设寄存器空间禁止TPTC写入地址范围0xFC00_0000到0xFC00_0FFF4KB。以下是基于C语言的伪代码实现假设我们已经有了访问寄存器的底层驱动如通过指针映射。// 假设寄存器基地址已定义 #define TPTC_MPU_BASE 0x02000000 // 示例基地址需查具体数据手册 // 寄存器偏移量定义 (基于你提供的资料) #define TPTC0WRMPUSTADD0_OFFSET 0x100 #define TPTC0WRMPUENDADD0_OFFSET 0x108 #define TPTC0WRMPUSTADD1_OFFSET 0x10C #define TPTC0WRMPUENDADD1_OFFSET 0x114 #define TPTCMPUVALIDCFG_OFFSET 0x214 #define TPTCMPUENCFG_OFFSET 0x218 // 寄存器访问宏 #define REG_WRITE(offset, value) (*(volatile uint32_t *)(TPTC_MPU_BASE (offset)) (value)) #define REG_READ(offset) (*(volatile uint32_t *)(TPTC_MPU_BASE (offset))) void configure_tptc0_wr_mpu(void) { // 第一步禁用MPU和所有区域确保配置环境干净 REG_WRITE(TPTCMPUENCFG_OFFSET, 0x0); // 清除所有使能位 REG_WRITE(TPTCMPUVALIDCFG_OFFSET, 0x0); // 清除所有区域有效位 // 第二步配置Region 0的起始和结束地址 (关键数据缓冲区) REG_WRITE(TPTC0WRMPUSTADD0_OFFSET, 0x80000000); REG_WRITE(TPTC0WRMPUENDADD0_OFFSET, 0x80003FFF); // 注意结束地址是包含在内的 // 第三步配置Region 1的起始和结束地址 (外设保护区) REG_WRITE(TPTC0WRMPUSTADD1_OFFSET, 0xFC000000); REG_WRITE(TPTC0WRMPUENDADD1_OFFSET, 0xFC000FFF); // 第四步设置区域有效位。TPTC0WRMPURNGVLD对应bit[7:0]我们使能Region0和Region1 uint32_t valid_cfg REG_READ(TPTCMPUVALIDCFG_OFFSET); valid_cfg ~(0xFF); // 先清零TPTC0_WR对应的字节低8位 valid_cfg | (1 0) | (1 1); // 使能Region 0 (bit0) 和 Region 1 (bit1) REG_WRITE(TPTCMPUVALIDCFG_OFFSET, valid_cfg); // 第五步最后使能TPTC0写端口的MPU功能 uint32_t en_cfg REG_READ(TPTCMPUENCFG_OFFSET); en_cfg | (1 0); // 设置TPTC0WRMPUEN (bit0) 为1 REG_WRITE(TPTCMPUENCFG_OFFSET, en_cfg); // 可选读取回写验证配置在调试阶段非常重要 if ((REG_READ(TPTC0WRMPUSTADD0_OFFSET) ! 0x80000000) || (REG_READ(TPTCMPUENCFG_OFFSET) 0x01) 0) { // 配置验证失败触发错误处理 handle_configuration_error(); } }配置顺序的“为什么”这个顺序禁用 - 配地址 - 设有效 - 总使能是防止误触发保护的关键。如果先使能MPU或区域有效位但地址寄存器还是复位值0那么MPU可能会认为区域0从0x0开始结束于0x0这个“零大小”区域可能意外拦截对低地址的合法访问。5. 调试与故障排查当MPU错误发生时即使配置看似正确在实际运行中仍可能触发MPU错误。TPTCxWRMPUERRADD和TPTCxRDMPUERRADD这两个只读寄存器是你的“第一现场取证工具”。5.1 错误排查流程捕获错误MPU错误通常会触发一个系统级错误中断如ESR。在你的中断服务程序ISR中首先要做的就是读取触发错误的地址。void mpu_error_isr(void) { uint32_t fault_addr REG_READ(TPTC0WRMPUERRADD_OFFSET); // 假设是TPTC0写错误 // 记录或打印 fault_addr log_error(MPU Write Fault at address: 0x%08X, fault_addr); // ... 其他处理 }分析地址将捕获的错误地址与你的MPU区域配置进行比对。它落在哪个你定义的区域内说明该区域本意可能是禁止访问的但发生了非法访问。它是否落在所有定义区域之外这说明你的区域覆盖不全存在“保护漏洞”。可能有一段本应受保护的内存没有被任何区域覆盖。检查地址是否对齐。非对齐访问有时也会触发MPU错误。检查访问源分析在错误发生时是哪个主设备哪个DMA通道、哪个CPU核心在通过TPTC访问内存。结合软件上下文任务、函数调用栈判断这次访问是否合理。清除错误标志在分析并可能修复问题后必须向TPTCMPUENCFG中对应的ERRCLR位写1来清除错误状态否则MPU可能会持续产生错误或锁定。// 清除TPTC0写端口的MPU错误标志 uint32_t en_cfg REG_READ(TPTCMPUENCFG_OFFSET); en_cfg | (1 4); // 设置TPTC0WRMPUERRCLR (bit4) 为1 REG_WRITE(TPTCMPUENCFG_OFFSET, en_cfg); // 注意该位是“写1清除”读回值可能仍是0。5.2 常见问题与解决思路问题现象可能原因排查步骤与解决方案系统一使能MPU就卡死或触发错误。1. 地址寄存器未正确初始化默认区域0覆盖了非法地址。2. 区域有效位和地址范围不匹配使能了未配置的区域。3. 对齐要求不满足。1. 检查初始化顺序确保先配地址再设有效位最后开总使能。2. 检查VALIDCFG寄存器确保使能的区域其STADD和ENDADD已正确配置。3. 确认配置的地址值是否符合数据手册规定的对齐粒度如4KB。特定数据传输任务运行时随机触发MPU错误。1. 缓冲区地址或长度计算错误导致访问越界。2. 多任务或中断上下文竞争缓冲区被意外修改或复用。3. DMA描述符链配置错误指向了错误地址。1. 仔细检查触发错误的地址回溯到软件中分配或计算该地址的代码。2. 检查任务同步机制如信号量、互斥锁确保对共享缓冲区的访问是串行化的。3. 检查DMA配置特别是源地址、目标地址和传输大小寄存器。错误地址看起来是“合法”的在定义的区域内。该区域的保护意图如只读与访问类型写操作冲突。注意TPTC MPU寄存器只定义了地址范围但访问权限读/写是隐含的写端口的MPU只检查写操作读端口的MPU只检查读操作。确认你的软件设计这个地址范围是否真的允许TPTC进行当前方向的访问例如一个配置给TPTC读端口作为源的数据区就不应该被TPTC写端口访问。需要从系统架构层面审查内存映射和访问权限规划。无法清除错误标志MPU持续报错。1. 错误清除操作不正确如写了0或写了其他位。2. 错误源持续存在刚清除又立即触发。3. 硬件可能存在锁死状态极少见。1. 严格按手册操作只向对应的ERRCLR位写1其他位保持原样。2. 在清除错误标志前必须先停止引发错误的传输活动如暂停DMA。3. 尝试先全局禁用MPUTPTCMPUENCFG使能位置0再重新进行完整配置流程。6. 高级应用与系统集成考量6.1 动态重配置与任务隔离在复杂的RTOS环境中不同任务可能需要不同的内存保护视图。虽然TPTC MPU的寄存器是全局的但你可以通过软件实现动态切换。例如在任务调度器进行上下文切换时除了保存/恢复CPU寄存器还可以保存/恢复当前任务所需的TPTC MPU配置一组地址和有效位。这为每个任务提供了专属的“数据传输沙箱”极大地增强了系统的健壮性。当然这需要额外的上下文切换开销并且要确保配置切换过程是原子的不会在切换中间被中断打断。6.2 与系统级MMU/MPU的协同TI 18xx处理器通常还包含CPU核心内的系统级MMU内存管理单元或MPU。TPTC的MPU和CPU的MMU/MPU是独立工作的。它们构成了多级保护CPU MPU/MMU保护CPU发起的访问定义任务间的代码和数据隔离。TPTC MPU保护通过TPTC发起的数据传输访问通常是DMA。这意味着一个内存地址必须同时通过CPU和TPTC的两套保护检查访问才会成功。在系统设计时需要统一规划。一个常见的做法是在CPU的MPU中将某段内存设置为“仅特权模式访问”或“不可执行”在TPTC MPU中则根据数据传输方向读/写设置对应的区域。两者相辅相成共同构建了深度的防御体系。6.3 性能与安全性的权衡启用MPU意味着TPTC在每次发起传输事务时都需要进行地址范围检查这会引入少量的额外延迟。对于追求极限带宽和低延迟的应用需要评估其影响。我的经验是在大部分应用中这点开销是微不足道的换取的系统稳定性收益是巨大的。但在配置时有一个优化技巧尽量将频繁访问的、需要保护的关键缓冲区放在同一个MPU区域内并确保该区域是连续且对齐的。避免让一次传输跨越多个MPU区域边界因为每次边界检查都可能带来停顿。如果传输必须跨越多个区域确保这些区域在地址空间上是连续的并且权限一致以减少硬件检查的状态切换。配置TPTC的MPU尤其是像TI 18xx这样拥有精细端口和区域控制的MPU初期会觉得繁琐。但一旦你理解了其设计逻辑——将高速数据通路的访问权限像手术刀一样精确控制起来——你就会意识到这是构建高可靠嵌入式系统的基石。它强迫你在软件设计早期就严谨地思考内存布局和数据流向。那些看似复杂的寄存器实际上是你与硬件签订的关于数据安全的契约。每一条配置都是在为系统的长期稳定运行添砖加瓦。多花时间理解并配置好它们远比后期在偶发的、难以复现的内存错误中挣扎要高效得多。

相关新闻

Nintendo Switch大气层Atmosphere稳定版:全面解锁游戏主机潜能的终极指南

Nintendo Switch大气层Atmosphere稳定版:全面解锁游戏主机潜能的终极指南

Nintendo Switch大气层Atmosphere稳定版:全面解锁游戏主机潜能的终极指南 【免费下载链接】Atmosphere-stable 大气层整合包系统稳定版 项目地址: https://gitcode.com/gh_mirrors/at/Atmosphere-stable 大气层Atmosphere稳定版是当前最成熟、最安全的Ninten…

2026/10/15 5:22:27 阅读更多 →
深耕三年日志框架,聊聊Java项目中slf4j+logback那些恶心的隐性坑点

深耕三年日志框架,聊聊Java项目中slf4j+logback那些恶心的隐性坑点

做后端开发的没人离得开日志,不管是线上问题排查、接口异常追踪,还是日常业务监控,日志都是最直接的依据。很多人开发项目都是直接引入starter依赖,默认配置直接跑,从来不会主动去改日志底层参数。平时本地测试没啥问题…

2026/10/14 1:07:54 阅读更多 →
百考通智能化AI一键生成,任务书让科研与项目启动更高效

百考通智能化AI一键生成,任务书让科研与项目启动更高效

在学术研究、课程设计与项目开发的起步阶段,一份规范、清晰的任务书是指引方向的核心纲领。但从选题构思到内容撰写,往往让研究者与学生陷入困境:选题迷茫、逻辑混乱、要求表述模糊,严重拖慢项目推进节奏。百考通(http…

2026/10/12 18:09:20 阅读更多 →

最新新闻

C++构造函数初始化列表:对象生命周期、性能与陷阱全解析

C++构造函数初始化列表:对象生命周期、性能与陷阱全解析

写C代码这么多年,有个问题我几乎每次聊构造函数都会被人问起:成员变量到底是放在初始化列表里写好,还是直接在大括号里赋值好?很多新手甚至干了两三年的开发者都说不清这两者的本质区别。借今天这篇,我打算把构造初始化…

2026/10/15 8:59:13 阅读更多 →
Genus iSpatial物理综合全解析:从模板跑通到Innovus一致性预测

Genus iSpatial物理综合全解析:从模板跑通到Innovus一致性预测

简介:围绕Cadence Genus综合平台iSpatial Flow的快速上手技术资料,面向数字IC前端综合工程师及后端物理实现人员,旨在帮助缩短RTL到GDS的设计周期,并提升综合对后端布局布线的预测准确性。文档系统讲解统一物理优化引擎、关键区域…

2026/10/15 8:59:13 阅读更多 →
游戏原型内嵌层设计:时间、反馈、节奏与心理层的实现与调试

游戏原型内嵌层设计:时间、反馈、节奏与心理层的实现与调试

1. 从“能跑就行”到“手感对了”:为什么原型阶段必须读懂内嵌层做游戏原型的人都有一个通病:拿到一个想法,恨不得当天就把它做成能跑能跳的Demo。角色能动、子弹能飞、分数能加,就觉得原型已经完成了。但真正做过几个项目之后你会…

2026/10/15 8:59:13 阅读更多 →
WebLogic 12.2.1.4.0 Linux通用版下载与静默安装实战指南

WebLogic 12.2.1.4.0 Linux通用版下载与静默安装实战指南

简介:这份资源面向需要在Linux服务器上部署Java企业级应用的运维与开发人员,提供Oracle WebLogic 12c 12.2.1.4.0的通用版本静默安装包,可用于搭建、部署和管理企业级Java应用,属于中间件层面的实战工具。压缩包为zip格式&#xf…

2026/10/15 8:59:13 阅读更多 →
SURPAC三维矿体建模全流程:从钻孔数据库到资源量估算

SURPAC三维矿体建模全流程:从钻孔数据库到资源量估算

简介:SURPAC是地质勘探、矿产资源评价与环境监测领域广泛应用的建模工具,这份Word文档系统梳理了SURPAC建模的核心知识点,适合初次接触SURPAC建模的工程师、地质技术人员及相关专业学生。内容涵盖项目数据在微机中的存贮组织、原始数据组织、…

2026/10/15 8:59:13 阅读更多 →
T3 Stack 全栈开发实战:类型安全架构从入门到避坑指南

T3 Stack 全栈开发实战:类型安全架构从入门到避坑指南

在前后端分离大行其道的今天,TypeScript 全栈方案已经不是什么新鲜词。但有一个技术组合,从 2022 年开始就在海外开发者圈子里持续霸榜,直到现在依然是很多团队做中大型项目的首选架构,就是 t3code 背后这套技术栈——更准确地说&…

2026/10/15 8:58:11 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →