一、 前言 DPDK是intel工程师开发的一款用来快速处理数据包的框架,最初的目的是为了证明传统网络数据包处理性能低不是intel处理器导致的,而是传统数据的处理流程导致,后来随着dpdk的开源及其生态的快速发展,dpdk成为了高性能网络数据处理的优秀框架。本篇文章主要介绍DPDK接收与发送报文的流程,包括CPU与网卡DMA协同工作的整个交互流程、数据包在内存、CPU、网卡之间游走的过程。 二、场景 DPDK从2013开始开源,经过前辈们的缝缝补补到现在为止DPDK框架比较成熟、使用比较方便,使得现在开发者在不需要深入了解底层数据包收发原理的情况下也可以做简单的项目开发。但是个人感觉做简单的项目尚且可以应付,如果需要做性能优化等类似的需求时就需要取全面的了解DPDK的收发包机制,因为收发包性能与驱动工作流程、前期初始化配置息息相关。话不多说,下面我们进入正题。 三、收发包处理流程 数据包接收的大体流程: 数据包到达网卡 网卡经过DMA操作将数据包从网卡拷贝到收包队列 DPDK应用从收包队列中取包 数据包发送的大体流程: DPDK应用将数据包送到发包队列 网卡经过DMA操作将网卡队列中的数据包拷贝到网卡 数据包从网卡发出 收发包流程中的关键操作,主要是网卡如何与DPDK应用交互: 网卡的初始化配置操作有哪些,因为网卡要想正常工作肯定需要进行初始化配置一些属性 网卡的DMA操作怎么找到DMA 地址,进而将数据包拷贝到系统主存供DPDK读取 网卡把数据包成功放到队列后如何通知DPDK应用去队列中读取 DPDK从队列中取完数据包后需要做哪些操作通知网卡为下一次收包做准备 DPDK将数据包送到发送队列中需要做哪些预操作 网卡从发送队列中取包需要做哪些操作 四、收包软件处理流程 DPDk在初始化阶段通过igb_alloc_rx_queue_mbufs 负责将描述符,mbuf, dma,接收队列给关联起来,如下图所示。 1、模块/硬件介绍 Network interface: 指以太网卡,它工作在OSI的下两层(物理层、数据链路层),工作在物理层的芯片称为PHY,工作在数据链路层的芯片称为MAC控制器,即Media Access Control,即媒体访问控制子层协议.该协议位于OSI七层协议中数据链路层的下半部分,但是目前好多网卡是将MAC和PHY功能做到了一颗芯片中,但是MAC和PHY的机制还是单独存在的,只是对外体现为一颗芯片。MAC控制器的功能主要是数据帧的构建、数据差错检查、传送控制、向网络层提供标准的数据接口等功能;PHY芯片的主要功能是将从PHY来的并行数据转换为穿行流数据,再按照物理层的编码规则把数字信号进行编码,最后再转换为模拟信号把数据发出去。 RX_FIFO: 数据接收缓冲区 TX_FIFO: 数据发送缓冲区 DMA Engine:Direct Memory Access,即直接寄存器访问,是一种告诉的数据传输方式,允许在外部设备和存储器之间直接读写数据,数据的读写不消耗CPU资源,DMA控制器通过一组描述符环形队列与CPU互相操作完成数据包的收发。CPU通过操作DMA寄存器来与DMA控制器进行部分通信与初始化配置,主要寄存器有Base、Size、Tail、Head,head寄存器用于DMA往rx_ring里插入时使用,tail是应用通过写寄存器通知给DMA控制器当前可用的最后一个描述符(head->next 为tail时表示当前rx_ring存满了,再来报文会被记录rx_missed_error)。 Rx_queue: 收包队列结构体:我们主要关注两个环形队列rx_ring、sw_ring Rx_ring:一个地址连续环形队列,存储的是描述符,描述符中包含将来存放数据包的物理地址、DD标志(下面会介绍DD标志)等,上面图中只画了存放数据包的物理地址,物理地址供网卡DMA模块使用,也称为DMA地址(硬件使用物理地址,当网卡收到数据包后会通过DMA操作将数据包拷贝到物理地址,物理地址是通过虚拟地址转换得到的,下面分析源码时会介绍) Sw_ring: 存储的是将来存放数据包的虚拟地址,虚拟地址供应用使用(软件应用使用虚拟地址,应用往虚拟地址读写数据包) DD标志:用于标识一个描述符buf是否可用,无论网卡是工作在轮询方式下还是中断方式,判断数据包接收成功或者是否发送成功都需要检查描述符中的完成状态位(Description Done)DD,该状态位由DMA控制器在完成操作后进行回写 Mbuf:对应于Mbuf内存池中的元素,通过alloc或者free操作内存池获取或者释放mbuf对象,这里需要说的一点是mbuf池创建的时候是连续的,但是rx_ring和sw_ring里指向的数据地址不一定是连续的,下面分析收包流程时会介绍 PCIE总线:采用高速串行通信互联标准,自上而下分为事务传输层、数据链路层、物理层,网卡与CPU之间数据包的传输、CPU对网卡寄存器的MMIO操作都通过PCIE进行传输 DMA寄存器:CPU配置网卡的操作通过操作网卡的寄存器,寄存器主要 2、收包流程 Rx_ring收数据时的状态如下: DMA控制器收到数据后往head写,当head=tail时表示当前队列为空,head->bext = tail表示当前队列已存满,dpdk启动刚初始化完后如下图所示: 可以看出来cpu对tail寄存器的更新并不是在rx_ring描述符中填充完dma地址后立马就执行,而是等dma可用描述符低于一定阈值时才执行写寄存器更新tail 具体详细流程如下: (1)CPU填缓冲地址(mbuf中的data)到收接收侧描述符(在dpdk初始化时就会第一次填充),也就是上图中rx_ring会指向mbuf池中的 部分mbuf用于接收数据包;另外CPU通过操作网卡的base、size寄存器,将rx_ring环形队列的起始地址和内存卡大小告诉给DMA控制器,将描述符队列的物理地址写入到寄存器后,dma 通过读这个寄存器就知道了描述符队列的地址,进而 dma收到报文后,会将报文保存到描述符指向的 mbuf 空间 (2)网卡读取rx_ring队列里接收侧的描述符进而获取系统缓冲区地址 (3)从外部到达网卡的报文数据先存储到网卡本地的RX_FIFO缓冲区 (4)DMA通过PCIE总线将报文数据写到系统的缓冲区地址 (5)网卡回写rx_ring接收侧描述符的更新状态DD标志,置1表示接收完毕 (6)CPU读取描述符sw_ring队列中元素的DD状态,如果为1则表示网卡已经接收完毕,应用可以读取数据包 (7)CPU从sw_ring中读取完数据包后有个“狸猫换太子”的动作,重新从mbuf池中申请一个mbuf替换到sw_ring的该描述符中 将新分配的mbuf虚拟地址转换为物理地址更新到rx_ring中该条目位置的dma物理地址、更新描述符rx_ring队列里的DD标志置0,这样网卡就可以持续往rx_ring缓冲区写数据了 (8)CPU判断rx_ring里可用描述符小于配置的阈值时更新tail寄存器,而不是回填一个mbuf到描述符就更新下tail寄存器(因为CPU高频率的操作寄存器是性能的杀手,所以改用此机制) (9)至此,应用接收数据包完毕 注意:这里有两个非常关键的队列rx_ring、sw_ring,rx_ring描述符里存放的是mbuf里data区的起始物理地址供DMA控制器收到报文后往该地址写入(硬件DMA直接操作物理地址,不需要cpu参与);sw_ring描述符里存放的是mbuf的起始虚拟地址供应用读取数据包 需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享 3、代码的实现过程 我们以e1000驱动类型网卡举例,来分析数据包接收相关的软件结构及接口 (1)接收队列的结构如下图,图中标出了两个重要的环形队列(上面已介绍): (2)数据包的软件接收流程如下图 (3)分析下eth_igb_recv_pkts接口源码,与第四章的收包内部流程相对应 uint16_teth_igb_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts){ struct igb_rx_queue *rxq; volatile union e1000_adv_rx_desc *rx_ring; volatile union e1000_adv_rx_desc *rxdp; struct igb_rx_entry *sw_ring; struct igb_rx_entry *rxe; struct rte_mbuf *rxm; struct rte_mbuf *nmb; union e1000_adv_rx_desc rxd; uint64_t dma_addr; uint32_t staterr; uint32_t hlen_type_rss; uint16_t pkt_len; uint16_t rx_id; uint16_t nb_rx; uint16_t nb_hold; uint64_t pkt_flags; nb_rx = 0; nb_hold = 0; rxq = rx_queue; rx_id = rxq->rx_tail; rx_ring = rxq->rx_ring; sw_ring = rxq->sw_ring; while (nb_rx < nb_pkts) { /*第一步:从描述符队列中找到被应用最后一次接收的那个文件描述符的位置*/ rxdp = &rx_ring[rx_id]; staterr = rxdp->wb.upper.status_error; /*第二步:检查DD状态是否为1,为1则说明驱动已经将报文成功放到接收队列,否则直接退出*/ if (! (staterr & rte_cpu_to_le_32(E1000_RXD_STAT_DD))) break; rxd = *rxdp; PMD_RX_LOG(DEBUG, "port_id=%u queue_id=%u rx_id=%u " "staterr=0x%x pkt_len=%u", (unsigned) rxq->port_id, (unsigned) rxq->queue_id, (unsigned) rx_id, (unsigned) staterr, (unsigned) rte_le_to_cpu_16(rxd.wb.upper.length)); /*第三步:从mbuf池中重新申请一个mbuf,为下面的填充做准备*/ nmb = rte_mbuf_raw_alloc(rxq->mb_pool); if (nmb == NULL) { PMD_RX_LOG(DEBUG, "RX mbuf alloc failed port_id=%u " "queue_id=%u", (unsigned) rxq->port_id, (unsigned) rxq->queue_id); rte_eth_devices[rxq->port_id].data->rx_mbuf_alloc_failed++; break; } nb_hold++; /*第四步:找到了描述符的位置,也就找到了需要取出的mbuf*/ rxe = &sw_ring[rx_id]; rx_id++; if (rx_id == rxq->nb_rx_desc) rx_id = 0; /* Prefetch next mbuf while processing current one. */ rte_igb_prefetch(sw_ring[rx_id].mbuf); /* * When next RX descriptor is on a cache-line boundary, * prefetch the next 4 RX descriptors and the next 8 pointers * to mbufs. */ if ((rx_id & 0x3) == 0) { rte_igb_prefetch(&rx_ring[rx_id]); rte_igb_prefetch(&sw_ring[rx_id]); } rxm = rxe->mbuf; /*第五步:给描述符sw_ring队列重新填写新申请的mbuf*/ rxe->mbuf = nmb; /*第六步:将新申请的mbuf的虚拟地址转换为物理地址,为rx_ring的缓冲区填充做准备*/ dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(nmb)); /*第七步:将rx_ring描述符中该条目的DD标志置0,表示允许DMA控制器操作*/ rxdp->read.hdr_addr = 0; /*第八步:重新填充rx_ring描述符中该条目的dma地址*/ rxdp->read.pkt_addr = dma_addr; /* * Initialize the returned mbuf. * 1) setup generic mbuf fields: * - number of segments, * - next segment, * - packet length, * - RX port identifier. * 2) integrate hardware offload data, if any: * - RSS flag & hash, * - IP checksum flag, * - VLAN TCI, if any, * - error flags. */ /*第九步:对获取到的数据包做部分封装,比如:报文类型、长度等*/ pkt_len = (uint16_t) (rte_le_to_cpu_16(rxd.wb.upper.length) - rxq->crc_len); rxm->data_off = RTE_PKTMBUF_HEADROOM; rte_packet_prefetch((char *)rxm->buf_addr + rxm->data_off); rxm->nb_segs = 1; rxm->next = NULL; rxm->pkt_len = pkt_len; rxm->data_len = pkt_len; rxm->port = rxq->port_id; rxm->hash.rss = rxd.wb.lower.hi_dword.rss; hlen_type_rss = rte_le_to_cpu_32(rxd.wb.lower.lo_dword.data); /* * The vlan_tci field is only valid when PKT_RX_VLAN is * set in the pkt_flags field and must be in CPU byte order. */ if ((staterr & rte_cpu_to_le_32(E1000_RXDEXT_STATERR_LB)) && (rxq->flags & IGB_RXQ_FLAG_LB_BSWAP_VLAN)) { rxm->vlan_tci = rte_be_to_cpu_16(rxd.wb.upper.vlan); } else { rxm->vlan_tci = rte_le_to_cpu_16(rxd.wb.upper.vlan); } pkt_flags = rx_desc_hlen_type_rss_to_pkt_flags(rxq, hlen_type_rss); pkt_flags = pkt_flags | rx_desc_status_to_pkt_flags(staterr); pkt_flags = pkt_flags | rx_desc_error_to_pkt_flags(staterr); rxm->ol_flags = pkt_flags; rxm->packet_type = igb_rxd_pkt_info_to_pkt_type(rxd.wb.lower. lo_dword.hs_rss.pkt_info); /* * Store the mbuf address into the next entry of the array * of returned packets. */ /*第十步:将获取到的报文放入将要返回给用户操作的指针数组中*/ rx_pkts[nb_rx++] = rxm; } rxq->rx_tail = rx_id; /* * If the number of free RX descriptors is greater than the RX free * threshold of the queue, advance the Receive Descriptor Tail (RDT) * register. * Update the RDT with the value of the last processed RX descriptor * minus 1, to guarantee that the RDT register is never equal to the * RDH register, which creates a "full" ring situtation from the * hardware point of view... */ /*第十步:CPU判断rx_ring里可用描述符小于配置的阈值时更新尾部寄存器供DMA控制器参考*/ nb_hold = (uint16_t) (nb_hold + rxq->nb_rx_hold); if (nb_hold > rxq->rx_free_thresh) { PMD_RX_LOG(DEBUG, "port_id=%u queue_id=%u rx_tail=%u " "nb_hold=%u nb_rx=%u", (unsigned) rxq->port_id, (unsigned) rxq->queue_id, (unsigned) rx_id, (unsigned) nb_hold, (unsigned) nb_rx); rx_id = (uint16_t) ((rx_id == 0) ? (rxq->nb_rx_desc - 1) : (rx_id - 1)); E1000_PCI_REG_WRITE(rxq->rdt_reg_addr, rx_id); nb_hold = 0; } rxq->nb_rx_hold = nb_hold; return nb_rx;} 五、发包软件处理流程 发包流程与第四章的收包流程有些区别,DPDk在初始化阶段不会从mbuf池中获取缓冲区插到描述符队列空间里,只有在真正的发送过程中才会从mbuf池中获取mbuf,然后插入到描述符队列空间里。 1、模块/硬件介绍 Tx_queue: 发包队列结构体:我们主要关注两个环形队列tx_ring、sw_ring Tx_ring:一个地址连续环形队列,存储的是描述符,描述符中包含将来存放数据包的物理地址、DD标志(下面会介绍DD标志)等,上面图中只画了存放数据包的物理地址,物理地址供网卡DMA模块使用,也称为DMA地址(硬件使用物理地址,当网卡收到数据包后会通过DMA操作将数据包拷贝到物理地址,物理地址是通过虚拟地址转换得到的,下面分析源码时会介绍) 2、发包流程 Tx_ring发数据时的状态如下: dpdk初始化完成时tx_ring的队列为空 DMA控制器通过head去判断当前的DD状态,如果为0则可以执行发送动作 CPU需要对tx_ring上网卡发送成功的描述符的缓存空间进行释放操作,待应用下次继续写入 (1)CPU读取发送侧描述符tx_ring队列,检查DD标志是否为1,为1则说明发送完毕 (2)针对发送完毕的描述符需要释放该描述符里对应的缓冲区 (3)CPU将准备发送的缓冲区mbuf的虚拟地址填充到描述符sw_ring (4)CPU通过将准备发送的缓冲区mbuf的虚拟地址转换得到该mbuf里data数据部分的物理地址填充到发送测描述符tx_ring队列中,并将DD标志清0 (5)DMA控制器读取base寄存器,获取发送侧描述符,根据发送测描述符获取tx_ring队列地址,读取head指针里的元素,判断DD标志释放为0则从描述符中获取数据缓存区地址,通过PCIE总线将数据拷贝到网卡硬件Tx_FIFO缓存中往外发送数据 (6)DMA控制器回写该描述符中队列里DD的标志置1,通知CPU该缓存中数据已成功发送 (7)至此,应用发送数据包完毕 注意:这里有两个非常关键的队列tx_ring、sw_ring,tx_ring描述符里存放的是mbuf里data区的起始物理地址供DMA控制器读取报文(硬件DMA直接操作物理地址,不需要cpu参与);sw_ring描述符里存放的是mbuf的起始虚拟地址供应用写入数据包 3、代码的实现过程 我们以e1000驱动类型网卡举例,来分析数据包发送相关的软件结构及接口 (1)发送队列的结构如下图,图中标出了两个重要的环形队列(上面已介绍): (2)数据包的软件发送流程如下图 (3) eth_igb_xmit_pkts接口源码,发包逻辑参考上面小节,这里不做补充了 六 、总结 到目前位置分析完了数据包在网卡、CPU、主存上游走的流程,可以看到DPDK收发包的流程设计的还是比较震撼的,充分考虑到了高性能收发数据,其中一些处理流程、数据结构的设计经验等值得我们在平时的开发项目中去运用和学习。
来源:网络随着环境的不断恶化,当前社会越来越重视新能源汽车技术的发展,作为新能源汽车关键零部件(电动机及变速器)的技术发展也越来越受到重视。电动机作为其主要驱动源,变速器则作为动力传输与分配机...
相信接触过无人机的小伙伴都会在别人的方案上看到一颗常见的IC:AT7456E 那AT7456E到底是干什么用的? 我们先看芯片手册 相信对于新手小伙伴来说即使看了芯片手册,也是云里雾里的 那其实,AT7456E就是一颗OSD芯片。 OSD:On Screen Display 称做图形叠加芯片。 在无人机的主控中一般都需要处理例如:陀螺仪,电量监控,高度仪,风速仪等等数据,那这些数据就可以借助OSD芯片整合起来,再把各个数据信息传回到终端(如遥控器或者手机/PC等)叠加在图传的图像上,如下图所以: OSD芯片极大的减少了无人机系统所需的其他功能外围器件,减低了设计成本,在很大程度上简化了硬件设计的板卡设计,降低了整机的复杂程度和故障率。 AT7456E在管脚设计上是兼容MAX7456的,但由于MAX7456已经停产了,所以国产的AT7456E在市场使用率上已经非常大了。 内部框架图和典型原理图如下: 芯片的其他知识点和注意事项,请查看手册,手册链接如下: https://item.szlcsc.com/datasheet/AT7456E/83508.html
1.连续时间周期信号的傅里叶级数分析 任何一个周期为T的正弦周期信号,只要满足狄利克里条件,就可以展开成傅里叶级数,(至于为什么能展开傅里叶级数和什么是狄利克利条件,这里先不说,我们知道有这样的结论就好)...
芯片设计进阶之路——门级优化和多阈值电压 低功耗深入理解(三) 在《芯片设计进阶之路——门控时钟》里面介绍了门控时钟。我们知道现在工具对门控时钟的支持已经十分成熟了,基本不需要我们设计上做任何改变,就能自...
▼关注下方公众号了解更多▼ 一、 摘要 现在几乎所有的电子产品都带RTC功能,因此RTC电池的寿命肯定是越长越好。 二、 问题描述 本案例是一个带RTC功能的工业产品,RTC部分的供电电路如下下图,产品发往市场半年以后,就提示更换RTC电池,远远低于设计寿命5年。 图1-有问题的RTC电池供电电路 三、 原因分析 产品返回公司以后,我们更换上新的RTC电池,串联高精度万用表进去测量电流,发现RTC的工作电流高达100uA, 和我们设计的5uA有很大的差距。我们怀疑的点有: 1、二极管D3漏电流太大,设备断电时,通过D3倒流到系统的电源上。 2、RTC芯片影响,原来的RTC芯片为NXP-PCF8563P,手册描述备用电源时功耗为0.25uA;中途有更换国产RTC; 3、RTC电源线路上有漏电路,例如电容的漏电流 4、电阻R71影响。 我们通过排除法,先排除D3,因为去除D3,电流只减小1uA左右;接着排除RTC电源上电容等漏电流,因为去除电容电流依然有100uA左右。 将RTC芯片更换为NXP-PCF8563P。电流正常,大约只有4uA。接着我们换回国产RTC,同时将电阻更换为100R,则电流也正常,只有4uA左右。 于是我们引出两个疑问: (1)RTC电源上的串联电阻多少合适? (2)为何串联10K的限流电阻会导致RTC芯片不仅没有变小,反而电流增大; 1. RTC电源串联电阻阻值多少合适? RTC电源上串联的电阻阻值在网络上的争论一直在,有人说0R,有人说1K、10K等各种阻值,但是能够理论讲清楚的基本没有。 首先我们 要明白这个电阻的目的:限流。参考各个厂商的一次性纽扣电池,以阳光动力的CR2025为例,其他品牌类似,厂家要求电池在任何情况下都不允许短路,否则有可能炸裂或者爆炸。因此,一旦发生后级短路时,限流电阻必须将电流限定在最大持续放电电流以内,运行产品工作不正常,但是不允许产品起火甚至爆炸。 因此该型号的限流电阻最小值为 R=V/I=3V/3mA=1KΩ;对于电池来说,电阻可以比该阻值大,但是不能比该阻值小。 图2-电池厂家的电池规格要求 2. 串联10K电阻为何电流变大 ? 回答问题前,我们先了解一下RTC芯片的特性: (1)、RTC芯片有两种工作模式,一种是正常工作模式,一种是备用电源工作模式,如下图,两者的供电电流可以相差200倍; (2)、每一种模式下,RTC芯片都可以理解为一个恒流源,比如电池模式需要1uA左右,正常模式需要200uA左右; (3)、RTC的芯片的电压范围非常广,可以在1.5V~5.5V之间都可以正常工作。 RTC芯片可以理解为一个电流源,串联一个10K的电阻,当流过电流为100uA时,在电阻上的压降将会达到1V,如果此时电池电压只有2.6V,则RTC芯片的工作电压只有1.6V,如果电池电压更小,RTC芯片获得的电压更低,由于RTC芯片工作电压范围很广,但是需要的电流是基本不变的,为了获得足够的电流,RTC芯片可以理解为进一步降低阻抗,导致电流进一步加大。 国产芯片可能在正常工作模式和备用电源模式之间的切换的逻辑不够清晰,导致使用电池的时候也进入正常工作模式。(此为猜测,没有从厂商的资料中找到根据)。 图3-RTC芯片的直流工作参数 四、 解决方案 经过上述分析可知,为了延长电池的寿命,主要降低RTC回路上的电流。回路上的损耗主要有:电阻、二极管、RTC芯片、电容。 1、RTC电池模式电流 目前大部分的厂家的RTC芯片在电池模式下可以做到几百nA到1uA左右,因此RTC电流可以按照1uA进行估算。 2、二极管的漏电流 二极管的主要损耗在于漏电流,因此需要选择漏电流尽可能小的二极管,下图是BAS70系列二极管的漏电流的曲线图,为例保守起见,也可以按照1uA进行估算。 图4-BAS70系列二极管漏电流 /温度/电压曲线 3、电容损耗 电容的损耗主要也是体现在漏电流,RTC电池对电源要求不高,因此使用100nF的电容滤波即可,漏电流可以评估约0.5uA。 图5- 常见陶瓷电容漏电流 4、电阻损耗 经过上述分析,总的电流=二极管漏电流+RTC芯片电流+电容漏电流=1uA+1uA+0.5uA=2.5uA。电阻一般可以选择1K。RTC芯片和电阻为串联关系。1K电阻1uA的压降 : V=IR=1K*2.5uA=0.0025V 功率为 p1=U*U/R=0.0025V*0.0025V/1000=0.00625uW RTC芯片的功率 P2=UI=(3V-0.2V-0.0025V)*1uA=2.7975uW 电阻的损耗占比=P1/P2=0.089%,因此电阻的损耗基本可以忽略不计。 5、电池的寿命估算 以阳光动力电池CR2025为例,电池自放电损失约每年1%,标称容量为150mAH,上述案例的寿命评估 T=150mAh*95%/(二极管漏电流1uA+RTC电流1uA+电容漏电流0.5uA)=57000H≈6.5年。 6、最终的解决方案 以阳光动力电池CR2025为例,二极管更换为更低漏电流1uA左右的BAS70系列,电阻只串联在电池上,只防电池短路,限制电流在3mA。 图6- 改善后的RTC供电电路 五、 总结 本文回复了RTC的两个问题。 1、RTC电池要不要串联电阻,电阻阻值多少合适。 2、RTC 寿命的评估考虑因素 声明:内容来源于网络,版权归原作者所有。如有侵权,请联系删除。
电场和磁场是两种不同的物理场,它们有着不同的性质和作用。核心答案是:电场是由电荷引起的物理场,它影响带电粒子的运动;而磁场是由电流或磁性物质引起的物理场,它对磁性物质和电流产生力和影响。