uboot中的SPL作用详解-编程语言及工具-飞外网

SPL是uboot第一阶段执行的代码。 主要负责搬移uboot第二阶段的代码到内存中运行。 SPL是由固化在芯片内部的ROM引导的。 我们知道很多芯片厂商固化的ROM支持从nandflash, SDCARD等外部介质启动。

所谓启动, 就是从这些外部介质中搬移一段固定大小(4K/8K/16K等)的代码到内部RAM中运行。 这里搬移的就是SPL. 在最新版本的uboot中, 可以看到SPL也支持nandflash, SDCARD等多种启动方式。 当SPL本身被搬移到内部RAM中运行时, 它会从nandflash, SDCARD等外部介质中搬移uboot第二阶段的代码到外部内存中。

SPL的文件组成 当我们在uboot下执行make命令的时候, 它最核心的功能是执行Makefile中的all目标编译出相应的文件。 我们来看看这个all目标

[plain] view plaincopyall: $$(ALL-y) $$(SUBDIR_EXAMPLES)

[plain] view plain copyall: $$(ALL-y) $$(SUBDIR_EXAMPLES)

all依赖于$$(ALL-y) 和 $$(SUBDIR_EXAMPLES), 这里我只关注ALL-y, 如下:

[plain] view plaincopy# Always append ALL so that arch config.mk‘s can add custom ones

ALL-y += $$(obj)u-boot.srec $$(obj)u-boot.bin $$(obj)System.map

ALL-$$(CONFIG_NAND_U_BOOT) += $$(obj)u-boot-nand.bin

ALL-$$(CONFIG_ONENAND_U_BOOT) += $$(obj)u-boot-onenand.bin

ALL-$$(CONFIG_SPL) += $$(obj)spl/u-boot-spl.bin

ALL-$$(CONFIG_SPL_FRAMEWORK) += $$(obj)u-boot.img

ALL-$$(CONFIG_TPL) += $$(obj)tpl/u-boot-tpl.bin

ALL-$$(CONFIG_OF_SEPARATE) += $$(obj)u-boot.dtb $$(obj)u-boot-dtb.bin

ifneq ($$(CONFIG_SPL_TARGET),)

ALL-$$(CONFIG_SPL) += $$(obj)$$(subst “,,$$(CONFIG_SPL_TARGET))

endif

# enable combined SPL/u-boot/dtb rules for tegra

ifneq ($$(CONFIG_TEGRA),)

ifeq ($$(CONFIG_OF_SEPARATE),y)

ALL-y += $$(obj)u-boot-dtb-tegra.bin

else

ALL-y += $$(obj)u-boot-nodtb-tegra.bin

endif

endif

[plain] view plain copy# Always append ALL so that arch config.mk’s can add custom ones

ALL-y += $$(obj)u-boot.srec $$(obj)u-boot.bin $$(obj)System.map

ALL-$$(CONFIG_NAND_U_BOOT) += $$(obj)u-boot-nand.bin

ALL-$$(CONFIG_ONENAND_U_BOOT) += $$(obj)u-boot-onenand.bin

ALL-$$(CONFIG_SPL) += $$(obj)spl/u-boot-spl.bin

ALL-$$(CONFIG_SPL_FRAMEWORK) += $$(obj)u-boot.img

ALL-$$(CONFIG_TPL) += $$(obj)tpl/u-boot-tpl.bin

ALL-$$(CONFIG_OF_SEPARATE) += $$(obj)u-boot.dtb $$(obj)u-boot-dtb.bin

ifneq ($$(CONFIG_SPL_TARGET),)

ALL-$$(CONFIG_SPL) += $$(obj)$$(subst ”,,$$(CONFIG_SPL_TARGET))

endif

# enable combined SPL/u-boot/dtb rules for tegra

ifneq ($$(CONFIG_TEGRA),)

ifeq ($$(CONFIG_OF_SEPARATE),y)

ALL-y += $$(obj)u-boot-dtb-tegra.bin

else

ALL-y += $$(obj)u-boot-nodtb-tegra.bin

endif

endif

因为本节是讨论SPL, 所以我们只关注其中的一句ALL-$$(CONFIG_SPL) += $$(obj)spl/u-boot-spl.bin

这句话表明

必须定义CONFIG_SPL才能编译出spl的bin: 一般在“include/configs/$${CONFIG_NAME}.h”中定义

SPL的bin依赖于u-boot-spl.bin

接着往下看

[plain] view plaincopy$$(obj)spl/u-boot-spl.bin: $$(SUBDIR_TOOLS) depend

$$(MAKE) -C spl all

[plain] view plain copy$$(obj)spl/u-boot-spl.bin: $$(SUBDIR_TOOLS) depend

$$(MAKE) -C spl all

这里可以发现, u-boot-spl.bin依赖于 $$(SUBDIR_TOOLS) depend

$$(SUBDIR_TOOLS) : 暂不分析

depend: 参考附录中的depend

进入spl目录, 执行make all

接下来进入spl目录, 看看它的Makefile : 这里只分析与SPL相关的部分

[plain] view plaincopyCONFIG_SPL_BUILD := y

export CONFIG_SPL_BUILD

[plain] view plain copyCONFIG_SPL_BUILD := y

export CONFIG_SPL_BUILD

export CONFIG_SPL_BUILD: 在接下来的编译中, 这个变量为y. 从后面的分析中可以看到, uboot的stage1, stage2阶段的代码用的是同一个Start.S, 只不过在Start.S中用#ifdef CONFIG_SPL_BUILD这种条件编译来区分。 类似的还有其他一些文件。

[plain] view plaincopyHAVE_VENDOR_COMMON_LIB = $$(if $$(wildcard $$(SRCTREE)/board/$$(VENDOR)/common/Makefile),y,n)

[plain] view plain copyHAVE_VENDOR_COMMON_LIB = $$(if $$(wildcard $$(SRCTREE)/board/$$(VENDOR)/common/Makefile),y,n)

[cpp] view plaincopy如果board/$$(VENDOR)/common目录中有Makefile文件,则HAVE_VENDOR_COMMON_LIB为y否则为n

[cpp] view plain copy如果board/$$(VENDOR)/common目录中有Makefile文件,则HAVE_VENDOR_COMMON_LIB为y否则为n

[plain] view plaincopyifdef CONFIG_SPL_START_S_PATH

START_PATH := $$(subst “,,$$(CONFIG_SPL_START_S_PATH))

else

START_PATH := $$(CPUDIR)

endif

[plain] view plain copyifdef CONFIG_SPL_START_S_PATH

START_PATH := $$(subst ”,,$$(CONFIG_SPL_START_S_PATH))

else

START_PATH := $$(CPUDIR)

endif

我们这里没有定义CONFIG_SPL_START_S_PATH, 所以START_PATH := $$(CPUDIR)

[plain] view plaincopySTART := $$(START_PATH)/start.o

[plain] view plain copySTART := $$(START_PATH)/start.o

依赖start.o, 综合来看, 就是要把CPUDIR下的start.S编译进来。

[plain] view plaincopyLIBS-y += arch/$$(ARCH)/lib/lib$$(ARCH).o

[plain] view plain copyLIBS-y += arch/$$(ARCH)/lib/lib$$(ARCH).o

依赖lib$$(ARCH).o, 具体来看, 就是依赖arch/arm/lib/libarm.o

[plain] view plaincopyLIBS-y += $$(CPUDIR)/lib$$(CPU).o

[plain] view plain copyLIBS-y += $$(CPUDIR)/lib$$(CPU).o

依赖lib$$(CPU).o, 具体来看, 就是依赖arch/arm/cpu/armv7/libarmv7.o

[plain] view plaincopyifdef SOC

LIBS-y += $$(CPUDIR)/$$(SOC)/lib$$(SOC).o

endif

[plain] view plain copyifdef SOC

LIBS-y += $$(CPUDIR)/$$(SOC)/lib$$(SOC).o

endif

