深度解析U-Boot网络实现(长篇好文)

嵌入式ARM 2020-03-23 00:00

1.U-Boot网络架构分析

TCP/IP OSI model 拓扑图:

下图比较清楚的描述TCP/IP模型与OSI 七层模型的对应关系以及实现细节:

对于U-Boot而言,并没有完整的实现上述模型,u-boot需要控制固件的尺寸,所以根据需要做了一些简化,其拓扑框架如下图所示:

注:这样分层绘制,仅为理解方便,按OSI模型是否严谨不是本文重点。

网络通讯的总调度接口位于./net.c中int net_loop(enum proto_t protocol)。

u-boot循环主题位于./common中的main.c

void main_loop(void)
{
    const char *s;
    bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");

#ifdef CONFIG_VERSION_VARIABLE
    setenv("ver", version_string);  
#endif /* CONFIG_VERSION_VARIABLE */
    /*初始化命令行解释器*/
    cli_init();

    /*从环境变量中获取"preboot"的定义
     *该变量包含了一些预启动命令,一般
     *环境变量中不包含该项配置
     */

    run_preboot_environment_command();

    /*如果使能了CONFIG_UPDATE_TFTP
     *则自动从TFTP服务器更新文件 
     */

#if defined(CONFIG_UPDATE_TFTP)
    update_tftp(0UL, NULLNULL);
#endif /* CONFIG_UPDATE_TFTP */

    /*从环境变量中取出"bootdelay"
    *和"bootcmd"的配置值,将取出的
    *"bootdelay"配置值转换成整数,
    *处理延时引导*/

    s = bootdelay_process();
    if (cli_process_fdt(&s))
        cli_secure_boot_cmd(s);

    autoboot_command(s);

    /*延时引导过程中有控制台输入,
    *进入命令行解释器*/

    cli_loop();
    panic("No CLI available");
}

在cli_loop中各依据输入的命令做出判断,如果输入命令验证是合法输入命令(格式参数语法正确校验通过)则进入上述网络框图中的应用层进行处理。其入口点是net_loop函数。

