RISCVLinuxkernel启动代码分析之六:setup_vm_final分析

原创 嵌入式Lee 2024-11-19 13:21

.前言

前面我们分析了setup_vm以及relocate,并详细手算了对应的页表了解了此时页表映射了哪些虚拟地址到哪个物理地址。现在继续来看setup_vm_final该函数实现最终的映射。

二. 分析过程

该函数调用路径如下

head.Srelocate之后

tail start_kernel->

start_kernel(init/main.c)->

setup_arch(arch/riscv/kernel/setup.c)->

paging_init(arch/riscv/mm/init.c)->

setup_vm_final(arch/riscv/mm/init.c)

实现如下

static void __init setup_vm_final(void){    uintptr_t va, map_size;    phys_addr_t pa, start, end;    u64 i;
    /**     * MMU is enabled at this point. But page table setup is not complete yet.     * fixmap page table alloc functions should be used at this point     */    pt_ops.alloc_pte = alloc_pte_fixmap;    pt_ops.get_pte_virt = get_pte_virt_fixmap;#ifndef __PAGETABLE_PMD_FOLDED    pt_ops.alloc_pmd = alloc_pmd_fixmap;    pt_ops.get_pmd_virt = get_pmd_virt_fixmap;#endif    /* Setup swapper PGD for fixmap */    create_pgd_mapping(swapper_pg_dir, FIXADDR_START,               __pa_symbol(fixmap_pgd_next),               PGDIR_SIZE, PAGE_TABLE);    /* Map all memory banks */    for_each_mem_range(i, &start, &end) {        if (start >= end)            break;        if (start <= __pa(PAGE_OFFSET) &&            __pa(PAGE_OFFSET) < end)            start = __pa(PAGE_OFFSET);        map_size = best_map_size(start, end - start);        for (pa = start; pa < end; pa += map_size) {            va = (uintptr_t)__va(pa);            create_pgd_mapping(swapper_pg_dir, va, pa,                       map_size, PAGE_KERNEL_EXEC);        }    }    /* Clear fixmap PTE and PMD mappings */    clear_fixmap(FIX_PTE);    clear_fixmap(FIX_PMD);    /* Move to swapper page table */    csr_write(CSR_SATP, PFN_DOWN(__pa_symbol(swapper_pg_dir)) | SATP_MODE);    local_flush_tlb_all();    /* generic page allocation functions must be used to setup page table */    pt_ops.alloc_pte = alloc_pte_late;    pt_ops.get_pte_virt = get_pte_virt_late;#ifndef __PAGETABLE_PMD_FOLDED    pt_ops.alloc_pmd = alloc_pmd_late;    pt_ops.get_pmd_virt = get_pmd_virt_late;#endif}

2.1 接口设置

开始设置接口

 /**     * MMU is enabled at this point. But page table setup is not complete yet.     * fixmap page table alloc functions should be used at this point     */    pt_ops.alloc_pte = alloc_pte_fixmap;    pt_ops.get_pte_virt = get_pte_virt_fixmap;#ifndef __PAGETABLE_PMD_FOLDED    pt_ops.alloc_pmd = alloc_pmd_fixmap;    pt_ops.get_pmd_virt = get_pmd_virt_fixmap;#endif

最后设置接口

 /* generic page allocation functions must be used to setup page table */    pt_ops.alloc_pte = alloc_pte_late;    pt_ops.get_pte_virt = get_pte_virt_late;#ifndef __PAGETABLE_PMD_FOLDED    pt_ops.alloc_pmd = alloc_pmd_late;    pt_ops.get_pmd_virt = get_pmd_virt_late;#endif

2.2配置根页表swapper_pg_dir

首先配置根页表swapper_pg_dir等下会从early_pg_dir切换到该页表

    /* Setup swapper PGD for fixmap */    create_pgd_mapping(swapper_pg_dir, FIXADDR_START,               __pa_symbol(fixmap_pgd_next),               PGDIR_SIZE, PAGE_TABLE);

此时参数为

setup_vm时一样,swapper_pg_dir315条目指向下一级fixmap_pmd

执行完后GDB查看如下,[315]位置的条目对应fixmap_pmd

(gdb) p /x swapper_pg_dir$1 = {{pgd = 0x0} times>, {pgd = 0x2075e801}, {pgd = 0x0} times>}(gdb)

2.3映射bank

   /* Map all memory banks */    for_each_mem_range(i, &start, &end) {        if (start >= end)            break;        if (start <= __pa(PAGE_OFFSET) &&            __pa(PAGE_OFFSET) < end)            start = __pa(PAGE_OFFSET);
        map_size = best_map_size(start, end - start);        for (pa = start; pa < end; pa += map_size) {            va = (uintptr_t)__va(pa);            create_pgd_mapping(swapper_pg_dir, va, pa,                       map_size, PAGE_KERNEL_EXEC);        }    }

for_each_mem_range

遍历所有块映射。

第一次,此时映射的范围是0x80200000~0x88000000

按照2MB单位进行映射

此时alloc_pgd_next

pt_ops.alloc_pmd(__va)

pt_ops.alloc_pmd = alloc_pmd_fixmap;

static phys_addr_t __init alloc_pmd_fixmap(uintptr_t va)

{

return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);

}

