页次: 1
论坛上分享了很多F1C100s的裸机工程,但基本都是包含了这样那样RTOS系统的代码,对我这样的小白来说,感觉很复杂,缺少一个简单的裸机程序,帮助初学者入门。经过几天研究,成功的用最简单代码完成了裸机点灯,现在把笔记分享一下,高手请飘过。
## 开发环境搭建
在ubuntu下搭建开发环境很简单,只需要安装交叉编译工具链和sunxi-tools
### 1. 安装交叉编译工具链
$ sudo apt install gcc-arm-none-eabi
### 2. 安装sunxi-tools
克隆sunxi-tools仓库,签出f1c100s-spiflash分支
$ git clone https://github.com/Icenowy/sunxi-tools.git
$ git checkout f1c100s-spiflash
$ sudo make sunxi-fel && sudo make install
安装好以后,将nano的SPI Flash CS接地,进入FEL模式
$ sudo sunxi-fel ver
AWUSBFEX soc=00001663(F1C100s) 00000001 ver=0001 44 08 scratchpad=00007e00 00000000 00000000
烧录裸机程序
$ sudo sunxi-fel -p spiflash-write 0 blinkled.bin
编写裸机点亮LED程序
1. 启动代码 start.s
.text
.arm
.global _start
_start:
/* Boot head information for BROM */
.long 0xea000006
.byte 'e', 'G', 'O', 'N', '.', 'B', 'T', '0'
.long 0, __bootloader_size
.byte 'S', 'P', 'L', 2
.long 0, 0
_reset:
/* Initialize stacks. Interrupts disabled */
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xdb
msr cpsr, r0
ldr sp, _stack_und_end
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd7
msr cpsr, r0
ldr sp, _stack_abt_end
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd2
msr cpsr, r0
ldr sp, _stack_irq_end
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd1
msr cpsr, r0
ldr sp, _stack_fiq_end
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xdf
msr cpsr, r0
ldr sp, _stack_sys_end
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
ldr sp, _stack_srv_end
/* Set vector to the low address */
// mrc p15, 0, r0, c1, c0, 0
// bic r0, #0x20000
// mcr p15, 0, r0, c1, c0, 0
//
/* Call main */
ldr r1, =main
mov pc, r1
/*
* The location of section
*/
.align 4
_stack_und_end:
.long 0x00006C00
_stack_abt_end:
.long 0x00007000
_stack_irq_end:
.long 0x00007400
_stack_fiq_end:
.long 0x00007800
_stack_sys_end:
.long 0x00008000
_stack_srv_end:
.long 0x00007C00
这段程序包括这样几个方面的内容:
1. Boot head information for BROM
SPL代码必须按照BROM要求的格式,提供文件头信息,包含特定的信息,否则BROM会认为代码不是有效的SPL引导程序,将不加载。
__bootloader_size是由连接脚本计算出来的代码尺寸。
2. 堆栈初始化
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
ldr sp, _stack_srv_end
类似这样的代码,是设置arm处理器各种模式的堆栈指针。_stack_srv_end是定义在文件末尾的。
3. 跳转到main程序
### 2. main程序
由于仅仅是让LED闪烁,所以程序没有对时钟、存储器等进行初始化,只是操作了GPIOA的寄存器,实现设置引脚状态。代码如下
#define PORTA_CFG0_REG ((volatile unsigned int *)(0x01C20800))
#define PORTA_DATA_REG ((volatile unsigned int *)(0x01C20810))
void port_a_init(void)
{
//Setup all port A pint for output
*PORT_A_CFG_REG = (*PORT_A_CFG_REG & 0xFFFF0000) | 0x00001111;
}
void port_a_output(unsigned char data)
{
*PORTA_DATA_REG = (*PORTA_DATA_REG & 0xFFFFFFF0) | (data & 0x0000000F);
}
int main(void)
{
int i;
port_a_init();
for(i=0;i<10000;i++);
while(1)
{
port_a_output(0x00);
for(i=0;i<10000;i++);
port_a_output(0x0F);
for(i=0;i<10000;i++);
}
}
* PORTA_CFG0_REG寄存器设置引脚的工作模式
* PORTA_DATA_REG设置引脚的值
### 3. 链接脚本
MEMORY
{
ram : org = 0x000000000, len = 32K
}
SECTIONS
{
. = ORIGIN(ram);
.text :
{
start.o (.text)
*(.text);
} >ram
__bootloader_size = SIZEOF(.text);
}
由于程序非常简单,小巧,链接脚本仅仅是指出将代码定位到0x0000_0000的SRAM位置,将start.o放置到程序的开始的位置。
### 4. Makefile
# Object Files
OBJECTFILES= \
blinkled.o \
start.o
AS=arm-none-eabi-gcc
CC=arm-none-eabi-gcc
RM=rm
# C Compiler Flags
CFLAGS=-Wall -Wno-write-strings -Wno-char-subscripts -fno-stack-protector -DNO_STDLIB=1 -mcpu='arm926ej-s' -O0
# CC Compiler Flags
CCFLAGS=
CXXFLAGS=
# Assembler Flags
ASFLAGS=-x assembler-with-cpp -c -O0 -mcpu='arm926ej-s' -mthumb -Wall -fmessage-length=0
# Link Libraries and Options
LDLIBSOPTIONS=
all: blinkled.elf
arm-none-eabi-objcopy -O binary blinkled.elf blinkled.bin
./mksunxi blinkled.bin
blinkled.elf: ${OBJECTFILES}
$(CC) -o blinkled.elf ${OBJECTFILES} ${LDLIBSOPTIONS} -T./blinkled.ld -nostdlib
blinkled.o: blinkled.c
${RM} "$@.d"
$(CC) $(CFLAGS) -c -g -MMD -MP -MF "$@.d" -o blinkled.o blinkled.c
start.o: start.S
$(AS) $(ASFLAGS) -g -o start.o start.S
Makefile写的也是最笨的方法,需要注意的是在编译.c文件时,需要指定不连接标准库。
程序生成完以后,需要使用mksunxi这个工具处理得到的bin文件,使得它成为一个“合法”的启动代码。
剩下的就是下载到开发板,就可以观察到LED在欢快的闪烁了。
## 简要说明下程序的加载过程
1. 芯片上电,运行片内固化的BROM
2. BROM在SD卡、SPI Nor Flash搜索“合法”的SPL
3. BROM将SPL加载到片内0000_0000开始的SRAM中(32K)
4. 跳转到SPL开始执行
@llinjupt
下载过程中,STC-ISP软件给出来的信息是这样的:
正在检测目标单片机 ...
单片机型号: STC8A8K64S4A12
固件版本号: 7.3.10U
当前芯片的硬件选项为:
. 系统ISP工作频率: 23.923MHz
. 内部IRC振荡器的频率: 11.021MHz
. 掉电唤醒定时器的频率: 34.600KHz
. 振荡器放大增益使能
. P3.2和P3.3与下次下载无关
. 上电复位时增加额外的复位延时
. 复位引脚用作普通I/O口
. 检测到低压时复位
. 低压检测门槛电压 : 2.20 V
. 上电复位时,硬件不启动内部看门狗
. 上电自动启动内部看门狗时的预分频数为 : 256
. 空闲状态时看门狗定时器停止计数
. 启动看门狗后,软件可以修改分频数,但不能关闭看门狗
. 下次下载用户程序时,将用户EEPROM区一并擦除
. 下次下载用户程序时,没有相关的端口控制485
. 下次下载时不需要校验下载口令
. TXD与RXD为相互独立的IO
. 芯片复位后,TXD脚为弱上拉双向口
. 芯片复位后,P2.0输出高电平
. 内部参考电压: 1340 mV (参考范围: 1270~1410mV)
. 内部安排测试时间: 2017年10月10日
单片机型号: STC8A8K64S4A12
固件版本号: 7.3.10U
开始调节频率 ...
下载失败 ! (6.88L)(2022-01-25 21:46:34)
这个过程中,可以看到是成功完成了第一个阶段的握手通信的,这说明目标CPU是有过一次的握手的,但ISP软件发出“开始调节频率”时,这时可以观察到,目标板已经开始跑用户程序了,所以ISP软件肯定不能成功完成“调节频率”这个功能,下载于是就失败了。
@llinjupt
你说的DTS信号,应该是指的某个利用DTS来自动切换电源,让STC冷启动的控制电路吧。我下载是直接手动切断电源,让STC冷启动的,因此我认为无法下载与DTS功能无关。
从CDC工作原理上的区别来说,确实不知道什么原因导致无法下载。整个下载过程大致是这样的:
1、点击STC-ISP软件下载按钮,串口发送下载命令;
2、STC单片机目标板接通电源,冷启动;
3、第一次握手成功(STC-ISP已经识别到了STC芯片)
4、STC-ISP软件下发“硬件自动调整”命令,因为不知道ISP协议是怎样的,这里估计是调节目标板的工作频率,通信波特率之类的参数。
在这一步中,下载软件将超时失败。这里观察目标板,他好像立即就退出了下载模式,开始运行用户程序了,所以会超时失败。
当然,我也尝试了固定下载软件的波特率设置,但是仍然在这一步中失败。
我还尝试了用stcgal这个下载工具,也是在这一步中会导致失败。
因此,我怀疑是CDC串口这里与CH340芯片行为上有一点什么区别,导致了STC芯片提前退出了下载模式,握手失败从而无法下载。
今天遇到一个奇怪的问题,我32M SPI Flash上刷入的系统,在串口终端下输入reboot重启系统,结果系统会反复重启,重启若干次以后(次数不一定)最后进入到系统。进入到系统后,貌似正常运行。
启动日志:
[ 1.471784] usb_phy_generic usb_phy_generic.0.auto: usb_phy_generic.0.auto supply vcc not found, using dummy regulator
[ 1.483289] musb-hdrc musb-hdrc.1.auto: MUSB HDRC host driver
[ 1.489140] musb-hdrc musb-hdrc.1.auto: new USB bus registered, assigned bus number 3
[ 1.498612] hub 3-0:1.0: USB hub found
[ 1.502524] hub 3-0:1.0: 1 port detected
[ 1.507903] sun6i-rtc 1c20400.rtc: setting system clock to 1970-01-01T19:25:12 UTC (69912)
[ 1.516544] vcc3v0: disabling
[ 1.519587] vcc5v0: disabling
[ 1.522556] ALSA device list:
[ 1.525520] No soundcards found.
[ 1.531353] random: fast init done
[ 1.575947] random: crng init done
[ 1.978432] usb 1-1: new high-speed USB device number 2 using ehci-platform
[ 2.191968] hub 1-1:1.0: USB hub found
[ 2.196112] hub 1-1:1.0: 4 ports detected
[ 2.618933] usb 1-1.1: new full-speed USB device number 3 using ehci-platform
[ 2.889517] cdc_acm 1-1.1:1.0: ttyACM0: USB ACM device
[ 3.098792] usb 1-1.3: new high-speed USB device number 4 using ehci-platform
[ 3.364986] usb-storage 1-1.3:1.0: USB Mass Storage device detected
[ 3.379465] scsi host0: usb-storage 1-1.3:1.0
[ 4.410958] scsi 0:0:0:0: Direct-Access USB SG Flash 1.00 PQ: 0 ANSI: 6
[ 4.423302] sd 0:0:0:0: [sda] 62914560 512-byte logical blocks: (32.2 GB/30.0 GiB)
[ 4.436926] sd 0:0:0:0: [sda] Write Protect is off
[ 4.447657] sd 0:0:0:0: [sda] No Caching mode page found
[ 4.453108] sd 0:0:0:0: [sda] Assuming drive cache: write through
[ 4.478072] sda: sda1
[ 4.489290] sd 0:0:0:0: [sda] Attached SCSI removable disk
[ 4.920960] VFS: Mounted root (jffs2 filesystem) on device 31:3.
[ 4.928814] devtmpfs: mounted
U-Boot SPL 2017.01-rc2-00073-gdd6e8740dc-dirty (Apr 22 2020 - 09:13:27)
DRAM: 64 MiB
Trying to boot from sunxi SPI
U-Boot 2017.01-rc2-00073-gdd6e8740dc-dirty (Apr 22 2020 - 09:13:27 +0800) Allwinner Technology
CPU: Allwinner V3s (SUN8I 1681)
Model: Lichee Pi Zero
DRAM: 64 MiB
MMC: SUNXI SD/MMC: 0
SF: Detected mx25l25635f with page size 256 Bytes, erase size 64 KiB, total 32 MiB
*** Warning - bad CRC, using default environment
Setting up a 800x480 lcd console (overscan 0x0)
dotclock: 33000kHz = 33000kHz: (1 * 3MHz * 66) / 6
In: serial@01c28000
Out: serial@01c28000
Err: serial@01c28000
U-Boot 2017.01-rc2-00073-gdd6e8740dc-dirty (Apr 22 2020 - 09:13:27 +0800) Allwinner Technology
CPU: Allwinner V3s (SUN8I 1681)
Model: Lichee Pi Zero
DRAM: 64 MiB
MMC: SUNXI SD/MMC: 0
SF: Detected mx25l25635f with page size 256 Bytes, erase size 64 KiB, total 32 MiB
*** Warning - bad CRC, using default environment
Setting up a 800x480 lcd console (overscan 0x0)
dotclock: 33000kHz = 33000kHz: (1 * 3MHz * 66) / 6
In: serial@01c28000
Out: serial@01c28000
Err: serial@01c28000
Net: No ethernet found.
starting USB...
No controllers found
Hit any key to stop autoboot: 0
SF: Detected mx25l25635f with page size 256 Bytes, erase size 64 KiB, total 32 MiB
device 0 offset 0x80000, size 0x4000
SF: 16384 bytes @ 0x80000 Read: OK
device 0 offset 0x90000, size 0x470000
SF: 4653056 bytes @ 0x90000 Read: OK
## Flattened Device Tree blob at 41800000
Booting using the fdt blob at 0x41800000
Loading Device Tree to 42dfa000, end 42dffd80 ... OK
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 5.2.0-licheepi-zero+ (xlee@ubuntu) (gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu1)) #16 SMP Sun Aug 2 12:45:11 CST 2020
[ 0.000000] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c5387d
[ 0.000000] CPU: div instructions available: patching division code
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[ 0.000000] OF: fdt: Machine model: Lichee Pi Zero
[ 0.000000] Memory policy: Data cache writealloc
[ 0.000000] percpu: Embedded 16 pages/cpu s34508 r8192 d22836 u65536
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 15883
[ 0.000000] Kernel command line: console=ttyS0,115200 earlyprintk panic=5 rootwait mtdparts=spi0.0:512k(uboot),64k(dtb)ro,4544k(kernel)ro,-(rootfs) root=/dev/mtdblock3 rw rootfstype=jffs2 init=/linuxrc vt.global_cur
sor_default=0
[ 0.000000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes, linear)
[ 0.000000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes, linear)
[ 0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
[ 0.000000] Memory: 52512K/64036K available (7168K kernel code, 311K rwdata, 1820K rodata, 1024K init, 253K bss, 11524K reserved, 0K cma-reserved, 0K highmem)
[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[ 0.000000] rcu: Hierarchical RCU implementation.
[ 0.000000] rcu: RCU event tracing is enabled.
[ 0.000000] rcu: RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=1.
[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
[ 0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1
[ 0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
[ 0.000000] random: get_random_bytes called from start_kernel+0x2f8/0x494 with crng_init=0
[ 0.000000] arch_timer: cp15 timer(s) running at 24.00MHz (virt).
[ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x588fe9dc0, max_idle_ns: 440795202592 ns
[ 0.000007] sched_clock: 56 bits at 24MHz, resolution 41ns, wraps every 4398046511097ns
[ 0.000019] Switching to timer-based delay loop, resolution 41ns
[ 0.000206] clocksource: timer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns
[ 0.000441] Console: colour dummy device 80x30
[ 0.000499] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=240000)
[ 0.000514] pid_max: default: 32768 minimum: 301
[ 0.000681] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[ 0.000694] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[ 0.001497] CPU: Testing write buffer coherency: ok
[ 0.002023] /cpus/cpu@0 missing clock-frequency property
[ 0.002050] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[ 0.002825] Setting up static identity map for 0x40100000 - 0x40100060
[ 0.003035] rcu: Hierarchical SRCU implementation.
[ 0.003558] smp: Bringing up secondary CPUs ...
[ 0.003581] smp: Brought up 1 node, 1 CPU
[ 0.003590] SMP: Total of 1 processors activated (48.00 BogoMIPS).
[ 0.003597] CPU: All CPU(s) started in SVC mode.
[ 0.004680] devtmpfs: initialized
[ 0.008215] VFP support v0.3: implementor 41 architecture 2 part 30 variant 7 rev 5
[ 0.008513] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[ 0.008544] futex hash table entries: 256 (order: 2, 16384 bytes, linear)
[ 0.008807] pinctrl core: initialized pinctrl subsystem
[ 0.009857] NET: Registered protocol family 16
[ 0.010547] DMA: preallocated 256 KiB pool for atomic coherent allocations
[ 0.011867] hw-breakpoint: found 5 (+1 reserved) breakpoint and 4 watchpoint registers.
[ 0.011886] hw-breakpoint: maximum watchpoint size is 8 bytes.
[ 0.036084] SCSI subsystem initialized
[ 0.036379] usbcore: registered new interface driver usbfs
[ 0.036435] usbcore: registered new interface driver hub
[ 0.036538] usbcore: registered new device driver usb
[ 0.036743] mc: Linux media interface: v0.10
[ 0.036788] videodev: Linux video capture interface: v2.00
[ 0.037031] Advanced Linux Sound Architecture Driver Initialized.
[ 0.038386] clocksource: Switched to clocksource arch_sys_counter
[ 0.050993] NET: Registered protocol family 2
[ 0.051807] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes, linear)
[ 0.051847] TCP established hash table entries: 1024 (order: 0, 4096 bytes, linear)
[ 0.051870] TCP bind hash table entries: 1024 (order: 1, 8192 bytes, linear)
[ 0.051892] TCP: Hash tables configured (established 1024 bind 1024)
[ 0.052040] UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
[ 0.052089] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
[ 0.052392] NET: Registered protocol family 1
[ 0.054358] Initialise system trusted keyrings
[ 0.054752] workingset: timestamp_bits=30 max_order=14 bucket_order=0
[ 0.061979] ntfs: driver 2.1.32 [Flags: R/W].
[ 0.062329] jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
[ 0.098138] Key type asymmetric registered
[ 0.098163] Asymmetric key parser 'x509' registered
[ 0.098283] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 250)
[ 0.098297] io scheduler mq-deadline registered
[ 0.098304] io scheduler kyber registered
[ 0.099433] sun4i-usb-phy 1c19400.phy: Couldn't request ID GPIO
[ 0.103240] sun8i-v3s-pinctrl 1c20800.pinctrl: initialized sunXi PIO driver
[ 0.172045] Serial: 8250/16550 driver, 8 ports, IRQ sharing disabled
[ 0.174478] sun8i-v3s-pinctrl 1c20800.pinctrl: 1c20800.pinctrl supply vcc-pb not found, using dummy regulator
[ 0.175605] printk: console [ttyS0] disabled
[ 0.195919] 1c28000.serial: ttyS0 at MMIO 0x1c28000 (irq = 33, base_baud = 1500000) is a U6_16550A
[ 0.722612] printk: console [ttyS0] enabled
[ 0.727415] sun8i-v3s-pinctrl 1c20800.pinctrl: 1c20800.pinctrl supply vcc-pe not found, using dummy regulator
[ 0.758850] 1c28400.serial: ttyS1 at MMIO 0x1c28400 (irq = 34, base_baud = 1500000) is a U6_16550A
[ 0.789739] 1c28800.serial: ttyS2 at MMIO 0x1c28800 (irq = 35, base_baud = 1500000) is a U6_16550A
[ 0.825470] sun8i-v3s-pinctrl 1c20800.pinctrl: 1c20800.pinctrl supply vcc-pc not found, using dummy regulator
[ 0.837276] m25p80 spi0.0: mx25l25635e (32768 Kbytes)
[ 0.842435] 4 cmdlinepart partitions found on MTD device spi0.0
[ 0.848373] Creating 4 MTD partitions on "spi0.0":
[ 0.853170] 0x000000000000-0x000000080000 : "uboot"
[ 0.860016] 0x000000080000-0x000000090000 : "dtb"
[ 0.866530] 0x000000090000-0x000000500000 : "kernel"
[ 0.873399] 0x000000500000-0x000002000000 : "rootfs"
[ 0.880923] libphy: Fixed MDIO Bus: probed
[ 0.885628] dwmac-sun8i 1c30000.ethernet: PTP uses main clock
[ 0.891537] dwmac-sun8i 1c30000.ethernet: No regulator found
[ 0.897760] dwmac-sun8i 1c30000.ethernet: Current syscon value is not the default 38000 (expect 58000)
[ 0.907164] dwmac-sun8i 1c30000.ethernet: No HW DMA feature register supported
[ 0.914406] dwmac-sun8i 1c30000.ethernet: RX Checksum Offload Engine supported
[ 0.921638] dwmac-sun8i 1c30000.ethernet: COE Type 2
[ 0.926598] dwmac-sun8i 1c30000.ethernet: TX Checksum insertion supported
[ 0.933390] dwmac-sun8i 1c30000.ethernet: Normal descriptors
[ 0.939054] dwmac-sun8i 1c30000.ethernet: Chain mode enabled
[ 0.944957] libphy: stmmac: probed
[ 0.949197] dwmac-sun8i 1c30000.ethernet: Found internal PHY node
[ 0.955483] libphy: mdio_mux: probed
[ 0.959177] dwmac-sun8i 1c30000.ethernet: Switch mux to internal PHY
[ 0.965533] dwmac-sun8i 1c30000.ethernet: Powering internal PHY
[ 0.972714] libphy: mdio_mux: probed
[ 0.976647] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[ 0.983291] ehci-platform: EHCI generic platform driver
[ 0.988839] ehci-platform 1c1a000.usb: EHCI Host Controller
[ 0.994481] ehci-platform 1c1a000.usb: new USB bus registered, assigned bus number 1
[ 1.002474] ehci-platform 1c1a000.usb: irq 25, io mem 0x01c1a000
[ 1.038389] ehci-platform 1c1a000.usb: USB 2.0 started, EHCI 1.00
[ 1.045599] hub 1-0:1.0: USB hub found
[ 1.049568] hub 1-0:1.0: 1 port detected
[ 1.054185] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[ 1.060518] ohci-platform: OHCI generic platform driver
[ 1.066090] ohci-platform 1c1a400.usb: Generic Platform OHCI controller
[ 1.072823] ohci-platform 1c1a400.usb: new USB bus registered, assigned bus number 2
[ 1.080812] ohci-platform 1c1a400.usb: irq 26, io mem 0x01c1a400
[ 1.153509] hub 2-0:1.0: USB hub found
[ 1.157371] hub 2-0:1.0: 1 port detected
[ 1.164675] usbcore: registered new interface driver cdc_acm
[ 1.170452] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[ 1.178599] usbcore: registered new interface driver usb-storage
[ 1.184718] usbcore: registered new interface driver usbserial_generic
[ 1.191345] usbserial: USB Serial support registered for generic
[ 1.197384] usbcore: registered new interface driver ch341
[ 1.202958] usbserial: USB Serial support registered for ch341-uart
[ 1.209309] usbcore: registered new interface driver usb_serial_simple
[ 1.215856] usbserial: USB Serial support registered for carelink
[ 1.222000] usbserial: USB Serial support registered for zio
[ 1.227676] usbserial: USB Serial support registered for funsoft
[ 1.233721] usbserial: USB Serial support registered for flashloader
[ 1.240109] usbserial: USB Serial support registered for google
[ 1.246045] usbserial: USB Serial support registered for libtransistor
[ 1.252622] usbserial: USB Serial support registered for vivopay
[ 1.258664] usbserial: USB Serial support registered for moto_modem
[ 1.264946] usbserial: USB Serial support registered for motorola_tetra
[ 1.271618] usbserial: USB Serial support registered for novatel_gps
[ 1.277988] usbserial: USB Serial support registered for hp4x
[ 1.283770] usbserial: USB Serial support registered for suunto
[ 1.289722] usbserial: USB Serial support registered for siemens_mpi
[ 1.298082] sun6i-rtc 1c20400.rtc: registered as rtc0
[ 1.303260] sun6i-rtc 1c20400.rtc: RTC enabled
[ 1.307929] i2c /dev entries driver
[ 1.312936] input: ns2009_ts as /devices/platform/soc/1c2ac00.i2c/i2c-0/0-0048/input/input0
[ 1.322691] sunxi-wdt 1c20ca0.watchdog: Watchdog enabled (timeout=16 sec, nowayout=0)
[ 1.331400] sun8i-v3s-pinctrl 1c20800.pinctrl: 1c20800.pinctrl supply vcc-pf not found, using dummy regulator
[ 1.367896] sunxi-mmc 1c0f000.mmc: initialized, max. request size: 16384 KB
[ 1.375461] sun8i-v3s-pinctrl 1c20800.pinctrl: 1c20800.pinctrl supply vcc-pg not found, using dummy regulator
[ 1.386877] usbcore: registered new interface driver usbhid
[ 1.392548] usbhid: USB HID core driver
[ 1.398851] Initializing XFRM netlink socket
[ 1.403168] NET: Registered protocol family 17
[ 1.408231] Registering SWP/SWPB emulation handler
[ 1.414298] Loading compiled-in X.509 certificates
[ 1.424375] simple-framebuffer 43e89000.framebuffer: framebuffer at 0x43e89000, 0x177000 bytes, mapped to 0x(ptrval)
[ 1.435028] simple-framebuffer 43e89000.framebuffer: format=x8r8g8b8, mode=800x480x32, linelength=3200
[ 1.450906] Console: switching to colour frame buffer device 100x30
[ 1.462995] simple-framebuffer 43e89000.framebuffer: fb0: simplefb registered!
[ 1.471873] usb_phy_generic usb_phy_generic.0.auto: usb_phy_generic.0.auto supply vcc not found, using dummy regulator
[ 1.483384] musb-hdrc musb-hdrc.1.auto: MUSB HDRC host driver
[ 1.489241] musb-hdrc musb-hdrc.1.auto: new USB bus registered, assigned bus number 3
[ 1.498743] hub 3-0:1.0: USB hub found
[ 1.502626] hub 3-0:1.0: 1 port detected
[ 1.507991] sun6i-rtc 1c20400.rtc: setting system clock to 1970-01-01T19:25:22 UTC (69922)
[ 1.516624] vcc3v0: disabling
[ 1.519671] vcc5v0: disabling
[ 1.522642] ALSA device list:
[ 1.525607] No soundcards found.
[ 1.531464] random: fast init done
[ 1.576059] random: crng init done
[ 1.978976] usb 1-1: new high-speed USB device number 2 using ehci-platform
[ 2.191870] hub 1-1:1.0: USB hub found
[ 2.198210] hub 1-1:1.0: 4 ports detected
[ 2.628983] usb 1-1.1: new full-speed USB device number 3 using ehci-platform
[ 2.899513] cdc_acm 1-1.1:1.0: ttyACM0: USB ACM device
[ 3.108818] usb 1-1.3: new high-speed USB device number 4 using ehci-platform
[ 3.374599] usb-storage 1-1.3:1.0: USB Mass Storage device detected
[ 3.387379] scsi host0: usb-storage 1-1.3:1.0
[ 4.411310] scsi 0:0:0:0: Direct-Access USB SG Flash 1.00 PQ: 0 ANSI: 6
[ 4.422302] sd 0:0:0:0: [sda] 62914560 512-byte logical blocks: (32.2 GB/30.0 GiB)
[ 4.435889] sd 0:0:0:0: [sda] Write Protect is off
[ 4.448119] sd 0:0:0:0: [sda] No Caching mode page found
[ 4.453546] sd 0:0:0:0: [sda] Assuming drive cache: write through
[ 4.476976] sda: sda1
[ 4.488158] sd 0:0:0:0: [sda] Attached SCSI removable disk
[ 4.920343] VFS: Mounted root (jffs2 filesystem) on device 31:3.
[ 4.928088] devtmpfs: mounted
[ 4.932613] Freeing unused kernel memory: 1024K
[ 4.937313] Run /linuxrc as init process
Starting syslogd: OK
Starting klogd: OK
Running sysctl: OK
Populating /dev using udev: [ 6.000578] udevd[111]: starting version 3.2.9
[ 6.930564] udevd[112]: starting eudev-3.2.9
[ 9.848390] i2c i2c-0: mv64xxx: I2C bus locked, block: 1, time_left: 0
[ 9.854945] input input0: Poll touch data failed: -110
done
Initializing random number generator: OK
Saving random seed: OK
Starting network: [ 10.047364] dwmac-sun8i 1c30000.ethernet eth0: PHY [0.1:01] driver [Generic PHY]
[ 10.056360] dwmac-sun8i 1c30000.ethernet eth0: No Safety Features support found
[ 10.063781] dwmac-sun8i 1c30000.ethernet eth0: No MAC Management Counters available
[ 10.071460] dwmac-sun8i 1c30000.ethernet eth0: PTP not supported by HW
[ 10.077990] dwmac-sun8i 1c30000.ethernet eth0: configuring for phy/mii link mode
[ 10.089548] dwmac-sun8i 1c30000.ethernet eth0: Link is Up - 100Mbps/Full - flow control rx/tx
OK
Starting dropbear sshd: OK
[ 10.755898] FAT-fs (sda1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
modify ip address
Stopping network: [ 10.871990] dwmac-sun8i 1c30000.ethernet eth0: Link is Down
OK
Starting network: [ 10.990080] dwmac-sun8i 1c30000.ethernet eth0: PHY [0.1:01] driver [Generic PHY]
[ 10.999058] dwmac-sun8i 1c30000.ethernet eth0: No Safety Features support found
[ 11.006381] dwmac-sun8i 1c30000.ethernet eth0: No MAC Management Counters available
[ 11.014079] dwmac-sun8i 1c30000.ethernet eth0: PTP not supported by HW
[ 11.020631] dwmac-sun8i 1c30000.ethernet eth0: configuring for phy/mii link mode
OK
Welcome to Buildroot for the LicheePi Zero
licheepi-zero login:
从启动信息看,好像没有看出哪里出错了,请教一下这是什么问题?
今天分享一个简单,但也许很实用的功能,大神请飘过。
## 设备树中与LED有关的内容
在设备树文件arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts中,有以下内容
leds {
compatible = "gpio-leds";
blue_led {
label = "licheepi:blue:usr";
gpios = <&pio 6 1 GPIO_ACTIVE_LOW>; /* PG1 */
};
green_led {
label = "licheepi:green:usr";
gpios = <&pio 6 0 GPIO_ACTIVE_LOW>; /* PG0 */
default-state = "on";
};
red_led {
label = "licheepi:red:usr";
gpios = <&pio 6 2 GPIO_ACTIVE_LOW>; /* PG2 */
};
};
其中
gpios = <&pio 6 1 GPIO_ACTIVE_LOW>; /* PG1 */
代表引脚 6 * 32 + 1 也就是 PG1( A~G: 0~6)
其名字为:licheepi:blue:usr
## 系统启动后与LED控制有关的文件
系统启动后,将看到这样的文件
# ls /sys/class/leds/
licheepi:blue:usr licheepi:green:usr licheepi:red:usr
这里三个文件夹分别对应设备树中定义的三个LED。
## 如何控制LED灯亮灭
点亮LED
echo 1 > /sys/class/leds/licheepi\:green\:usr/brightness
熄灭LED
echo 0 > /sys/class/leds/licheepi\:green\:usr/brightness
控制LED闪烁
# ls /sys/class/leds/licheepi\:blue\:usr/
brightness max_brightness subsystem uevent
device power trigger
# cat /sys/class/leds/licheepi\:blue\:usr/trigger
[none] kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock mmc0 heartbeat default-on
这里可以看到当前的值为none,表示没有trigger,将其值改成heartbeat就可以看到闪烁了
# echo heartbeat > /sys/class/leds/licheepi\:blue\:usr/trigger
后记
本笔记资料来源于whycan网的多位大神,感谢晕哥这个平台提供了大量资料。我这篇帖子只能算一篇笔记吧,把这几天各种尝试、爬楼的结果记录下来,一来给自己做一个备忘,如果能帮助到更多向我这样的新手,就不胜荣幸了。
另目前还有一些自觉不够完美的地方,现在自己的技术实力又搞不定,留坑待以后再填吧。
1. 是不是能够通过boot.scr脚本文件设置bootcmd、bootargs参数;不能老是去改uboot的代码吧?
2. 创建UBIFS文件系统,存放除了uboot以外所有需要的文件;用文件系统存放启动脚本boot.scr和设备树文件,分区规划应该更自由,只需要1个分区存放uboot镜像,剩下的都留给根文件系统,修改起来好像更方便?
3. 使用buildroot的genimage工具生成系统镜像,这个方法感觉更好,genimage的脚本制作启动镜像,看上去更易懂一些。
4. 如果完全从主线uboot、kernel、buildroot拉代码,要在荔枝派上跑起来,该如何修改呢,原理又是啥,这个坑好大。
打包生成Flash镜像
1. 打包脚本
按照分区规划,将上面得到的文件,用dd写入到指定的位置就可以得到需要的镜像文件。打包命令如下:
#!/bin/bash
dd if=/dev/zero bs=1MiB count=32 | tr "\000" "\377" > flash_32m.bin
mkfs.jffs2 --pad=0x1B00000 -d rootfs/ -o jffs2.bin
dd if=notrunc if=u-boot-sunxi-with-spl.bin of=flash_32m.bin seek=0
dd if=notrunc if=sun8i-v3s-licheepi-zero.dtb of=flash_32m.bin bs=$((0x80000)) seek=1
dd if=notrunc if=zImage of=flash_32m.bin bs=$((0x90000)) seek=1
dd if=notrunc if=jffs2.bin of=flash_32m.bin bs=$((0x500000)) seek=1
*PS: 不懂 bs=$((0x80000))这个地方的语法,为啥要用$符号还要加两个括号,照着大神的抄过来的。*
2. 烧录Flash镜像
让开发板进入FEL模式,使用sunxi-fel工具,将镜像写入SPI Flash。
2.1 烧录整个flash
$ sudo sunxi-fel -p spiflash-write 0 flash_32m.bin
2.2 也可以独立烧录
下面的命令是根据前面的分区规划来的,如果你的分区规划不一样,需要修改一下地址。独立烧录的价值在于调试阶段,因为sunxi-fel的烧录非常的慢,如果能少写入一点数据可以提高不少的性能。
$sudo sunxi-fel -p spiflash-write 0 u-boot-sunxi-with-spl.bin
$sudo sunxi-fel -p spiflash-write 0xF0000 sun8i-v3s-licheepi-zero-dock.dtb
$sudo sunxi-fel -p spiflash-write 0x100000 zImage
$sudo sunxi-fel -p spiflash-write 0x600000 jffs2.bin
3. 编写自己的Hello,World
系统启动来以后,总是要自己写点程序试一下的,先来一个Hello,World
$ cat myapp/hello.c
#include <stdio.h>
int main(void)
{
printf("Hello,World!\n");
return 0;
}
$ arm-linux-gnueabihf-gcc myapp/hello.c -o myapp/hello
将交叉编译得到的hello直接拷贝到rootfs目录里面,重新生成根文件系统,烧录进去就OK了。
但文件系统非常大,烧录太慢,看来还得支持scp拷贝才行。后面慢慢折腾吧。
使用buildroot制作根文件系统
其实buildroot可以直接制作uboot和内核的,但是国内通过git下载uboot和kernel的代码实在太慢,几乎无法成功,所以前面已经独立的下载了这两个仓库,所以这里就不使用buildroot来生成uboot和kernel了。
1. 获取buildroot源代码
git clone git://git.busybox.net/buildroot
2. 配置
在最新的buildroot有一个licheepi的默认配置文件
$ make licheepi_zero_defconfig
通过这个配置文件,可以得到一个sdcard.img的文件,直接dd烧录进入sd卡,就可以启动Linux系统。
使用这个默认配置的好处在于,如果从零开始,对我这样的初学者实在不知道该选择那些选项,不该选择那些选项,使用默认配置至少可以得到一个基本能用的起点,后面在这个基础上慢慢改就可以了。
但是这个默认配置的uboot不能支持spi(其实是我不会),linux内核使用的5.3.5版本,默认配置还不支持网卡(我也不会添加修改),暂时先用前面两个步骤得到的uboot和kernel,只用其得到的根文件系统。
3. 工具链设置
默认的配置使用ulibc作为C库,我猜测这个库不能支持Qt,所以要换掉。
可以使用buildroot来生成工具链,但是下载实在是太慢了,几乎不会下载成功。干脆配置buildroot使用系统自带的工具链。(其实前面编译uboot和kernel也是使用系统自带的工具链。)
更新:工具链最终还是使用的buildroot构建的工具链。系统自带工具链会产生错误。
4. 软件包
软件包目前还没有太多需求,默认配置能够得到一个可用的rootfs,先把系统启动起来,后面再研究一下Qt如何配置。
Linux内核编译
1. 获取源代码
git clone https://github.com/Lichee-Pi/linux.git -b zero-5.2.y
这里切换到了该仓库中,内核最新的分支,经测试该分支已经包含了Ethernet的支持,满足我自己的需要。
2. 配置源代码
2.1 首先导入默认配置
CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm make licheepi_zero_defconfig
2.2 修改设备树,加入SPI Flash和Ethernet的支持
修改文件`arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts`,在该文件适当的位置加入以下内容。(PS:我现在也不懂设备树,但是打开这个文件后,按照以下内容提示应该知道改哪些部分吧?)
aliases {
serial0 = &uart0;
ethernet0 = &emac;
};
&emac {
phy-handle = <&int_mii_phy>;
phy-mode = "mii";
allwinner,leds-active-low;
status = "okay";
};
&spi0 {
status ="okay";
mx25l25635e:mx25l25635e@0 {
compatible = "jedec,spi-nor";
reg = <0x0>;
spi-max-frequency = <50000000>;
#address-cells = <1>;
#size-cells = <1>;
};
};
2.3 配置选项
* 加入SPI Flash的支持
Device Drivers --->
<*> Memory Technology Device (MTD) support --->
<*> Command line partition table parsing (用以支持命令行参数 mtdparts=spi0.0:512k(uboot)ro, … )
<*> Caching block device access to MTD devices
<*> SPI-NOR device support --->
[ ] Use small 4096 B erase sectors (取消这个选型,否则jffs2文件系统会报错)
特别注意这里的两个选项Command line partition table parsing,如果不选中这个,加无法识别mtd分区,启动系统时回报错
Wait for root filesystem /dev/mtdblock3
第二个选项是Use small 4096 B erase sectors,必须取消选中它,否则jffs2文件系统会大量报错,而无法加载进入系统。
* 加入jffs2文件系统支持
File systems --->
[*] Miscellaneous filesystems --->
<*> Journalling Flash File System v2 (JFFS2) support
(0) JFFS2 debugging verbosity (0 = quiet, 2 = noisy)
[*] JFFS2 write-buffering support
[ ] Verify JFFS2 write-buffer reads
[ ] JFFS2 summary support
[ ] JFFS2 XATTR support
[ ] Advanced compression options for JFFS2
* 加入Ethernet支持
Device Drivers --->
[*] Network device support --->
[*] Ethernet driver support --->
[*] STMicroelectronics devices
<*> STMicroelectronics Multi-Gigabit Ethernet driver
[ ] Support for STMMAC Selftests
<*> STMMAC Platform bus support
< > Support for snps,dwc-qos-ethernet.txt DT binding.
<*> Generic driver for DWMAC
<*> Allwinner GMAC support
<*> Allwinner sun8i GMAC support
(很奇怪,全志的芯片网络支持会在STMicroelectronics deveices配置菜单下面。)
3. 编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs
最后生成的文件在下面路径
$ ls -lh arch/arm/boot/zImage
-rwxrwxr-x 1 xlee xlee 4.2M Apr 23 10:41 arch/arm/boot/zImage
$ ls -lh arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dtb
-rw-rw-r-- 1 xlee xlee 12K Apr 22 23:33 arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dtb
uboot的配置和编译
V3s启动时,首先是芯片内的BROM运行,这个启动代码会搜索SD卡,SPI Flash特定位置,加载BootLoader中的SPL部分,
再由SPL加载完整的uboot镜像,由uboot加载内核和设备树文件。
1. 获取支持SPI Flash的uboot代码
由于制作完成的镜像存放在SPI Flash中,uboot需要支持从SPI Flash设备,以实现加载过程。从以下仓库中获取代码,并切换到v3s-spi-experimental分支。
$ git clone https://github.com/Lichee-Pi/u-boot.git -b v3s-spi-experimental
可通过`git branch -r `命令查看代码仓库所有的分支
$ git branch -r
origin/HEAD -> origin/master
origin/master
origin/nano-lcd800480
origin/nano-v2018.01
origin/next
origin/origin
origin/s3-l0p-exp
origin/u-boot-2009.11.y
origin/u-boot-2013.01.y
origin/u-boot-2016.09.y
origin/v3s-current
origin/v3s-spi-experimental
2. 配置uboot
该仓库的代码与Licheepi开发板有关的配置文件有以下三个,可根据需要选择,我选择支持800x480LCD的这个配置
$ cd u-boot
$ ls -1 configs/LicheePi*
configs/LicheePi_Zero_480x272LCD_defconfig
configs/LicheePi_Zero_800x480LCD_defconfig
configs/LicheePi_Zero_defconfig
$ make LicheePi_Zero_800x480LCD_defconfig
使用32M Flash需要加入Bank/Extended支持,make menuconfig,加入以下选项
Device Drivers --->
SPI Flash Support --->
[*] Enable Driver Model for SPI flash
[*] Legacy SPI Flash Interface support
[*] SPI flash Bank/Extended address register support
[*] Macronix SPI flash support
[*] Spansion SPI flash support
[*] STMicro SPI flash support
[*] Winbond SPI flash support
[*] Support for SPI Flash on Allwinner SoCs in SPL
3. 修改uboot,设置bootcmd和bootargs参数
uboot加载完毕后,会运行环境变量bootcmd中存放的命令,通过这些命令加载内核和设备树文件到内存,并启动内核。Uboot可以通过读取启动分区(?)中的boot.scr脚本文件来设置bootcmd、bootargs变量,也可以修改代码,硬编码设置这几个变量的值。这里是通过修改`include/configs/sun8i.h`这个头文件,硬编码设置这两个变量的值(实际上,我不懂如何做才能让uboot搜索分区中的文件,以加载变量的值,显然通过文件加载变量的值更好,因为不需要重新编译uboot就可以修改bootcmd变量,更加灵活)。
#define CONFIG_BOOTCOMMAND "sf probe 0:0 6000000; " \
"sf read 0x41800000 0x80000 0x4000; " \
"sf read 0x41000000 0x90000 0x470000;" \
"bootz 0x41000000 - 0x41800000;"
#define CONFIG_BOOTARGS "console=ttyS0,115200 earlyprintk panic=5 rootwait mtdparts=spi0.0:512k(uboot),64k(dtb)ro,4544k(kernel)ro,-(rootfs) root=/dev/mtdblock3 rw rootfstype=jffs2 init=/linuxrc vt.global_cursor_default=0"
命令的功能解释如下:
* sf probe 0:0 60000000 挂载SPI Flash设备(PS:后面这个60000000不知道什么意思,好像不加也可以)
* sf read 0x4100000 0x90000 0x470000,该命令加载内核, 从SPI Flash的0x90000地址处,读取0x470000字节内容到内存0x41000000处,完成内核加载;
* sf read 0x41800000 0x80000 0x4000 该命令加载设备树文件到0x41800000内存地址处。
由此可见,根据分区规划的不同,内核文件的尺寸的不同,需要修改这些数值。
4. 设置bootargs参数
这里仍然选择硬编码的方法,修改bootargs参数,该参数是启动内核时,传递给内核的命令行参数,目的在于将SPI的分区结构传递给内核,以便于内核从正确的位置加载根文件系统。
console=ttyS0,115200 earlyprintk panic=5 rootwait mtdparts=spi32766.0:512k(uboot),64k(dtb)ro,4544k(kernel)ro,-(rootfs) root=/dev/mtdblock3 rw rootfstype=jffs2 init=/linuxrc vt.global_cursor_default=0
在这个命令行参数中,使用mtdparts参数传递了flash的分区信息,其参数的语法格式在文件linux/drivers/mtd/cmdlinepart.c中描述如下:
/*
* mtdparts=<mtddef>[;<mtddef]
* <mtddef> := <mtd-id>:<partdef>[,<partdef>]
* <partdef> := <size>[@<offset>][<name>][ro][lk]
* <mtd-id> := unique name used in mapping driver/device (mtd->name)
* <size> := standard linux memsize OR "-" to denote all remaining space
* size is automatically truncated at end of device
* if specified or truncated size is 0 the part is skipped
* <offset> := standard linux memsize
* if omitted the part will immediately follow the previous part
* or 0 if the first part
* <name> := '(' NAME ')'
* NAME will appear in /proc/mtd
*
* <size> and <offset> can be specified such that the parts are out of order
* in physical memory and may even overlap.
*
* The parts are assigned MTD numbers in the order they are specified in the
* command line regardless of their order in physical memory.
*/
由上可知,命令行
mtdparts=spi0.0:512k(uboot),64k(dtb)ro,4544k(kernel)ro,-(rootfs)
可以解释为:
* spi0.0 <mtd-id>,这个是内核识别到的spi flash设备号
参考[荔枝派zero linux5.2,spi flash启动识别不到分区](https://whycan.cn/t_4119.html),从内核启动信息中,可以看到这个mtd-id为spi0.0
[ 0.769344] m25p80 spi0.0: mx25l25635e (32768 Kbytes)
[ 0.774436] 4 cmdlinepart partitions found on MTD device spi0.0
[ 0.780416] Creating 4 MTD partitions on "spi0.0":
[ 0.785214] 0x000000000000-0x000000080000 : "uboot"
[ 0.792040] 0x000000080000-0x000000090000 : "dtb"
[ 0.798618] 0x000000090000-0x000000500000 : "kernel"
[ 0.805369] 0x000000500000-0x000002000000 : "rootfs"
* 512k(uboot) 这个部分定义了一个partdef,size为512k,name为uboot,其余类推
进入Linux后,可以看到如下信息
# cat /proc/mtd
dev: size erasesize name
mtd0: 00080000 00010000 "uboot"
mtd1: 00010000 00010000 "dtb"
mtd2: 00470000 00010000 "kernel"
mtd3: 01b00000 00010000 "rootfs"
原理及分区规划
制作原理
一个系统镜像由BootLoader、Kernel Image、dtb file、Root Filesystem构成,所以制作一个系统镜像第一步就是要制作这几个文件。
-rw-r--r-- 1 xlee xlee 28311552 Apr 23 11:17 jffs2.bin 根文件系统制作的磁盘镜像
drwxr-xr-x 17 xlee xlee 4096 Apr 21 21:04 rootfs 根文件系统
-rw-rw-r-- 1 xlee xlee 11413 Apr 22 23:34 sun8i-v3s-licheepi-zero.dtb 设备树文件
-rw-rw-r-- 1 xlee xlee 418388 Apr 22 23:03 u-boot-sunxi-with-spl.bin uboot启动镜像
-rwxrwxr-x 1 xlee xlee 4315384 Apr 23 11:17 zImage Linux Kernel内核
分区规划
这个系统镜像最终是存储在SPI Flash上的,通常只有16M、32M的大小,需要仔细规划有限的存储空间。
# 总共32MiB 0x000000 - 0x1FFFFFF
uboot 0x0000 - 0x7FFFF (512KiB)
dtb 0x80000 - 0x8FFFF (64KiB)
zImage 0x90000 - 0x4FFFFF (4MiB+448Kib)
rootfs 0x500000 - 0x1FFFFFF (27MiB = 32MiB - 5MiB)
Sunxi-tools的安装
1. 依赖包
$ apt-get install libusb-1.0-0-dev
2. clone代码包
官网给出的地址如下
git clone https://github.com/linux-sunxi/sunxi-tools
但以上地址,V3s上实验发现不支持SPI Flash,应从以下地址下载
git clone https://github.com/Icenowy/sunxi-tools.git -b spi-rebase
注意使用spi-rebase分支
3. 支持32M的SPI Flash
由于SPI flash 的地址是24bit,也就是最大16M 地址空间,所以对于32M flash,需要增加bank切换支持。
uboot中有CONFIG_SPI_FLASH_BAR选项可以使能bank切换。
但是sunxi-fel中尚未支持,所以下载的时候超出16M会循环覆盖掉。
这里介绍对sunxi-fel增加16M以上flash支持的方法。
Filename: fel-spiflash.c
/*
* Write data to the SPI flash. Use the first 4KiB of SRAM as the data buffer.
*/
#define CMD_WRITE_ENABLE 0x06
#define SPI_FLASH_16MB_BOUN 0x1000000
# define CMD_BANKADDR_BRWR 0x17 //only SPANSION flash use it
# define CMD_BANKADDR_BRRD 0x16
# define CMD_EXTNADDR_WREAR 0xC5
# define CMD_EXTNADDR_RDEAR 0xC8
size_t bank_curr = 0;
void aw_fel_spiflash_write_helper(feldev_handle *dev,
uint32_t offset, void *buf, size_t len,
size_t erase_size, uint8_t erase_cmd,
size_t program_size, uint8_t program_cmd)
{
uint8_t *buf8 = (uint8_t *)buf;
size_t max_chunk_size = dev->soc_info->scratch_addr - dev->soc_info->spl_addr;
size_t cmd_idx, bank_sel;
if (max_chunk_size > 0x1000)
max_chunk_size = 0x1000;
uint8_t *cmdbuf = malloc(max_chunk_size);
cmd_idx = 0;
prepare_spi_batch_data_transfer(dev, dev->soc_info->spl_addr);
//add bank support
{
cmd_idx = 0;
bank_sel = offset /SPI_FLASH_16MB_BOUN;
if (bank_sel == bank_curr)
goto bar_end;
/* Emit write enable command */
cmdbuf[cmd_idx++] = 0;
cmdbuf[cmd_idx++] = 1;
cmdbuf[cmd_idx++] = CMD_WRITE_ENABLE;
/* Emit write bank */
cmdbuf[cmd_idx++] = 0;
cmdbuf[cmd_idx++] = 2;
cmdbuf[cmd_idx++] = CMD_EXTNADDR_WREAR;
cmdbuf[cmd_idx++] = offset >> 24;
/* Emit wait for completion */
cmdbuf[cmd_idx++] = 0xFF;
cmdbuf[cmd_idx++] = 0xFF;
/* Emit the end marker */
cmdbuf[cmd_idx++] = 0;
cmdbuf[cmd_idx++] = 0;
aw_fel_write(dev, cmdbuf, dev->soc_info->spl_addr, cmd_idx);
aw_fel_remotefunc_execute(dev, NULL);
bar_end:
bank_curr = bank_sel;
}
cmd_idx = 0;
prepare_spi_batch_data_transfer(dev, dev->soc_info->spl_addr);
while (len > 0) {
while (len > 0 && max_chunk_size - cmd_idx > program_size + 64) {
if (offset % erase_size == 0) {
/* Emit write enable command */
cmdbuf[cmd_idx++] = 0;
cmdbuf[cmd_idx++] = 1;
cmdbuf[cmd_idx++] = CMD_WRITE_ENABLE;
/* Emit erase command */
cmdbuf[cmd_idx++] = 0;
cmdbuf[cmd_idx++] = 4;
cmdbuf[cmd_idx++] = erase_cmd;
cmdbuf[cmd_idx++] = offset >> 16;
cmdbuf[cmd_idx++] = offset >> 8;
cmdbuf[cmd_idx++] = offset;
/* Emit wait for completion */
cmdbuf[cmd_idx++] = 0xFF;
cmdbuf[cmd_idx++] = 0xFF;
}
/* Emit write enable command */
cmdbuf[cmd_idx++] = 0;
cmdbuf[cmd_idx++] = 1;
cmdbuf[cmd_idx++] = CMD_WRITE_ENABLE;
/* Emit page program command */
size_t write_count = program_size;
if (write_count > len)
write_count = len;
cmdbuf[cmd_idx++] = (4 + write_count) >> 8;
cmdbuf[cmd_idx++] = 4 + write_count;
cmdbuf[cmd_idx++] = program_cmd;
cmdbuf[cmd_idx++] = offset >> 16;
cmdbuf[cmd_idx++] = offset >> 8;
cmdbuf[cmd_idx++] = offset;
memcpy(cmdbuf + cmd_idx, buf8, write_count);
cmd_idx += write_count;
buf8 += write_count;
len -= write_count;
offset += write_count;
/* Emit wait for completion */
cmdbuf[cmd_idx++] = 0xFF;
cmdbuf[cmd_idx++] = 0xFF;
}
/* Emit the end marker */
cmdbuf[cmd_idx++] = 0;
cmdbuf[cmd_idx++] = 0;
/* Flush */
aw_fel_write(dev, cmdbuf, dev->soc_info->spl_addr, cmd_idx);
aw_fel_remotefunc_execute(dev, NULL);
cmd_idx = 0;
}
free(cmdbuf);
}
4. 编译安装
$ sudo make
$ sudo make install
5. 烧录系统的方法
烧录整个flash:
$ sudo sunxi-fel -p spiflash-write 0 v3s_flash_32m.bin
独立烧录:
$ sudo sunxi-fel -p spiflash-write 0 u-boot-sunxi-with-spl.bin
$ sudo sunxi-fel -p spiflash-write 0x50000 whycan.bmp.gz
$ sudo sunxi-fel -p spiflash-write 0xF0000 sun8i-v3s-licheepi-zero-dock.dtb
$ sudo sunxi-fel -p spiflash-write 0x100000 zImage
$ sudo sunxi-fel -p spiflash-write 0x600000 jffs2.bin
读取flash
# 读取flash从0地址开始100个字节,读到read.bin文件
$ sudo sunxi-fel -p spiflash-read 0 0x100 read.bin
6. 如何查看是否进入FEL模式
方法一,查看是否检测到一个新的USB设备
在命令行输入lsusb,将看到一下输出
Bus 001 Device 074: ID 1f3a:efe8
关注设备号 1f3a:efe8
V3s看到的是如下信息
Bus 002 Device 005: ID 1f3a:efe8 Onda (unverified) V972 tablet in flashing mode
方法二,运行sunxi-fel工具
$ sudo sunxi-fel version
AWUSBFEX soc=00162500(A13) 00000001 ver=0001 44 08 scratchpad=00007e00 00000000 00000000
7. 如何进入FEL模式
7.1. 通过一个特殊的FEL 按钮
7.2. 按住standard button
7.3 通过串口
上电启动过程中,通过发送字符’1’(有的设备是’2’),采用该方法调用了Boot1代码。
在较新的SoCs,U-Boot支持一个 “efex” 命令,可以进入到FEL模式
如果不支持efex命令,可以使用 go命令
Go 0xffff0020
7.4 通过一个特殊的SD 卡映像。
官方的sunxi-tools仓库中,有一个小的SD卡启动镜像,其功能仅仅是跳到FEL
wget https://github.com/linux-sunxi/sunxi-tools/raw/master/bin/fel-sdboot.sunxi
dd if=fel-sdboot.sunxi of=/dev/sdX bs=1024 seek=8
7.5 没有找到有效的boot image
如果BROM没有找到有效的启动镜像,会自动进入FEL模式
ubuntu20.04 快发布了,作为一个爱折腾新系统的人,自然要使用最新的系统了。
这里就发帖记录一下从头制作Licheepi V3s Zero的SPI Flash系统镜像(32M)的过程,把每个步骤的个人理解和疑惑记录下来,给我一样的新手作为参考。
(PS:ubuntu下需要的工具软件安装就不记录了,以下过程如果运行报错,可能是某个工具没有安装,直接sudo apt install xxx就可以了。)
内容目录大致包括:
1. sunxi-fel
2. uboot (2017.01)
3. Linux kernel(使用的5.2)
4. rootfs制作(使用的buildroot 2020.02)
5. 烧录镜像制作
6. 后记
打算从uboot、kernel、rootfs自己做一个32M Flash上的系统,折腾好几天了,期间遇到各种问题,现在感觉已经看到曙光了,但还是启动失败。
从启动信息来看,应该是jffs2.bin制作的参数不对。jffs2.bin的制作是仿照晕哥的命令来制作的。
mkfs.jffs2 --pad 0x1A00000 -d output/target
所用的flash芯片为32M的Nor Flash,型号为:MX25L256
启动信息为
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 5.2.0-licheepi-zero+ (xlee@ubuntu) (gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu1)) #3 SMP Wed Apr 22 20:06:32 CST 2020
[ 0.000000] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c5387d
[ 0.000000] CPU: div instructions available: patching division code
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[ 0.000000] OF: fdt: Machine model: Lichee Pi Zero
[ 0.000000] Memory policy: Data cache writealloc
[ 0.000000] percpu: Embedded 16 pages/cpu s34508 r8192 d22836 u65536
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 15883
[ 0.000000] Kernel command line: console=ttyS0,115200 mtdparts=spi0.0:512k(uboot)ro,512k(dtb)ro,5120k(kernel)ro,-(rootfs) root=/dev/mtdblock3 rw rootfstype=jffs2 init=/linuxrc
[ 0.000000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes, linear)
[ 0.000000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes, linear)
[ 0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
[ 0.000000] Memory: 53544K/64036K available (6144K kernel code, 303K rwdata, 1740K rodata, 1024K init, 253K bss, 10492K reserved, 0K cma-reserved, 0K highmem)
[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[ 0.000000] rcu: Hierarchical RCU implementation.
[ 0.000000] rcu: RCU event tracing is enabled.
[ 0.000000] rcu: RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=1.
[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
[ 0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1
[ 0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
[ 0.000000] random: get_random_bytes called from start_kernel+0x2f8/0x494 with crng_init=0
[ 0.000000] arch_timer: cp15 timer(s) running at 24.00MHz (virt).
[ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x588fe9dc0, max_idle_ns: 440795202592 ns
[ 0.000007] sched_clock: 56 bits at 24MHz, resolution 41ns, wraps every 4398046511097ns
[ 0.000020] Switching to timer-based delay loop, resolution 41ns
[ 0.000208] clocksource: timer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns
[ 0.000444] Console: colour dummy device 80x30
[ 0.000500] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=240000)
[ 0.000515] pid_max: default: 32768 minimum: 301
[ 0.000677] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[ 0.000694] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[ 0.001522] CPU: Testing write buffer coherency: ok
[ 0.002048] /cpus/cpu@0 missing clock-frequency property
[ 0.002076] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[ 0.002901] Setting up static identity map for 0x40100000 - 0x40100060
[ 0.003119] rcu: Hierarchical SRCU implementation.
[ 0.003671] smp: Bringing up secondary CPUs ...
[ 0.003695] smp: Brought up 1 node, 1 CPU
[ 0.003705] SMP: Total of 1 processors activated (48.00 BogoMIPS).
[ 0.003713] CPU: All CPU(s) started in SVC mode.
[ 0.004809] devtmpfs: initialized
[ 0.008207] VFP support v0.3: implementor 41 architecture 2 part 30 variant 7 rev 5
[ 0.008543] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[ 0.008576] futex hash table entries: 256 (order: 2, 16384 bytes, linear)
[ 0.008834] pinctrl core: initialized pinctrl subsystem
[ 0.010033] NET: Registered protocol family 16
[ 0.010581] DMA: preallocated 256 KiB pool for atomic coherent allocations
[ 0.011881] hw-breakpoint: found 5 (+1 reserved) breakpoint and 4 watchpoint registers.
[ 0.011899] hw-breakpoint: maximum watchpoint size is 8 bytes.
[ 0.035669] SCSI subsystem initialized
[ 0.035938] usbcore: registered new interface driver usbfs
[ 0.036016] usbcore: registered new interface driver hub
[ 0.036129] usbcore: registered new device driver usb
[ 0.036353] mc: Linux media interface: v0.10
[ 0.036395] videodev: Linux video capture interface: v2.00
[ 0.036633] Advanced Linux Sound Architecture Driver Initialized.
[ 0.037981] clocksource: Switched to clocksource arch_sys_counter
[ 0.051124] NET: Registered protocol family 2
[ 0.051944] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes, linear)
[ 0.051986] TCP established hash table entries: 1024 (order: 0, 4096 bytes, linear)
[ 0.052011] TCP bind hash table entries: 1024 (order: 1, 8192 bytes, linear)
[ 0.052035] TCP: Hash tables configured (established 1024 bind 1024)
[ 0.052183] UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
[ 0.052235] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
[ 0.052540] NET: Registered protocol family 1
[ 0.054482] Initialise system trusted keyrings
[ 0.054875] workingset: timestamp_bits=30 max_order=14 bucket_order=0
[ 0.062077] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[ 0.062295] jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
[ 0.098852] Key type asymmetric registered
[ 0.098877] Asymmetric key parser 'x509' registered
[ 0.098980] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 250)
[ 0.098993] io scheduler mq-deadline registered
[ 0.099000] io scheduler kyber registered
[ 0.100066] sun4i-usb-phy 1c19400.phy: Couldn't request ID GPIO
[ 0.103821] sun8i-v3s-pinctrl 1c20800.pinctrl: initialized sunXi PIO driver
[ 0.177283] Serial: 8250/16550 driver, 8 ports, IRQ sharing disabled
[ 0.179932] sun8i-v3s-pinctrl 1c20800.pinctrl: 1c20800.pinctrl supply vcc-pb not found, using dummy regulator
[ 0.181079] printk: console [ttyS0] disabled
[ 0.201397] 1c28000.serial: ttyS0 at MMIO 0x1c28000 (irq = 33, base_baud = 1500000) is a U6_16550A
[ 0.724959] printk: console [ttyS0] enabled
[ 0.755647] sun8i-v3s-pinctrl 1c20800.pinctrl: 1c20800.pinctrl supply vcc-pc not found, using dummy regulator
[ 0.767376] m25p80 spi0.0: mx25l25635e (32768 Kbytes)
[ 0.772538] 4 cmdlinepart partitions found on MTD device spi0.0
[ 0.778476] Creating 4 MTD partitions on "spi0.0":
[ 0.783275] 0x000000000000-0x000000080000 : "uboot"
[ 0.790101] 0x000000080000-0x000000100000 : "dtb"
[ 0.796601] 0x000000100000-0x000000600000 : "kernel"
[ 0.803489] 0x000000600000-0x000002000000 : "rootfs"
[ 0.811053] libphy: Fixed MDIO Bus: probed
[ 0.815288] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[ 0.821907] ehci-platform: EHCI generic platform driver
[ 0.827406] ehci-platform 1c1a000.usb: EHCI Host Controller
[ 0.833077] ehci-platform 1c1a000.usb: new USB bus registered, assigned bus number 1
[ 0.841045] ehci-platform 1c1a000.usb: irq 25, io mem 0x01c1a000
[ 0.868009] ehci-platform 1c1a000.usb: USB 2.0 started, EHCI 1.00
[ 0.875250] hub 1-0:1.0: USB hub found
[ 0.879215] hub 1-0:1.0: 1 port detected
[ 0.883841] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[ 0.890178] ohci-platform: OHCI generic platform driver
[ 0.895744] ohci-platform 1c1a400.usb: Generic Platform OHCI controller
[ 0.902478] ohci-platform 1c1a400.usb: new USB bus registered, assigned bus number 2
[ 0.910466] ohci-platform 1c1a400.usb: irq 26, io mem 0x01c1a400
[ 0.983092] hub 2-0:1.0: USB hub found
[ 0.986937] hub 2-0:1.0: 1 port detected
[ 0.994249] usbcore: registered new interface driver usb-storage
[ 1.001881] sun6i-rtc 1c20400.rtc: registered as rtc0
[ 1.006947] sun6i-rtc 1c20400.rtc: RTC enabled
[ 1.011672] i2c /dev entries driver
[ 1.016594] input: ns2009_ts as /devices/platform/soc/1c2ac00.i2c/i2c-0/0-0048/input/input0
[ 1.026294] sunxi-wdt 1c20ca0.watchdog: Watchdog enabled (timeout=16 sec, nowayout=0)
[ 1.034965] sun8i-v3s-pinctrl 1c20800.pinctrl: 1c20800.pinctrl supply vcc-pf not found, using dummy regulator
[ 1.070622] sunxi-mmc 1c0f000.mmc: initialized, max. request size: 16384 KB
[ 1.078185] sun8i-v3s-pinctrl 1c20800.pinctrl: 1c20800.pinctrl supply vcc-pg not found, using dummy regulator
[ 1.089610] usbcore: registered new interface driver usbhid
[ 1.095192] usbhid: USB HID core driver
[ 1.101882] Initializing XFRM netlink socket
[ 1.106198] NET: Registered protocol family 17
[ 1.111332] Registering SWP/SWPB emulation handler
[ 1.117215] Loading compiled-in X.509 certificates
[ 1.127287] simple-framebuffer 43e89000.framebuffer: framebuffer at 0x43e89000, 0x177000 bytes, mapped to 0x(ptrval)
[ 1.137984] simple-framebuffer 43e89000.framebuffer: format=x8r8g8b8, mode=800x480x32, linelength=3200
[ 1.154206] Console: switching to colour frame buffer device 100x30
[ 1.166345] simple-framebuffer 43e89000.framebuffer: fb0: simplefb registered!
[ 1.175200] usb_phy_generic usb_phy_generic.0.auto: usb_phy_generic.0.auto supply vcc not found, using dummy regulator
[ 1.186725] musb-hdrc musb-hdrc.1.auto: MUSB HDRC host driver
[ 1.192577] musb-hdrc musb-hdrc.1.auto: new USB bus registered, assigned bus number 3
[ 1.201686] hub 3-0:1.0: USB hub found
[ 1.205564] hub 3-0:1.0: 1 port detected
[ 1.211074] sun6i-rtc 1c20400.rtc: setting system clock to 1970-01-01T02:35:28 UTC (9328)
[ 1.219621] vcc3v0: disabling
[ 1.222604] vcc5v0: disabling
[ 1.225571] ALSA device list:
[ 1.228600] No soundcards found.
[ 1.236091] jffs2: Node at 0x00000c38 with length 0x00000752 would run over the end of the erase block
[ 1.245538] jffs2: Perhaps the file system was created with the wrong erase size?
[ 1.253191] jffs2: jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00000c3c: 0x0752 instead
[ 1.262793] jffs2: jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00000c40: 0xe5db instead
[ 1.272355] jffs2: jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00000c44: 0x0017 instead
[ 1.281847] jffs2: jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00000c48: 0x0001 instead
[ 1.291325] jffs2: jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00000c4c: 0x81ed instead
[ 1.300801] jffs2: jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00000c50: 0x03e8 instead
[ 1.310278] jffs2: jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00000c54: 0x4bdc instead
请教一下,是什么地方做错了?
以前没有怎么用C51写过较大的程序,这次因为一个项目的原因,用C51写程序,踩了很多坑,这里总结分享一下,愚人千虑必有一得。
## 常见的中断陷阱之一: volatile变量
如果,中断中修改了一个变量的值,这个变量会被另外的函数访问,这个变量应该声明为 volatile
## 常见的中断陷阱: 临界区
用于中断的引入,程序中产生了真正的并发。
假设有一个变量a,在中断服务isr和funA中都访问了同一个变量a,而对a的操作是非原子的(即对a的操作需要多于1条指令),那么可能发生的情况是funA对a的操作还没有完成,中断发生了,等中断返回,回到funA后,变量a的值已经被破坏了,但funA并不知道,因此将得到了一个错误结果。
对中断和普通函数共享变量的访问,应该是原子操作。如果不是原子操作,那么对变量访问期间,应该关闭中断。
显然,16或32bit 变量操作,在8位CPU中,是非原子的,对他们的操作应该关闭中断。
还有一些8位变量的操作也是非原子操作。操作flags |= 0x80在51单片机中,是非原子的。
## 常见的中断陷阱: 堆栈溢出
中断的返回地址和寄存器是保存在堆栈之中的,所以中断执行时,应该有足够的堆栈空间。
堆栈溢出通常发生在非常深的子程序调用中。
## 常见的中断陷阱: 使用不可重入的函数
特别值得说明的是,整数乘法、浮点数操作可能使用外部的支持函数来实现的。
尽可能避免在中断中调用不可重入的函数,因为这很可能产生难以发现的bug
函数funA是不可重入的,在其内部使用了固定地址的存储空间;若funA在执行过程中,被某一个中断打断,而该中断服务函数又调用了funA,那么中断将破坏原本funA的执行现场,导致错误。这种错误不一定会发生,但如果发生,将非常难于发现。
### 不可重入的函数什么时候会导致错误
C51在固定的位置分配变量的存储空间。一个函数,如果在执行中途,被中断打断,而且中断中又再次调用该函数,那么中断就可能破坏掉原来的执行现场(分配在固定空间的值)导致执行出错。
我来发一个PC机上的测试数据,配置为R7 2700的KVM虚拟机,分配了8核和8G内存。不考虑sysbench的版本的话,速度是V3s的70倍。
sysbench --test=cpu --cpu-max-prime=20000 run
WARNING: the --test option is deprecated. You can pass a script name or path on the command line without any options.
sysbench 1.0.15 (using system LuaJIT 2.0.5)
Running the test with following options:
Number of threads: 1
Initializing random number generator from current time
Prime numbers limit: 20000
Initializing worker threads...
Threads started!
CPU speed:
events per second: 686.40
General statistics:
total time: 10.0002s
total number of events: 6865
Latency (ms):
min: 1.31
avg: 1.45
max: 1.85
95th percentile: 1.52
sum: 9947.28
Threads fairness:
events (avg/stddev): 6865.0000/0.00
execution time (avg/stddev): 9.9473/0.00
页次: 1