对框图中的基本协议进行总结:

  • NFS:网络文件系统,英文Network File System(NFS),是由SUN公司研制的UNIX表示层协议(presentation layer protocol),能使使用者访问网络上别处的文件就像在使用自己的计算机一样。NFS是基于UDP/IP协议的应用,其实现主要是采用远程过程调用RPC机制,RPC提供了一组与机器、操作系统以及低层传送协议无关的存取远程文件的操作。RPC采用了XDR的支持。XDR是一种与机器无关的数据描述编码的协议,他以独立与任意机器体系结构的格式对网上传送的数据进行编码和解码,支持在异构系统之间数据的传送。

  • DNS:域名系统(服务)协议(DNS)是一种分布式网络目录服务,主要用于域名与 IP 地址的相互转换,以及控制因特网的电子邮件的发送。

  • BOOTP:BOOTP(Bootstrap Protocol,引导程序协议)是一种引导协议,基于UDP/IP协议,也称自举协议,是DHCP协议的前身。BOOTP用于无盘工作站的局域网中,可以让无盘工作站从一个中心服务器上获得IP地址。通过BOOTP协议可以为局域网中的无盘工作站分配动态IP地址,这样就不需要管理员去为每个用户去设置静态IP地址。

  • PING:PING (Packet Internet Groper),因特网包探索器,用于测试网络连接量的程序 [1]  。Ping是工作在 TCP/IP网络体系结构中应用层的一个服务命令, 主要是向特定的目的主机发送 ICMP(Internet Control Message Protocol 因特网报文控制协议)Echo 请求报文,测试目的站是否可达及了解其有关状态 [2]  。

  • TFTP:TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。端口号为69。TFTP是一个传输文件的简单协议,它基于UDP协议而实现。此协议设计的时候是进行小文件传输的。因此它不具备通常的FTP的许多功能,它只能从文件服务器上获得或写入文件,不能列出目录,不进行认证,它传输8位数据。传输中有三种模式:netascii,这是8位的ASCII码形式,另一种是octet,这是8位源数据类型;最后一种mail已经不再支持,它将返回的数据直接返回给用户而不是保存为文件。

  • SNTP:简单网络时间协议(Simple Network Time Protocol),由 NTP 改编而来,主要用来同步因特网中的计算机时钟。在 RFC2030 中定义。SNTP协议采用客户端/服务器的工作方式,可以采用单播(点对点)或者广播(一点对多点)模式操作。SNTP服务器通过接收GPS信号或自带的原子钟作为系统的时间基准。单播模式下,SNTP客户端能够通过定期访问SNTP服务器获得准确的时间信息,用于调整客户端自身所在系统的时间,达到同步时间的目的。广播模式下,SNTP服务器周期性地发送消息给指定的IP广播地址或者IP多播地址。SNTP客户端通过监听这些地址来获得时间信息。

  • UDP:Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。RFC 768 [1]  描述了 UDP。UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768 [1]  是UDP的正式规范。UDP在IP报文的协议号是17。

  • LINK-LOCAL:链路本地地址(Link-local address),又称连结本地位址是计算机网络中一类特殊的地址, 它仅供于在网段,或广播域中的主机相互通信使用。这类主机通常不需要外部互联网服务,仅有主机间相互通讯的需求。IPv4链路本地地址定义在169.254.0.0/16地址块。IPv6定义在fe80::/10地址块。

  • ARP:地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。地址解析协议是建立在网络中各个主机互相信任的基础上的,局域网络上的主机可以自主发送ARP应答消息,其他主机收到应答报文时不会检测该报文的真实性就会将其记入本机ARP缓存;由此攻击者就可以向某一主机发送伪ARP应答报文,使其发送的信息无法到达预期的主机或到达错误的主机,这就构成了一个ARP欺骗。ARP命令可用于查询本机ARP缓存中IP地址和MAC地址的对应关系、添加或删除静态对应关系等。相关协议有RARP、代理ARP。NDP用于在IPv6中代替地址解析协议。

  • RARP:反向地址转换协议(RARP:Reverse Address Resolution Protocol) 反向地址转换协议(RARP)允许局域网的物理机器从网关服务器的 ARP 表或者缓存上请求其 IP 地址。网络管理员在局域网网关路由器里创建一个表以映射物理地址(MAC)和与其对应的 IP 地址。当设置一台新的机器时,其 RARP 客户机程序需要向路由器上的 RARP 服务器请求相应的 IP 地址。假设在路由表中已经设置了一个记录,RARP 服务器将会返回 IP 地址给机器,此机器就会存储起来以便日后使用。RARP 可以使用于以太网、光纤分布式数据接口及令牌环 LAN。

    ARP(地址解析协议)是设备通过自己知道的IP地址来获得自己不知道的物理地址的协议。假如一个设备不知道它自己的IP地址,但是知道自己的物理地址,网络上的无盘工作站就是这种情况,设备知道的只是网络接口卡上的物理地址。这种情况下应该怎么办呢?RARP(逆地址解析协议)正是针对这种情况的一种协议。
    RARP以与ARP相反的方式工作。RARP发出要反向解析的物理地址并希望返回其对应的IP地址,应答包括由能够提供所需信息的RARP服务器发出的IP地址。虽然发送方发出的是广播信息,RARP规定只有RARP服务器能产生应答。许多网络指定多个RARP服务器,这样做既是为了平衡负载也是为了作为出现问题时的备份。

  • PHY:PHY(英语:Port Physical Layer),中文可称之为端口物理层,是一个对OSI模型物理层的共同简称。PHY连接一个数据链路层的设备(MAC)到一个物理媒介,如光纤或铜缆线。典型的PHY包括PCS(Physical Coding Sublayer,物理编码子层)和PMD(Physical Media Dependent,物理介质相关子层)。PCS对被发送和接受的信息加码和解码,目的是使接收器更容易恢复信号。