动态分配的pmd地址为0x87fff000

sz2M

条目值为0x21fffc01

0x87fff000转为虚拟地址nextp=0xffffffcefeffe000

继续下一级pdm条目的配置,指向对应的2MB物理地址

然后继续2MB配置,直到0x8800000

动态分配的pmd物理地址为0x87fff000

虚拟地址计算接口如下

   pt_ops.get_pmd_virt = get_pmd_virt_fixmap;
static pmd_t *__init get_pmd_virt_fixmap(phys_addr_t pa){    clear_fixmap(FIX_PMD);    return (pmd_t *)set_fixmap_offset(FIX_PMD, pa);}


#define set_fixmap_offset(idx, phys) \    __set_fixmap_offset(idx, phys, FIXMAP_PAGE_NORMAL)

/* Return a pointer with offset calculated */#define __set_fixmap_offset(idx, phys, flags)               \({                                  \    unsigned long ________addr;                 \    __set_fixmap(idx, phys, flags);                 \    ________addr = fix_to_virt(idx) + ((phys) & (PAGE_SIZE - 1));   \    ________addr;                           \})

fix_to_virt

static __always_inline unsigned long fix_to_virt(const unsigned int idx){    BUILD_BUG_ON(idx >= __end_of_fixed_addresses);    return __fix_to_virt(idx);}

其中

void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot){    unsigned long addr = __fix_to_virt(idx);    pte_t *ptep;
    BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);    ptep = &fixmap_pte[pte_index(addr)];    if (pgprot_val(prot))        set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));    else        pte_clear(&init_mm, addr, ptep);    local_flush_tlb_page(addr);}

通过fixmap_pte临时映射虚拟地址,对应如下地址,解决此时只能访问虚拟地址不能访问物理地址的问题

即将0x87fff000映射到了上述FIX_PMD页,然后通过去虚拟地址就可以访问该物理地址了。

#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))

xFIX_PMD=2

FIXADDR_TOP=0xffffffcefee00000+0x200000=0xffffffceff000000

0xffffffceff000000-(2<<12)=0xFFFF FFCE FEFF E000

get_pmd_virt_fixmap->set_fixmap_offset

此时查看该pmd的内容