如果定义了SOC, 则依赖lib$$(SOC).o, 具体来看, 就是依赖arch/arm/cpu/s5pc1xx/libs5pc1xx.o

[plain] view plaincopyLIBS-y += board/$$(BOARDDIR)/lib$$(BOARD).o

[plain] view plain copyLIBS-y += board/$$(BOARDDIR)/lib$$(BOARD).o

依赖lib$$(BOARD).o, 具体来看, 就是依赖board/samsung/TIny210/libTIny210.o

[plain] view plaincopyLIBS-$$(HAVE_VENDOR_COMMON_LIB) += board/$$(VENDOR)/common/lib$$(VENDOR).o

[plain] view plain copyLIBS-$$(HAVE_VENDOR_COMMON_LIB) += board/$$(VENDOR)/common/lib$$(VENDOR).o

如果HAVE_VENDOR_COMMON_LIB为y, 则依赖lib$$(VENDOR).o, 具体来看, 就是依赖board/samsung/common/libsamsung.o

[plain] view plaincopyLIBS-$$(CONFIG_SPL_FRAMEWORK) += common/spl/libspl.o

LIBS-$$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/libcommon.o

LIBS-$$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/libdisk.o

LIBS-$$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/libi2c.o

LIBS-$$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/libgpio.o

LIBS-$$(CONFIG_SPL_MMC_SUPPORT) += drivers/mmc/libmmc.o

LIBS-$$(CONFIG_SPL_SERIAL_SUPPORT) += drivers/serial/libserial.o

LIBS-$$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/libspi_flash.o

LIBS-$$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/libspi.o

LIBS-$$(CONFIG_SPL_FAT_SUPPORT) += fs/fat/libfat.o

LIBS-$$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/libgeneric.o

LIBS-$$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/libpower.o

drivers/power/pmic/libpmic.o

LIBS-$$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/libnand.o

LIBS-$$(CONFIG_SPL_ONENAND_SUPPORT) += drivers/mtd/onenand/libonenand.o

LIBS-$$(CONFIG_SPL_DMA_SUPPORT) += drivers/dma/libdma.o

LIBS-$$(CONFIG_SPL_POST_MEM_SUPPORT) += post/drivers/memory.o

LIBS-$$(CONFIG_SPL_NET_SUPPORT) += net/libnet.o

LIBS-$$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/libnet.o

LIBS-$$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/phy/libphy.o

LIBS-$$(CONFIG_SPL_USBETH_SUPPORT) += drivers/net/phy/libphy.o

LIBS-$$(CONFIG_SPL_MUSB_NEW_SUPPORT) += drivers/usb/musb-new/libusb_musb-new.o

LIBS-$$(CONFIG_SPL_USBETH_SUPPORT) += drivers/usb/gadget/libusb_gadget.o

LIBS-$$(CONFIG_SPL_WATCHDOG_SUPPORT) += drivers/watchdog/libwatchdog.o

[plain] view plain copyLIBS-$$(CONFIG_SPL_FRAMEWORK) += common/spl/libspl.o

LIBS-$$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/libcommon.o

LIBS-$$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/libdisk.o

LIBS-$$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/libi2c.o

LIBS-$$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/libgpio.o

LIBS-$$(CONFIG_SPL_MMC_SUPPORT) += drivers/mmc/libmmc.o

LIBS-$$(CONFIG_SPL_SERIAL_SUPPORT) += drivers/serial/libserial.o

LIBS-$$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/libspi_flash.o

LIBS-$$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/libspi.o

LIBS-$$(CONFIG_SPL_FAT_SUPPORT) += fs/fat/libfat.o

LIBS-$$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/libgeneric.o

LIBS-$$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/libpower.o

drivers/power/pmic/libpmic.o

LIBS-$$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/libnand.o

LIBS-$$(CONFIG_SPL_ONENAND_SUPPORT) += drivers/mtd/onenand/libonenand.o

LIBS-$$(CONFIG_SPL_DMA_SUPPORT) += drivers/dma/libdma.o

LIBS-$$(CONFIG_SPL_POST_MEM_SUPPORT) += post/drivers/memory.o

LIBS-$$(CONFIG_SPL_NET_SUPPORT) += net/libnet.o

LIBS-$$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/libnet.o

LIBS-$$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/phy/libphy.o

LIBS-$$(CONFIG_SPL_USBETH_SUPPORT) += drivers/net/phy/libphy.o

LIBS-$$(CONFIG_SPL_MUSB_NEW_SUPPORT) += drivers/usb/musb-new/libusb_musb-new.o

LIBS-$$(CONFIG_SPL_USBETH_SUPPORT) += drivers/usb/gadget/libusb_gadget.o

LIBS-$$(CONFIG_SPL_WATCHDOG_SUPPORT) += drivers/watchdog/libwatchdog.o

根据具体配置, 选择相应的依赖关系

[plain] view plaincopyifeq ($$(SOC),exynos)

LIBS-y += $$(CPUDIR)/s5p-common/libs5p-common.o

endif

[plain] view plain copyifeq ($$(SOC),exynos)

LIBS-y += $$(CPUDIR)/s5p-common/libs5p-common.o

endif

如果SOC为exynos, 则依赖libs5p-common.o, 我们这里的SOC为s5pc1xx, 所以不依赖

[plain] view plaincopySTART := $$(addprefix $$(SPLTREE)/,$$(START))

LIBS := $$(addprefix $$(SPLTREE)/,$$(sort $$(LIBS-y)))

[plain] view plain copySTART := $$(addprefix $$(SPLTREE)/,$$(START))

LIBS := $$(addprefix $$(SPLTREE)/,$$(sort $$(LIBS-y)))

给START和LIBS加上前缀, $$(SPLTREE), 具体来看, 就是编译过程中生成的.o文件都会放到spl/目录下面

[plain] view plaincopy# Linker Script

ifdef CONFIG_SPL_LDSCRIPT

# need to strip off double quotes

LDSCRIPT := $$(addprefix $$(SRCTREE)/,$$(subst “,,$$(CONFIG_SPL_LDSCRIPT)))

endif

ifeq ($$(wildcard $$(LDSCRIPT)),)

LDSCRIPT := $$(TOPDIR)/board/$$(BOARDDIR)/u-boot-spl.lds

endif

ifeq ($$(wildcard $$(LDSCRIPT)),)

LDSCRIPT := $$(TOPDIR)/$$(CPUDIR)/u-boot-spl.lds

endif

ifeq ($$(wildcard $$(LDSCRIPT)),)

LDSCRIPT := $$(TOPDIR)/arch/$$(ARCH)/cpu/u-boot-spl.lds

endif

ifeq ($$(wildcard $$(LDSCRIPT)),)

$$(error could not find linker script)

endif

[plain] view plain copy# Linker Script

ifdef CONFIG_SPL_LDSCRIPT

# need to strip off double quotes

LDSCRIPT := $$(addprefix $$(SRCTREE)/,$$(subst ”,,$$(CONFIG_SPL_LDSCRIPT)))

endif

ifeq ($$(wildcard $$(LDSCRIPT)),)

LDSCRIPT := $$(TOPDIR)/board/$$(BOARDDIR)/u-boot-spl.lds

endif

ifeq ($$(wildcard $$(LDSCRIPT)),)

LDSCRIPT := $$(TOPDIR)/$$(CPUDIR)/u-boot-spl.lds

endif

ifeq ($$(wildcard $$(LDSCRIPT)),)

LDSCRIPT := $$(TOPDIR)/arch/$$(ARCH)/cpu/u-boot-spl.lds

endif

ifeq ($$(wildcard $$(LDSCRIPT)),)

$$(error could not find linker script)

endif

找到spl的链接配置文件, 具体来看, 用的是arch/arm/cpu下的u-boot-spl.lds

[plain] view plaincopyALL-y += $$(obj)$$(SPL_BIN).bin

ifdef CONFIG_SAMSUNG

ALL-y += $$(obj)$$(BOARD)-spl.bin

endif

all: $$(ALL-y)

ifdef CONFIG_SAMSUNG