2.协议栈工作机制

2.1 以nfs为例

NFS的实现命令入口位于./cmd/net.c (注:不同版本U-Boot文件名不一样,有的版本叫cmd_net.c) ,U_BOOT_CMD创建的do_nfs实现函数,该函数会调用netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,char * const argv[]) 调用会话层的具体实现。proto_t 为协议类型枚举变量:BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,TFTPSRV, TFTPPUT, LINKLOCAL。不同的应用协议传入不同的协议类型,以NFS为例:

  • netboot_common(NFS, cmdtp, argc, argv);

    对应NFS 的调用接口与函数实现就容易理解了

    nfs  [loadAddress] [[hostIPaddr:]bootfilename]

从层级调用的角度分析,会话层nfs.c收到该请求,将依据NFS协议向下层发送UDP报文请求:net_send_udp_packet。同时将接收处理回调函数udp_packet_handler设置为nfs接收报文处理函数。net_send_udp_packet该函数的原型为:

int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport,int payload_len)

  • ether:NFS服务器以太网MAC地址,即开发主机的MAC地址

  • struct in_addr dest:NFS服务器IP地址,即开发主机的IP地址

  • int sport:端口号

  • int payload_len:有效载荷长度

传输层将上层的发送请求用net_send_packet发送至设备层:

inline void net_send_packet(uchar *pkt, int len)

  • uchar *pkt:报文指针

  • int len:长度

设备层通过eth_send调用驱动层的具体发送函数,这取决于是采用代理模式或通用设备框架,见物理层实现章节描述。设备层接收到底层设备驱动的接收报文请求调用eth_rx(),将接收报文返回给传输层。

函数原型为:int eth_rx(void)

int eth_rx(void)
{
    struct udevice *current;
    uchar *packet;
    int flags;
    int ret;
    int i;

    current = eth_get_dev();
    if (!current)
        return -ENODEV;

    if (!device_active(current))
        return -EINVAL;

    /* Process up to 32 packets at one time */
    flags = ETH_RECV_CHECK_DEVICE;
    for (i = 0; i < 32; i++) {
        ret = eth_get_ops(current)->recv(current, flags, &packet);
        flags = 0;
        if (ret > 0)
            net_process_received_packet(packet, ret);
        if (ret >= 0 && eth_get_ops(current)->free_pkt)
            eth_get_ops(current)->free_pkt(current, packet, ret);
        if (ret <= 0)
            break;
    }
    if (ret == -EAGAIN)
        ret = 0;
    if (ret < 0) {
        /* We cannot completely return the error at present */
        debug("%s: recv() returned error %d\n", __func__, ret);
    }
    return ret;
}

int eth_rx将调用net_process_received_packet处理报文解析,如果报文IP头部校验通过,将调用udp_packet_handler对应的接收处理回调函数,进行NFS应用协议的处理。这样就完成了完整的收发通信过程。

2.2 报文封装

报文封装与拆包大略示意图如下,自上而下,数据传入下一层将加上该层的头部:

IP/UDP头部

struct ip_udp_hdr {
    /*IP 头部*/
    u8      ip_hl_v;    /* header length and version    */
    u8      ip_tos;     /* type of service      */
    u16     ip_len;     /* total length         */
    u16     ip_id;      /* identification       */
    u16     ip_off;     /* fragment offset field    */
    u8      ip_ttl;     /* time to live         */
    u8      ip_p;       /* protocol         */
    u16     ip_sum;     /* checksum         */
    struct in_addr  ip_src;     /* Source IP address        */
    struct in_addr  ip_dst;     /* Destination IP address   */

    /*以下为UDP头部*/
    u16     udp_src;    /* UDP source port      */
    u16     udp_dst;    /* UDP destination port     */
    u16     udp_len;    /* Length of UDP packet     */
    u16     udp_xsum;   /* Checksum         */
};

3.物理层实现