p /x *(pmd_t (*)[512])(0xffffffcefeffe000)$38 = {{pmd = 0x200800ef}, {pmd = 0x201000ef}, {pmd = 0x201800ef}, {pmd = 0x202000ef}, {pmd = 0x202800ef}, {pmd = 0x203000ef}, {    pmd = 0x203800ef}, {pmd = 0x204000ef}, {pmd = 0x204800ef}, {pmd = 0x205000ef}, {pmd = 0x205800ef}, {pmd = 0x206000ef}, {    pmd = 0x206800ef}, {pmd = 0x207000ef}, {pmd = 0x207800ef}, {pmd = 0x208000ef}, {pmd = 0x208800ef}, {pmd = 0x209000ef}, {    pmd = 0x209800ef}, {pmd = 0x20a000ef}, {pmd = 0x20a800ef}, {pmd = 0x20b000ef}, {pmd = 0x20b800ef}, {pmd = 0x20c000ef}, {    pmd = 0x20c800ef}, {pmd = 0x20d000ef}, {pmd = 0x20d800ef}, {pmd = 0x20e000ef}, {pmd = 0x20e800ef}, {pmd = 0x20f000ef}, {    pmd = 0x20f800ef}, {pmd = 0x210000ef}, {pmd = 0x210800ef}, {pmd = 0x211000ef}, {pmd = 0x211800ef}, {pmd = 0x212000ef}, {    pmd = 0x212800ef}, {pmd = 0x213000ef}, {pmd = 0x213800ef}, {pmd = 0x214000ef}, {pmd = 0x214800ef}, {pmd = 0x215000ef}, {    pmd = 0x215800ef}, {pmd = 0x216000ef}, {pmd = 0x216800ef}, {pmd = 0x217000ef}, {pmd = 0x217800ef}, {pmd = 0x218000ef}, {    pmd = 0x218800ef}, {pmd = 0x219000ef}, {pmd = 0x219800ef}, {pmd = 0x21a000ef}, {pmd = 0x21a800ef}, {pmd = 0x21b000ef}, {    pmd = 0x21b800ef}, {pmd = 0x21c000ef}, {pmd = 0x21c800ef}, {pmd = 0x21d000ef}, {pmd = 0x21d800ef}, {pmd = 0x21e000ef}, {    pmd = 0x21e800ef}, {pmd = 0x21f000ef}, {pmd = 0x21f800ef}, {pmd = 0x0} 449 times>}(gdb)

以上看到

看到映射了632MB的块

一共126M

刚好是0x80200000~0x88000000的范围126MB

2.4清除fixmappte级别条目(FIX_PTEFIX_PMD对应的页)

    /* Clear fixmap PTE and PMD mappings */    clear_fixmap(FIX_PTE);    clear_fixmap(FIX_PMD);

其中include/asm-generic/fixmap.h

#ifndef clear_fixmap#define clear_fixmap(idx)           \    __set_fixmap(idx, 0, FIXMAP_PAGE_CLEAR)#endif

arch/riscv/mm/init.c

void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot){    unsigned long addr = __fix_to_virt(idx);    pte_t *ptep;
    BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);    ptep = &fixmap_pte[pte_index(addr)];    if (pgprot_val(prot))        set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));    else        pte_clear(&init_mm, addr, ptep);    local_flush_tlb_page(addr);}

FIX_PTE=1

FIX_PMD=2

FIX_PTEFIX_PMD对应如下的页表,PTEPMD的后级,所以先清除PTE条目,再清除PMD条目

对应

__set_fixmap(1,0,0)

__set_fixmap(2,0,0)

cleanPMD下有一个条目

(gdb) p /x fixmap_pmd$1 = {{pmd = 0x0} times>, {pmd = 0x2075f001}, {pmd = 0x0}, {pmd = 0x0}, {pmd = 0x0}, {pmd = 0x0}, {    pmd = 0x0}, {pmd = 0x0}, {pmd = 0x0}, {pmd = 0x0}}(gdb)

Pte下有一个条目

(gdb) p /x fixmap_pte$2 = {{pte = 0x0} times>, {pte = 0x21fffce7}, {pte = 0x0}}(gdb)

来看__set_fixmap实现

   unsigned long addr = __fix_to_virt(idx);

include/asm-generic/fixmap.h

#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))

FIXADDR_TOP=0xffffffcefee00000+0x200000

所以addrPTEPMD时分别是

0xffffffcefee00000+0x200000-(1<<12)=FFFFFFCEFEFFF000

0xffffffcefee00000+0x200000-(2<<12)=FFFFFFCEFEFFE000

然后检查

BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);

页索引要在以下范围内

include/asm-generic/fixmap.h中的宏

