【实战解析】RTL8306MB交换芯片驱动开发中的RMII接口调试陷阱

【网络BSP开发经验】交换芯片驱动开发1(RTL8306MB交换芯片驱动开发) 网络BSP 交换芯片驱动开发 阅读详情

1. 从一次诡异的“哑火”说起:我的RTL8306MB驱动调试历险记

大家好,我是老张,一个在嵌入式网络驱动领域摸爬滚打了十多年的老码农。今天想和大家分享一个我最近在项目中遇到的、极具代表性的调试案例,主角是RTL8306MB这款非常经典的百兆交换芯片。事情是这样的,我们当时在做一款工业网关设备,主控CPU通过RMII接口连接这颗交换芯片,以实现多路以太网接入。硬件同事拍着胸脯说板子画好了,驱动移植的活儿自然就落到了我头上。

按照常规流程,我先搞定了SMI(也就是MDC/MDIO管理总线)的驱动。这部分很顺利,用GPIO模拟一下时序,读写芯片的寄存器、读取Chip ID都一次成功。我心里还暗喜,觉得这次项目进度能快不少。可当我信心满满地开始调试RMII数据通道时,怪事发生了:无论我怎么操作,CPU侧的MAC控制器统计不到任何收发包计数,交换芯片那边的MAC5端口计数器也一动不动。整个数据链路就像彻底“哑火”了一样,两边的日志都干干净净,没有任何错误提示,但数据就是不通。

这种“静默式”的故障最让人头疼。没有崩溃,没有报错,但功能就是不行。我首先怀疑的是软件配置:RMII模式使能了吗?时钟方向对吗?寄存器配置对不对?我把芯片手册和驱动代码翻来覆去看了好几遍,甚至把参考设计里的配置原封不动搬过来,问题依旧。这时候,一个经验告诉我:当软件查不出明显问题时,问题的根因很可能已经埋在了硬件连接里。这次调试,让我对RMII接口那些看似简单、实则暗藏玄机的信号线,有了刻骨铭心的认识。接下来,我就把这趟“踩坑”之旅的详细过程和总结出的“避坑指南”分享给大家,尤其是那些正在或即将进行类似交换芯片驱动开发的朋友们。

2. 理解基石:快速厘清MII、RMII与我们的调试场景

在深入陷阱之前,我们得先确保站在同一理解平面上。尤其是对于刚接触网络驱动的朋友,很容易被MII、RMII、GMII这些名词绕晕。我用最直白的方式解释一下它们在我们这个场景里的角色。

你可以把网络数据传输想象成工厂里的流水线。CPU(或说CPU里的MAC模块) 是负责打包/拆包的生产车间,物理层芯片(PHY) 是负责把包裹搬上卡车(网线)或从卡车卸货的装卸平台。而MII(介质无关接口) 以及它的简化版RMII,就是连接车间和装卸平台之间的传送带及其控制规则。

  • MII接口:这是比较早期的标准传送带,设计得比较“宽裕”。它需要16根信号线,其中包括4根数据线用于发送(TXD[3:0]),4根用于接收(RXD[3:0]),还有独立的发送时钟、接收时钟、发送使能、接收数据有效、载波侦听等等。在100Mbps速率下,时钟是25MHz。
  • RMII接口:为了节省芯片引脚和PCB布线空间,RMII(精简MII) 应运而生。它把传送带“精简”了,数据线宽度减半,只用2根数据线发送(TXD[1:0])和2根接收(RXD[1:0])。同时,它把发送和接收时钟合并为一根50MHz的参考时钟(REF_CLK)。最关键的变化之一,是把MII中的“接收数据有效(RX_DV)”和“载波侦听(CRS)”两个信号合并成了CRS_DV这一个信号。

