历史上的今天
返回首页

历史上的今天

今天是:2024年10月14日(星期一)

正在发生

2018年10月14日 | tiny4412的Uboot启动流程

2018-10-14 来源:eefocus

基于友善之臂tiny4412开发板,uboot版本是2010.12:

一般我们将UBOOT分为2个阶段,第一阶段主要为汇编代码,用于初始化必要的硬件并将UBOOT copy到SDRAM中并跳转到SDRAM执行,第二阶段主要为c代码,主要作用是加载kernel到SDRAM,准备启动kernel的参数最后跳转到kernel处执行,当然uboot里也可以有许多扩展功能,比如下载功能,实现各种驱动程序等.


第一阶段:

1.首先就是uboot的入口的地址是arch/arm/cpu/armv7/start.S, 这可以从相同路径下的连接脚本u-boot.lds 中知道,如下:

----------------------------------------------------------------------------------------------------------------

ENTRY(_start)  

SECTIONS  

{  

    . = 0x00000000;  

 

    . = ALIGN(4);  

    .text   :  

    {  

        arch/arm/cpu/armv7/start.o  (.text)  

        *(.text)  

    }  

----------------------------------------------------------------------------------------------------------------


2.下面开始结合代码分析启动流程,一开始就会无条件跳转到reset 处执行:

----------------------------------------------------------------------------------------------------------------

.globl _start  

_start: b   reset //直接跳到reset处执行  

    ldr pc, _undefined_instruction    // 设置异常向量表    

    ldr pc, _software_interrupt  

    ldr pc, _prefetch_abort  

    ldr pc, _data_abort  

    ldr pc, _not_used  

    ldr pc, _irq  

    ldr pc, _fiq  

----------------------------------------------------------------------------------------------------------------


3.然后找到reset 处,先关中断,进SVC32模式:

----------------------------------------------------------------------------------------------------------------

// the actual reset code  

  

reset:  

    // set the cpu to SVC32 mode  

    mrs r0, cpsr  

    bic r0, r0, #0x1f   //cpsr的低五位被清零  

    orr r0, r0, #0xd3  //关中断(irq, fiq),并进入SVC32模式   

    msr cpsr,r0  

----------------------------------------------------------------------------------------------------------------


4.然后跳转到cpu_init_crit 处执行:

----------------------------------------------------------------------------------------------------------------

// the mask ROM code should have PLL and others stable   

ifndef CONFIG_SKIP_LOWLEVEL_INIT   //not define  

bl  cpu_init_crit  //跳转到cpu_init_crit,初始化内存,时钟等关键寄存器 ,就在本文件内,在稍后的地方  

endif  

----------------------------------------------------------------------------------------------------------------


5.cpu_init_crit,主要工作就是对cache,MMU的操作,另一个非常重要的事情就是会调用执行板级初始化的文件,具体看注释吧

----------------------------------------------------------------------------------------------------------------

 // CPU_init_critical registers  

 //  

 // setup important registers  

 // setup memory timing   


cpu_init_crit:  


    bl cache_init  // 在本版本中此函数为空函数,什么也不做,直接返回  

    //初始化cache,位置在 ./board/samsung/tiny4412/lowlevel_init.S:cache_init:  

  

    // Invalidate L1 I/D  

    mov r0, #0          @ set up for MCR  

    mcr p15, 0, r0, c8, c7, 0   @ invalidate TLBs   

    //armv7手册P1374  //清页表  

    //ARM最多可支持16个协处理器p0-p15  

    mcr p15, 0, r0, c7, c5, 0   @ invalidate icache 

    // 看注释应该是关指令cache,armv7手册P1730,未定义此处的命令,

    //不知道什么意思,期待大神现身说法,fix me   

  

    //   disable MMU stuff and caches  

    //   cp15 c1寄存器的操作在armv7手册p1334  

    mrc p15, 0, r0, c1, c0, 0  // 读cp15 c1寄存器到r0    

    bic r0, r0, #0x00002000 @ clear bits 13 (--V-) 

    //设置异常向量表基地址为0x00000000?<==此地址不是IROM地址码?

    //记得好像此地址应该设置为0xffff0000,fixme    

    

    bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)  // 关数据 cache,关 MMU  

    orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align  //strict alignment fault checking enabled.  

    orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB  //打开指令cache  

    mcr p15, 0, r0, c1, c0, 0  

 

     // Jump to board specific initialization...  

     // The Mask ROM will have already initialized  

     // basic memory. Go here to bump up clock rate and handle  

     // wake up conditions.  

       

    mov ip, lr          @ persevere link reg across call  

    bl  lowlevel_init       @ go setup pll,mux,memory,

    // 进行板级的初始化,主要是时钟,内存,串口,nand等,位置在:

    //   /board/samsung/tiny4412/lowlevel_init.S lowlevel_init:  

    

    mov lr, ip          @ restore link  

    mov pc, lr          @ back to my caller // 返回   