$$(obj)$$(BOARD)-spl.bin: $$(obj)u-boot-spl.bin

$$(OBJTREE)/tools/mk$$(BOARD)spl

$$(obj)u-boot-spl.bin $$(obj)$$(BOARD)-spl.bin

endif

$$(obj)$$(SPL_BIN).bin: $$(obj)$$(SPL_BIN)

$$(OBJCOPY) $$(OBJCFLAGS) -O binary $$《 $$@

GEN_UBOOT =

cd $$(obj) && $$(LD) $$(LDFLAGS) $$(LDFLAGS_$$(@F)) $$(__START)

--start-group $$(__LIBS) --end-group $$(PLATFORM_LIBS)

-Map $$(SPL_BIN).map -o $$(SPL_BIN)

$$(obj)$$(SPL_BIN): depend $$(START) $$(LIBS) $$(obj)u-boot-spl.lds

$$(GEN_UBOOT)

$$(START): depend

$$(MAKE) -C $$(SRCTREE)/$$(START_PATH) $$@

$$(LIBS): depend

$$(MAKE) -C $$(SRCTREE)$$(dir $$(subst $$(SPLTREE),,$$@))

$$(obj)u-boot-spl.lds: $$(LDSCRIPT) depend

$$(CPP) $$(CPPFLAGS) $$(LDPPFLAGS) -I$$(obj)。 -ansi -D__ASSEMBLY__ -P - 《 $$《 》 $$@

depend: $$(obj).depend

.PHONY: depend

[plain] view plain copyALL-y += $$(obj)$$(SPL_BIN).bin

ifdef CONFIG_SAMSUNG

ALL-y += $$(obj)$$(BOARD)-spl.bin

endif

all: $$(ALL-y)

ifdef CONFIG_SAMSUNG

$$(obj)$$(BOARD)-spl.bin: $$(obj)u-boot-spl.bin

$$(OBJTREE)/tools/mk$$(BOARD)spl

$$(obj)u-boot-spl.bin $$(obj)$$(BOARD)-spl.bin

endif

$$(obj)$$(SPL_BIN).bin: $$(obj)$$(SPL_BIN)

$$(OBJCOPY) $$(OBJCFLAGS) -O binary $$《 $$@

GEN_UBOOT =

cd $$(obj) && $$(LD) $$(LDFLAGS) $$(LDFLAGS_$$(@F)) $$(__START)

--start-group $$(__LIBS) --end-group $$(PLATFORM_LIBS)

-Map $$(SPL_BIN).map -o $$(SPL_BIN)

$$(obj)$$(SPL_BIN): depend $$(START) $$(LIBS) $$(obj)u-boot-spl.lds

$$(GEN_UBOOT)

$$(START): depend

$$(MAKE) -C $$(SRCTREE)/$$(START_PATH) $$@

$$(LIBS): depend

$$(MAKE) -C $$(SRCTREE)$$(dir $$(subst $$(SPLTREE),,$$@))

$$(obj)u-boot-spl.lds: $$(LDSCRIPT) depend

$$(CPP) $$(CPPFLAGS) $$(LDPPFLAGS) -I$$(obj)。 -ansi -D__ASSEMBLY__ -P - 《 $$《 》 $$@

depend: $$(obj).depend

.PHONY: depend

all: $$(ALL-y), 还记得本篇上面说的, 进入到spl目录下之后干啥事吗? 没错, 执行make all, 其实执行的就是这里的all目标。 它依赖$$(ALL-y)。 具体的依赖关系就不赘述了, 顺藤摸瓜即可

ifdef CONFIG_SAMSUNG: 这个是针对Samsung平台的特殊之处。

利用tools/mk$$(BOARD)spl这个工具, 将u-boot-spl.bin转为$$(BOARD)-spl.bin

转换的本质, 就是在u-boot-spl.bin前面加入head info.关于head info是什么, 可以参考文档S5PV210_iROM_ApplicaTIonNote_Preliminary_20091126.pdf. 顺便可以理解一下samsung芯片的启动流程

tools/mk$$(BOARD)spl这个工具是在tools/Makefile里面生成的。

OK, 分析结束, 接下来, 就基于我们上面的分析开始分析代码了。

SPL代码分析

u-boot-spl.lds: 它的位置在上文中我们分析了

根据u-boot-spl.lds中的规则, 我们知道CPUDIR/start.o被放在了最前面。 它所对应的文件就是arch/arm/cpu/armv7/start.S

start.S

下面我们看看start.S

[plain] view plaincopy.globl _start

_start: b 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

[plain] view plain copy.globl _start

_start: b 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

_start是我们在lds里面指定的ENTRY(_start)

首先会跳转到reset处

ldr pc, _xxx定义的是中断向量表

[plain] view plaincopy#ifdef CONFIG_SPL_BUILD

_undefined_instruction: .word _undefined_instruction

_software_interrupt: .word _software_interrupt

_prefetch_abort: .word _prefetch_abort

_data_abort: .word _data_abort

_not_used: .word _not_used

_irq: .word _irq

_fiq: .word _fiq

_pad: .word 0x12345678 /* now 16*4=64 */

#else

_undefined_instruction: .word undefined_instruction

_software_interrupt: .word software_interrupt

_prefetch_abort: .word prefetch_abort

_data_abort: .word data_abort

_not_used: .word not_used

_irq: .word irq

_fiq: .word fiq

_pad: .word 0x12345678 /* now 16*4=64 */

#endif /* CONFIG_SPL_BUILD */

[plain] view plain copy#ifdef CONFIG_SPL_BUILD

_undefined_instruction: .word _undefined_instruction

_software_interrupt: .word _software_interrupt

_prefetch_abort: .word _prefetch_abort

_data_abort: .word _data_abort

_not_used: .word _not_used

_irq: .word _irq

_fiq: .word _fiq

_pad: .word 0x12345678 /* now 16*4=64 */

#else

_undefined_instruction: .word undefined_instruction

_software_interrupt: .word software_interrupt

_prefetch_abort: .word prefetch_abort

_data_abort: .word data_abort

_not_used: .word not_used

_irq: .word irq

_fiq: .word fiq

_pad: .word 0x12345678 /* now 16*4=64 */

#endif /* CONFIG_SPL_BUILD */

当CONFIG了SPL_BUILD之后, 一旦发生异常中断, 就会进入死循环。 所以我们的SPL里面不允许出发异常中断

不过正常的uboot(即stage2阶段)还是可以处理异常中断的。

reset

[plain] view plaincopy/*

* the actual reset code

*/

reset:

bl save_boot_params

/*

* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,

* except if in HYP mode already

*/

mrs r0, cpsr

and r1, r0, #0x1f @ mask mode bits

teq r1, #0x1a @ test for HYP mode

bicne r0, r0, #0x1f @ clear all mode bits

orrne r0, r0, #0x13 @ set SVC mode

orr r0, r0, #0xc0 @ disable FIQ and IRQ

msr cpsr,r0

/* 。。。。。。。。 */

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

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl cpu_init_cp15

bl cpu_init_crit

#endif

bl _main

[plain] view plain copy/*

* the actual reset code

*/

reset:

bl save_boot_params

/*

* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,

* except if in HYP mode already

*/

mrs r0, cpsr

and r1, r0, #0x1f @ mask mode bits

teq r1, #0x1a @ test for HYP mode

bicne r0, r0, #0x1f @ clear all mode bits

orrne r0, r0, #0x13 @ set SVC mode

orr r0, r0, #0xc0 @ disable FIQ and IRQ

msr cpsr,r0

/* 。。。。。。。。 */

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

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl cpu_init_cp15

bl cpu_init_crit

#endif

bl _main

当初次上电或者复位时, Uboot最新运行的就是这里的代码

bl save_boot_params: 如果没有重新定义save_boot_params,则使用《arch/arm/cpu/armv7/start.S》中的save_boot_params。其不做任何事情,直接返回

禁止FIQ, IRQ; 设置CPU工作在SVC32模式

bl cpu_init_cp15: (I/D-Cache, MMU, TLBs),具体见下面代码中注释