U-Boot网络架构的物理层的主要职责是负责网络报文的收发。控制以太网收发芯片工作,并将二进制数据流接收发送。如上图所示,其底层驱动抽象剥离实现于./drivers/net,该层主要与设备抽象层交互,主要与eth_legacy.c或者eth-uclass.c交互。而设备抽象层通过net_send_packet服务原语提供对上层的发送报文服务,报文接收主要由net_process_received_packet服务原语提供物理层接收报文服务,U-Boot为简化设计,物理层的接收函数直接在net_loop函数解析。依据接收的报文类型再做出后续的处理动作。eth_common主要实现物理MAC地址读与改写等操作,并实现将当前设备接入系统的操作,由函数eth_set_current实现。

设备抽象层主要由eth_legacy.c或者eth-uclass.c实现,这两个文件位于./net下:

  • 当使能设备管理框架宏时CONFIG_DM_ETH时,使用eth-uclass.c与底层设备驱动进行交互。此时网络底层设备采用udevice通用设备框架进行交互。

  • 当关闭设备管理框架宏时CONFIG_DM_ETH时,使用eth_legacy.c与底层设备驱动进行交互。此时网络底层驱动程序通过代理模式实现具体底层驱动与上层应用进行交互,实现了对上层的接口统一,以及对底层设备驱动差异化的兼容代理。

  • eth_legacy.c和eth-uclass.c 都实现了eth_set_dev接口,将设备根据环境变量ethprime,将网络设备设置为系统当前的主网络设备。

3.1 eth_legacy.c 代理模式

eth_legacy.c 对外的设备接口为 eth_device结构体,该结构体对设备的基本属性进行抽象封装:

eth_device 以太网设备接口,抽象了底层设备的以下主要属性以及基本操作:

  • char name[16]:字符串命名,如"RTL8139#%d

  • unsigned char enetaddr[6]:48位 MAC地址

  • phys_addr_t iobase:以太网收发芯片IO基址

  • int state:设备状态机,ETH_STATE_INIT/ETH_STATE_PASSIVE/ETH_STATE_ACTIVE三种状态

  • int (*init)(struct eth_device *, bd_t *):设备初始化接口

  • int (*send)(struct eth_device *, void *packet, int length):设备发生报文接口

  • int (*recv)(struct eth_device *):设备接收报文接口

  • void (*halt)(struct eth_device *):设备停止处理接口

  • int (*mcast)(struct eth_device *, const u8 *enetaddr, u8 set):多播接口

  • int (*write_hwaddr)(struct eth_device *):写MAC地址接口,有的芯片内置MAC地址存储器,故可选地需要实现这个接口。

对于设备驱动如以代理模式工作,只需要根据芯片DATASHEET实现上述接口,并调用int eth_register(struct eth_device *dev)接口将该结构体操作符注册进入代理设备框架,即实现了设备驱动的移植。当底层设备收到报文时,./net中函数net_process_received_packet(uchar *in_packet, int len)会自动通过eth_device设备操作接口完成数据接收以及解析。

那么对于设备层驱动在什么函数进行设备注册呢?以常见的RTL8139芯片为例,实现rtl8139_initialize,将rtl8139模块内部上述操作的局部接口函数初始化eth_device变量,同时将该结构体变量注册挂载进代理框架就完成了设备的挂载。

