1. 移植驱动前先搞清楚中断子系统到底在帮你做什么做驱动移植最怕拿到一份源码就开干改改寄存器地址、换换时钟频率结果中断死活不触发或者一触发就死机。我见过太多人卡在中断上本质问题不是代码写错了而是对整个中断子系统缺少一张地图——不知道中断从硬件引脚到CPU执行回调函数中间到底经过了哪些环节、每一层由谁负责、移植时哪些东西必须跟着SoC变化、哪些东西是内核帮你挡掉的。先说个场景。你在A平台的开发板上跑得好好的驱动换到B平台系统起来后cat /proc/interrupts看不到你的中断号或者能看到号但计数永远不涨又或者中断风暴直接把CPU打满。这时候如果你脑子里没有中断子系统的整体框架排查起来就是瞎猫碰死耗子一会怀疑设备树写错了一会怀疑寄存器配置不对一会又怀疑是内核版本差异。而实际上问题可能只是中断控制器Interrupt Controller的映射关系没对上或者中断类型电平触发、边沿触发在硬件上根本配不出来。所以这篇我打算把Linux中断子系统的整体框架掰开揉碎讲一遍并且站在“驱动移植”的视角——重点不是你从头写一个中断子系统而是当你把驱动从一个平台搬到另一个平台时哪些环节最容易出问题、为什么出问题、该怎么定位。框架搞明白了移植过程中的九成中断问题你都能自己判断个大概。先给一张总览图后面逐个环节拆硬件中断源外设→ 中断控制器GIC等→ CPU的IRQ引脚内核侧irq domain负责把硬件中断号翻译成Linux内部中断号virqirq_desc每个virq对应一个描述符存放回调函数、标志位、线程化信息中断流控层handle_irq系列处理不同触发类型的中断流驱动回调request_irq/devm_request_irq注册的handler最终被执行通俗点说中断子系统就是一套“硬件中断事件 → 内核事件分发 → 驱动处理函数”的管道系统。移植驱动的过程就是让这套管道在你新的硬件平台上重新畅通。2. 硬件中断号怎么变成Linux的irq号从GIC到virq的映射逻辑2.1 GIC是绝大多数SoC中断的起点无论是高通、海思、瑞芯微还是全志主流ARM SoC的中断控制器基本都走ARM GICGeneric Interrupt Controller架构。GIC的版本从GIC-400、GIC-500到GIC-600系列差异主要在支持的CPU核数、中断数、亲和性配置上但基本概念一致。GIC把中断分为三类SGISoftware Generated Interrupt软件触发的中断用于核间通信0~15号。PPIPrivate Peripheral Interrupt私有外设中断每个CPU核独享比如每个核的local timer16~31号。SPIShared Peripheral Interrupt共享外设中断所有核都能收到32号往上一般到几百号。在设备树里你经常看到类似这样的节点uart0: serialff580000 { compatible rockchip,rk3399-uart; reg 0x0 0xff580000 0x0 0x100; interrupts GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH; };这里的GIC_SPI 115就是指SPI中断硬件中断号是115。注意这个115是GIC视角的硬件编号不是Linux内部使用的irq号。从GIC的115到Linux的irq号中间隔着一个关键的数据结构——irq domain。2.2 irq domain就是一张翻译表在老版本内核里硬件中断号和Linux irq号经常是线性对应的irq 32 hw_irq之类的简单公式就能算出来。但后来中断控制器层级变多、需要动态分配内核引入了irq domain机制。每一个中断控制器注册一个irq_domain通过irq_domain_ops里的map和translate回调实现硬件中断号到virq的转换。驱动移植中最常见的一个问题就是你板子上的外设中断在设备树里写的硬件号是GIC视角的号而内核跑起来之后你cat /proc/interrupts看到的号是virq。这两者往往不一致。比如某外设硬件中断号是211在/proc/interrupts里却显示为86这都是正常的由irq domain和分配顺序决定。以经典GIC驱动为例注册的irq_domain大概是这个流程gic_init_bases(...) - irq_domain_add_linear(gic-base, gic-irq_nr, gic_irq_domain_ops, gic)irq_domain_add_linear创建线性映射域gic_irq_domain_ops里核心是两个回调gic_irq_domain_map把GIC硬件中断号映射成irq_desc并设置irq_chipgic_irq_domain_translate解析设备树interrupts属性里的GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH三元组移植驱动时你要清楚一件事设备树里你写的中断号是给GIC翻译用的翻译完之后的virq才是驱动里真正注册使用的号。你在驱动代码里写irq platform_get_irq(pdev, 0)拿到的是这个virq。2.3 移植中最常见的三类映射错误第一类设备树中断号写错。比如芯片手册里说某个外设中断是SPI 118结果你写成118后驱动始终不触发查手册发现在另一个中断控制器域下或者实际要减去偏移。尤其当SoC内部有多个中断控制器级联时设备树里写的号必须参照该控制器域的定义。第二类interrupt-parent指错。多控制器SoC上外设节点要用interrupt-parent指定挂在哪个中断控制器下。如果漏写或者指到错误的父节点内核会用默认域的翻译方式去解析出来的号可能对不上硬件实际接的那条线。第三类触发类型不匹配。设备树里写IRQ_TYPE_LEVEL_HIGH但硬件外设的实际中断输出是低电平有效、需要IRQ_TYPE_LEVEL_LOW。这种问题在/proc/interrupts里能看到中断号但计数不涨因为电平一直没被拉低中断控制器采样不到有效信号。3. 驱动侧的中断注册流程从request_irq到回调执行的完整链路3.1 platform_get_irq与request_irq之间的微妙关系写驱动时标准流程一般是static int foo_probe(struct platform_device *pdev) { int irq; irq platform_get_irq(pdev, 0); if (irq 0) return irq; ret devm_request_threaded_irq(pdev-dev, irq, foo_irq_handler, foo_irq_thread_fn, IRQF_TRIGGER_HIGH, foo, dev); return ret; }很多人不清楚platform_get_irq到底做了什么。函数内部经历大致是解析设备树节点 → 走of_irq_get→ 找到interrupt-parent对应的irq domain→ 调用irq_create_of_mapping把硬件中断号翻译成virq→ 返回。注意platform_get_irq拿到virq后中断还没有真正被请求。驱动此时只是拿到了一个“令牌”真正把我们的处理函数挂到中断管道上是后续的request_irq或devm_request_irq完成的。移植时经常遇到的情况probe里platform_get_irq返回-ENXIO也就是拿不到中断号。排查思路按顺序来设备树节点是否存在interrupts属性。设备树节点是否设置了正确的interrupt-parent。对应中断控制器的驱动是否已经初始化完成probe顺序问题经常被人忽略。of_irq_get解析时是否因为触发类型字段非法而失败。3.2 top half和bottom half为什么你的回调不能干重活Linux中断处理函数跑在中断上下文它有几个硬性约束不能睡眠、不能调用可能睡眠的APImutex_lock、kmalloc带GFP_KERNEL都不行、不能做太耗时的操作。因为中断上下文里CPU不参与调度你在里面转5毫秒整个系统就卡5毫秒。于是有了bottom half机制。传统做法是tasklet现在更推荐用threaded irq也就是上面代码里的devm_request_threaded_irq。这种模式下中断触发时先跑handler如果handler返回IRQ_WAKE_THREAD内核会唤醒一个内核线程去执行thread_fn而thread_fn运行在普通进程上下文可以睡眠、可以加锁、可以调用各种胖接口。移植驱动的经验之谈如果外设中断处理里要操作i2c或者spi总线读取状态寄存器就强烈建议用threaded irq。因为i2c控制器本身也是中断驱动的中断上下文里再去等它的中断完成很容易死锁而在线程化上下文里i2c传输可以正常睡眠等待。3.3 中断标志位IRQF_TRIGGER_*与设备树触发类型是一致的吗request_irq里第四个参数IRQF_TRIGGER_HIGH/LOW/RISING/FALLING指定触发类型。在设备树已经写了触发类型的前提下驱动里再指定一次两者到底听谁的这里有坑。GIC这类现代中断控制器设备树里的触发类型最终会下发到硬件层GIC配置对应中断的触发方式和优先级。驱动里request_irq的IRQF_TRIGGER_*是Linux中断子系统的软件标志但如果底层irq_chip已经根据设备树完成了硬件配置驱动里的标志可能被忽略或覆盖不同内核版本行为不一样。我的建议设备树里明确写触发类型驱动里request_irq直接传0或IRQF_TRIGGER_NONE不要让两个地方出现冲突。尤其移植时原始平台设备树写的是IRQ_TYPE_EDGE_RISING新平台换成IRQ_TYPE_LEVEL_HIGH而驱动代码里还保留老标志这就会埋雷。4. 中断控制器驱动与irq_chip移植时真正要动刀的地方4.1 irq_chip是中断控制器在内核里的抽象irq_chip封装了中断控制器的硬件操作包括irq_mask/irq_unmask屏蔽/使能某个中断源irq_ack中断应答irq_set_type设置触发类型irq_set_wake使能唤醒irq_set_affinity设置CPU亲和性每个irq_desc里挂着一个irq_chip指针驱动调用enable_irq、disable_irq、irq_set_irq_type时最终都会落到对应irq_chip的回调上。在GIC驱动的实现里gic_handle_irq是最核心的函数它做的事是读GICC_IAR寄存器拿到硬件中断号 → 如果小于16SGI做核间处理如果是PPI/SPI调用generic_handle_irq分发到对应virq的处理流程。移植驱动到新平台时如果新平台的中断控制器不是标准GIC比如有些国产SoC用了私有中断控制器或者经过了一层自定义的级联封装你就需要看这个芯片厂商是否提供了对应的irq_chip实现。如果厂商没提供驱动里任何中断都无法正常工作因为irq_set_type、irq_mask这些操作都没有落点。4.2 irq domain层级级联时怎么排查有些SoC内部不止一个中断控制器。典型例子主GIC外挂一个GPIO控制器而GPIO控制器本身又作为中断控制器把多路GPIO中断汇聚成一路SPI中断送往GIC。这种层级关系在设备树里表现为gpio2: gpioff790000 { compatible rockchip,gpio-bank; reg 0x0 0xff790000 0x0 0x100; interrupt-controller; #interrupt-cells 2; interrupts GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH; };此时一个外设挂了gpio2的第5号引脚作为中断源foo_device { interrupt-parent gpio2; interrupts 5 IRQ_TYPE_EDGE_RISING; };of_irq_get解析时就会先走到gpio2的irq domain把5翻译成gpio2域的virq与此同时gpio2本身作为中断源又挂在GIC的116号上形成一个链外设中断 → GPIO控制器 → GIC → CPU。移植时这种层级最容易出问题。常见的坑interrupt-controller和#interrupt-cells属性遗漏导致外设节点无法解析。GPIO控制器里某个引脚的中断和别的外设冲突/proc/interrupts里能看到gpio底下所有中断事件归属同一个virq计数。层次多了之后触发类型可能被某一层的irq_chip改变。比如外设和GPIO控制器申请的是边沿触发但GPIO控制器汇入GIC时如果只支持电平触发内核会自动做一次转换吗不会。所以你必须保证每层中断控制器的触发类型配置都合理否则边缘触发的外设在GIC层采样不到。排查这种层级问题时我一般会在设备树里临时加interrupts-extended来跳过中间层直接指定上层控制器快速确认问题是出在中间层还是最终层。4.3 percpu中断和共享中断在移植中的区别处理中断还有一种分类方式是否per-CPU的以及是否可共享。PPI中断比如每核的local timer就是per-CPU的。设备树里你会看到类似arch_timer { interrupts GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW); };注意这里中断号是GIC_PPI 13而且多了一个GIC_CPU_MASK_SIMPLE(4)来指定中断发给哪些CPU核。移植这种设备时如果有人把PPI当成SPI去注册或者request_percpu_irq和request_irq用混了就乱了。PPI必须用request_percpu_irq配合enable_percpu_irq处理函数里访问per-CPU变量也有一套固定写法。而共享中断IRQF_SHARED是多个设备共用一个中断号。这类中断在request_irq时必须传入设备ID指针内核触发时会逐个调用注册在同一virq上的handler直到某个handler返回IRQ_HANDLED。移植时如果驱动里没用IRQF_SHARED却在设备树里和别的设备共用了中断号request_irq会直接失败返回-EBUSY。5. 从硬件触发到回调执行的瞬间中断流控层与desc处理流程5.1 handle_irq系列函数到底做了什么中断流控层是不少人忽略的环节。在generic_handle_irq被调用后内核会根据中断的触发类型和是否唤醒等属性调用不同的流控函数。最常看到的有handle_level_irq电平触发中断走这个handle_edge_irq边沿触发中断走这个handle_fasteoi_irqGIC这种支持EOIEnd of Interrupt的控制器走这个handle_simple_irq某些不做硬件屏蔽的控制器用这些函数的职责是管理中断的屏蔽/使能状态、处理中断嵌套和pending状态、调用irq_desc里注册的action链也就是驱动注册的handler。移植时你不需要改这些流控函数但你必须理解它们的差异。最常见的现象电平触发的中断如果handler里没做irq_ack或者中断源没有被真正清掉handle_level_irq会在handler返回后立刻再次触发导致中断风暴。边沿触发的中断则容易丢中断如果中断触发时irq_desc正被屏蔽边沿信号不会像电平信号那样被锁存恢复使能后可能就丢了。5.2 实测中最容易翻车的场景中断风暴与丢失中断我实际移植一个网卡驱动时遇到过这么一件事设备树里写的中断触发类型是IRQ_TYPE_LEVEL_HIGH但实际上网卡芯片的中断输出引脚在空闲时本来就是高电平只有产生中断时才短暂拉低。结果驱动一旦enable_irqGIC采样到高电平就一直认为有中断中断风暴瞬间打满CPU。当时的排查过程很有代表性/proc/interrupts里该中断的计数在疯狂暴涨CPU0的si时间百分比飙到90%以上但驱动里的handler却进得很少——因为风暴中断全被流控层拦截处理了。后来把设备树里的触发类型改成IRQ_TYPE_LEVEL_LOW一次问题就没了。另一个方向是丢中断。用边沿触发时外设产生中断的脉冲非常窄如果在GIC采样到之前信号就消失了这个中断就丢了。这类问题在低速总线的外设上尤其明显——外设快、主机慢两个时钟域之间的脉冲宽度不足。排查手段是在驱动里做一次“虚假中断检测”handler里读外设中断状态寄存器如果发现没有对应中断标志就返回IRQ_NONE让内核把该virq标记为可疑中断/proc/interrupts旁边会出现[NMI]之类的错误提示。5.3 irq_desc里的action链表多个handler怎么排队一个virq可以挂多个action这正是共享中断的实现基础。request_irq时传入的dev_id就是用来区分不同action的。当handle_*_irq运行时会遍历irq_desc的action链表逐个调用handler直到有一个返回IRQ_HANDLED。这里有个性能考虑共享中断链越长每个中断触发需要遍历的handler就越多。所以移植时如果发现某个中断号和多个设备共享性能敏感的场景下最好在硬件层面错开中断源或者确认每个handler开头都能快速判断“这个中断是不是我的”。6. 设备树里中断相关的关键属性移植时逐项核对清单6.1 interrupt-parent、interrupts、interrupt-names的配合设备树中断属性三板斧是interrupt-parent指定中断控制器父节点告诉内核该设备的某个引脚接到哪个中断控制器的哪个输入上。interrupts一般是中断类型 中断号 触发类型或中断号 触发类型取决于父控制器的#interrupt-cells。interrupt-names给每个中断起个名字配合platform_get_irq_byname使用。多中断设备很常见比如一个触摸屏控制器有触摸中断和唤醒中断两个引脚touch38 { interrupt-parent gpio1; interrupts 5 IRQ_TYPE_EDGE_FALLING, 6 IRQ_TYPE_EDGE_FALLING; interrupt-names touch, wakeup; };驱动里用platform_get_irq_byname(pdev, touch)去拿对应中断号。移植时改名会导致platform_get_irq_byname返回-EINVAL而很多人排查时老是检查interrupts却忘了interrupt-names对应不上。6.2 中断控制器节点的关键属性中断控制器节点自身也有几个属性决定它如何被内核识别interrupt-controller空属性声明该节点是一个中断控制器。#interrupt-cells声明子节点里interrupts需要几个单元格来描述。GIC是3个类型、号、触发方式GPIO控制器是2个引脚号、触发方式。interrupts声明这个中断控制器本身接到上级控制器的哪个中断上级联时才有。interrupt-parent指向更上一级的控制器。移植新板子时如果外设中断完全不可用我一般会先检查控制器节点这4个属性是否齐全。这里有个隐蔽的问题部分SoC的设备树里GPIO节点的interrupt-controller属性会被注释掉或者缺失因为GPIO IP在芯片内部不是传统意义上的“中断控制器”但驱动里如果某个外设把它当父控制器用解析就失败。6.3 中断映射失败时内核日志怎么看设备树解析中断失败时串口日志里一般能看到类似could not get irq或failed to get interrupt resource的信息。但更早的解析错误提示很模糊。定位手段一个是打开动态调试echo 1 /sys/kernel/debug/tracing/tracing_on echo irq:* /sys/kernel/debug/tracing/set_event另一个更直接的办法是查/sys/kernel/debug/irq/irqs/下的每个irq_desc信息确认设备树映射后virq对应的irq_chip是不是你预期的那颗控制器cat /sys/kernel/debug/irq/irqs/86如果irq_chip显示的是gic而设备树里你接的是gpio2的域说明级联映射没有生效问题基本出在interrupt-parent。7. 中断号查询与映射调试把/proc/interrupts读成诊断书7.1 /proc/interrupts每一列怎么读驱动移植调中断/proc/interrupts是第一现场。它的基本格式CPU0 CPU1 16: 1234 0 GICv3 49 Level arch_timer 86: 56789 321 gpio 20 Edge fdd40000.ethernet第一列是virq号后面每列是一个CPU核上该中断触发的次数然后是中断控制器名称和硬件内部分组接着是硬件中断号、触发类型最后是request_irq时注册的设备名。判断标准计数一直为0中断根本没到控制器或没被使能。计数暴涨触发类型或清中断逻辑有问题。多个中断源的计数都归到一个virq下共享中断需要靠寄存器判断是哪路外设。计数在两个CPU核间来回跳动说明中断被设置了亲和性或GIC做了负载均衡正常现象。7.2 驱动注册成功但中断不触发时的排查顺序如果/proc/interrupts里能看到你的virq、设备名也对但计数一直0我一般按这个顺序排查确认外设确实产生了中断信号。用示波器或者直接在驱动里临时写一个测试IO触发外设发送中断后再读外设的中断状态寄存器确认硬件层面中断标志有没有置起来。检查中断控制器的屏蔽状态。/sys/kernel/debug/irq/irqs/86里能看到irq_data的state确认IRQ_MASKED标志是否置位。检查触发类型。/proc/interrupts里显示的触发类型是否和硬件实际信号匹配。检查时钟。没有外设时钟外设根本不会工作更不会产生中断。这个听着很傻但确实在移植中踩过好多次。我的一个具体案例某传感器中断一直不触发排查到最后发现设备树里给它配的时钟源没有通过clk_prepare_enable打开传感器压根没跑起来自然不会有中断。7.3 线程化中断在/proc/interrupts里的表现线程化中断在/proc/interrupts里会看到一个配套的内核线程名字一般是irq/86-fdd40000.ethernet之类的。中断触发时handler只做快速处理真正的业务逻辑在irq/86-xxx线程里执行。调这类问题时除了看/proc/interrupts的计数变化还要看线程的调度状态ps -eo pid,comm,state | grep irq/如果线程处于D状态不可中断睡眠长期不返回多半是thread_fn里阻塞在了某个等待队列或锁上。这在移植时很常见因为原始平台的外设寄存器延迟和时序和新平台不同原本毫秒级的等待变成几十毫秒或者直接超时了。8. 移植后的中断验证与踩坑复盘8.1 冒烟测试中断链路的压测脚本思路移植完之后我一般会做一个简单的冒烟验证不是只触发一次中断看看handler进没进而是压一轮高频中断# 模拟高频中断事件例如用perf触发大量定时器中断或者IRQ stress-ng --timer 32 --timeout 30 cat /proc/interrupts观察几个点中断计数和中断源触发次数是否线性匹配允许少量合理丢失但不能差一个数量级。CPU的si软中断和hi硬中断占比是否正常正常情况下不应持续高位。驱动handler是否出现超时报错内核日志里有没有IRQ handler type mismatch或nobody cared这类字样。cat /proc/interrupts时如果发现某中断触发了可观的次数但handler没有任何反应优先怀疑IRQF_TRIGGER_*配置。如果使用threaded irq建议也在压测期间观察ps里对应的irq/xxx线程的CPU占用率正常情况下它应该能跟上中断频率。如果线程CPU占满而实际业务没完成说明thread_fn里存在忙等或者频繁轮询的问题移植时尤其要注意。8.2 两种移植场景的处理差异原样替换和跨内核版本移植中断相关代码时有两种典型场景一是原厂BSP提供了完整的内核和驱动你只是把某个外设驱动移到自己的板卡上。这种情况基础设施多半是好的重点检查设备树、时钟、IO复用和中断引脚。中断相关代码需要动的可能性不大除非SoC中断控制器本身变了。二是跨内核版本移植比如把4.19的驱动往6.1内核上搬。这时中断子系统API变化比较明显最典型的是of_irq_get和platform_get_irq的返回值语义在老内核里可能是0表示成功新内核里0表示无效且失败返回值是负数。如果你用老驱动的判断逻辑在新内核上会误判。devm_request_threaded_irq的引入时间、request_percpu_irq的语义变化。老内核里handle_irq的入口行为和新内核不同部分自定义irq_chip在旧平台还能工作新平台因为缺少irq_set_affinity或者irq_set_wake的调用上下文直接报错。这类场景下建议先把老驱动的中断请求段完整分析一遍确认每一处API在当前内核版本下的行为再动手改设备树。8.3 我总结的七条中断移植注意事项这几条不是教科书上的原话是踩了不少坑之后我自己定的检查顺序先确认硬件电气连接再谈软件配置。GPIO复用的pinmux没配好中断引脚根本到不了控制器。设备树里interrupt-parent一定显式写别依赖默认值不同内核版本的默认解析逻辑很不一样。触发类型双层核对设备树写一次request_irq里保持一致不要copy老代码时带上旧平台的标志。中断处理函数里不要做总线操作除非你用threaded irq或者确认总线控制器支持中断上下文使用。移植后先跑高频中断压力测试别只测一次触发。中断丢失和死锁往往在高频下才现原形。/sys/kernel/debug/irq/和/proc/interrupts配合使用一个看静态配置一个看动态计数。千万别在中断handler里加调试打印尤其串口打印。串口本身也是中断驱动的中断上下文里打串口很容易把系统锁死要打印就记录标志位thread_fn里统一处理。9. 最后再补一个定位中断问题的野路子很多中断问题表面上是“驱动注册失败”或者“中断计数不对”实际根源在别的驱动或者系统初始化顺序上。比如之前遇到一次某个外设的probe成功、中断注册也成功但一使能外部中断整机就重启。查到最后发现是另一个驱动把GIC的某种电源域关了导致GIC在处理该中断时访问了未上电的寄存器直接触发总线错误。所以移植驱动时如果中断问题怎么都查不通不妨回头看看这几件事该外设的电源域和reset GPIO在目标平台上的配置是否和原平台一致。内核里CONFIG_ARM_GIC_V3这类中断控制器配置项是否和实际SoC匹配。配置不对的话中断控制器可能只初始化了一部分。启动日志里GIC相关的初始化信息确认它识别的中断范围是否覆盖了你外设使用的硬件中断号。中断子系统是一个典型的“一荣俱荣、一损俱损”的链条。驱动侧代码再正确只要中间任何一环没对齐——硬件连接、设备树解析、控制器配置、流控机制——整个链条就断了。把这套框架装进脑子里移植时按图索骥比盲目改代码高效得多。
企业数字化 ERP 产品动态
相关推荐
STM32调试失效的根源:BOOT0/NRST硬件握手与底层启动机制 1. 为什么STM32调试总像在拆炸弹?——从BOOT0和NRST开始的生死时速你有没有过这种体验:代码烧录成功,LED却不亮;串口助手收不到半个字节;调试器连上芯片,却提示“Target not connected”;甚至刚… · 2026/9/25 12:04:35
STM32开源项目实战:代码、原理图与Proteus仿真全打通 1. 项目缘起与整体设计思路STM32 项目开源这件事,我前前后后做过好几轮,从最早只丢一个 Keil 工程压缩包,到后来把代码、原理图、仿真工程打包成一套完整资料,中间踩过的坑基本能写一本小册子。这次想聊的这套开源项目,… · 2026/9/25 12:04:29
公网、私网、内网、外网彻底讲清楚:NAT、内网穿透与DDNS实战 1. 先把概念理清楚:公网、私网、内网、外网到底在说什么很多人第一次接触这几个词,是在配路由器、连 NAS、搭开发环境或者调试服务器的时候。明明感觉自己懂一点网络,结果一看到“公网 IP”“内网穿透”“NAT 模式”就懵了。更麻烦的是&#… · 2026/9/25 14:19:58
全华南鸿蒙智行车友汽车防爆贴膜求推荐 深圳倍韧性汽车服务有限公司靠谱门店 行业大众选汽车防爆贴膜的4大踩坑难题作为鸿蒙智行车友,我身边不少车主都有过贴膜的糟心经历。总结下来,踩坑的情况基本集中在这几类:
找不到精准适配的专业门店:市面上改装店大多什么车都接,对鸿蒙智行全系车型的原车… · 2026/9/25 14:19:52
在 Groovy Gradle 项目中添加 Exposed 依赖:模块化构建完整指南 ORM后端数据存储 【免费下载链接】Exposed Kotlin SQL Framework 项目地址: https://gitcode.com/gh_mirrors/ex/Exposed 点击查看 免费下载 导读:Exposed 是 Kotlin 生态中一款类型安全的 SQL 框架,它按功能拆分成了 exposed-core、exposed… · 2026/9/25 14:19:46
Atlas 300V 24G推理卡部署YOLOv8实战:从模型转换到多路并发调优 手里这张Atlas 300V 24G,是我最近一个月做推理服务部署时一直在用的加速卡。先说结论:它确实是运算加速卡,但和常见的GPU训练卡是两个路子。它是华为昇腾系列里专门面向数据中心推理场景的AI加速卡,24GB显存是它最大的卖点&#x… · 2026/9/25 14:19:46
果味黄酒在哪些场合喝?夏天、露营、朋友聚会的场景玩法整理 很多人买了果味黄酒只知道冰镇后直接喝,其实它在不同场景里有不少顺手的玩法。这篇按夏天居家、露营外出、朋友聚会三种常见场合,把怎么带、怎么调、怎么搭配整理出来,都是容易落地的做法。先说明:下文涉及的具体产品以缤果日纪果… · 2026/9/25 14:19:46
昇腾Atlas 300V 24G推理卡实战:从环境部署到跑通YOLO目标检测全解析 拿到这块卡的时候,我第一反应是有点懵。Atlas 300V 24G,这名字听起来像个显卡,但插上服务器之后,nvidia-smi根本不认它。查了一圈才知道,这压根不是GPU,而是华为昇腾系列的AI推理加速卡。更折腾的是&#x… · 2026/9/25 14:19:39
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37