bl cpu_init_crit : 主要是设置CPU的PLL, GPIO管脚复用, memory等。 具体见下面

bl _main : 跳转到《arch/arm/lib/crt0.S》中的_main. 具体见下面

cpu_init_cp15

[plain] view plaincopy/*************************************************************************

*

* cpu_init_cp15

*

* Setup CP15 registers (cache, MMU, TLBs)。 The I-cache is turned on unless

* CONFIG_SYS_ICACHE_OFF is defined.

*

*************************************************************************/

ENTRY(cpu_init_cp15)

/*

* Invalidate L1 I/D

*/

mov r0, #0 @ set up for MCR

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

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

mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array

mcr p15, 0, r0, c7, c10, 4 @ DSB

mcr p15, 0, r0, c7, c5, 4 @ ISB

/*

* disable MMU stuff and caches

*/

mrc p15, 0, r0, c1, c0, 0

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

bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)

orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align

orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB

#ifdef CONFIG_SYS_ICACHE_OFF

bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache

#else

orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache

#endif

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

#ifdef CONFIG_ARM_ERRATA_716044

mrc p15, 0, r0, c1, c0, 0 @ read system control register

orr r0, r0, #1 《《 11 @ set bit #11

mcr p15, 0, r0, c1, c0, 0 @ write system control register

#endif

#ifdef CONFIG_ARM_ERRATA_742230

mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register

orr r0, r0, #1 《《 4 @ set bit #4

mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register

#endif

#ifdef CONFIG_ARM_ERRATA_743622

mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register

orr r0, r0, #1 《《 6 @ set bit #6

mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register

#endif

#ifdef CONFIG_ARM_ERRATA_751472

mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register

orr r0, r0, #1 《《 11 @ set bit #11

mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register

#endif

mov pc, lr @ back to my caller

ENDPROC(cpu_init_cp15)

[plain] view plain copy/*************************************************************************

*

* cpu_init_cp15

*

* Setup CP15 registers (cache, MMU, TLBs)。 The I-cache is turned on unless

* CONFIG_SYS_ICACHE_OFF is defined.

*

*************************************************************************/

ENTRY(cpu_init_cp15)

/*

* Invalidate L1 I/D

*/

mov r0, #0 @ set up for MCR

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

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

mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array

mcr p15, 0, r0, c7, c10, 4 @ DSB

mcr p15, 0, r0, c7, c5, 4 @ ISB

/*

* disable MMU stuff and caches

*/

mrc p15, 0, r0, c1, c0, 0

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

bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)

orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align

orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB

#ifdef CONFIG_SYS_ICACHE_OFF

bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache

#else

orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache

#endif

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

#ifdef CONFIG_ARM_ERRATA_716044

mrc p15, 0, r0, c1, c0, 0 @ read system control register

orr r0, r0, #1 《《 11 @ set bit #11

mcr p15, 0, r0, c1, c0, 0 @ write system control register

#endif

#ifdef CONFIG_ARM_ERRATA_742230

mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register

orr r0, r0, #1 《《 4 @ set bit #4

mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register

#endif

#ifdef CONFIG_ARM_ERRATA_743622

mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register

orr r0, r0, #1 《《 6 @ set bit #6

mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register

#endif

#ifdef CONFIG_ARM_ERRATA_751472

mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register

orr r0, r0, #1 《《 11 @ set bit #11

mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register

#endif

mov pc, lr @ back to my caller

ENDPROC(cpu_init_cp15)

cpu_init_crit

[plain] view plaincopy#ifndef CONFIG_SKIP_LOWLEVEL_INIT

/*************************************************************************

*

* CPU_init_critical registers

*

* setup important registers

* setup memory timing

*

*************************************************************************/

ENTRY(cpu_init_crit)

/*

* 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.

*/

b lowlevel_init @ go setup pll,mux,memory

ENDPROC(cpu_init_crit)

#endif

[plain] view plain copy#ifndef CONFIG_SKIP_LOWLEVEL_INIT

/*************************************************************************

*

* CPU_init_critical registers

*

* setup important registers

* setup memory timing

*

*************************************************************************/

ENTRY(cpu_init_crit)

/*

* 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.

*/

b lowlevel_init @ go setup pll,mux,memory

ENDPROC(cpu_init_crit)

#endif

b lowlevel_init : 跳转到《arch/arm/cpu/armv7/lowlevel_init.S》中的lowlevel_init

lowlevel_init.S

lowlevel_init

[plain] view plaincopy#include 《asm-offsets.h》

#include 《config.h》

#include 《linux/linkage.h》

ENTRY(lowlevel_init)

/*

* Setup a temporary stack

*/

ldr sp, =CONFIG_SYS_INIT_SP_ADDR

bic sp, sp, #7 /* 8-byte alignment for ABI compliance */

#ifdef CONFIG_SPL_BUILD

ldr r9, =gdata

#else

sub sp, #GD_SIZE

bic sp, sp, #7

mov r9, sp

#endif

/*

* Save the old lr(passed in ip) and the current lr to stack

*/

push {ip, lr}

/*

* go setup pll, mux, memory

*/

bl s_init

pop {ip, pc}

[plain] view plain copy#include 《asm-offsets.h》

#include 《config.h》

#include 《linux/linkage.h》

ENTRY(lowlevel_init)

/*

* Setup a temporary stack

*/

ldr sp, =CONFIG_SYS_INIT_SP_ADDR

bic sp, sp, #7 /* 8-byte alignment for ABI compliance */

#ifdef CONFIG_SPL_BUILD

ldr r9, =gdata

#else

sub sp, #GD_SIZE

bic sp, sp, #7

mov r9, sp

#endif

/*

* Save the old lr(passed in ip) and the current lr to stack

*/

push {ip, lr}

/*

* go setup pll, mux, memory

*/

bl s_init

pop {ip, pc}

以前老版本的uboot, lowlevel_init一般都是在board/xxx下面的板级文件夹下面实现的。 现在直接放到CPUDIR下面了, 那它做了什么事情呢

对stack pointer赋值成CONFIG_SYS_INIT_SP_ADDR

确保sp是8字节对齐

将gdata的地址存入到r9寄存器中

跳转到 s_init: 这个s_init就需要芯片厂商或者我们自己在板级文件里面实现了。 它主要做的事情

setup pll, mux, memory

我个人感觉, 新版本的uboot在CPUDIR下实现了一个lowlevel_init.S文件, 主要目标是初始化sp, 这样s_init就可以用C语言实现了。 而以前的老版本里面, s_init里面要做的事情都是用汇编做的。

crt0.S

_main

[plain] view plaincopyENTRY(_main)

/*

* Set up initial C runtime environment and call board_init_f(0)。

*/

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)

ldr sp, =(CONFIG_SPL_STACK)

#else

ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)

#endif

bic sp, sp, #7 /* 8-byte alignment for ABI compliance */

sub sp, #GD_SIZE /* allocate one GD above SP */

bic sp, sp, #7 /* 8-byte alignment for ABI compliance */

mov r9, sp /* GD is above SP */

mov r0, #0

bl board_init_f

[plain] view plain copyENTRY(_main)

/*

* Set up initial C runtime environment and call board_init_f(0)。

*/

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)

ldr sp, =(CONFIG_SPL_STACK)

#else

ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)

#endif

bic sp, sp, #7 /* 8-byte alignment for ABI compliance */

sub sp, #GD_SIZE /* allocate one GD above SP */

bic sp, sp, #7 /* 8-byte alignment for ABI compliance */

mov r9, sp /* GD is above SP */

mov r0, #0

bl board_init_f

重新对SP赋值, 确认sp是8字对齐

在栈顶保留一个global_data的大小, 这个global_data是uboot里面的一个全局数据, 很多地方都会用到。 俗称 gd_t

确认更新后的sp是8字对齐

r9指向global_data, 后面别的地方想用global_data时候, 可以直接从r9里面获取地址。

r0赋值0