int rtl8139_initialize(bd_t *bis)
{
    pci_dev_t devno;
    int card_number = 0;
    struct eth_device *dev;
    u32 iobase;
    int idx=0;

    while(1){
        /* Find RTL8139 */
        if ((devno = pci_find_devices(supported, idx++)) < 0)
            break;

        pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
        iobase &= ~0xf;
        debug ("rtl8139: REALTEK RTL8139 @0x%x\n", iobase);
        dev = (struct eth_device *)malloc(sizeof *dev);
        if (!dev) {
            printf("Can not allocate memory of rtl8139\n");
            break;
        }
        memset(dev, 0sizeof(*dev));
        sprintf (dev->name, "RTL8139#%d", card_number);

        dev->priv = (void *) devno;
        dev->iobase = (int)bus_to_phys(iobase);
        dev->init = rtl8139_probe;
        dev->halt = rtl_disable;
        dev->send = rtl_transmit;
        dev->recv = rtl_poll;
#ifdef CONFIG_MCAST_TFTP
        dev->mcast = rtl_bcast_addr;
#endif
        eth_register (dev);

        card_number++;
        pci_write_config_byte (devno, PCI_LATENCY_TIMER, 0x20);

        udelay (10 * 1000);
    }
    return card_number;
}

3.2 udevice 框架模式

eth-uclass.c对设备驱动层进行操作抽象封装,驱动程序需要实现操作符eth_ops:

  • int (*start)(struct udevice *dev):启动设备

  • int (*send)(struct udevice *dev, void *packet, int length):发送报文

  • int (*recv)(struct udevice *dev, int flags, uchar **packetp):接收报文

  • int (*free_pkt)(struct udevice *dev, uchar *packet, int length):释放报文

  • void (*stop)(struct udevice *dev):停止设备

  • int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join):多播

  • int (*write_hwaddr)(struct udevice *dev):写MAC操作

  • int (*read_rom_hwaddr)(struct udevice *dev):读ROM MAC地址操作

以mcs7830芯片为例:

/*操作函数实现略*/
/*1.实现操作符eth_ops mcs7830_eth_ops以及对应的操作函数*/
static const struct eth_ops mcs7830_eth_ops = {
 .start  = mcs7830_eth_start,
 .send   = mcs7830_eth_send,
 .recv   = mcs7830_eth_recv,
.free_pkt = mcs7830_free_pkt,
 .stop   = mcs7830_eth_stop,
 .write_hwaddr = mcs7830_write_hwaddr,
};
/*2.利用U_BOOT_DRIVER定义BOOT driver*/
U_BOOT_DRIVER(mcs7830_eth) = {
  .name   = "mcs7830_eth",
  .id = UCLASS_ETH,
  .probe = mcs7830_eth_probe,
  .ops    = &mcs7830_eth_ops,
  .priv_auto_alloc_size = sizeof(struct mcs7830_private),
  .platdata_auto_alloc_size = sizeof(struct eth_pdata),
  .flags  = DM_FLAG_ALLOC_PRIV_DMA,
};
/*3.定义ID表*/
static const struct usb_device_id mcs7830_eth_id_table[] = {
  { USB_DEVICE(0x97100x7832) },     /* Moschip 7832 */
  { USB_DEVICE(0x97100x7830), },    /* Moschip 7830 */
  { USB_DEVICE(0x97100x7730), },    /* Moschip 7730 */
  { USB_DEVICE(0x0df60x0021), },    /* Sitecom LN 30 */
  { }     /* Terminating entry */
};
/*4.定义BOOT_USB设备*/
U_BOOT_USB_DEVICE(mcs7830_eth, mcs7830_eth_id_table);
  1. 实现操作符eth_ops mcs7830_eth_ops以及对应的操作函数

  2. 利用U_BOOT_DRIVER定义BOOT driver

  3. 定义ID表

  4. 定义BOOT_USB设备

对于U_BOOT_USB_DEVICE,在<<读U-Boot源码-C语言编程技巧总结篇二>>对类似的宏有过推导,这里简要描述方便理解。

#define U_BOOT_USB_DEVICE(__name, __match) \
  ll_entry_declare(struct usb_driver_entry, __name, usb_driver_entry) = {\
    .driver = llsym(struct driver, __name, driver), \
    .match = __match, \
    }