在我们的RTL8306MB项目中,芯片的MAC5端口被配置为RMII模式与CPU连接。这里有一个非常重要的概念:对于CPU的MAC控制器来说,它通常认为自己对端连接的是一个PHY。但RTL8306MB本身是一个交换芯片,它内部既有MAC也有PHY。那怎么连接呢?答案就是,我们需要把RTL8306MB与CPU相连的那个端口(MAC5),通过配置,让它“扮演”成一个PHY的角色。这时,从CPU的视角看出去,它通过RMII连接的就是一个普通的PHY;而从RTL8306MB内部看,是它的一个MAC在通过RMII接口与CPU的MAC对话。这种MAC-to-MAC的连接,要求两端的RMII信号定义必须严格匹配,任何错位都会导致通信失败。

为了更直观,我把RMII接口的关键信号线、作用和常见连接关系整理成了下面这个表格,这在后续的硬件检查中会非常有用:

RTL8306MB交换芯片驱动开发实战:RMII接口调试陷阱与寄存器配置指南 在嵌入式网络设备开发中,交换芯片驱动是连接主控SoC与物理端口的核心环节,而RMII接口作为精简的MAC-PHY互联方式,凭借引脚少、带宽足的优势,广泛应用于工业网关、路由器和物联网终端。RMII的本质是利用50MHz参考时钟和2位数据线实现百兆传输,但正因为时序余量小,芯片内部延迟配置、时钟源方向、双工模式对齐等细节极易引发隐蔽故障。理解RMII信号线定义、MDIO寄存器访问机制以及交换芯片的端口隔离和VLAN转发逻辑,是驱动稳定运行的基础。实际项目中,常见的小包通大包丢、MDIO读不到Device ID 阅读详情

相关推荐

RTL8306MB交换芯片驱动开发全解析:从MII到RMII的接口选择与配置陷阱

本文深入解析RTL8306MB交换芯片驱动开发中的MII与RMII接口配置策略,详细对比两种接口的架构差异、时钟系统设计及硬件兼容性问题。通过实战案例和寄存器配置指南,帮助开发者规避常见陷阱,优化网络设备性能,特别适合嵌入式网络设备开发者参考。

j0k1l2m3n的博客 625

RTL8306MB交换芯片驱动开发避坑指南:从硬件接线到SDK移植全流程解析

本文详细解析了RTL8306MB交换芯片驱动开发的全流程,重点从硬件接线、SDK移植到实战调试。针对RMII模式下的常见问题,特别是TXEN与RXDV信号交叉连接等关键“坑点”,提供了清晰的排查指南和解决方案,旨在帮助嵌入式工程师高效完成网络设备开发。

270

嵌入式开发中的RMII接口调试:RTL8306MB交换芯片实践与避坑指南

在嵌入式开发中,网络接口的驱动调试往往牵一发而动全身,尤其是 RMII 接口与交换芯片的适配,常因时序、电平、时钟方向等底层细节而陷入困境。RMII 通过精简引脚和50MHz参考时钟实现数据高速传输,但其协议本身存在多种配置模式,主控与 PHY 之间必须严格匹配“主从”关系。理解接口的工作原理、管理通道(MDIO/MDC)的读写机制以及信号完整性要求,是排查链路异常的基础。在实际工程中,从硬件检查清单到 uboot 阶段的 PHY 验证,再到 Linux 下的 ethtool 与寄存器读回校验,一套系统化的

weixin_33834075的博客 302

【嵌入式网络开发实战】RTL8306MB交换芯片驱动调试与RMII接口问题排查

本文分享了RTL8306MB交换芯片驱动开发与RMII接口调试的实战经验。文章详细剖析了SMI管理接口的稳定性要点,并重点记录了RMII链路不通的排查过程,通过示波器抓取信号,最终定位并解决了因TXEN与RXDV信号线错配导致的经典硬件设计问题,为嵌入式网络开发提供了宝贵的调试思路。

weixin_28396629的博客 323

手把手教你移植RTL8306MB交换芯片SDK:基于GPIO模拟MDC/MDIO的完整流程