bl board_init_f: 跳转到board_init_f. 在编译SPL时, 分析Makefile可以看出, 该函数的实现是在《arch/arm/lib/spl.c》。

arch/arm/lib/spl.c

board_init_f

[plain] view plaincopy/*

* In the context of SPL, board_init_f must ensure that any clocks/etc for

* DDR are enabled, ensure that the stack pointer is valid, clear the BSS

* and call board_init_f. We provide this version by default but mark it

* as __weak to allow for platforms to do this in their own way if needed.

*/

void __weak board_init_f(ulong dummy)

{

/* Clear the BSS. */

memset(__bss_start, 0, __bss_end - __bss_start);

/* Set global data pointer. */

gd =

board_init_r(NULL, 0);

}

[plain] view plain copy/*

* In the context of SPL, board_init_f must ensure that any clocks/etc for

* DDR are enabled, ensure that the stack pointer is valid, clear the BSS

* and call board_init_f. We provide this version by default but mark it

* as __weak to allow for platforms to do this in their own way if needed.

*/

void __weak board_init_f(ulong dummy)

{

/* Clear the BSS. */

memset(__bss_start, 0, __bss_end - __bss_start);

/* Set global data pointer. */

gd =

board_init_r(NULL, 0);

}

__weak: 表明该函数可以被重新定义

对BSS段进行清零操作

gd =

gd的定义在DECLARE_GLOBAL_DATA_PTR 《arch/arm/include/asm/global_data.h》

#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm (“r9”)

还记得r9这个寄存器吗, 在上面初始化过了

gdata的定义在本文件中: gd_t gdata __attribute__ ((section(“.data”)));

它是一个 gd_t 也就是global_data类型的变量

__attribute__表示这个变量会被放到“.data”这个输入段中。 连接器会把输入段按照链接脚本(u-boot-spl.lds)里面指定的规则存放到输出段。

为什么会有这个赋值操作, 不太明白。。。

board_init_r : 在编译SPL时, 分析Makefile可以看出, 该函数的实现是在《common/spl/spl.c》

common/spl/spl.c

board_init_r

[plain] view plaincopy#ifdef CONFIG_SYS_SPL_MALLOC_START

mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,

CONFIG_SYS_SPL_MALLOC_SIZE);

#endif

[plain] view plain copy#ifdef CONFIG_SYS_SPL_MALLOC_START

mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,

CONFIG_SYS_SPL_MALLOC_SIZE);

#endif

如果定义了:CONFIG_SYS_SPL_MALLOC_START, 则进行memory的malloc池初始化。 以后调用malloc就在这个池子里面分配内存

[plain] view plaincopy#ifndef CONFIG_PPC

/*

* timer_init() does not exist on PPC systems. The timer is initialized

* and enabled (decrementer) in interrupt_init() here.

*/

timer_init();

#endif

[plain] view plain copy#ifndef CONFIG_PPC

/*

* timer_init() does not exist on PPC systems. The timer is initialized

* and enabled (decrementer) in interrupt_init() here.

*/

timer_init();

#endif

如果没有定义:CONFIG_PPC, 则进行timer的初始化。 《arch/arm/cpu/armv7/s5p-common/timer.c》里面定义

[plain] view plaincopy#ifdef CONFIG_SPL_BOARD_INIT

spl_board_init();

#endif

[plain] view plain copy#ifdef CONFIG_SPL_BOARD_INIT

spl_board_init();

#endif

SPL阶段, 如果还需要做什么初始化动作, 可以放在这里。 具体的实现可以在BOARDDIR下面。

[plain] view plaincopyboot_device = spl_boot_device();

debug(“boot device - %d”, boot_device);

[plain] view plain copyboot_device = spl_boot_device();

debug(“boot device - %d”, boot_device);

必须实现spl_boot_device, 返回是从哪个外部设备启动的(NAND/SDCARD/NOR.。。)。 可以厂商或者自己在BOARDDIR下面实现

[plain] view plaincopyswitch (boot_device) {

#ifdef CONFIG_SPL_RAM_DEVICE

case BOOT_DEVICE_RAM:

spl_ram_load_image();

break;

#endif

#ifdef CONFIG_SPL_MMC_SUPPORT

case BOOT_DEVICE_MMC1:

case BOOT_DEVICE_MMC2:

case BOOT_DEVICE_MMC2_2:

spl_mmc_load_image();

break;

#endif

#ifdef CONFIG_SPL_NAND_SUPPORT

case BOOT_DEVICE_NAND:

spl_nand_load_image();

break;

#endif

#ifdef CONFIG_SPL_ONENAND_SUPPORT

case BOOT_DEVICE_ONENAND:

spl_onenand_load_image();

break;

#endif

#ifdef CONFIG_SPL_NOR_SUPPORT

case BOOT_DEVICE_NOR:

spl_nor_load_image();

break;

#endif

#ifdef CONFIG_SPL_YMODEM_SUPPORT

case BOOT_DEVICE_UART:

spl_ymodem_load_image();

break;

#endif

#ifdef CONFIG_SPL_SPI_SUPPORT

case BOOT_DEVICE_SPI:

spl_spi_load_image();

break;

#endif

#ifdef CONFIG_SPL_ETH_SUPPORT

case BOOT_DEVICE_CPGMAC:

#ifdef CONFIG_SPL_ETH_DEVICE

spl_net_load_image(CONFIG_SPL_ETH_DEVICE);

#else

spl_net_load_image(NULL);

#endif

break;

#endif

#ifdef CONFIG_SPL_USBETH_SUPPORT

case BOOT_DEVICE_USBETH:

spl_net_load_image(“usb_ether”);

break;

#endif

default:

debug(“SPL: Un-supported Boot Device”);

hang();

}

[plain] view plain copy switch (boot_device) {

#ifdef CONFIG_SPL_RAM_DEVICE

case BOOT_DEVICE_RAM:

spl_ram_load_image();

break;

#endif

#ifdef CONFIG_SPL_MMC_SUPPORT

case BOOT_DEVICE_MMC1:

case BOOT_DEVICE_MMC2:

case BOOT_DEVICE_MMC2_2:

spl_mmc_load_image();

break;

#endif

#ifdef CONFIG_SPL_NAND_SUPPORT

case BOOT_DEVICE_NAND:

spl_nand_load_image();

break;

#endif

#ifdef CONFIG_SPL_ONENAND_SUPPORT

case BOOT_DEVICE_ONENAND:

spl_onenand_load_image();

break;

#endif

#ifdef CONFIG_SPL_NOR_SUPPORT

case BOOT_DEVICE_NOR:

spl_nor_load_image();

break;

#endif

#ifdef CONFIG_SPL_YMODEM_SUPPORT

case BOOT_DEVICE_UART:

spl_ymodem_load_image();

break;

#endif

#ifdef CONFIG_SPL_SPI_SUPPORT

case BOOT_DEVICE_SPI:

spl_spi_load_image();

break;

#endif

#ifdef CONFIG_SPL_ETH_SUPPORT

case BOOT_DEVICE_CPGMAC:

#ifdef CONFIG_SPL_ETH_DEVICE

spl_net_load_image(CONFIG_SPL_ETH_DEVICE);

#else

spl_net_load_image(NULL);

#endif

break;

#endif

#ifdef CONFIG_SPL_USBETH_SUPPORT

case BOOT_DEVICE_USBETH:

spl_net_load_image(“usb_ether”);

break;

#endif

default:

debug(“SPL: Un-supported Boot Device”);

hang();

}

将image从具体的外部设备中load到ram中。 这里暂时先不分析具体的load过程。

[plain] view plaincopyswitch (spl_image.os) {

case IH_OS_U_BOOT:

debug(“Jumping to U-Boot”);

break;

#ifdef CONFIG_SPL_OS_BOOT

case IH_OS_LINUX:

debug(“Jumping to Linux”);

spl_board_prepare_for_linux();

jump_to_image_linux((void *)CONFIG_SYS_SPL_ARGS_ADDR);

#endif

default:

debug(“Unsupported OS image.。 Jumping nevertheless.。”);

}

