1. 项目缘起与整体设计思路
1.1 为什么要在iTOP-4412上折腾蓝牙移植
手里有一块iTOP-4412开发板,跑的是Android 4.4,板子本身没有板载蓝牙模块,但项目需求要求实现蓝牙音频传输和串口数据透传。这个需求在当年的嵌入式圈子里非常典型——三星Exynos 4412这颗四核A9处理器性能足够,但Android 4.4的蓝牙协议栈(Bluetooth Stack)默认走的是BlueZ还是Bluedroid,取决于芯片原厂的BSP包怎么配。iTOP-4412的官方BSP默认没有启用蓝牙相关的HCI接口,所以整个移植过程本质上就是三件事:打通硬件层的UART/I2S通道、把HCI协议栈跑起来、让上层应用能正常调用BluetoothAdapter。
我前后折腾了大概两周,中间踩了不少坑,包括串口流控配置错误导致HCI命令超时、蓝牙固件加载失败、以及Android 4.4特有的Bluedroid初始化顺序问题。这篇文章就把整个移植过程拆开揉碎讲清楚,适合手里有iTOP-4412或者类似Exynos 4412平台、需要在Android 4.4上做蓝牙移植的嵌入式开发者参考。即使你用的是其他开发板,只要蓝牙芯片走UART HCI接口,整体思路也是通用的。
1.2 方案选型:为什么选UART HCI而不是SDIO或USB
蓝牙模块和主控之间的物理接口常见的有三种:UART、SDIO、USB。iTOP-4412开发板引出了多路UART,其中UART2和UART3可以通过排针引出,而SDIO接口已经被WiFi模块占用,USB Host虽然可用但Android 4.4对USB蓝牙适配器的支持并不友好,需要额外改HAL层。所以UART HCI是最稳妥的选择。
具体来说,我选用的蓝牙模块是常见的CSR8311方案(基于CSR8811芯片),支持蓝牙4.0双模,走UART HCI接口,波特率最高支持3Mbps。这个模块在当年的开发板圈子里很常见,固件和驱动资料相对好找。模块和开发板的连接方式如下:
| 模块引脚 | iTOP-4412引脚 | 功能说明 |
|---|---|---|
| VCC | 3.3V | 供电,注意模块峰值电流约100mA |
| GND | GND | 共地 |
| TXD | UART2_RXD | 模块发送,板子接收 |
| RXD | UART2_TXD | 模块接收,板子发送 |
| CTS | UART2_CTS | 硬件流控,必须接 |
| RTS | UART2_RTS | 硬件流控,必须接 |
| PCM_SYNC | 悬空 | 音频走HCI PCM,暂不使用 |
注意:CSR8311的UART电平是1.8V,而iTOP-4412的UART2默认是3.3V电平,直接连接会烧模块。我一开始就犯了这个错误,烧了一个模块才反应过来。后来加了一片TXS0108E电平转换芯片才解决。如果你用的模块是3.3V电平,那就可以直连。
1.3 Android 4.4蓝牙架构的版本特殊性
Android 4.4的蓝牙协议栈处于一个过渡期。Android 4.2之前用的是BlueZ,4.2开始Google引入了Bluedroid(博通贡献的协议栈),到4.4时Bluedroid已经比较稳定了,但和BlueZ的配置方式完全不同。iTOP-4412的BSP包里默认是BlueZ的配置,所以第一步要确认BSP里到底用的是哪套协议栈。
判断方法很简单,看external/bluetooth/目录下有没有bluedroid文件夹。如果有,说明BSP已经集成了Bluedroid;如果没有,只有bluez,那就需要自己把Bluedroid的源码移植进来。我拿到的BSP包里两者都有,但默认编译的是BlueZ,所以需要在BoardConfig.mk里把BOARD_HAVE_BLUETOOTH和BLUETOOTH_HCI_USE_MCT这两个宏重新配置。
2. 核心细节解析与实操要点
2.1 内核层:UART HCI驱动的配置与调试
内核层的核心工作是让HCI数据能通过UART正常收发。Exynos 4412的UART驱动在drivers/tty/serial/samsung.c里,但蓝牙HCI需要走drivers/bluetooth/hci_ldisc.c这条线路。具体配置步骤如下:
第一步,确认内核配置里打开了以下选项:
CONFIG_BT=y CONFIG_BT_HCIUART=y CONFIG_BT_HCIUART_H4=y CONFIG_BT_HCIUART_BCSP=y CONFIG_BT_HCIUART_LL=y CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=y CONFIG_BT_HIDP=y其中CONFIG_BT_HCIUART_H4是必须的,因为CSR8311用的是H4协议(HCI UART Transport Layer)。如果你用的是其他模块,比如TI的CC256x,可能需要BCSP协议。
第二步,在板级配置文件里注册UART2作为蓝牙HCI接口。在arch/arm/mach-exynos/board-itop4412.c里添加:
static struct platform_device itop_bluetooth_device = { .name = "bluetooth", .id = -1, .dev = { .platform_data = &itop_bt_platform_data, }, };同时需要配置UART2的GPIO复用功能,把GPA1_0到GPA1_3设置为UART2的TXD、RXD、CTS、RTS。这个在arch/arm/mach-exynos/setup-uart.c里改,具体寄存器操作是设置GPA1CON的对应位为0x2(UART功能)。
第三步,编译内核后通过串口终端验证。加载hci_uart模块后,用hciconfig命令应该能看到hci0设备:
insmod hci_uart.ko hciconfig -a如果看到hci0但状态是DOWN,说明驱动加载成功但HCI通道还没建立。这时候需要用hcitool发送HCI Reset命令测试:
hcitool -i hci0 cmd 0x03 0x0003如果返回HCI Command timeout,大概率是流控没配对。CSR8311默认启用硬件流控,所以内核里必须把UART2的CRTSCTS标志打开。在board-itop4412.c里配置UART2的platform data时加上.flags = UPF_BOOT_AUTOCONF | UPF_CONS_FLOW。
实操心得:调试HCI UART时,最有效的工具是逻辑分析仪。我一开始用示波器看TX/RX波形,发现发送HCI Reset后模块没有任何回应,后来用逻辑分析仪抓CTS/RTS信号,才发现RTS一直拉高导致模块无法发送数据。把流控配置改对之后,HCI Reset立刻返回了
04 0E 04 01 03 0C 00,这就是成功的标志。
2.2 协议栈层:Bluedroid的初始化流程与配置修改
Android 4.4的Bluedroid初始化流程比BlueZ复杂得多,核心入口在external/bluetooth/bluedroid/btif/src/btif_core.c的btif_init_bluetooth()函数。整个初始化顺序是:HCI层初始化 -> BTU层初始化 -> BTA层初始化 -> 各Profile注册。任何一步失败都会导致蓝牙打不开。
关键配置在external/bluetooth/bluedroid/include/bt_target.h里,需要确认以下宏定义:
#define BTU_BTA_INCLUDED TRUE #define BTA_INCLUDED TRUE #define BTIF_AV_INCLUDED TRUE #define BTIF_A2DP_SINK_INCLUDED TRUE #define BTIF_A2DP_SOURCE_INCLUDED TRUE #define BTIF_RFCOMM_INCLUDED TRUE另外,bt_stack.conf文件里的配置也很关键。这个文件在/system/etc/bluetooth/目录下,主要配置日志级别和HCI通道参数:
BtLogLevel=2 BtLogMask=0x1F BtHciChannel=1 BtA2dpSinkEnabled=true BtA2dpSourceEnabled=true其中BtHciChannel=1表示使用/dev/ttyS1作为HCI通道,对应内核里的UART2。如果你的板子用的是其他UART口,这里要相应修改。
还有一个容易忽略的点:Android 4.4的Bluedroid默认会尝试加载/system/etc/firmware/下的蓝牙固件。CSR8311需要csr8311_fw.bin和csr8311_patch.bin两个文件。如果固件加载失败,HCI Reset能成功但后续的Read Local Version会返回错误。固件文件需要从模块厂商提供的资料包里提取,然后用adb push放到对应目录,权限设为644。
2.3 硬件抽象层:HAL与JNI的适配
Android 4.4的蓝牙HAL层在hardware/libhardware/include/hardware/bluetooth.h里定义,具体实现在external/bluetooth/bluedroid/下。iTOP-4412的BSP包里通常已经包含了HAL层的实现,但需要确认bluetooth.default.so这个库是否被正确编译和安装。
检查方法是在out/target/product/itop4412/system/lib/hw/目录下看有没有bluetooth.default.so。如果没有,需要在device/samsung/itop4412/BoardConfig.mk里加上:
BOARD_HAVE_BLUETOOTH := true BOARD_HAVE_BLUETOOTH_BCM := false BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR := device/samsung/itop4412/bluetooth然后在device/samsung/itop4412/bluetooth/bdroid_buildcfg.h里配置:
#define BTM_DEF_LOCAL_NAME "iTOP-4412-BT" #define BTA_DM_COD {0x1A, 0x01, 0x0C} #define BTIF_AV_SOURCE_ENABLED TRUE #define BTIF_AV_SINK_ENABLED TRUEJNI层的适配相对简单,因为Android 4.4的JNI接口已经标准化了,只要HAL层实现正确,上层BluetoothAdapter就能正常调用。但有一个坑:Android 4.4的BluetoothManagerService在启动时会检查bluetooth.default.so的版本号,如果版本不匹配会直接拒绝加载。这个版本号在bluetooth.h里的HAL_VERSION宏定义,需要和系统期望的一致。
3. 实操过程与核心环节实现
3.1 硬件连接与电平匹配的完整操作
硬件连接是整个移植的基础,接错了后面全是白费功夫。我整理了一份详细的连接检查清单:
| 检查项 | 正确状态 | 错误后果 |
|---|---|---|
| 供电电压 | 3.3V ±5% | 电压过高烧模块,过低无法启动 |
| 电平匹配 | 1.8V转3.3V | 直连会烧模块或通信失败 |
| TXD/RXD交叉 | 模块TXD接板子RXD | 接反了完全无通信 |
| CTS/RTS连接 | 必须交叉连接 | 流控失效,HCI超时 |
| 地线连接 | 共地 | 信号电平漂移,通信不稳定 |
| 天线连接 | 2.4G天线接好 | 信号极弱,搜索不到设备 |
电平转换我用的是TXS0108E,这是一款8通道双向电平转换芯片,支持1.8V和3.3V之间的转换。接线方式是:A端接1.8V参考电压和模块侧信号,B端接3.3V参考电压和板子侧信号,OE引脚接3.3V使能。实测下来,不加电平转换的话,模块的TXD输出1.8V高电平,板子的UART2输入阈值是2.0V,勉强能识别但误码率很高,表现为HCI命令偶尔超时。
天线部分也要注意,CSR8311模块通常用的是IPEX接口或者板载陶瓷天线。如果用IPEX接口,一定要接2.4G频段的天线,我试过接错5G天线,结果蓝牙搜索距离不到10厘米。
3.2 内核编译与设备树配置的详细步骤
iTOP-4412的BSP包用的是传统的板级文件而不是设备树(Device Tree),所以配置都在arch/arm/mach-exynos/目录下。具体编译步骤如下:
第一步,进入内核源码目录,执行配置:
cd kernel make itop4412_android_defconfig make menuconfig在menuconfig里确认以下配置:
Networking support -> Bluetooth subsystem support -> Bluetooth device drivers -> HCI UART driver选中HCI UART driver后,进入子菜单,把H4 protocol选上。同时确认RFCOMM protocol support、BNEP protocol support、HIDP protocol support都选上。
第二步,修改板级文件。在arch/arm/mach-exynos/board-itop4412.c里添加蓝牙设备的platform data:
static struct resource itop_bt_resources[] = { [0] = { .start = EXYNOS4_PA_UART2, .end = EXYNOS4_PA_UART2 + 0x100, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_UART2, .end = IRQ_UART2, .flags = IORESOURCE_IRQ, }, }; static struct platform_device itop_bt_device = { .name = "hci_uart", .id = 0, .num_resources = ARRAY_SIZE(itop_bt_resources), .resource = itop_bt_resources, };然后在itop4412_devices[]数组里加上&itop_bt_device。
第三步,配置UART2的GPIO。在arch/arm/mach-exynos/setup-uart.c里找到exynos4_uart2_cfg_gpio函数,确认GPIO配置为:
s3c_gpio_cfgpin(GPIO_UART2_TXD, S3C_GPIO_SFN(0x2)); s3c_gpio_cfgpin(GPIO_UART2_RXD, S3C_GPIO_SFN(0x2)); s3c_gpio_cfgpin(GPIO_UART2_CTS, S3C_GPIO_SFN(0x2)); s3c_gpio_cfgpin(GPIO_UART2_RTS, S3C_GPIO_SFN(0x2));第四步,编译内核:
make -j4编译完成后,用fastboot或者dd命令把zImage烧写到开发板的boot分区。
实操心得:编译内核时最容易出错的地方是GPIO冲突。iTOP-4412的UART2引脚和某些GPIO扩展口是复用的,如果BSP里其他地方也配置了这些引脚,会导致编译报错或者运行时冲突。我的做法是在
board-itop4412.c里搜索GPA1,把所有涉及GPA1_0到GPA1_3的配置都注释掉,确保只有UART2在用。
3.3 Android系统层的编译与固件打包
内核编译好之后,还需要编译Android系统层。iTOP-4412的Android 4.4源码编译流程如下:
第一步,设置环境变量:
source build/envsetup.sh lunch itop4412-eng第二步,修改device/samsung/itop4412/BoardConfig.mk,确保蓝牙相关配置正确:
BOARD_HAVE_BLUETOOTH := true BOARD_HAVE_BLUETOOTH_BCM := false BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR := device/samsung/itop4412/bluetooth BOARD_BLUEDROID_VENDOR_CONF := device/samsung/itop4412/bluetooth/vnd_itop4412.txt第三步,在device/samsung/itop4412/bluetooth/目录下创建bdroid_buildcfg.h,内容如下:
#ifndef _BDROID_BUILDCFG_H #define _BDROID_BUILDCFG_H #define BTM_DEF_LOCAL_NAME "iTOP-4412" #define BTA_DM_COD {0x1A, 0x01, 0x0C} #define BTIF_AV_SOURCE_ENABLED TRUE #define BTIF_AV_SINK_ENABLED TRUE #define BTIF_HF_CLIENT_ENABLED TRUE #define BTIF_HF_SERVICE_ENABLED TRUE #endif第四步,编译整个系统:
make -j4编译完成后,在out/target/product/itop4412/目录下会生成system.img、boot.img、userdata.img等镜像文件。用fastboot烧写到开发板。
第五步,烧写完成后,把蓝牙固件文件推送到开发板:
adb push csr8311_fw.bin /system/etc/firmware/ adb push csr8311_patch.bin /system/etc/firmware/ adb shell chmod 644 /system/etc/firmware/csr8311_fw.bin adb shell chmod 644 /system/etc/firmware/csr8311_patch.bin然后重启开发板,进入系统设置里的蓝牙选项,应该就能打开蓝牙并搜索到设备了。
3.4 蓝牙功能验证与性能测试
系统启动后,验证蓝牙功能是否正常,我一般按以下顺序测试:
第一,检查HCI设备是否就绪:
adb shell hciconfig -a正常输出应该包含hci0的详细信息,包括BD Address、Features、Packet type等。
第二,测试蓝牙扫描:
adb shell hcitool scan如果能扫描到周围的蓝牙设备,说明射频部分工作正常。
第三,测试A2DP音频传输。需要先配对蓝牙耳机,然后播放音乐。Android 4.4的A2DP Sink和Source都需要在bdroid_buildcfg.h里启用。实测下来,CSR8311的A2DP音质在SBC编码下延迟约200ms,看视频会有明显音画不同步,但听音乐没问题。
第四,测试RFCOMM串口透传。这个在工业场景里很常用,可以用rfcomm命令绑定串口:
adb shell rfcomm bind /dev/rfcomm0 <目标MAC地址> 1然后通过/dev/rfcomm0收发数据。
性能测试方面,我测了以下几个指标:
| 测试项 | 结果 | 备注 |
|---|---|---|
| 蓝牙扫描距离 | 约8米 | 空旷环境,板载天线 |
| A2DP音频延迟 | 约200ms | SBC编码,44.1kHz |
| RFCOMM吞吐量 | 约80KB/s | 115200波特率下 |
| 配对成功率 | 95%以上 | 首次配对偶尔失败 |
| 待机功耗增加 | 约15mA | 蓝牙开启但未连接 |
4. 常见问题与排查技巧实录
4.1 HCI命令超时与流控问题排查
HCI命令超时是移植过程中最常见的问题,表现是hciconfig能看到hci0但状态一直是DOWN,或者hcitool cmd返回HCI Command timeout。排查思路如下:
首先确认硬件流控是否配置正确。CSR8311默认启用硬件流控,如果内核里没有配置CRTSCTS,模块会因为RTS信号不对而拒绝接收数据。检查方法是在内核启动日志里搜索ttyS1,看有没有flow control相关的打印。
其次确认波特率是否匹配。CSR8311上电后的默认波特率是115200,但有些模块的固件会把波特率改成3Mbps。如果内核里配置的是115200而模块实际跑3Mbps,就会通信失败。解决方法是在hci_uart驱动初始化时先发送HCI命令切换波特率,或者直接用模块厂商提供的工具修改模块的默认波特率。
还有一个隐蔽的问题:UART2的时钟源配置错误。Exynos 4412的UART时钟来自CLK_UART2,如果这个时钟没使能,UART2根本无法工作。检查方法是在内核里加打印:
printk(KERN_INFO "UART2 clock rate: %lu\n", clk_get_rate(uart_clk));正常应该是100000000(100MHz)或者50000000(50MHz)。
4.2 蓝牙固件加载失败的解决路径
固件加载失败的表现是HCI Reset能成功,但Read Local Version返回的版本号不对,或者蓝牙能打开但搜索不到任何设备。排查步骤如下:
第一步,确认固件文件是否存在且权限正确:
adb shell ls -l /system/etc/firmware/应该看到csr8311_fw.bin和csr8311_patch.bin,权限是-rw-r--r--。
第二步,确认固件文件的内容是否正确。CSR8311的固件文件有特定的头部格式,如果文件损坏或者版本不对,加载会失败。可以用hexdump查看文件头:
adb shell hexdump -C /system/etc/firmware/csr8311_fw.bin | head -5正常的文件头应该是00 00 00 00开头,后面跟着固件长度和校验和。
第三步,检查内核日志里有没有固件加载相关的错误:
adb shell dmesg | grep -i firmware如果看到firmware request failed或者invalid firmware header,说明固件文件有问题,需要重新从模块厂商那里获取。
实操心得:CSR8311的固件分为两部分,
fw.bin是主固件,patch.bin是补丁文件。有些模块厂商只提供fw.bin,这时候需要在bt_stack.conf里把BtPatchEnabled设为false,否则Bluedroid会一直尝试加载不存在的补丁文件,导致初始化超时。
4.3 蓝牙打开后自动关闭的排查方法
蓝牙打开后几秒钟自动关闭,这是Android 4.4上比较棘手的问题。根本原因通常是Bluedroid初始化过程中某个Profile注册失败,导致整个协议栈回滚。排查方法如下:
首先抓取logcat日志:
adb logcat -s BluetoothManagerService:V btif:V btu:V重点关注btif_init_bluetooth之后的日志,如果看到BTA_EnableBluetooth failed或者btif_core_init failed,说明初始化失败。
其次检查bt_stack.conf里的配置是否完整。Android 4.4的Bluedroid需要以下配置项:
BtLogLevel=2 BtLogMask=0x1F BtHciChannel=1 BtA2dpSinkEnabled=true BtA2dpSourceEnabled=true BtHfpEnabled=true BtHidEnabled=true如果缺少BtHfpEnabled,HFP Profile注册会失败,导致蓝牙自动关闭。
还有一个常见原因是bluetooth.default.so的版本不匹配。Android 4.4的HAL版本号是0x0100,如果编译出来的库版本号是0x0200,系统会拒绝加载。检查方法是在hardware/libhardware/include/hardware/bluetooth.h里确认HAL_VERSION宏的值。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| hciconfig看不到hci0 | 内核驱动未加载 | 检查CONFIG_BT_HCIUART是否编译进内核 |
| HCI Command timeout | 流控未配置 | 内核里启用CRTSCTS |
| 蓝牙打开后自动关闭 | Profile注册失败 | 检查bt_stack.conf配置完整性 |
| 搜索不到设备 | 天线未接或固件未加载 | 检查天线连接和固件文件 |
| A2DP音频卡顿 | 波特率太低 | 把UART波特率提高到921600以上 |
| 配对失败 | COD配置错误 | 修改bdroid_buildcfg.h里的BTA_DM_COD |
| RFCOMM连接断开 | 流控或缓冲区溢出 | 增大UART接收缓冲区 |
| 蓝牙MAC地址为00:00:00:00:00:00 | 固件未加载 | 检查固件文件路径和权限 |
5. 移植后的优化与扩展方向
5.1 提升蓝牙音频传输质量的参数调优
A2DP音频传输质量受多个参数影响,我在实测中总结了几组优化配置。首先是UART波特率,CSR8311支持最高3Mbps,但iTOP-4412的UART2在3Mbps下误码率较高,建议用921600或者1.5Mbps。修改方法是在内核里配置UART2的波特率为921600:
static struct s3c2410_uartcfg itop_uart2_cfg = { .hwport = 2, .flags = 0, .ucon = 0x3c5, .ulcon = 0x03, .ufcon = 0x51, .clk_rate = 921600, };其次是A2DP的编码参数。Android 4.4的Bluedroid默认用SBC编码,码率是328kbps。如果追求更高音质,可以在btif_av.c里修改BTIF_A2DP_DEFAULT_BITRATE为512kbps,但需要模块支持。实测下来,512kbps下音频延迟会增加到300ms左右,看视频的话音画不同步会更明显。
还有一个优化点是减少HCI命令的轮询间隔。Android 4.4的Bluedroid默认每100ms轮询一次HCI事件,如果改成50ms,蓝牙响应速度会更快,但功耗会增加约10%。修改位置在btu_hcif.c里的BTU_HCIF_CMD_TIMEOUT宏。
5.2 蓝牙与WiFi共存的干扰处理
iTOP-4412上WiFi和蓝牙都工作在2.4G频段,如果同时使用,会出现明显的干扰。表现是WiFi吞吐量下降、蓝牙音频卡顿。解决方法有以下几种:
第一种是时分复用。在bt_stack.conf里启用BtCoexEnabled=true,让Bluedroid和WiFi驱动协调信道使用。但这个需要WiFi驱动也支持共存接口,iTOP-4412的WiFi模块是RTL8188EU,默认不支持,需要改驱动。
第二种是信道避让。把WiFi固定在1、6、11信道中的一个,蓝牙跳频时会避开这些信道。实测下来,WiFi用信道1时,蓝牙音频卡顿明显减少。
第三种是降低蓝牙发射功率。在bdroid_buildcfg.h里设置BTM_DEF_TX_POWER为0x04(约0dBm),减少对WiFi的干扰。但这样蓝牙传输距离会缩短到3米左右。
5.3 后续可扩展的功能方向
蓝牙移植完成后,还可以在此基础上扩展更多功能。比如蓝牙BLE(低功耗蓝牙),CSR8311支持BLE 4.0,但Android 4.4的Bluedroid对BLE的支持还不完善,需要打补丁。补丁主要在btif_gatt.c和bta_gattc.c里,增加GATT Client和Server的初始化代码。
另一个方向是蓝牙HID设备模拟,把开发板模拟成蓝牙键盘或鼠标。这个需要在bdroid_buildcfg.h里启用BTIF_HID_DEVICE_ENABLED,然后实现HID Report Descriptor。实测下来,Android 4.4的HID Device模式比较稳定,延迟在20ms左右,可以用来做远程控制。
还有一个实用的扩展是蓝牙串口透传的自动化。在工业场景里,经常需要开发板通过蓝牙和传感器通信。可以写一个守护进程,监听/dev/rfcomm0,收到数据后自动转发到指定串口。这个用rfcomm命令加cat和echo就能实现,不需要写代码。
整个移植过程大概就是这样,从硬件连接到内核配置,再到系统层编译和调优,每一步都有坑,但踩过去之后回头看,其实逻辑很清晰。最关键的是理解HCI UART的通信机制和Bluedroid的初始化流程,剩下的就是耐心调试。我在实际操作中的体会是,逻辑分析仪和示波器是必备工具,光靠看日志很难定位硬件层的问题。另外,固件文件一定要从可靠渠道获取,版本不对的话,后面所有配置都是白费功夫。