#define ll_entry_declare(_type, _name, _list)                \
  _type _u_boot_list_2_##_list##_2_##_name __aligned(4)       \
    __attribute__((unused,              \
    section(".u_boot_list_2_"#_list"_2_"#_name)))   


#define llsym(_type, _name, _list) \
    ((_type *)&_u_boot_list_2_##_list##_2_##_name)

对U_BOOT_USB_DEVICE展开为:

ll_entry_declare(struct usb_driver_entry, mcs7830_eth, usb_driver_entry) = {\
 .driver = llsym(struct driver, mcs7830_eth, driver), \
 .match = mcs7830_eth_id_table, \
}

对ll_entry_declare以及llsym展开为:

struct usb_driver_entry _u_boot_list_2_usb_driver_entry_2_mcs7830_eth __aligned(4) \
 __attribute__((unused,  \
 section(".u_boot_list_2_""usb_driver_entry""_2_""mcs7830_eth")))={\
 .driver = ((struct driver *)&_u_boot_list_2_mcs7830_eth_2_mcs7830_eth), \
 .match = mcs7830_eth_id_table, \
}    

而usb_driver_entry为:

struct usb_driver_entry {
 struct driver *driver;
 const struct usb_device_id *match;
};

设备的加载在设备树框架中,通过读取设备树文件自动加载完成,这里不做展开。


本文授权转载自公众号 “嵌入式客栈”,作者逸珺

嵌入式ARM 关注这个时代最火的嵌入式ARM,你想知道的都在这里。
评论
  • 根据环洋市场咨询(Global Info Research)项目团队最新调研,预计2030年全球无人机锂电池产值达到2457百万美元,2024-2030年期间年复合增长率CAGR为9.6%。 无人机锂电池是无人机动力系统中存储并释放能量的部分。无人机使用的动力电池,大多数是锂聚合物电池,相较其他电池,锂聚合物电池具有较高的能量密度,较长寿命,同时也具有良好的放电特性和安全性。 全球无人机锂电池核心厂商有宁德新能源科技、欣旺达、鹏辉能源、深圳格瑞普和EaglePicher等,前五大厂商占有全球
    GIRtina 2025-01-07 11:02 127浏览
  • 大模型的赋能是指利用大型机器学习模型(如深度学习模型)来增强或改进各种应用和服务。这种技术在许多领域都显示出了巨大的潜力,包括但不限于以下几个方面: 1. 企业服务:大模型可以用于构建智能客服系统、知识库问答系统等,提升企业的服务质量和运营效率。 2. 教育服务:在教育领域,大模型被应用于个性化学习、智能辅导、作业批改等,帮助教师减轻工作负担,提高教学质量。 3. 工业智能化:大模型有助于解决工业领域的复杂性和不确定性问题,尽管在认知能力方面尚未完全具备专家级的复杂决策能力。 4. 消费
    丙丁先生 2025-01-07 09:25 122浏览
  • 每日可见的315MHz和433MHz遥控模块,你能分清楚吗?众所周知,一套遥控设备主要由发射部分和接收部分组成,发射器可以将控制者的控制按键经过编码,调制到射频信号上面,然后经天线发射出无线信号。而接收器是将天线接收到的无线信号进行解码,从而得到与控制按键相对应的信号,然后再去控制相应的设备工作。当前,常见的遥控设备主要分为红外遥控与无线电遥控两大类,其主要区别为所采用的载波频率及其应用场景不一致。红外遥控设备所采用的射频信号频率一般为38kHz,通常应用在电视、投影仪等设备中;而无线电遥控设备
    华普微HOPERF 2025-01-06 15:29 172浏览
  • 「他明明跟我同梯进来,为什么就是升得比我快?」许多人都有这样的疑问:明明就战绩也不比隔壁同事差,升迁之路却比别人苦。其实,之间的差异就在于「领导力」。並非必须当管理者才需要「领导力」,而是散发领导力特质的人,才更容易被晓明。许多领导力和特质,都可以通过努力和学习获得,因此就算不是天生的领导者,也能成为一个具备领导魅力的人,进而被老板看见,向你伸出升迁的橘子枝。领导力是什么?领导力是一种能力或特质,甚至可以说是一种「影响力」。好的领导者通常具备影响和鼓励他人的能力,并导引他们朝着共同的目标和愿景前
    优思学院 2025-01-08 14:54 74浏览
  • 本文介绍编译Android13 ROOT权限固件的方法,触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。关闭selinux修改此文件("+"号为修改内容)device/rockchip/common/BoardConfig.mkBOARD_BOOT_HEADER_VERSION ?= 2BOARD_MKBOOTIMG_ARGS :=BOARD_PREBUILT_DTB
    Industio_触觉智能 2025-01-08 00:06 95浏览
  • 故障现象一辆2017款东风风神AX7车,搭载DFMA14T发动机,累计行驶里程约为13.7万km。该车冷起动后怠速运转正常,热机后怠速运转不稳,组合仪表上的发动机转速表指针上下轻微抖动。 故障诊断 用故障检测仪检测,发动机控制单元中无故障代码存储;读取发动机数据流,发现进气歧管绝对压力波动明显,有时能达到69 kPa,明显偏高,推断可能的原因有:进气系统漏气;进气歧管绝对压力传感器信号失真;发动机机械故障。首先从节气门处打烟雾,没有发现进气管周围有漏气的地方;接着拔下进气管上的两个真空
    虹科Pico汽车示波器 2025-01-08 16:51 79浏览
  • By Toradex 秦海1). 简介嵌入式平台设备基于Yocto Linux 在开发后期量产前期,为了安全以及提高启动速度等考虑,希望将 ARM 处理器平台的 Debug Console 输出关闭,本文就基于 NXP i.MX8MP ARM 处理器平台来演示相关流程。 本文所示例的平台来自于 Toradex Verdin i.MX8MP 嵌入式平台。  2. 准备a). Verdin i.MX8MP ARM核心版配合Dahlia载板并
    hai.qin_651820742 2025-01-07 14:52 111浏览
  • 在智能家居领域中,Wi-Fi、蓝牙、Zigbee、Thread与Z-Wave等无线通信协议是构建短距物联局域网的关键手段,它们常在实际应用中交叉运用,以满足智能家居生态系统多样化的功能需求。然而,这些协议之间并未遵循统一的互通标准,缺乏直接的互操作性,在进行组网时需要引入额外的网关作为“翻译桥梁”,极大地增加了系统的复杂性。 同时,Apple HomeKit、SamSung SmartThings、Amazon Alexa、Google Home等主流智能家居平台为了提升市占率与消费者
    华普微HOPERF 2025-01-06 17:23 209浏览
  • 村田是目前全球量产硅电容的领先企业,其在2016年收购了法国IPDiA头部硅电容器公司,并于2023年6月宣布投资约100亿日元将硅电容产能提升两倍。以下内容主要来自村田官网信息整理,村田高密度硅电容器采用半导体MOS工艺开发,并使用3D结构来大幅增加电极表面,因此在给定的占位面积内增加了静电容量。村田的硅技术以嵌入非结晶基板的单片结构为基础(单层MIM和多层MIM—MIM是指金属 / 绝缘体/ 金属) 村田硅电容采用先进3D拓扑结构在100um内,使开发的有效静电容量面积相当于80个
    知白 2025-01-07 15:02 145浏览
  •  在全球能源结构加速向清洁、可再生方向转型的今天,风力发电作为一种绿色能源,已成为各国新能源发展的重要组成部分。然而,风力发电系统在复杂的环境中长时间运行,对系统的安全性、稳定性和抗干扰能力提出了极高要求。光耦(光电耦合器)作为一种电气隔离与信号传输器件,凭借其优秀的隔离保护性能和信号传输能力,已成为风力发电系统中不可或缺的关键组件。 风力发电系统对隔离与控制的需求风力发电系统中,包括发电机、变流器、变压器和控制系统等多个部分,通常工作在高压、大功率的环境中。光耦在这里扮演了
    晶台光耦 2025-01-08 16:03 66浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