jump_to_image_no_args(&spl_image);

[plain] view plain copy switch (spl_image.os) {

case IH_OS_U_BOOT:

debug(“Jumping to U-Boot”);

break;

#ifdef CONFIG_SPL_OS_BOOT

case IH_OS_LINUX:

debug(“Jumping to Linux”);

spl_board_prepare_for_linux();

jump_to_image_linux((void *)CONFIG_SYS_SPL_ARGS_ADDR);

#endif

default:

debug(“Unsupported OS image.。 Jumping nevertheless.。”);

}

jump_to_image_no_args(&spl_image);

判断image的类型

如果是u-boot,则直接break, 去运行u-boot

如果是Linux,则启动Linux

至此,SPL结束它的生命,控制权交于u-boot或Linux

在接下来的一篇中, 我们会分析当控制权交给u-boot之后, uboot的运行流程

总结

SPL移植注意点

s_init: C语言实现此函数, 必须的。 如果是厂商提供的, 一般在arch/arm/cpu/xxx下面。 如果厂商没有提供, 我们可以在BOARDDIR下面实现。 主要完成以下功能

设置CPU的PLL, GPIO管脚复用, memory等

spl_board_init: C语言实现, 可选的。 如果是厂商提供的, 一般在arch/arm/cpu/xxx下面。 如果厂商没有提供, 我们可以在BOARDDIR下面实现。 主要完成的功能自己决定

spl_boot_device: C语言实现, 必须的。 如果是厂商提供的, 一般在arch/arm/cpu/xxx下面。 如果厂商没有提供, 我们可以在BOARDDIR下面实现。 主要完成的功能

返回是从什么设备启动的(NAND/SDCARD/Nor 。。。)。 像Atmel, Samsung的芯片, 都是有办法做这个事情的.