本文详细介绍了如何通过GPIO模拟MDC/MDIO接口实现RTL8306MB交换芯片SDK的移植,包括硬件分析、时序实现、驱动层适配及调试技巧。特别针对缺乏原生SMI接口的嵌入式平台,提供完整的实战指南和性能优化建议,助力开发者高效完成网络设备驱动开发。

rnn9storyteller的博客 1049

RK3568平台(网络篇)添加网络交换芯片RTL8306M

该交换芯片支持I2C、SPI、mdio通信,但是看ast1520的uboot代码采用的是mdio去通信phy芯片的,所以暂时也先采用mdio的方式,需要配置相应的引脚才可以配置成mdio通信模式,具体的配置硬件工程师解决。RTL8306M芯片上可能没有提供MDC/MDIO接口,可以通过GPIO(General Purpose Input/Output)来模拟,GPIO可实现串行输入输出,且一般CPU上会提供很多GPIO接口供用户自定义使用。

weixin_49303682的博客 3925

RK3399平台开发系列讲解(内核驱动外设篇)6.13、add ethernet(RTL8306MB) support

平台 内核版本 安卓版本 RK3399 Linux4.4 Android7.1 文章目录dtsconfigdrivers dts 目录arch/arm64/boot/dts/rockchip/rk3399-b201-rev1.dts vcc_phy: vcc-phy-regulator { compatible = "regulator-fixed"; regu...

内核笔记 6726

驱动开发答疑

片上外设寄存器基地址源自芯片手册(如P2020参考手册)、设备树(DTS)及BSP头文件定义。ISR即中断服务函数,16550寄存器基于NS16550标准,可在手册中查证。驱动通过读写THR(发送)、RBR(接收)、LSR(状态)、FCR(FIFO)等寄存器实现RS422通信,当前为轮询模式,无软件缓存,仅依赖16字节硬件FIFO,存在溢出风险。虽名为“422驱动”,实为基于UART控制器的物理层适配,因外接MAX3232实际为RS232。驱动可周期收发数据,但缺乏多任务保护与后台处理,适用于简单场景。开发

coldmood77的博客 9

RTL8309M,8+1口交换机原理图和芯片资料

8+1口 10M/100M自适应交换机,设计采用瑞昱高集成交换机控制管理芯片RTL8309,具有外围电路简单,无需软件就能实现交换机的功能,内含PCB走线指导和原理图(ORCAD)以及芯片资料。

交换芯片RTL8306M规格书

交换芯片RTL8306M规格书交换芯片RTL8306M规格书交换芯片RTL8306M规格书交换芯片RTL8306M规格书

Realtek RTL8306芯片以太网路由器评估板开发板硬件设计pads(原理图+PCB+LIB封装库)+网口布局布线说明文件

Realtek RTL8306芯片以太网路由器评估板开发板硬件设计pads(原理图+PCB+LIB封装库)+网口布局布线说明文件,仅供学习及设计参考。

反射机制——通过反射调用service中方法

需求:现在有一群service接口,有同一个方法名称,内部逻辑除了调用不同的调用自身的方法外其他基本都一致,那现在就需要一个独立的方法来勾勒出这个方法 1.SpringContextUtil package com.XXX.report.util; import org.apache.log4j.Logger; import org.springframework.beans.BeansE...

东天里的冬天 8514

SLAM工程师面试避坑指南:2025年最新高频考点与实战代码解析

本文为SLAM工程师提供2025年最新面试避坑指南,涵盖高频技术考点如VINS初始化、三维几何处理、多传感器融合架构设计等,并包含实战代码解析。特别针对算法工程师面试中的常见陷阱,提供系统设计框架和代码模板,帮助求职者提升通过率。

metaverse5vr的博客 240

CFD-POST中建立变量的方法

本文以测量文丘里管中全压为例阐述CFD_POST中建立变量的方式 点击进入CFD-POST界面的expressions栏中 2.与expression栏中空白处右键,new-输入新建的表达式名称 3. 在下方的空白栏中右键-varible选择需要的变量,并根据公式进行修改 4.点击进入varibles栏,空白处右击-new-输入变量名totalpressure,在下拉框中找到之前定义的totalpressure 完成后可以在varibles栏中看到新建的...

sidxi的博客 1万+

fluent linux运行算例,Fluent算例精选|03利用VOF和蒸发-冷凝模型

通过学习本算例您将获得?1、学会基本的VOF模型设置流程2、学会利用蒸发-冷凝模型来模拟传热沸腾目录1摘要42传热沸腾模型介绍43前处理44求解设置54.1启动Fluent54.2网格缩放64.3求解器设置74.4多相流模型设置84.5能量方程求解设置94.6紊流模型设置104.7添加材料114.8多相流中相设置124.9操作条件设置144.10边界条件设置154.10.1heatsource边界...

weixin_33278819的博客 3183

【OpenClaw从入门到精通】第24篇:OpenClaw Skill商业化实战指南——从0开发付费技能,在ClawHub变现(2026实测版)

本文聚焦OpenClaw Skill商业化的全流程落地,基于2026年生态现状、公开行业报告及开发者指南,拆解付费Skill的市场机会、商业模式、技术实现、发布运营及避坑要点。核心围绕“Freemium API Backend”主流路径,通过虚拟但贴合真实场景的“金融研报复现”案例,提供从需求分析、定价设计到代码开发、ClawHub上架的完整实操方案。文中包含可直接复用的代码片段、执行结果演示及流程图解,既满足新手快速入门的需求,也为进阶开发者提供商业化落地的关键思路,帮助读者抓住AI Agent早期红利。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1074

遗传算法(GA)全面解析:从生物基础到工程实践

本文全面解析了遗传算法(GA),从其生物基础到工程实践应用。遗传算法模拟自然进化过程,通过选择、交叉和变异等操作在解空间中高效搜索最优解。文章详细介绍了算法的生物学基础(达尔文进化论、孟德尔遗传定律)、基本概念(种群、个体、基因等)和核心思想。重点阐述了遗传算法的数学模型,包括编码机制、适应度函数设计、遗传算子(选择、交叉、变异)以及关键控制参数。最后提供了一个完整的Python实现示例,展示了遗传算法求解函数最大值问题的具体应用。该算法具有群体搜索、概率导向、无需梯度等特点,适用于各类复杂优化问题。

qq_42212808的博客 1164

Ubuntu零基础入门到精通【4.4讲】:网络、蓝牙、显示器、声音与输入法设置!

🏆 本文收录于 《滚雪球学 Ubuntu》 专栏。 本专栏面向有一定计算机基础,但尚未系统学习 Linux / Ubuntu 的读者,采用“滚雪球式学习法”:先装好、再会用、再理解、再优化、再实战,带你从第一次进入 Ubuntu 桌面 / 终端开始,逐步掌握 Ubuntu 的日常使用、命令操作、软件安装、系统配置、开发环境搭建与服务器部署能力。

**My Coding Family** 1476

YOLOv11【第六章:模型压缩与极致优化篇·第15节】YOLOv11 专用剪枝工具库使用指南!

🏆 本文收录于专栏 《YOLOv11实战:从入门到深度优化》。本专栏围绕 YOLOv11 的改进、训练、部署与工程优化 展开,系统梳理并复现当前主流的 YOLOv11 实战案例与优化方案,内容目前已覆盖 分类、检测、分割、追踪、关键点、OBB 检测 等多个方向。

**My Coding Family** 1303

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

上一篇: 避坑指南:QComboBox设置可编辑状态时容易忽略的5个细节
下一篇: 群晖Active Backup for Business保姆级教程:从安装到首次备份全流程(含局域网优化技巧)
CloudCruiser
博客等级 码龄10年 53粉丝 1593原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值