----------------------------------------------------------------------------------------------------------------


6.下面进入lowlevel_init.S的 lowlevel_init() 进行板级相关的初始化,其位置在/board/samsung/tiny4412/lowlevel_init.S中

这里面先进行的是一些设置:设置栈指针,判断启动方式,点亮一个LED等

----------------------------------------------------------------------------------------------------------------

.globl lowlevel_init  

lowlevel_init:  //主要对PLL及memory初始化,此函数需要移植来完成  

  

    // use iROM stack in bl2   

    ldr sp, =0x02060000 //设置栈指针,Iram的最高地址  

    push    {lr}  

  

    // check reset status  

    //    INF_REG_BASE的值为0x10020800,为power management info 寄存器的基地址  

    //    此处INF_REG1_OFFSET的值为4  

    //    故此处为取INFORM1 寄存器的值  

    //    此处的意思为判断系统是否为从sleep状态唤醒而来  

  

    ldr r0, =(INF_REG_BASE + INF_REG1_OFFSET)  

    ldr r1, [r0]  

  

    // Sleep wakeup reset   

    ldr r2, =S5P_CHECK_SLEEP  

    cmp r1, r2  

    beq wakeup_reset  

  

    // set CP reset to low   

    ldr r0, =0x11000C60    

    ldr r1, [r0]  

    ldr r2, =0xFFFFFF0F  

    and r1, r1, r2  

    orr r1, r1, #0x10  

    str r1, [r0]       

    //此处0x11000C60 为寄存器GPX3CON的地址,此处将此寄存器[4:7]置1,即将GPX3DAT_1 设为output


    ldr r2, =0xFFFFFFF3  

    and r1, r1, r2  

    orr r1, r1, #0x4  

    str r1, [r0]   

    //此处0x11000C68 为寄存器 GPX3PUD的地址,  

    //此处将此寄存器[2]置1,即enable GPX3PUD_1 pull_down 

      

    ldr r0, =0x11000C64  

    ldr r1, [r0]  

    ldr r2, =0xFFFFFFFD  

    and r1, r1, r2  

    str r1, [r0]

    // 此处0x11000C64 为寄存器 GPX3DAT的地址,  

    // 此处将此寄存器[2]置1,即enable GPX3DAT_1 置0 

  

    // 经查电路发现,GPX3DAT_1的信号为XEINT25,外部连的是Gsensor MMA7660的中断信号  

    // 启动系统时为何将此引脚设为GPIO output 并clear to 0?? fixme!!   

  

    // led (GPM4_0~3) on  

    // 0x110002E0 为寄存器GPM4CON的地址,将GPM4DAT 0~3设为output,GPM4DATA 4~7   

    // 设为input  

    // 最后两句将GPM4DATA0设为0,查看电路图发现就是点亮LED1   

    ldr r0, =0x110002E0  

    ldr r1, =0x00001111  

    str r1, [r0]  

    ldr r1, =0x0e  

    str r1, [r0, #0x04]  

  

    // During sleep/wakeup or AFTR mode, pmic_init function is not available  

    // and it causes delays. So except for sleep/wakeup and AFTR mode,  

    // the below function is needed   

#if defined(CONFIG_HAS_PMIC) 

    // 未定义此宏,即开发板上没有PMIC,都是分立元件产生的power,

    //tiny4412.h中已显性取消此宏的定义,#undef CONFIG_HAS_PMIC 

    bl  pmic_init  

#endif  

  

#if defined(CONFIG_ONENAND) // 未定义此宏   

    bl  onenandcon_init  

#endif  

  

#if defined(NAND_BOOTING)   //  未定义此宏   

    bl  nand_asm_init  

#endif  

----------------------------------------------------------------------------------------------------------------


7.下面就会去判断启动的位置,

bl  read_om // 读取启动设备,在本文件的稍后面  


这个函数的实现由兴趣的可以看一次下,看这里:

----------------------------------------------------------------------------------------------------------------

read_om:// 读取启动设备  

    // Read booting information   

    ldr r0, =S5PV310_POWER_BASE // power management 寄存器的基地址   

    ldr r1, [r0,#OMR_OFFSET]         // 0x0,读 OM_STAT 寄存器的值  

    bic r2, r1, #0xffffffc1                // 除[1:5] 位外,其他位清零,并存入r2  

  

    // NAND BOOT  

@   cmp r2, #0x0        @ 512B 4-cycle  

@   moveq   r3, #BOOT_NAND  

  

@   cmp r2, #0x2        @ 2KB 5-cycle  

@   moveq   r3, #BOOT_NAND  

  

@   cmp r2, #0x4        @ 4KB 5-cycle   8-bit ECC  

@   moveq   r3, #BOOT_NAND  

  

    //真正的决定硬件连接的启动方式有下面的与r2做比较的常数决定,本开发板中的启动选择  

    //开关只能选择从EMMC or SD卡启动,而此处EMMC启动的寄存器数字为0x6,SD卡启动为  

    //0x4,故启动选择开关只会影响XOM1的值   

    cmp r2, #0xA  

    moveq   r3, #BOOT_ONENAND  

  

    cmp r2, #0x10       @ 2KB 5-cycle   16-bit ECC  

    moveq   r3, #BOOT_NAND  

  

    // SD/MMC BOOT 

    cmp r2, #0x4  

    moveq   r3, #BOOT_MMCSD  

  

    // eMMC BOOT    

    cmp r2, #0x6  

    moveq   r3, #BOOT_EMMC  

  

    // eMMC 4.4 BOOT   

    cmp r2, #0x8  

    moveq   r3, #BOOT_EMMC_4_4  

    cmp r2, #0x28  

    moveq   r3, #BOOT_EMMC_4_4  

  

    ldr r0, =INF_REG_BASE   

    str r3, [r0, #INF_REG3_OFFSET]    // 将读到的启动设备的结果写入INFORM3 寄存器 

  

    mov pc, lr //  返回  

----------------------------------------------------------------------------------------------------------------


8.回来接着主程序往下看,下面会判断一下程序是否已经运行在RAM里,显然这是公版uboot里的代码,友善之臂并没有删减掉

----------------------------------------------------------------------------------------------------------------

    // when we already run in ram, we don't need to relocate U-Boot.  

    // and actually, memory controller must be configured before U-Boot  

    // is running in ram.  

   

  

    //  此处比较PC与0xc3e00000中间3位的值,如果相等则判断现在已经运行在SDRAM里  

    //  就会跳过SDRAM的初始化,但此时程序还运行在IRAM里,PC的值显然不可能指向SDRAM   

    ldr r0, =0xff000fff  

    bic r1, pc, r0      // r0 <- current base addr of code  

    ldr r2, _TEXT_BASE  // r1 <- original base addr in ram ,值为0xc3e00000,在本文件开始处定义 

    bic r2, r2, r0      // r0 <- current base addr of code  

    cmp r1, r2          // compare r0, r1   

    beq after_copy      // r0 == r1 then skip sdram init and u-boot.bin loading    

----------------------------------------------------------------------------------------------------------------


9.既然程序还未运行在SDRAM里,那么系统肯定还处于“远古时代”,接着就要进行三个最重要的硬件初始化,

----------------------------------------------------------------------------------------------------------------

// init system clock   

bl  system_clock_init  

// 看名字就知道是系统时钟初始化,定义在./board/samsung/tiny4412/clock_init_tiny4412.S  

  

//Memory initialize 

bl  mem_ctrl_asm_init // 内存初始化,在/board/samsung/tiny4412/mem_init_tiny4412.S   

  

// init uart for debug    

bl  uart_asm_init // 串口初始化,定义在本文件稍后的地方  

----------------------------------------------------------------------------------------------------------------

这三个初始化程序相对过于复杂,本文重点在于理清uboot的启动流程,这里不再赘述,有兴趣的童鞋可以另寻时间study.


10.下面uboot还贴心的给出了一段测试的代码

----------------------------------------------------------------------------------------------------------------

// 至此PLL, SDRAM, UART已全部初始化OK, 启动时要用的最基本的硬件已准备就绪 

// 下面一段代码是对上面硬件初始化的测试,经验证后已OK,表示到此CLK, SDRAM, UART都已初始化OK 

#if CONFIG_LL_DEBUG  

    mov r4, #0x4000  

.L0:  

    sub r4, r4, #1  

    cmp r4, #0    

    bne .L0  

  

    mov r0, #'\r'  

    bl  uart_asm_putc  

    mov r0, #'\n'  

    bl  uart_asm_putc  

  

    ldr r1, =0x40000000 //内存首地址 

    ldr r2, =0x87654321  

    str r2, [r1]  

    str r2, [r1, #0x04]  

    str r2, [r1, #0x08]  

    ldr r2, =0x55aaaa55  

    str r2, [r1, #0x10]  

    nop  

  

    mov r4, #0xC0000  

.L1:  

    subs    r4, r4, #1  

    bne .L1  

  

    ldr r0, [r1]  

    bl  uart_asm_putx  

    mov r0, #'.'  

    bl  uart_asm_putc  

  

    ldr r0, [r1, #0x04]  

    bl  uart_asm_putx  

    mov r0, #'.'  

    bl  uart_asm_putc  

  

    ldr r0, [r1, #0x08]  

    bl  uart_asm_putx  

    mov r0, #'.'  

    bl  uart_asm_putc  

  

    ldr r0, [r1, #0x10]  

    bl  uart_asm_putx  

    mov r0, #'>'  

    bl  uart_asm_putc  

#endif // CONFIG_LL_DEBUG  

----------------------------------------------------------------------------------------------------------------


11.继续走起,trustzone 这东西真心不懂...,之前有一次编译内核没把trustzone disable 掉,启动kernel时会卡住.


bl  tzpc_init       // 初始化trust zone protection controller,定义在本文件稍后位置  

b   load_uboot // 将u-boot完整代码copy到内存0x43e00000开始的SDRAM地址上,定义在本文件稍后位置  

不过这个load_uboot要看一次下,他就是将uboot完整源码copy到SDRAM的函数, 调试的时候一般从sd卡启动的多,故以SD卡启动为例:

----------------------------------------------------------------------------------------------------------------

load_uboot:  

    // 根据启动设备跳转到相应处执行  

    ldr r0, =INF_REG_BASE  

    ldr r1, [r0, #INF_REG3_OFFSET] ////read_om将判断结果放在寄存器INF_REG3_OFFSET  

    cmp r1, #BOOT_NAND  

    beq nand_boot  

    cmp r1, #BOOT_ONENAND  

    beq onenand_boot  

    cmp r1, #BOOT_MMCSD // SD卡启动  

    beq mmcsd_boot  

    cmp r1, #BOOT_EMMC  

    beq emmc_boot  

    cmp r1, #BOOT_EMMC_4_4  

    beq emmc_boot_4_4  

    cmp r1, #BOOT_NOR  

    beq nor_boot  

    cmp r1, #BOOT_SEC_DEV  

    beq mmcsd_boot  

  

nand_boot:  

    mov r0, #0x1000  

    bl  copy_uboot_to_ram  

    b   after_copy  

  

onenand_boot:  

    bl  onenand_bl2_copy // goto 0x1010    

    b   after_copy  

  

mmcsd_boot:  

  

#ifdef CONFIG_SMDKC220 // tiny4412.h 中已定义    

//#ifdef CONFIG_CLK_BUS_DMC_200_400  

    ldr r0, =ELFIN_CLOCK_BASE      //CLK寄存器首地址,0x10030000  

    ldr r2, =CLK_DIV_FSYS2_OFFSET //Sets clock divider ratio for FSYS_BLK  

    ldr r1, [r0, r2]  

    orr r1, r1, #0xf  

   // DIVMMC2 Clock Divider Ratio   

   // DOUTMMC2 = MOUTMMC2/(MMC2_RATIO + 1)设置分频系数为16  

   //查看电路图发现SD卡用的即为第2路MMC总线  

    str r1, [r0, r2]  // 设置时钟,此处将SCLK_MMC2的时钟设为EPLL/16    

//#endif  

#else  

// 下面几个宏都未设置,不会执行下面的代码  

#if defined(CONFIG_CLK_1000_400_200) || defined(CONFIG_CLK_1000_200_200) ||  \

                 defined(CONFIG_CLK_800_400_200)  

    ldr r0, =ELFIN_CLOCK_BASE  

    ldr r2, =CLK_DIV_FSYS2_OFFSET  

    ldr r1, [r0, r2]  

    orr r1, r1, #0xf  

    str r1, [r0, r2]  

#endif  

#endif  

    bl  movi_uboot_copy  // 将uboot copy到SDRAM中,定义在arch/arm/cpu/armv7/exynos/Irom_copy.c    

    b   after_copy  

----------------------------------------------------------------------------------------------------------------


12.下面进movi_uboot_copy看一下,定义在定义在arch/arm/cpu/armv7/exynos/Irom_copy.c中:

----------------------------------------------------------------------------------------------------------------

void movi_uboot_copy(void)  

{  

#ifdef CONFIG_RAM_TEST // 已定义此宏  

    uboot_mem_test();  // 测试初始化的CLK, SDRAM, UART  

#endif  

  

#ifdef CONFIG_CORTEXA5_ENABLE // 未定义 

    SDMMC_ReadBlocks(MOVI_UBOOT_POS, MOVI_UBOOT_BLKCNT, 0x40000000);  

#endif  

  

//此函数即是将uboot完整程序复制到SDRAM 0x43e0000开始的内存中,此函数实际调用的是放在IRAM 0x02023030处的一个函数指针  

//    函数的实现代码是在IROM里,函数的功能为将SD卡中的数据复制到SDRAM中,详见Android_Exynos4412_iROM_Secure_Booting_Guide_Ver.1.00.00 P21  

//    三个参数分别为开始块,要copy的块数,copy到内存的起始地址,故此处传入的参数为17,32,0x43e00000  

//    此处的内存地址是物理地址,当开启MMU后对应的地址的0XC3E00000, 与uboot的链接地址一致   

    SDMMC_ReadBlocks(MOVI_UBOOT_POS, MOVI_UBOOT_BLKCNT, CONFIG_PHY_UBOOT_BASE);  

  

#ifdef CONFIG_SECURE_BOOT // 未定义  

    if (Check_Signature((SB20_CONTEXT *)SECURE_CONTEXT_BASE,  

                (unsigned char*)CONFIG_PHY_UBOOT_BASE, PART_SIZE_UBOOT-256,  

                (unsigned char*)(CONFIG_PHY_UBOOT_BASE+PART_SIZE_UBOOT-256), 256) != 0)  

    {  

        while(1);  

    }  

#endif  

}  

----------------------------------------------------------------------------------------------------------------


13.接下来就是after_copy了,即将进入第二阶段:

----------------------------------------------------------------------------------------------------------------

after_copy:  

  

    // led (GPM4_0~3) on    

    ldr r0, =0x110002E0  

    ldr r1, =0x0c  

    str r1, [r0, #0x04] //LED1~LED2 on 

  

#ifdef CONFIG_SMDKC220 //tiny4412.h中已定义 

    // set up C2C 

    ldr r0, =S5PV310_SYSREG_BASE  

    ldr r2, =GENERAL_CTRL_C2C_OFFSET  

    ldr r1, [r0, r2]  

    ldr r3, =0x4000  

    orr r1, r1, r3  

    str r1, [r0, r2] //将GENERAL_CTRL_C2C的bit[14]置1,dram_init_done signal for wake up sequence  

#endif  

  

#ifdef CONFIG_ENABLE_MMU //tiny4412中已定义 

    bl  enable_mmu //打开MMU   

#endif  

  

    // store second boot information in u-boot C level variable  

    ldr r0, =CONFIG_PHY_UBOOT_BASE   //0X43E00000 

    sub r0, r0, #8  

    ldr r1, [r0]  

    ldr r0, _second_boot_info  // 在tiny4412.c里定义的全局变量unsigned int second_boot_info = 0xffffffff  

    str r1, [r0]  // 不知为何意,fix me  

  

    // Print 'K'    

    ldr r0, =S5PV310_UART_CONSOLE_BASE  

    ldr r1, =0x4b4b4b4b  

    str r1, [r0, #UTXH_OFFSET] // 打印字符'K',与UART初始化时最后显示的'O'组成UBOOT最开始显示的"OK"   

  

    ldr r0, _board_init_f

    // 取函数board_init_f 的地址,该函数在\arch\arm\lib\board.c中实现,

    // 主要实现gd全局结构体的填充及SDRAM的空间分配   

    mov pc, r0 // 跳转到函数board_init_f处执行,从此处开始在SDRAM中执行    

  

   // uboot第一阶段 结束,将进入第二阶段C代码的执行   

  

_board_init_f:  

    .word board_init_f  

  

_second_boot_info:  

    .word second_boot_info 

----------------------------------------------------------------------------------------------------------------


推荐阅读

史海拾趣

高创科技(gotrend)公司的发展小趣事

聚辰(Giantec)公司电子行业发展的五个故事

故事一:技术传承与独立运营

聚辰半导体股份有限公司(Giantec Semiconductor Corporation)的故事始于2009年,由美国ISSI公司与其高管共同出资成立。这家公司继承了ISSI在EEPROM和智能卡芯片技术上的专利和研发团队,为后续的快速发展奠定了坚实基础。随着ISSI公司股权的变动,聚辰半导体逐渐由国资企业接手并开始独立运营。这一转变不仅让聚辰获得了更大的自主权,也为其在存储芯片领域的深耕细作提供了有力支持。

故事二:全球布局与市场拓展

自成立以来,聚辰半导体便致力于全球化布局,不仅在上海设立总部,还在美国硅谷、韩国、中国香港、中国台湾、深圳、南京、苏州等地设立了子公司、办事处或销售机构。这一战略布局使得聚辰能够更好地服务全球客户,迅速响应市场需求。同时,聚辰的产品线不断扩展,从最初的EEPROM存储芯片,逐步延伸到NOR Flash、音圈马达驱动芯片和智能卡芯片等多个领域,广泛应用于智能手机、汽车电子、工业控制等多个行业。

故事三:技术突破与产品创新

在技术创新方面,聚辰半导体始终走在行业前列。2012年,聚辰推出的EEPROM存储芯片成功进入三星、OPPO等手机品牌的摄像头模组供应链,标志着公司在全球EEPROM存储芯片市场的地位逐渐稳固。此后,聚辰不断推出新产品,如音圈马达驱动芯片与EEPROM二合一产品,进一步提升了其在手机摄像头模组中的竞争力。同时,聚辰还积极布局汽车电子市场,多款车规级存储芯片获得市场认可,为公司带来了新的增长点。

故事四:资本市场助力与品牌提升

2019年,聚辰半导体在上海证券交易所科创板成功上市,为公司的发展注入了强劲动力。资本市场的助力不仅让聚辰获得了更多的资金支持,还显著提升了公司的品牌影响力和市场认知度。上市以来,聚辰持续加大研发投入,优化产品结构,提升产品性能,进一步巩固了其在存储芯片领域的市场地位。

故事五:荣誉加身与行业认可

近年来,聚辰半导体凭借其出色的业绩和技术实力赢得了多项荣誉和行业认可。公司多次入选中国物联网企业百强榜单、上海硬核科技企业TOP100榜单等权威榜单,彰显了其在行业内的领先地位。同时,聚辰还积极履行社会责任,参与公益事业,如向中国科学技术大学捐赠资金用于支持人工智能创新中心建设等,进一步提升了公司的社会形象和品牌价值。这些荣誉和认可不仅是对聚辰过去努力的肯定,也是对其未来发展的期待和鼓舞。

Federal Custom Cable公司的发展小趣事

在电缆产品性能和质量得到提升的同时,Federal Custom Cable也积极开拓新的市场领域。他们深入了解不同行业对电缆的需求特点,针对不同行业推出了一系列定制化的电缆产品。这些产品广泛应用于通信、医疗、航空等领域,并赢得了客户的一致好评。同时,Federal Custom Cable还加强了品牌建设和市场推广力度,提高了品牌知名度和美誉度。

Amphenol(安费诺)公司的发展小趣事

Federal Custom Cable非常重视客户服务工作。他们建立了完善的客户服务体系,为客户提供从产品咨询、选型、定制到售后服务的全方位支持。同时,Federal Custom Cable还积极与合作伙伴建立长期稳定的合作关系,共同推动电缆行业的发展。这种以客户需求为导向、以合作伙伴关系为基础的经营模式,为Federal Custom Cable的持续发展提供了有力保障。

DACHANG公司的发展小趣事

在追求经济效益的同时,DACHANG公司始终不忘承担社会责任。公司积极参与公益事业,关注环境保护和社会发展。无论是在捐款助学、扶贫济困还是在环保减排方面,DACHANG公司都积极履行自己的社会责任,为社会做出了积极贡献。这种对社会责任的担当和履行,不仅提升了DACHANG公司的品牌形象,也赢得了社会各界的广泛赞誉。

Aptina (ON Semiconductor)公司的发展小趣事

在快速发展的同时,Aptina注重技术研发与专利布局。公司投入大量资源用于研发,不断推出具有创新性的图像传感器产品。这些产品不仅提升了公司的市场竞争力,还为Aptina积累了大量的技术专利。这些专利成为了公司宝贵的资产,为公司的长期发展奠定了坚实基础。

Astron Wireless Technologies Inc公司的发展小趣事

随着无线通信技术的快速发展,Astron Wireless Technologies Inc公司面临着来自同行的竞争压力。为了保持竞争优势,公司不断加大研发投入,推出了一系列具有更高性能、更低成本的无线通信产品。同时,公司还加强了与客户的沟通与合作,及时了解市场需求变化,并根据客户需求进行产品调整和优化。这些措施使得公司在激烈的市场竞争中保持了领先地位。

问答坊 | AI 解惑

C51教程完整版

这是在其他地方下到的东西,感觉很不错,拿过来和大家分享分享…

查看全部问答>

公司版STM32工作原理

公司版STM32工作原理  晶振:老板,带两个秘书(电容),有时老板不在秘书说了算(内部时钟模式) 时钟PLL:老板娘,老板控制局面,但还是要听老板娘的话。 CPU:人力资源部,调动人员齐心合力 APB1,APB2时钟:部门经理,发布任务进度, ...…

查看全部问答>

TEA 加解密算法在嵌入式系统通信中的应用

嵌入式系统的远程数据传输经常要使用公共通信线路这给数据安全带来隐患本文介绍的T E A 数据 加密算法高效可靠适用于资源有限的嵌入式系统同时文章还给出T E A 算法的一个应用实例…

查看全部问答>

谁能给详细的介绍下有源功率因数校正的工作原理步骤?

来自电源群:38592946 市电怎么一步一步转化的?…

查看全部问答>

tcpmp支持usb插拔吗,

如果支持 那么就会自动游览影音文件?…

查看全部问答>

机器人自主导航?

最近做一个家庭机器人的项目,需要用到激光传感器实现自主建立地图,自主导航。还没有什么明确的思路,各位高手有没有搞过这个的给学生一点建议,感谢…

查看全部问答>

求购开发板

需要嵌入式Linux与VxWorks开发板各一块,最好CPU频率400MHz以上, 必须带BSP支持。最好带完整的嵌入式Linux系统。VxWorks开发板支持WindML. 有意者请联系:010-51615759 邮箱:ancring.hk@163.com …

查看全部问答>

我用EVC作的MFC程序,为什么使用共享库在目标机上运行出错,使用静态库就可以正常运行?

我用EVC作的MFC程序,为什么使用共享库在目标机上运行出错,使用静态库就可以正常运行?…

查看全部问答>

evc下打开文件夹对话框

evc有没有打开文件夹对话框的api啊,SHBrowseForFolder()这个函数在evc里编译不过啊,还有没有其他的方法啊。 wince不会只能打开文件吧。 各位大虾帮帮忙啊!…

查看全部问答>