UBOOT添加新的显示支持uboot添加新的显示支持。 一、MIPI接口能够连接的显示设备 OKMX8MM-C开发板只有一个MIPI DSI显示接口,这个接口除了可以连接MIPI显示屏,还可以通过MIPI转LVDS模块,连接LVDS显示屏或HDM2022-01-06 16:40:4657uboot成功移植到STM32F103ZET6(前言)三年前就想把uboot移植到STM32上,虽然官方已经有成功移植到F4的例程,不过是基于GCC的,对我们这些习惯使用MDK或IAR的帮助不大。当时想着把旧版本的uboot尝试移植到F1上,发现IAR2021-12-27 18:34:168IMX6ULL Uboot 移植使用的开发板:正点原子ALPHA V2.2Uboot简介在学习STM32的过程中使用过IAP在线升级就会知道,有引导程序+APP程序,即bootloader程序+APP。在学习嵌入式Linux的时候2021-12-22 19:08:427嵌入式linux学习 Day1 uboot基础嵌入式linux学习 Day1 uboot基础2021-12-05 20:51:076KEIL中启动文件详解(汇编语言)KEIL中启动文件详解(汇编语言)2021-12-04 12:06:092启明分享|ISP烧录uboot遇到问题解决方法及sigmastar工具使用说明SP烧录ubootISP烧录uboot无法连接设备(connect fail):1、是否购买了我们的烧录器(debug Tool)。2、是否安装ISP工具的驱动。3、PC是否能正常识别到烧录工具2021-12-03 19:51:0602021-07-28-uboot-CC2640uboot命令开发指南:30.4 uboot命令一、uboot启动log简析需要调试性质的开发 ,uboot都是烧写到SD卡中的;arm - linux-gnueabihf直接使用2021-11-30 09:51:0511SRAM在MCU中的作用飞外网站提供《SRAM在MCU中的作用.pdf》资料免费2021-11-16 09:21:0412SSD202D核心板ISP烧录uboot遇到问题时该如何解决有不少开发小伙伴使用SSD201 / SSD202D 核心板时,在ISP烧录uboot一般遇到最多的问题,启明云端用心整理了你在开发过程中可能会遇到的问题以及快速上手的简明教程供开发小伙伴参考2021-11-15 10:36:00122uboot研读笔记 | 00 - 嵌入式Linux系统中Bootloader的作用和基本运行原理1. 嵌入式Linux系统开发架构一个嵌入式Linux的系统的架构如下图:软件程序开发中,从下往上每一次的作用依次为:Bootloader:将硬件初始化,并将内核引导起来;Linux Kernel2021-11-02 13:36:318嵌入式Linux 系统启动流程,即SPL;三、二级启动:SPL+uboot1.SPL: Secondary Program Loader:作用:初始化DDR;从启动的设备搬移第二段代码到RAM中,加载uboot;...2021-11-01 16:26:231【嵌入式】构建嵌入式Linux系统(uboot、内核、文件系统)嵌入式Linux系统知识架构及层次嵌入式Linux系统构成及启动略析嵌入式Linux三剑客之uboot技术嵌入式Linux三剑客之内核技术嵌入式Linux三剑客之文件系统技术知识架构及层次Linux2021-10-20 18:20:5922旁路电容、去耦电容及滤波电容的作用详解旁路电容、去耦电容、滤波电容的作用介绍 什么是旁路电容、去耦电容、滤波电容?作用是什么? 滤波电容——用在电源整流电路中,用来滤除交流成分,使输出的直流更平滑。去耦电容——用在放大电路中不需要交流2021-06-21 23:23:111604汽车音响车规电容器在电路中的作用详解车规电容器在电路中的作用 汽车音响车规电容器在电路中的作用一二部详解 1、滤波:滤除电源中的各种噪声。电容器具有电极两端电压不能突变的特性,因此电源供应装置的噪声波被电容器吸收,在电源电路进入2021-06-10 14:47:57326Linux系统中EXP命令详解质量汇总Linux系统中EXP命令详解质量汇总2021-05-13 13:40:430很多人拿到uboot,编译不知如何下手!资料飞外网为你提供很多人拿到uboot,编译不知如何下手!资料的电子资料,更有其他相关的电路图、源代码、课件教程、中文资料、英文资料、参考设计、用户指南、解决方案等资料,希望可以帮助到广大的电子工程师们。2021-04-26 08:46:471详解单片机上拉电阻、下拉电阻的意义及作用资料飞外网为你提供详解单片机上拉电阻、下拉电阻的意义及作用资料的电子资料,更有其他相关的电路图、源代码、课件教程、中文资料、英文资料、参考设计、用户指南、解决方案等资料,希望可以帮助到广大的电子工程师们。2021-04-21 08:51:104高精度低功耗的小型双气压计芯片SPL06-007SPL06-007是一种高精度、低电流消耗的小型化双气压计。SPL06-007既是压力传感器又是温度传感器。压力传感器元件基于电容式传感原理,确保温度变化时的高精度。小型封装使SPL06-007成为2021-04-08 17:19:593电路中反馈的作用和计算详解资料飞外网为你提供电路中反馈的作用和计算详解资料的电子资料,更有其他相关的电路图、源代码、课件教程、中文资料、英文资料、参考设计、用户指南、解决方案等资料,希望可以帮助到广大的电子工程师们。2021-03-27 08:46:103产品认证中EMC知识详解原文标题:产品认证中EMC相关知识详解 文章出处:【微信公众号:电磁兼容之家】欢迎添加关注!文章转载请注明出处。 责任编辑:haq2020-10-22 09:32:421144关于升级uboot遇到的两个问题之前做过一次uboot的升级,当时留下了一些记录,本文摘录其中比较有意思的两个问题。2020-09-21 11:44:201402uboot它的作用是什么,它可以用来解决什么问题公共许可证之下发布的自由软件。 uboot 属于bootloader的一种,是用来引导启动内核的,它的最终目的就是,从flash中读出内核,放到内存中,启动内核,所以,由上面描述的,就知道,UBOOT2020-07-16 13:50:201060一文分析Uboot启动流程Uboot是嵌入式系统中最常用的bootloader,这里我们以s3c2410为例分析一下uboot的启动流程。首先通过uboot的链接文件,我们可以看到uboot运行是执行的第一段代码在start.S中。2020-06-20 10:07:092406贸泽电子开售Osram SPL SxL90A LiDAR激光器贸泽电子分销的Osram SPL S1L90A和SPL S4L90A激光器可在单个通道上提供120W、40A的典型输出,能效高达33%,并且它们的热阻非常低,即使在大电流下运行也很容易散热。2020-06-10 15:21:32719STM32标准外设库SPL转换成 Cube LLSTM32标准外设库SPL转换成Cube LL2020-01-09 10:31:462201搞嵌入式,为啥要有uboot?搞嵌入式的,为啥要有uboot?2020-01-09 09:48:501934英创信息技术快速启动Linux工控主板简介运行uboot命令,从而设置内核启动参数或者在现有内核出错的情况下新的内核更新系统等,同时内核会通过调试串口输出大部分的启动信息,方便用户对启动过程进行检查; 另外一种为快速启动模式,此模式下加载精简的uboot-spl,uboot-spl只初始化必要的硬件以使Linux内核能够正常启动,2019-09-24 21:04:53483关于电路中0欧电阻的作用电路中0欧电阻的作用2020-01-09 09:47:177088英创信息技术嵌入式Linux工控主板uboot命令简介在此基础上进行二次开发,从而快速完成应用产品的开发。 在本文中主要介绍其中uboot部分操作命令,即如何利用uboot命令进行启动参数的设置。EM9X60系列工控主板在uboot中实现了自动显示开机启动2019-09-24 20:56:10503SPL06-001数字压力传感器的数据手册免费SPL06-001是一种小型化的数字气压传感器,具有高精度和低电流消耗。SPL06-001是一个压力和温度传感器。压力传感器元件基于电容传感原理,保证温度变化时的高精度。小包装使SPL2019-12-13 14:14:33155uboot中进行LCD初始化的流程免费本文档的主要内容详细介绍的是uboot中进行LCD初始化的流程免费。2019-08-12 11:10:4910电容在pcb板中的作用电容在电路板的运行过程中是缺一不可的配置,在电路板中起着重要的作用,电容主要的作用是:耦合作用、滤波作用。2019-06-10 16:21:447464你知道Uboot中的net是怎样的?你知道Uboot中的net是怎样的?2019-04-02 14:28:25530你了解Embeded linux中的Uboot参数与内核?uboot环境变量:bootdelay、bootcmd、bootargs等参数,键与值用0x3d,即“=”隔开,两参数之间用0x00,即\0隔开2019-04-02 14:28:171070Uboot启动的全过程详细资料分析本文档的主要内容详细介绍的是Uboot启动的全过程详细资料分析。2019-04-24 19:29:055uboot的配置流程分析的,拿到源码包看README是个很好的习惯,比如uboot-2016-07的配置命令是这个样子的:在uboot-2013-01中,我们去到顶层目录下的boards.cfs文件中查看它支持的开发板和相应2020-10-09 03:02:0181电路中电阻的作用本视频主要详细介绍了电路中电阻的作用,分别是限流、分流、分压以及将电能转化为内能。2019-03-12 16:48:2531882PHP中传值赋值和引用赋值的详细资料详解本文档的主要内容详细介绍的是PHP中传值赋值和引用赋值的详细资料详解。2019-03-06 17:25:225晶闸管在电路中的作用晶闸管又叫可控硅。提到可控硅模块,人们都会想到它是一种类似于二极管的东西,但是详细作用往往不是特别了解,尤其是在电路中的作用更是知之甚少,下面就详细讲解可控硅模块在电路中的作用。2019-01-19 14:41:0117261关于uboot的功能分析透彻方案如果我们想快速的移植uboot,那么我们就要先将我们用到的uboot的功能分析透彻,uboot最终目的就是**引导内核**,但是在实际开发中为了方便开发调试,我们将uboot加入了很多功能,比如2018-07-31 09:10:584543PCB中TOP PASTE和TOP SOLDER的区别_PCB层的含义详解本文首先介绍了PCB的作用及特点,其次阐述了PCB中TOP PASTE和TOP SOLDER的区别,最后介绍了PCB层的含义详解,具体的跟随小编一起来了解一下。2018-05-17 18:16:5557055AM335x uboot spl分析在335x 中ROM code是第一级的bootlader。mpu上电后将会自动执行这里的代码,完成部分初始化和引导第二级的bootlader,第二级的bootlader引导第三级bootader,在ti官方上对于第二级和第三级的bootlader由uboot提供。 2018-04-10 07:21:012964AM335x UBOOT移植编译命令详细概述本文的主要内容是TI的产品AM335x 的UBOOT移植编译命令详细概述2018-04-24 16:30:5433AM335x如何在Uboot时增加自定义的命令控制LCD功能中文概述图片生成十六进制的数据数组四. 在新版本的processor SDK v3.0中,在uboot阶段如何实现增加LCD logo的显示五. 基于第四点内容,增加Uboot的命令,效果是在Uboot进入命令模式,使用自定义的命令控制LCD屏的开、关和复位2018-04-23 17:13:349Sitara AM335x Bootloader的流程分析详细概述文章内容:第一部分概括移植Linux的启动整体步骤,接着第二部分会描述出厂固化在am335x的ROM code的作用、引导模式和执行流程,然后第三部分描述SPL和Uboot的运行的位置和一下基础性知识。最后就是重点:SPL、Uboot的流程图,以及DDR的内容分布。2018-04-23 15:53:4034基于ARM9 2410之上uboot移植全过程解析uboot 移植全过程---基于ARM9 2410 uboot@localhost ~]#mkdir -p dev_home/uboot [uboot@localhost ~]#cd2018-04-04 00:54:01417674ls245的工作原理及作用详解本文开始介绍了74HC245的作用与74hc245引脚及功能,其次介绍了 74LS245工作原理,最后介绍了74LS245N使用及仿真详解。2018-01-27 09:53:5440546对于嵌入式为什么要有uboot的深度解析(1)uboot主要作用是用来启动操作系统内核。(2)uboot还要负责部署整个计算机系统。(3)uboot中还有操作Flash等板子上硬盘的驱动。(4)uboot还得提供一个命令行界面供人来操作。2018-01-17 17:18:4723998uboot编译过程详细分析现在的uboot已经做得和kernel很像,最主要的一点是,uboot也使用了dtb的方法,将设备树和代码分离开来(当然可以通过宏来控制)。2017-12-11 16:11:2019806UBOOT命令总结分享到: 很好的UBOOT命令总结,起步时就是看的这篇东西,熟悉了以后就用?看自带帮助就行:) Printenv 打印环境变量。 Uboot》 printenv baudrate=1152002017-11-08 10:30:2015Uboot中start.S源码的指令级的详尽解析Uboot中start.S源码的指令级的详尽解析2017-10-30 08:50:2518Uboot移植步骤详解Uboot移植步骤详解2017-10-30 08:47:3917在Linux运行期间升级Linux系 统Uboot+kernel+Rootfs在Linux运行期间升级Linux系 统Uboot+kernel+Rootfs2017-10-30 08:45:405《Linux设备驱动开发详解》第7章、Linux设备驱动中的并发控制《Linux设备驱动开发详解》第7章、Linux设备驱动中的并发控制2017-10-27 11:40:318uboot移植详细解释uboot移植详细解释2017-10-26 10:10:5225uboot源码分析,思路还算清晰uboot源码分析,思路还算清晰2017-10-24 15:27:5918Exynos4x12 uboot developers_guideExynos4x12 uboot developers_guide2017-10-24 10:21:42651寄存器的所有寄存器名称,(包括寄存器每一位的作用及用法)资源详解51寄存器的所有寄存器名称,(包括寄存器每一位的作用及用法)资源详解2017-10-16 13:08:2312详解hashcode方法的作用一.hashCode方法的作用 对于包含容器类型的程序设计语言来说,基本上都会涉及到hashCode。在Java中也一样,hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散2017-09-26 17:18:520Java中bean的作用域java开发者都会在实体对象的属性中加上private关键字,而在业务类对外发放的方法中写上public关键字,这并不是习惯,而是开发者深谙其道,这就是java对象中filed的作用域。 举个2017-09-25 16:39:120uboot到底是干嘛的?1.为什么要有uboot1.1、计算机系统的主要部件(1)计算机系统就是以CPU为核心来运行的系统。典型的计2017-09-25 16:35:4714341电路中地的作用电路中地的作用,深刻解析模拟地和数字地的区别。2017-07-20 14:41:446uboot启动分析UBOOT 启动基本步奏分析2017-04-26 16:45:321电感在电路中的作用电感在电路中的作用2017-03-04 11:49:258编译uboot(Second Stage Boot Loader/SSBL)我们使用Digilent公司提供的uboot作为Second Stage Boot Loader(SSBL)。SSBL用于加载压缩的linux内核镜像,设备树文件,根文件系统到内存中,并解压2020-09-22 23:00:01109在github上Xilinx提供的Opensource linux和uboot内核gz格式压缩包的方法Xilinx提供的linux和uboot内核版本会不断地维护升级和更新,有些时候,我们碰到的问题可能换一个别的内核版本就能解决。在此,总结一下内核版本的方式,方便大家使用。 Step1:在浏览器2020-09-22 19:13:01152详解电源中的电容作用及注意事项详解电源中的电容作用及注意事项2017-01-10 13:16:3710VB中关于MSComm控件使用详解VB中关于MSComm控件使用详解2016-11-25 13:33:5415传感器检测中的抗干扰技术详解传感器检测中的抗干扰技术详解,学习资料,感兴趣的可以瞧一瞧。2016-09-30 21:23:3014磁珠资料--详解磁珠及其作用电路教程相关知识的资料,关于磁珠资料--详解磁珠及其作用2016-09-26 23:23:0833VC-MFC中socket编程详解VC编程---MFC中socket编程详解,感兴趣的可以看看。2016-08-31 21:56:4125PCB设计中地线干扰抑制方法详解PCB设计中地线干扰抑制方法详解,感兴趣的小伙伴们可以看看。2016-07-26 08:59:0516uboot分析和笔记移植uboot时应该修改和注意的地方。一般修改的是/include/configs/xxxxx.h和./include/configs/xxxx.h。2016-06-14 19:10:342电容作用详解电容的类型、单位换算、在电路起到的作用,2016-04-25 23:51:566电机控制与驱动电路设计中模拟信号隔离技巧详解电机控制与驱动电路设计中模拟信号隔离技巧详解2015-12-31 22:22:1773基于ar9331 mips架构AP121 uboot分析基于ar9331 mips架构AP121 uboot分析2015-11-29 16:41:2838uboot lds 文件说明linux 的uboot lds 文件说明2015-10-31 21:23:449uboot1-1-6代码详细分析uboot 1-1-6版本的 代码详细分析2015-10-31 21:24:0725基于AM335x的U-Boot/SPL 的CCS 调试在基于Linux的AM335x软件开发流程中,第一步就是U-Boot/SPL(SecondProgram Loader)的移植。##2.调试环境的准备##3.3 SPL的调试2014-08-21 15:51:217231详解照明电源的电容作用在日常生活中,我们不要轻视小小电容。他的作用很大,用过电容等的电子产品。什么地方都有如果用得不好,或用得好的,所以首先介绍电容的作用:2013-01-18 10:35:06865基于uboot的2410调试平台的实现首先移植一个可以用的uboot,至少要包含tftp和go命令,然后将其烧到nand flash里边,每次系统上电的时候能顺利运行uboot;然后我们将编译链接好的目标代码通过uboot到SDRAM里边,再从2011-12-28 10:12:523006UBoot移植方法详解U-Boot,全称Universal Boot Loader,是遵循GPL条款的开放源码项目。从FADSROM、8xxROM、PPCBOOT逐步发展演化而来。其源码目录、编译形式与Linux内核很相似,事实上,不少U-Boot源码就是相应的Li2011-12-15 15:13:59127OrCAD中创建总线及用法详解OrCAD中创建总线及用法详解,如何创建总线,菜单place->bus或者右侧快捷按钮2011-12-02 10:19:1621502路由协议的分类和作用详解介绍关于路由协议的概念、原理,路由协议的分类和作用详解。2011-11-03 15:11:427391SPL170精密直流电源用户手册SPL170 精密直流电源 (以下简称电源)是高稳定度直流线性恒流型功率电源。具有智能化程度高、稳定度好、精度高、使用方便、输出电流连续可调等优点。实现了源表一体化,特2010-07-24 23:39:185SPL120(A)数字功率计用户使用手册SPL120(A)数字功率计采用数字同步采样技术、准确测量单相用电设备的电压、电流、功率、功率因数、频率等参数的真有效值。仪表精度为0.5 级或0.2 级,具有测试速度快、精度2010-07-24 23:38:3513SPL710光强电参数测试仪用户使用手册LED 行业在高速发展,LED 应用日趋广泛,对于LED 的电性能及光强的测量,也显得越来越重要,为此,本公司研制了SPL710 LED 光强测试仪。该仪器具有用户自设定正向工作电流,2010-07-24 23:35:5520SPL100数字功率计用户使用手册SPL100数字功率计采用数字同步采样技术、准确测量单相用电设备的电压、电流、功率、功率因数、频率等参数的真有效值。仪表精度为0.5 级或0.2 级,具有测试速度快、精度高2010-07-24 23:32:4917SPL711 LED光通量电参数测试仪用户使用手册SPL711 LED光通量电参数测试仪用户使用手册:LED 行业在高速发展,LED 应用日趋广泛,对于LED 的电性能及光通量的测量,也显得越来越重要,为此,本公司研制了SPL711 LED 光通量测试仪2010-07-24 23:13:5027uboot中C语言代码入口函数(start_armboot)uboot中C语言代码入口函数(start_armboot)的注释uboot中C语言代码入口函数(start_armboot)的注释//打印BANK的相关信息display_dram_config,NULL, //用以标识2010-03-13 14:35:0959Uboot_readme中文注释版.rarUboot_readme中文注释版这是本人在网上搜集整理的,希望和我对大家能够有帮助,希望大家不断的将其完善,大家的改进版希望能够给我回发一份,感谢大家。2010-03-13 14:25:44172Jlink快速烧写TQ2440 ubootJlink快速烧写TQ2440 uboot说明:此手册为天嵌出品的《Jlink ---AXD 仿真实验手册》的姐妹篇。现在的pc ,越来越少并口了,特别是手提电脑。那怎么用Jtag 成为众多2010-03-10 13:54:03142SPL10A4+SPCA753A电路原理图 (SUNPLUSSPL10A4+SPCA753A电路原理图:SUNPLUS解决方案。2009-10-27 17:48:5333路由算法详解路由算法详解如果您已经阅读过博闻网中的路由器工作原理一文,您会了解到路由器的作用是管理网络流量和找到发送分组数据包的最佳路由。但是您是否想过2009-08-03 09:00:205415单片机中volatile定义的作用详解单片机中volatile定义的作用详解一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不2009-07-16 15:16:101971电源回路,电源回路详解,什么是电源回路电源回路,电源回路详解,什么是电源回路电源回路是主板中的一个重要组成部分,其作用是对主机电源输送过来的电流进行电压的转换,将电压变换2009-04-26 18:37:1612465北桥芯片详解北桥芯片详解 北桥芯片(North Bridge)是主板芯片组中起主导作用的最重要的组成部分,也称2009-04-26 17:41:281260速普乐SPL-10A电磁炉电路图速普乐SPL-10A电磁炉电路图2009-02-15 00:09:314473电感在电路中的作用电感在电路中的作用基本作用:滤波、振荡、延迟、陷波等 形象说法:“通直流,阻交流” 细化解2008-11-09 15:34:123193速普乐电磁炉电路图SPL-10A型速普乐电磁炉电路图SPL-10A型2008-01-24 12:35:4648