enum fixed_addresses {    FIX_HOLE,    FIX_PTE,    FIX_PMD,    FIX_TEXT_POKE1,    FIX_TEXT_POKE0,    FIX_EARLYCON_MEM_BASE,
    __end_of_permanent_fixed_addresses,    /*     * Temporary boot-time mappings, used by early_ioremap(),     * before ioremap() is functional.     */#define NR_FIX_BTMAPS       (SZ_256K / PAGE_SIZE)#define FIX_BTMAPS_SLOTS    7#define TOTAL_FIX_BTMAPS    (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS)    FIX_BTMAP_END = __end_of_permanent_fixed_addresses,    FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,    __end_of_fixed_addresses};

然后

ptep = &fixmap_pte[pte_index(addr)];

include/linux/pgtable.hPAGE_SHIFT=12PTRS_PER_PTE=512

static inline unsigned long pte_index(unsigned long address){    return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);}

所以

pte_index(0xFFFFFFCEFEFFF000)=511

pte_index(0xFFFFFFCEFEFFE000)=510

继续prot0,所以走

pte_clear(&init_mm, addr, ptep);

arch/riscv/include/asm/pgtable.h

static inline void pte_clear(struct mm_struct *mm,    unsigned long addr, pte_t *ptep){    set_pte_at(mm, addr, ptep, __pte(0));}

arch/riscv/include/asm/pgtable.h

static inline void set_pte_at(struct mm_struct *mm,    unsigned long addr, pte_t *ptep, pte_t pteval){    if (pte_present(pteval) && pte_exec(pteval))        flush_icache_pte(pteval);
    set_pte(ptep, pteval);}
static inline void set_pte(pte_t *ptep, pte_t pteval){    *ptep = pteval;}

即将ptep设置为0.

fixmap_pte[511]=0

fixmap_pte[510]=0

最后local_flush_tlb_page调用

sfence.vma刷新tlb

执行完这两句后,看到fixmap_pte[511]变为了0.

(gdb) p /x fixmap_pmd$4 = {{pmd = 0x0} times>, {pmd = 0x2075f001}, {pmd = 0x0}, {pmd = 0x0}, {pmd = 0x0}, {pmd = 0x0}, {    pmd = 0x0}, {pmd = 0x0}, {pmd = 0x0}, {pmd = 0x0}}(gdb)
(gdb) p /x fixmap_pte$5 = {{pte = 0x0} times>}(gdb)

2.5切换页表

然后切换satpswapper_pg_dir

    /* Move to swapper page table */    csr_write(CSR_SATP, PFN_DOWN(__pa_symbol(swapper_pg_dir)) | SATP_MODE);    local_flush_tlb_all();

arch/riscv/include/asm/page.h

#define __pa_symbol(x) __phys_addr_symbol(RELOC_HIDE((unsigned long)(x), 0))

#define __phys_addr_symbol(x) __va_to_pa_nodebug(x)

#define __va_to_pa_nodebug(x) ((unsigned long)(x) - va_pa_offset)

所以__pa_symbol(swapper_pg_dir)

计算物理地址就是&swapper_pg_dir-va_pa_offset

对应汇编代码如下

此时swapper_pg_dir地址为0xffffffe001b7e000对应寄存器a5

(gdb) p &swapper_pg_dir$1 = (pgd_t (*)[512]) 0xffffffe001b7e000 (gdb)

变量va_pa_offset的值 0xffffffdf7fe00000为对应寄存器a4

实际就是(PAGE_OFFSET-load_pa=0xffffffe000000000-0x80200000).

(gdb) p /x va_pa_offset$1 = 0xffffffdf7fe00000(gdb)

计算完后值为0x81d7e000

0xffffffe001b7e000 -0xffffffdf7fe00000

include/linux/pfn.h

#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)

arch/riscv/include/asm/csr.h

#define SATP_MODE_39 _AC(0x8000000000000000, UL)

#define SATP_MODE SATP_MODE_39

所以写入satp寄存器的值是

(0x81d7e000>>12)|0x8000000000000000=0x8000000000081d7e 

然后

local_flush_tlb_all();即调用sfence.vma刷新tlb

arch/riscv/include/asm/tlbflush.h

/* Flush one page from local TLB */static inline void local_flush_tlb_page(unsigned long addr){#ifdef CONFIG_NO_SFENCE_VMA    csr_write(CSR_SMCIR, 1 << 26);#else    __asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory");#endif}

三. 设置之后页表

借助上一篇,我们实现了在mmu使能后继续使用GDB调试,我们可以直接跳到

setup_vm_final,一步步查看执行过程分析。

hb setup_vm_final 打断点到函数入口

C 全速运行到函数处

可以运行完后查看页表信息

(gdb) p &swapper_pg_dir$1 = (pgd_t (*)[512]) 0xffffffe001b7e000 (gdb)
(gdb) p /x swapper_pg_dir$3 = {{pgd = 0x0} times>, {pgd = 0x2075e801}, {pgd = 0x0} times>, {pgd = 0x21fffc01}, { pgd = 0x0} times>}(gdb)

swapper_pg_dir[315]指向的正是fixmap_pmd

(gdb) p &fixmap_pmd$4 = (pmd_t (*)[512]) 0xffffffe001b7a000 (gdb)
(gdb) p /x fixmap_pmd$5 = {{pmd = 0x0} times>, {pmd = 0x2075f001}, {pmd = 0x0}, {pmd = 0x0}, {pmd = 0x0}, {pmd = 0x0}, {pmd = 0x0}, { pmd = 0x0}, {pmd = 0x0}, {pmd = 0x0}}(gdb)

指向的 fixmap_pmd[503]正是fixmap_pte

(gdb) p & fixmap_pte$6 = (pte_t (*)[512]) 0xffffffe001b7c000 (gdb)
(gdb) p /x fixmap_pte$7 = {{pte = 0x0} times>}(gdb)

fixmap_pte后没有映射了,前面看到clean了。

swapper_pg_dir[384]条目值是

((x>>12 ) <<10)| 1=0x21fffc01

所以反推对应的pdb页表地址为0x87FFF000

此处对应的虚拟地址为0xffffffcefeffe000

PA-VA的计算方式前面已经分析

通过fixmap_pte[FIX_PMD]映射对应物理地址0x87fff000,虚拟地址是

0xffffffcefeffe000

p /x *(pmd_t (*)[512])(0xffffffcefeffe000)$38 = {{pmd = 0x200800ef}, {pmd = 0x201000ef}, {pmd = 0x201800ef}, {pmd = 0x202000ef}, {pmd = 0x202800ef}, {pmd = 0x203000ef}, {    pmd = 0x203800ef}, {pmd = 0x204000ef}, {pmd = 0x204800ef}, {pmd = 0x205000ef}, {pmd = 0x205800ef}, {pmd = 0x206000ef}, {    pmd = 0x206800ef}, {pmd = 0x207000ef}, {pmd = 0x207800ef}, {pmd = 0x208000ef}, {pmd = 0x208800ef}, {pmd = 0x209000ef}, {    pmd = 0x209800ef}, {pmd = 0x20a000ef}, {pmd = 0x20a800ef}, {pmd = 0x20b000ef}, {pmd = 0x20b800ef}, {pmd = 0x20c000ef}, {    pmd = 0x20c800ef}, {pmd = 0x20d000ef}, {pmd = 0x20d800ef}, {pmd = 0x20e000ef}, {pmd = 0x20e800ef}, {pmd = 0x20f000ef}, {    pmd = 0x20f800ef}, {pmd = 0x210000ef}, {pmd = 0x210800ef}, {pmd = 0x211000ef}, {pmd = 0x211800ef}, {pmd = 0x212000ef}, {    pmd = 0x212800ef}, {pmd = 0x213000ef}, {pmd = 0x213800ef}, {pmd = 0x214000ef}, {pmd = 0x214800ef}, {pmd = 0x215000ef}, {    pmd = 0x215800ef}, {pmd = 0x216000ef}, {pmd = 0x216800ef}, {pmd = 0x217000ef}, {pmd = 0x217800ef}, {pmd = 0x218000ef}, {    pmd = 0x218800ef}, {pmd = 0x219000ef}, {pmd = 0x219800ef}, {pmd = 0x21a000ef}, {pmd = 0x21a800ef}, {pmd = 0x21b000ef}, {    pmd = 0x21b800ef}, {pmd = 0x21c000ef}, {pmd = 0x21c800ef}, {pmd = 0x21d000ef}, {pmd = 0x21d800ef}, {pmd = 0x21e000ef}, {    pmd = 0x21e800ef}, {pmd = 0x21f000ef}, {pmd = 0x21f800ef}, {pmd = 0x0} 449 times>}(gdb)

可以看到最终页表如下

其中

pmd_t xxx_pmd[PTRS_PER_PMD]

0x87fff000是动态分配出来的PMD

PMD要通过虚拟地址访问,则需要先对齐进行映射,这是通过

pmd_t fixmap_pmd[PTRS_PER_PMD]

下映射pte_t fixmap_pte[PTRS_PER_PTE]

下映射一个4KB的页来实现的,这个映射是临时的,访问完xxx_pmd即可clean

四. 总结

setup_vm_final最终切换到了swapper_pg_dir这个页表,映射了PAGE_OFFSET0xffffffe000000000开始的126MB0x80200000开始的126MB物理地址。

进行上述映射动态分配了xxx_pmd需要访问该地址,则现在使能了MMU不能直接访问物理地址,所以需要先借助fixmap_pmd->fixmap_pte临时映射一个xxx_pmd物理地址对应的虚拟地址,以便设置xxx_pmd的内容。这就是fixmap_pmd/pte的作用。




























评论
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 52浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 73浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 186浏览
  •  光伏及击穿,都可视之为 复合的逆过程,但是,复合、光伏与击穿,不单是进程的方向相反,偏置状态也不一样,复合的工况,是正偏,光伏是零偏,击穿与漂移则是反偏,光伏的能源是外来的,而击穿消耗的是结区自身和电源的能量,漂移的载流子是 客席载流子,须借外延层才能引入,客席载流子 不受反偏PN结的空乏区阻碍,能漂不能漂,只取决于反偏PN结是否处于外延层的「射程」范围,而穿通的成因,则是因耗尽层的过度扩张,致使跟 端子、外延层或其他空乏区 碰触,当耗尽层融通,耐压 (反向阻断能力) 即告彻底丧失,
    MrCU204 2025-01-17 11:30 182浏览
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 150浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 390浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 100浏览
  • 日前,商务部等部门办公厅印发《手机、平板、智能手表(手环)购新补贴实施方案》明确,个人消费者购买手机、平板、智能手表(手环)3类数码产品(单件销售价格不超过6000元),可享受购新补贴。每人每类可补贴1件,每件补贴比例为减去生产、流通环节及移动运营商所有优惠后最终销售价格的15%,每件最高不超过500元。目前,京东已经做好了承接手机、平板等数码产品国补优惠的落地准备工作,未来随着各省市关于手机、平板等品类的国补开启,京东将第一时间率先上线,满足消费者的换新升级需求。为保障国补的真实有效发放,基于
    华尔街科技眼 2025-01-17 10:44 221浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 41浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 112浏览
  • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
    Industio_触觉智能 2025-01-17 14:09 164浏览
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 122浏览
  • 随着消费者对汽车驾乘体验的要求不断攀升,汽车照明系统作为确保道路安全、提升驾驶体验以及实现车辆与环境交互的重要组成,日益受到业界的高度重视。近日,2024 DVN(上海)国际汽车照明研讨会圆满落幕。作为照明与传感创新的全球领导者,艾迈斯欧司朗受邀参与主题演讲,并现场展示了其多项前沿技术。本届研讨会汇聚来自全球各地400余名汽车、照明、光源及Tier 2供应商的专业人士及专家共聚一堂。在研讨会第一环节中,艾迈斯欧司朗系统解决方案工程副总裁 Joachim Reill以深厚的专业素养,主持该环节多位
    艾迈斯欧司朗 2025-01-16 20:51 198浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